From 782ce1631d8ba5121c5632ac153c6343ffe0ab36 Mon Sep 17 00:00:00 2001 From: Cem Bassoy Date: Sun, 3 Mar 2019 14:47:33 +0100 Subject: [PATCH 01/36] readme updated. --- README.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 66e2b271f..9570d8bd8 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,18 @@ -Boost.uBLAS Linear Algebra Library +Boost Linear and Multilinear Algebra Library ===== -Boost.uBLAS is part of the [Boost C++ Libraries](http://github.com/boostorg). It is directed towards scientific computing on the level of basic linear algebra constructions with matrices and vectors and their corresponding abstract operations. +[![Language](https://img.shields.io/badge/C%2B%2B-11-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) +[![License](https://img.shields.io/badge/license-BSL-blue.svg)](https://opensource.org/licenses/BSL-1.0) +[![Documentation](https://img.shields.io/badge/ublas-documentation-blue.svg)](https://www.boost.org/doc/libs/1_69_0/libs/numeric/ublas/doc/index.html) +[![Wiki](https://img.shields.io/badge/ublas-wiki-blue.svg)](https://github.com/boostorg/ublas/wiki) +[![Mailing List](https://img.shields.io/badge/ublas-mailing%20list-4eb899.svg)](https://lists.boost.org/mailman/listinfo.cgi/ublas) +[![Gitter](https://img.shields.io/badge/ublas-chat%20on%20gitter-4eb899.svg)](https://gitter.im/boostorg/ublas) + +**Boost.uBLAS** is part of the [Boost C++ Libraries](http://github.com/boostorg). It is directed towards scientific computing on the level of basic linear and multilinear algebra operations with tensors, matrices and vectors. ## Documentation uBLAS is documented at [boost.org](https://www.boost.org/doc/libs/1_69_0/libs/numeric/ublas/doc/index.html). -The development has a [wiki page](https://github.com/uBLAS/ublas/wiki). -The tensor extension has a separate [wiki page](https://github.com/BoostGSoC18/tensor/wiki). +The tensor extension has a [wiki page](https://github.com/BoostGSoC18/tensor/wiki). ## License Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). @@ -21,10 +27,10 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org ## Build Status -Branch | Travis | Appveyor | codecov.io | Docs | -:-------------: | ------ | -------- | ---------- | ---- | -[`master`](https://github.com/boostorg/ublas/tree/master) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=master)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/master?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/master) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) -[`develop`](https://github.com/boostorg/ublas/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=develop)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/develop?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/develop) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) +Branch | Travis | Appveyor | Regression | codecov.io | Docs | +:-------------: | ------ | -------- | ---------- | ---------- | ---- | +[`master`](https://github.com/boostorg/ublas/tree/master) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=master)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/master?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/master) | [![ublas](https://img.shields.io/badge/ublas-master-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) +[`develop`](https://github.com/boostorg/ublas/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=develop)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/develop?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/develop) | [![ublas](https://img.shields.io/badge/ublas-develop-blue.svg)](https://www.boost.org/development/tests/develop/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) ## Directories @@ -39,6 +45,7 @@ Branch | Travis | Appveyor | codecov.io | Docs | ## More information +* If you would like to test the library, contribute new feature or a bug fix, see [contribution](https://github.com/boostorg/ublas/wiki/Guidelines-for-Contribution) where the whole development infrastructure and the contributing workflow is explained in details. * Ask questions in [stackoverflow](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-ublas) with `boost-ublas` or `ublas` tags. * Report [bugs](https://github.com/boostorg/ublas/issues) and be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well. * Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). From 1f5105a62b891745f6787dfb52e1522e9920af34 Mon Sep 17 00:00:00 2001 From: Ashar Date: Mon, 13 May 2019 01:37:02 +0530 Subject: [PATCH 02/36] Adds code coverage to ublas --- .ci/report_coverage.sh | 19 +++++++++++++++ .gitignore | 1 + .travis.yml | 22 ++++++++++++++---- README.md | 2 +- codecov.yml | 3 +++ include/boost/numeric/ublas/tensor/tensor.hpp | 23 ++++++++++--------- test/Jamfile | 2 +- test/tensor/Jamfile | 2 +- 8 files changed, 55 insertions(+), 19 deletions(-) create mode 100755 .ci/report_coverage.sh create mode 100644 .gitignore create mode 100644 codecov.yml diff --git a/.ci/report_coverage.sh b/.ci/report_coverage.sh new file mode 100755 index 000000000..0106329de --- /dev/null +++ b/.ci/report_coverage.sh @@ -0,0 +1,19 @@ +#! /bin/bash -e + +# Only collect and upload coverage reports from C++17 Builds +# This is required because Tensor Extension only runs with C++17 + +if [ $CXXSTD == '17' ] + then + # Capture all the coverge reports + lcov --rc lcov_branch_coverage=1 --directory $BOOST_ROOT --capture --output-file coverage.info + + # Remove all unwanted coverages libs. + # Boost.uBLAS depends uses many internal boost libs, we don't want them to be in coverage. + + lcov --rc lcov_branch_coverage=1 --extract coverage.info "*/boost/numeric/ublas/*" "*/libs/numeric/ublas/*" --output-file coverage.info + + lcov --rc lcov_branch_coverage=1 --list coverage.info +else + echo "Skipping Coverage Reporting as CXXSTD is 11" +fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..dbe9c82b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 6d9eac8ef..1aca62316 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,6 +40,7 @@ addons: - clinfo - opencl-headers - ocl-icd-opencl-dev + - lcov before_install: - if [ ${TRAVIS_OS_NAME} == "linux" ]; then .ci/install-ocl-ubuntu.sh; fi @@ -56,10 +57,11 @@ install: - git submodule update --init --jobs 8 libs/config - git submodule update --init --jobs 8 tools/boostdep - mkdir -p libs/numeric/ - - cp -r $TRAVIS_BUILD_DIR/* libs/numeric/ublas + - cp -rp $TRAVIS_BUILD_DIR/. libs/numeric/ublas - python tools/boostdep/depinst/depinst.py -I benchmarks numeric/ublas - ./bootstrap.sh - - ./b2 -j 8 headers + - ./b2 -j 8 headers + - export BOOST_ROOT="`pwd`" # Use before_script: to run configure steps before_script: @@ -72,9 +74,19 @@ script: echo "using clblas : : ${CLBLAS_PREFIX}/include ${CLBLAS_PREFIX}/lib ;" >> ~/user-config.jam; cp $TRAVIS_BUILD_DIR/opencl.jam ~/ cp $TRAVIS_BUILD_DIR/clblas.jam ~/ - - ./b2 -j 8 libs/numeric/ublas/test toolset=$TOOLSET cxxstd=$CXXSTD - - ./b2 -j 8 libs/numeric/ublas/benchmarks toolset=$TOOLSET cxxstd=$CXXSTD - - ./b2 -j 8 libs/numeric/ublas/examples/tensor toolset=$TOOLSET cxxstd=$CXXSTD + - cd libs/numeric/ublas + - $BOOST_ROOT/b2 -j 8 test toolset=$TOOLSET cxxstd=$CXXSTD + - $BOOST_ROOT/b2 -j 8 benchmarks toolset=$TOOLSET cxxstd=$CXXSTD + - $BOOST_ROOT/b2 -j 8 examples/tensor toolset=$TOOLSET cxxstd=$CXXSTD + +after_success: + - .ci/report_coverage.sh + # Uploading to CodeCov + # '-f' specifies file(s) to use and disables manual coverage gathering and file search which has already been done above + - curl -s https://codecov.io/bash > cov.sh + - chmod +x cov.sh + - ./cov.sh -f coverage.info || echo "Codecov did not collect coverage reports" + notifications: email: diff --git a/README.md b/README.md index 9570d8bd8..17e9f3e27 100644 --- a/README.md +++ b/README.md @@ -50,4 +50,4 @@ Branch | Travis | Appveyor | Regression | codecov.io | Docs | * Report [bugs](https://github.com/boostorg/ublas/issues) and be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well. * Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). * Developer discussions about the library are held on the [Boost developers mailing list](https://lists.boost.org/mailman/listinfo.cgi/ublas). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[ublas]` tag at the beginning of the subject line -* For any other questions, you can contact David, Stefan or Cem: david.bellot-AT-gmail-DOT-com, cem.bassoy-AT-gmail-DOT-com stefan-AT-seefeld-DOT-name +* For any other questions, you can contact David, Stefan or Cem: david.bellot-AT-gmail-DOT-com, cem.bassoy-AT-gmail-DOT-com stefan-AT-seefeld-DOT-name \ No newline at end of file diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..07a279125 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,3 @@ +fixes: + - "home/travis/build/*/boost-root/boost/::include/boost/" + - "home/travis/build/*/boost-root/libs/numeric/ublas/::" diff --git a/include/boost/numeric/ublas/tensor/tensor.hpp b/include/boost/numeric/ublas/tensor/tensor.hpp index ea4521c29..ea79b60cc 100644 --- a/include/boost/numeric/ublas/tensor/tensor.hpp +++ b/include/boost/numeric/ublas/tensor/tensor.hpp @@ -66,22 +66,23 @@ class vector; -/** @brief A dense tensor of values of type \c T. - * - * For a \f$n\f$-dimensional tensor \f$v\f$ and \f$0\leq i < n\f$ every element \f$v_i\f$ is mapped - * to the \f$i\f$-th element of the container. A storage type \c A can be specified which defaults to \c unbounded_array. - * Elements are constructed by \c A, which need not initialise their value. - * - * @tparam T type of the objects stored in the tensor (like int, double, complex,...) - * @tparam A The type of the storage array of the tensor. Default is \c unbounded_array. \c and \c std::vector can also be used - */ + /** @brief A dense tensor of values of type \c T. + * + * For a \f$n\f$-dimensional tensor \f$v\f$ and \f$0\leq i < n\f$ every element \f$v_i\f$ is mapped + * to the \f$i\f$-th element of the container. A storage type \c A can be specified which defaults to \c unbounded_array. + * Elements are constructed by \c A, which need not initialise their value. + * + * @tparam T type of the objects stored in the tensor (like int, double, complex,...) + * @tparam A The type of the storage array of the tensor. Default is \c unbounded_array. \c and \c std::vector can also be used + */ template> > class tensor: public detail::tensor_expression,tensor> { - static_assert( std::is_same::value || - std::is_same::value, "boost::numeric::tensor template class only supports first- or last-order storage formats."); + static_assert( std::is_same::value || + std::is_same::value, + "boost::numeric::tensor template class only supports first- or last-order storage formats."); using self_type = tensor; public: diff --git a/test/Jamfile b/test/Jamfile index 26b67b045..59f251e51 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -51,7 +51,7 @@ project boost-ublas-test : requirements BOOST_UBLAS_NO_EXCEPTIONS vacpp:"BOOST_UBLAS_NO_ELEMENT_PROXIES" - gcc:"-Wall -Wno-unknown-pragmas" + gcc:"-Wall -Wno-unknown-pragmas -O0 --coverage -g" --coverage msvc:/bigobj msvc:"/W4" # == all # The define of macros below prevent warnings about the checked versions of SCL and CRT libraries. diff --git a/test/tensor/Jamfile b/test/tensor/Jamfile index 0bbf2c569..7d7b18ec6 100644 --- a/test/tensor/Jamfile +++ b/test/tensor/Jamfile @@ -10,7 +10,7 @@ project boost/ublas/test/tensor : requirements # these tests require C++17 11:no - gcc:"-Wall -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-but-set-variable" + gcc:"-Wall -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-but-set-variable -O0 --coverage -g" --coverage ; alias unit_test_framework From a490a29cdcc95fd75cfcd23e46296e9cb5012fef Mon Sep 17 00:00:00 2001 From: Ashar Date: Mon, 20 May 2019 23:32:12 +0530 Subject: [PATCH 03/36] Disable coverage for non-tensor unit tests --- test/Jamfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Jamfile b/test/Jamfile index 59f251e51..26b67b045 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -51,7 +51,7 @@ project boost-ublas-test : requirements BOOST_UBLAS_NO_EXCEPTIONS vacpp:"BOOST_UBLAS_NO_ELEMENT_PROXIES" - gcc:"-Wall -Wno-unknown-pragmas -O0 --coverage -g" --coverage + gcc:"-Wall -Wno-unknown-pragmas" msvc:/bigobj msvc:"/W4" # == all # The define of macros below prevent warnings about the checked versions of SCL and CRT libraries. From 005b606a327da0c86e543110d42822ecc7382457 Mon Sep 17 00:00:00 2001 From: Ashar Date: Mon, 20 May 2019 23:46:10 +0530 Subject: [PATCH 04/36] Adding the expr_template and framework branch builds --- .appveyor.yml | 2 ++ .travis.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 527af3598..a6e824c0f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -11,6 +11,8 @@ branches: - master - develop - /feature\/.*/ + - expr_template + - framework environment: matrix: diff --git a/.travis.yml b/.travis.yml index 1aca62316..c8dc8105b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ branches: - develop - doc - ci + - expr_template + - framework # env: specifies additional global variables to define per row in build matrix env: From 8654ba7f478b35f2949ec0d1f966cf419336b05c Mon Sep 17 00:00:00 2001 From: Ashar Date: Mon, 20 May 2019 23:54:09 +0530 Subject: [PATCH 05/36] Adding tags and badges to README --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 17e9f3e27..87827cb82 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,12 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org ## Build Status -Branch | Travis | Appveyor | Regression | codecov.io | Docs | -:-------------: | ------ | -------- | ---------- | ---------- | ---- | -[`master`](https://github.com/boostorg/ublas/tree/master) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=master)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/master?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/master) | [![ublas](https://img.shields.io/badge/ublas-master-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) -[`develop`](https://github.com/boostorg/ublas/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=develop)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/develop?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/develop) | [![ublas](https://img.shields.io/badge/ublas-develop-blue.svg)](https://www.boost.org/development/tests/develop/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) + Branch | Travis | Appveyor | Regression | codecov.io | Docs | + :----------------------------------------------------------: | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ---- + [`expr_template`](https://github.com/BoostGSoC19/tensor/tree/expr_template) | | | [![ublas](https://img.shields.io/badge/tensor-expr_template-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | + [`framework`](https://github.com/BoostGSoC19/tensor/tree/framework) | | | [![ublas](https://img.shields.io/badge/tensor-framework-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | + [`master`](https://github.com/boostorg/ublas/tree/master) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=master)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/master?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/master) | [![ublas](https://img.shields.io/badge/ublas-master-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | + [`develop`](https://github.com/boostorg/ublas/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=develop)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/develop?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/develop) | [![ublas](https://img.shields.io/badge/ublas-develop-blue.svg)](https://www.boost.org/development/tests/develop/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | ## Directories From 832bc70c6f9c6cccbaf0d53a9f228a8c382b14e9 Mon Sep 17 00:00:00 2001 From: Ashar Date: Tue, 21 May 2019 00:13:59 +0530 Subject: [PATCH 06/36] Add all badges with refactoring --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 87827cb82..ff5b3ac58 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,10 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org ## Build Status - Branch | Travis | Appveyor | Regression | codecov.io | Docs | +Branch | Travis | Appveyor | Regression | codecov.io | Docs | :----------------------------------------------------------: | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ---- - [`expr_template`](https://github.com/BoostGSoC19/tensor/tree/expr_template) | | | [![ublas](https://img.shields.io/badge/tensor-expr_template-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | - [`framework`](https://github.com/BoostGSoC19/tensor/tree/framework) | | | [![ublas](https://img.shields.io/badge/tensor-framework-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | + [`expr_template`](https://github.com/BoostGSoC19/tensor/tree/expr_template) | [![Build Status](https://travis-ci.org/BoostGSoC19/tensor.svg?branch=expr_template)](https://travis-ci.org/BoostGSoC19/tensor) | [![Build status](https://ci.appveyor.com/api/projects/status/1aeqlamaymy3sas2/branch/expr_template?svg=true)](https://ci.appveyor.com/project/coder3101/tensor/branch/expr_template) | [![ublas](https://img.shields.io/badge/tensor-expr_template-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/BoostGSoC19/tensor/branch/expr_template/graph/badge.svg)](https://codecov.io/gh/BoostGSoC19/tensor) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | + [`framework`](https://github.com/BoostGSoC19/tensor/tree/framework) | [![Build Status](https://travis-ci.org/BoostGSoC19/tensor.svg?branch=framework)](https://travis-ci.org/BoostGSoC19/tensor) | [![Build status](https://ci.appveyor.com/api/projects/status/1aeqlamaymy3sas2/branch/framework?svg=true)](https://ci.appveyor.com/project/coder3101/tensor/branch/framwork) | [![ublas](https://img.shields.io/badge/tensor-framework-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/BoostGSoC19/tensor/branch/framework/graph/badge.svg)](https://codecov.io/gh/BoostGSoC19/tensor) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | [`master`](https://github.com/boostorg/ublas/tree/master) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=master)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/master?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/master) | [![ublas](https://img.shields.io/badge/ublas-master-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | [`develop`](https://github.com/boostorg/ublas/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=develop)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/develop?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/develop) | [![ublas](https://img.shields.io/badge/ublas-develop-blue.svg)](https://www.boost.org/development/tests/develop/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | From 0a37700bae0905dbe8f0a0587198062ccf7a5afe Mon Sep 17 00:00:00 2001 From: Ashar Date: Tue, 21 May 2019 00:21:49 +0530 Subject: [PATCH 07/36] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ff5b3ac58..2ba291c00 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org ## Build Status -Branch | Travis | Appveyor | Regression | codecov.io | Docs | - :----------------------------------------------------------: | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ---- +Branch | Travis | Appveyor | Regression | codecov.io | Docs | +:-----: | ------ | --------- | ----------- | ----------- | ----- | [`expr_template`](https://github.com/BoostGSoC19/tensor/tree/expr_template) | [![Build Status](https://travis-ci.org/BoostGSoC19/tensor.svg?branch=expr_template)](https://travis-ci.org/BoostGSoC19/tensor) | [![Build status](https://ci.appveyor.com/api/projects/status/1aeqlamaymy3sas2/branch/expr_template?svg=true)](https://ci.appveyor.com/project/coder3101/tensor/branch/expr_template) | [![ublas](https://img.shields.io/badge/tensor-expr_template-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/BoostGSoC19/tensor/branch/expr_template/graph/badge.svg)](https://codecov.io/gh/BoostGSoC19/tensor) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | [`framework`](https://github.com/BoostGSoC19/tensor/tree/framework) | [![Build Status](https://travis-ci.org/BoostGSoC19/tensor.svg?branch=framework)](https://travis-ci.org/BoostGSoC19/tensor) | [![Build status](https://ci.appveyor.com/api/projects/status/1aeqlamaymy3sas2/branch/framework?svg=true)](https://ci.appveyor.com/project/coder3101/tensor/branch/framwork) | [![ublas](https://img.shields.io/badge/tensor-framework-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/BoostGSoC19/tensor/branch/framework/graph/badge.svg)](https://codecov.io/gh/BoostGSoC19/tensor) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | [`master`](https://github.com/boostorg/ublas/tree/master) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=master)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/master?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/master) | [![ublas](https://img.shields.io/badge/ublas-master-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | @@ -52,4 +52,4 @@ Branch | Travis * Report [bugs](https://github.com/boostorg/ublas/issues) and be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well. * Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). * Developer discussions about the library are held on the [Boost developers mailing list](https://lists.boost.org/mailman/listinfo.cgi/ublas). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[ublas]` tag at the beginning of the subject line -* For any other questions, you can contact David, Stefan or Cem: david.bellot-AT-gmail-DOT-com, cem.bassoy-AT-gmail-DOT-com stefan-AT-seefeld-DOT-name \ No newline at end of file +* For any other questions, you can contact David, Stefan or Cem: david.bellot-AT-gmail-DOT-com, cem.bassoy-AT-gmail-DOT-com stefan-AT-seefeld-DOT-name From b31dee5bb0f480ad5a1ab78025b6a989c649d795 Mon Sep 17 00:00:00 2001 From: Ashar Date: Tue, 21 May 2019 01:26:30 +0530 Subject: [PATCH 08/36] Disable running unit tests of non-tensor modules --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c8dc8105b..74257e5de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -77,7 +77,7 @@ script: cp $TRAVIS_BUILD_DIR/opencl.jam ~/ cp $TRAVIS_BUILD_DIR/clblas.jam ~/ - cd libs/numeric/ublas - - $BOOST_ROOT/b2 -j 8 test toolset=$TOOLSET cxxstd=$CXXSTD + - $BOOST_ROOT/b2 -j 8 test/tensor toolset=$TOOLSET cxxstd=$CXXSTD - $BOOST_ROOT/b2 -j 8 benchmarks toolset=$TOOLSET cxxstd=$CXXSTD - $BOOST_ROOT/b2 -j 8 examples/tensor toolset=$TOOLSET cxxstd=$CXXSTD From cdf219ca0fe397caf02abb143e916cde70e8921a Mon Sep 17 00:00:00 2001 From: Ashar Date: Mon, 19 Aug 2019 02:16:07 +0530 Subject: [PATCH 09/36] Fix for Appveyor CI Failures Recently due to some changes to vcpkg the CI was failing to work with VS2017 using cached vcpkg. This is however fixed if we update the vcpkg. To prevent this from happening in future I am adding the upgrade to vcpkg as a pre-step for building our code. --- .appveyor.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 527af3598..1dc1f5013 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -21,10 +21,14 @@ environment: TOOLSET: msvc-14.0 CXXSTD: 11 -cache: - - c:\tools\vcpkg\installed\ +# cache: + # - c:\tools\vcpkg\installed\ install: + - cd "C:\Tools\vcpkg" + - git pull + - .\bootstrap-vcpkg.bat + - cd %appveyor_build_folder% # Install OpenCL runtime (driver) for Intel / Xeon package - appveyor DownloadFile "http://registrationcenter-download.intel.com/akdlm/irc_nas/9022/opencl_runtime_16.1.1_x64_setup.msi" - start /wait msiexec /i opencl_runtime_16.1.1_x64_setup.msi /qn /l*v msiexec2.log From e68819c645ae85aa3d432269edf467024d2793f8 Mon Sep 17 00:00:00 2001 From: Amit Singh Date: Tue, 14 Apr 2020 21:17:13 +0530 Subject: [PATCH 10/36] Phase 1: adding static extents and static strides fix macro for MSVC adding noexcept fixing test and making changes adding comparison test and adding resolving issue changing extents API fixing MSVC errors fixing MSVC error adding static prod function and adding std::array to static extents and static strides fixing get_number_list refactoring meta_function into type_traits and adding staic_traits for static_extents fixing extents_result_type_outer_prod and combining static_functions and functions removing unnecessary code and header file removing unnecessary forward declaration private member resize and adding removed constructors for matrix and vector changing size_t to std::size_t and fixing stride_t adding is_resizable type trait for tensor resizing improve documenting of is_resizable refactoring code changing msvc version in .yml changing toolset msvc-14.1 to msvc-14.16 and adding VSCLCOMPILER changing toolset msvc-14.2 and image to VS 2019 refactoring code and adding new matrix to appveyor adding VS 2019 with msvc-14.1 and disabling VS 2019 with msvc-14.2 and c++2a adding VS 2019 with msvc-14.2 and changing flag to latest removing VS 2019 with msvc-14.2 and c++17 and adding timeout to travis.yml travis_wait workaround removing VS 2017 from appveyor and refactoring code adding clang support for c++17 and c++20 and refactoring code changing dist to bionic and adding source link to clang 10 fixing travis, bugs and adding new examples fixing example bugs for msvc updating licence and adding test_expression to jamfile adding new tests, refactoring code and fixing bugs fix for msvc c++20 fixing memory problem due to BOOST_AUTO_TEST_SUITE macro defining after fixture removing const from tests and enabling test_tensor.cpp removing const from test_fixed_rank_expression_evaluation.cpp fixing msvc bug fixing msvc-14.2 bug for c++ latest where it cannot properly capture variables in lambda func disintegrating tests into smaller units reducing test_types for testing reducing tests reducing test_types for testing in operator arithmetic improving msvc warinings and separating test_function.cpp into it's own module --- .appveyor.yml | 9 +- .gitignore | 3 +- .travis.yml | 19 +- examples/tensor/Jamfile | 6 +- examples/tensor/construction_access.cpp | 13 +- examples/tensor/einstein_notation.cpp | 29 +- examples/tensor/prod_expressions_1.cpp | 424 ++++++ ...expressions.cpp => prod_expressions_2.cpp} | 23 +- examples/tensor/simple_expressions.cpp | 7 +- examples/tensor/tensor_construction.cpp | 171 +++ .../boost/numeric/ublas/tensor/algorithms.hpp | 38 +- .../ublas/tensor/detail/extents_functions.hpp | 375 +++++ .../tensor/detail/static_extents_traits.hpp | 150 ++ .../tensor/{ => detail}/storage_traits.hpp | 5 +- .../ublas/tensor/detail/type_traits.hpp | 111 ++ .../tensor/detail/type_traits_extents.hpp | 64 + .../tensor/detail/type_traits_strides.hpp | 68 + .../numeric/ublas/tensor/dynamic_extents.hpp | 449 ++++++ .../numeric/ublas/tensor/dynamic_strides.hpp | 363 +++++ .../boost/numeric/ublas/tensor/expression.hpp | 14 +- .../ublas/tensor/expression_evaluation.hpp | 37 +- .../boost/numeric/ublas/tensor/extents.hpp | 365 +---- .../boost/numeric/ublas/tensor/functions.hpp | 1335 ++++++++++------- .../numeric/ublas/tensor/multi_index.hpp | 3 +- .../ublas/tensor/multi_index_utility.hpp | 2 +- .../numeric/ublas/tensor/multiplication.hpp | 10 +- .../ublas/tensor/operators_arithmetic.hpp | 18 +- .../ublas/tensor/operators_comparison.hpp | 12 +- .../boost/numeric/ublas/tensor/ostream.hpp | 11 +- .../numeric/ublas/tensor/static_extents.hpp | 167 +++ .../numeric/ublas/tensor/static_strides.hpp | 296 ++++ .../boost/numeric/ublas/tensor/storage.hpp | 46 + .../boost/numeric/ublas/tensor/strides.hpp | 387 ++--- include/boost/numeric/ublas/tensor/tensor.hpp | 357 +++-- test/tensor/Jamfile | 41 +- test/tensor/test_algorithms.cpp | 541 ++++++- test/tensor/test_einstein_notation.cpp | 30 +- test/tensor/test_expression.cpp | 10 +- test/tensor/test_expression_evaluation.cpp | 22 +- test/tensor/test_extents.cpp | 1066 +++++++++++-- .../test_fixed_rank_expression_evaluation.cpp | 284 ++++ .../test_fixed_rank_operators_arithmetic.cpp | 243 +++ .../test_fixed_rank_operators_comparison.cpp | 205 +++ test/tensor/test_fixed_rank_tensor.cpp | 511 +++++++ .../test_fixed_rank_tensor_matrix_vector.cpp | 482 ++++++ test/tensor/test_functions.cpp | 1117 +++++++++++++- test/tensor/test_multi_index.cpp | 12 +- test/tensor/test_multiplication.cpp | 109 +- test/tensor/test_operators_arithmetic.cpp | 10 +- test/tensor/test_operators_comparison.cpp | 12 +- .../test_static_expression_evaluation.cpp | 220 +++ test/tensor/test_static_extents.cpp | 519 +++++++ .../test_static_operators_arithmetic.cpp | 242 +++ .../test_static_operators_comparison.cpp | 201 +++ test/tensor/test_static_strides.cpp | 155 ++ test/tensor/test_static_tensor.cpp | 407 +++++ .../test_static_tensor_matrix_vector.cpp | 460 ++++++ test/tensor/test_strides.cpp | 148 +- test/tensor/test_tensor.cpp | 88 +- test/tensor/test_tensor_matrix_vector.cpp | 71 +- test/tensor/utility.hpp | 72 +- 61 files changed, 10926 insertions(+), 1739 deletions(-) create mode 100644 examples/tensor/prod_expressions_1.cpp rename examples/tensor/{prod_expressions.cpp => prod_expressions_2.cpp} (88%) create mode 100644 examples/tensor/tensor_construction.cpp create mode 100644 include/boost/numeric/ublas/tensor/detail/extents_functions.hpp create mode 100644 include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp rename include/boost/numeric/ublas/tensor/{ => detail}/storage_traits.hpp (92%) create mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits.hpp create mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp create mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp create mode 100644 include/boost/numeric/ublas/tensor/dynamic_extents.hpp create mode 100644 include/boost/numeric/ublas/tensor/dynamic_strides.hpp create mode 100644 include/boost/numeric/ublas/tensor/static_extents.hpp create mode 100644 include/boost/numeric/ublas/tensor/static_strides.hpp create mode 100644 include/boost/numeric/ublas/tensor/storage.hpp create mode 100644 test/tensor/test_fixed_rank_expression_evaluation.cpp create mode 100644 test/tensor/test_fixed_rank_operators_arithmetic.cpp create mode 100644 test/tensor/test_fixed_rank_operators_comparison.cpp create mode 100644 test/tensor/test_fixed_rank_tensor.cpp create mode 100644 test/tensor/test_fixed_rank_tensor_matrix_vector.cpp create mode 100644 test/tensor/test_static_expression_evaluation.cpp create mode 100644 test/tensor/test_static_extents.cpp create mode 100644 test/tensor/test_static_operators_arithmetic.cpp create mode 100644 test/tensor/test_static_operators_comparison.cpp create mode 100644 test/tensor/test_static_strides.cpp create mode 100644 test/tensor/test_static_tensor.cpp create mode 100644 test/tensor/test_static_tensor_matrix_vector.cpp diff --git a/.appveyor.yml b/.appveyor.yml index a6e824c0f..0d50d565e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -16,8 +16,11 @@ branches: environment: matrix: - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - TOOLSET: msvc-14.1 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + TOOLSET: msvc-14.2 + CXXSTD: latest + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + TOOLSET: msvc-14.2 CXXSTD: 17 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 TOOLSET: msvc-14.0 @@ -57,7 +60,7 @@ install: local toolset = [ regex.split [ os.environ TOOLSET ] "-" ] ; local vcpkg_i = [ os.environ VCPKG_I ] ; local vcpkg_l = [ os.environ VCPKG_L ] ; - using $(toolset[1]) : $(toolset[2-]:J="-") : ; + using $(toolset[1]) : $(toolset[2-]:J="-") : ; using opencl : : $(vcpkg_i) $(vcpkg_l) ; using clblas : : $(vcpkg_i) $(vcpkg_l) ; '@ | sc "$env:USERPROFILE/user-config.jam" diff --git a/.gitignore b/.gitignore index dbe9c82b3..51858600e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.vscode/ \ No newline at end of file +.vscode/ +.DS_Store \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 74257e5de..ff6bf3a47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,8 @@ language: cpp +dist: bionic + sudo: required branches: @@ -28,14 +30,25 @@ matrix: - os: linux env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=11 - os: linux - env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=17 + env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=17 + - os: linux + env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=2a + - os: linux + env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=17 + - os: linux + env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=2a addons: apt: sources: - - ubuntu-toolchain-r-test + - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + - sourceline: 'ppa:ubuntu-toolchain-r/test' packages: - g++-7 + - g++-9 + - clang-7 + - clang-10 - libopenblas-base - rpm2cpio - cpio @@ -77,7 +90,7 @@ script: cp $TRAVIS_BUILD_DIR/opencl.jam ~/ cp $TRAVIS_BUILD_DIR/clblas.jam ~/ - cd libs/numeric/ublas - - $BOOST_ROOT/b2 -j 8 test/tensor toolset=$TOOLSET cxxstd=$CXXSTD + - travis_wait 120 sleep infinity & $BOOST_ROOT/b2 -j 8 test/tensor toolset=$TOOLSET cxxstd=$CXXSTD - $BOOST_ROOT/b2 -j 8 benchmarks toolset=$TOOLSET cxxstd=$CXXSTD - $BOOST_ROOT/b2 -j 8 examples/tensor toolset=$TOOLSET cxxstd=$CXXSTD diff --git a/examples/tensor/Jamfile b/examples/tensor/Jamfile index 42f2fe633..a3cff6da5 100644 --- a/examples/tensor/Jamfile +++ b/examples/tensor/Jamfile @@ -21,5 +21,7 @@ project boost-ublas-tensor-example exe construction_access : construction_access.cpp ; exe simple_expressions : simple_expressions.cpp ; -exe prod_expressions : prod_expressions.cpp ; -exe einstein_notation : einstein_notation.cpp ; \ No newline at end of file +exe prod_expressions_1 : prod_expressions_1.cpp ; +exe prod_expressions_2 : prod_expressions_2.cpp ; +exe einstein_notation : einstein_notation.cpp ; +exe tensor_construction : tensor_construction.cpp ; \ No newline at end of file diff --git a/examples/tensor/construction_access.cpp b/examples/tensor/construction_access.cpp index 053690c79..8a4987a8d 100644 --- a/examples/tensor/construction_access.cpp +++ b/examples/tensor/construction_access.cpp @@ -1,12 +1,13 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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 IOSB, Ettlingen, Germany +// Google and Fraunhofer IOSB, Ettlingen, Germany // #include @@ -42,7 +43,7 @@ int main() // according to the last-order storage format // and initializes it with the default value. using ctype = std::complex; - auto B = tensor(shape{5,4,3,2},ctype{}); + auto B = tensor,last_order>(dynamic_extents<>{5,4,3,2},ctype{}); // initializes the tensor with increasing values along the last-index // using a single-index @@ -57,7 +58,7 @@ int main() - auto C = tensor(B.extents()); + auto C = tensor,last_order>(B.extents()); // computes the complex conjugate of elements of B // using multi-index notation. for(auto i = 0u; i < B.size(0); ++i) @@ -73,7 +74,7 @@ int main() // computes the complex conjugate of elements of B // using iterators. - auto D = tensor(B.extents()); + auto D = tensor,last_order>(B.extents()); std::transform(B.begin(), B.end(), D.begin(), [](auto const& b){ return std::conj(b); }); std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; @@ -82,7 +83,7 @@ int main() // reshaping tensors. auto new_extents = B.extents().base(); std::next_permutation( new_extents.begin(), new_extents.end() ); - D.reshape( shape(new_extents) ); + D.reshape( dynamic_extents<>(new_extents) ); std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "newD=" << D << ";" << std::endl << std::endl; diff --git a/examples/tensor/einstein_notation.cpp b/examples/tensor/einstein_notation.cpp index 1d95fc06b..90b637c17 100644 --- a/examples/tensor/einstein_notation.cpp +++ b/examples/tensor/einstein_notation.cpp @@ -1,12 +1,13 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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 IOSB, Ettlingen, Germany +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -21,18 +22,18 @@ int main() using format_t = column_major; using value_t = float; - using tensor_t = tensor; + using tensor_t = tensor,format_t>; using matrix_t = matrix; using namespace boost::numeric::ublas::index; // Tensor-Vector-Multiplications - Including Transposition { - auto n = shape{3,4,2}; + auto n = dynamic_extents<>{3,4,2}; auto A = tensor_t(n,1); auto B1 = matrix_t(n[1],n[2],2); - auto v1 = tensor_t(shape{n[0],1},2); - auto v2 = tensor_t(shape{n[1],1},2); + auto v1 = tensor_t(dynamic_extents<>{n[0],1},2); + auto v2 = tensor_t(dynamic_extents<>{n[1],1},2); // auto v3 = tensor_t(shape{n[2],1},2); // C1(j,k) = B1(j,k) + A(i,j,k)*v1(i); @@ -65,12 +66,12 @@ int main() // Tensor-Matrix-Multiplications - Including Transposition { - auto n = shape{3,4,2}; + auto n = dynamic_extents<>{3,4,2}; auto m = 5u; auto A = tensor_t(n,2); - auto B = tensor_t(shape{n[1],n[2],m},2); - auto B1 = tensor_t(shape{m,n[0]},1); - auto B2 = tensor_t(shape{m,n[1]},1); + auto B = tensor_t(dynamic_extents<>{n[1],n[2],m},2); + auto B1 = tensor_t(dynamic_extents<>{m,n[0]},1); + auto B2 = tensor_t(dynamic_extents<>{m,n[1]},1); // C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i); @@ -106,12 +107,12 @@ int main() // Tensor-Tensor-Multiplications Including Transposition { - auto na = shape{3,4,5}; - auto nb = shape{4,6,3,2}; + auto na = dynamic_extents<>{3,4,5}; + auto nb = dynamic_extents<>{4,6,3,2}; auto A = tensor_t(na,2); auto B = tensor_t(nb,3); - auto T1 = tensor_t(shape{na[2],na[2]},2); - auto T2 = tensor_t(shape{na[2],nb[1],nb[3]},2); + auto T1 = tensor_t(dynamic_extents<>{na[2],na[2]},2); + auto T2 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2); // C1(j,l) = T1(j,l) + A(i,j,k)*A(i,j,l) + 5; diff --git a/examples/tensor/prod_expressions_1.cpp b/examples/tensor/prod_expressions_1.cpp new file mode 100644 index 000000000..c51be2c67 --- /dev/null +++ b/examples/tensor/prod_expressions_1.cpp @@ -0,0 +1,424 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#include +#include +#include +#include + +int main() +{ + using namespace boost::numeric::ublas; + + using format_t = column_major; + using value_t = float; // std::complex; + using matrix_t = matrix; + using vector_t = vector; + + // Tensor-Vector-Multiplications - Including Transposition + // dynamic_extents with dynamic rank + { + + auto n = dynamic_extents<>{3,4,2}; + auto A = tensor(n,value_t(2)); + using tensor_t = decltype(A); + auto q = 0u; // contraction mode + + // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); + q = 1u; + tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q) ; + + // C2(i,k) = A(i,j,k)*T1(j) + 4; + q = 2u; + tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4 ; + + // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); + tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); + + // C4(i,j) = A(k,i,j)*T1(k) + 4; + q = 1u; + tensor_t C4 = prod(trans(A,{2,3,1}),vector_t(n[2],1),q) + 4 ; + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; + std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,j) = A(k,i,j)*T1(k) + 4;" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + + } + + // Tensor-Vector-Multiplications - Including Transposition + // dynamic_extents with static rank + { + + auto n = dynamic_extents<3>{3,4,2}; + auto A = tensor(n,value_t(2)); + using tensor_t = tensor< value_t, dynamic_extents<2> >; + auto q = 0u; // contraction mode + + // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); + q = 1u; + tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); + + // C2(i,k) = A(i,j,k)*T1(j) + 4; + q = 2u; + tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; + + // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); + tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; + std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; + + } + + // Tensor-Vector-Multiplications - Including Transposition + // static_extents + { + + auto n = static_extents<3,4,2>{}; + auto A = tensor(n,value_t(2)); + auto q = 0u; // contraction mode + + // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); + q = 1u; + tensor< value_t, static_extents<4,2> > C1 = matrix_t(n[1],n[2],2) + prod<1ul /* q = 1 */ >(A,vector_t(n[q-1],1)); + + // C2(i,k) = A(i,j,k)*T1(j) + 4; + q = 2u; + tensor< value_t, static_extents<3,2> > C2 = prod<2ul /* q = 2 */ >(A,vector_t(n[q-1],1)) + 4; + + // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); + auto C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); + + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; + std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; + + } + + + // Tensor-Matrix-Multiplications - Including Transposition + // dynamic_extents with dynamic rank + { + + auto n = dynamic_extents<>{3,4,2}; + auto A = tensor(n,value_t(2)); + using tensor_t = decltype(A); + auto m = 5u; + auto q = 0u; // contraction mode + + // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); + q = 1u; + tensor_t C1 = tensor( dynamic_extents<>{m,n[1],n[2]},value_t(2) ) + prod(A,matrix_t(m,n[q-1],1),q); + + // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; + q = 2u; + tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4 ; + + // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); + q = 3u; + tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q) ; + + // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); + tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1) ; + + // C5(i,k,l) = A(i,k,j)*T1(l,j) + 4; + q = 3u; + tensor_t C5 = prod(trans(A,{1,3,2}),matrix_t(m,n[1],1),q) + 4 ; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C5(i,k,l) = A(i,k,j)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C5=" << C5 << ";" << std::endl << std::endl; + } + + // Tensor-Matrix-Multiplications - Including Transposition + // dynamic_extents with static rank + { + + auto n = dynamic_extents<3>{3,4,2}; + auto A = tensor(n,value_t(2)); + using tensor_t = decltype(A); + auto m = 5u; + auto q = 0u; // contraction mode + + // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); + q = 1u; + tensor_t C1 = tensor( dynamic_extents<3>{m,n[1],n[2]},value_t(2) ) + prod(A,matrix_t(m,n[q-1],1),q); + + // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; + q = 2u; + tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4 ; + + // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); + q = 3u; + tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q) ; + + // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); + tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1) ; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; + + } + + // Tensor-Matrix-Multiplications - Including Transposition + // static_extents + { + + auto n = static_extents<3,4,2>{}; + auto A = tensor(n,value_t(2)); + static constexpr auto m = 5u; + auto q = 0u; // contraction mode + + // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); + q = 1ul; + tensor< value_t, static_extents<5,4,2> > C1 = tensor( static_extents{},value_t(2) ) + + prod < 1ul /* q */, m /*n[q-1] => n[1-1] => n[0]*/ > (A, matrix_t(m,n[q-1],value_t(1) )) ; + + // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; + q = 2u; + tensor< value_t, static_extents<3,5,2> > C2 = prod<2ul/* q = 2 */, m>(A,matrix_t(m,n[q-1],1)) + 4 ; + + // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); + q = 3u; + auto C3 = prod<3ul, m + 2>( prod<2ul /* q(3) - 1 = 2 */, m + 1 >(A,matrix_t(m+1,n[q-2],1)), matrix_t(m+2,n[q-1],1) ) ; + + // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); + auto C4 = prod<2ul, m + 1>( prod<3ul, m + 2>(A,matrix_t(m+2,n[q-1],1)), matrix_t(m+1,n[q-2],1) ) ; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; + + } + + + + + + // Tensor-Tensor-Multiplications Including Transposition + // dynamic_extents with dynamic rank + { + + using perm_t = std::vector; + + auto na = dynamic_extents<>{3,4,5}; + auto nb = dynamic_extents<>{4,6,3,2}; + auto A = tensor(na,value_t(2)); + auto B = tensor(nb,value_t(3)); + using tensor_t = decltype(A); + + + // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; + tensor_t C1 = tensor(dynamic_extents<>{na[2],na[2]},value_t(2)) + prod(A,A,perm_t{1,2}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + + // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; + tensor_t C2 = tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + + // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; + tensor_t C3 = tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + } + + // Tensor-Tensor-Multiplications Including Transposition + // dynamic_extents with static rank + { + + using perm_t = std::vector; + + auto na = dynamic_extents<3>{3,4,5}; + auto nb = dynamic_extents<4>{4,6,3,2}; + auto A = tensor(na,value_t(2)); + auto B = tensor(nb,value_t(3)); + using tensor_t = tensor< value_t, dynamic_extents<> >; + + + // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; + // Right now there exist no tensor other than dynamic_extents with + // dynamic rank so every tensor times tensor operator automatically + // to dynamic tensor + tensor_t C1 = tensor(dynamic_extents<>{na[2],na[2]},value_t(2)) + prod(A,A,perm_t{1,2}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + + // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; + // Similar Problem as above + tensor_t C2 = tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + + // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; + // Similar Problem as above + tensor_t C3 = tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + } +} diff --git a/examples/tensor/prod_expressions.cpp b/examples/tensor/prod_expressions_2.cpp similarity index 88% rename from examples/tensor/prod_expressions.cpp rename to examples/tensor/prod_expressions_2.cpp index 6ff725214..267fe40f0 100644 --- a/examples/tensor/prod_expressions.cpp +++ b/examples/tensor/prod_expressions_2.cpp @@ -1,12 +1,13 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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 IOSB, Ettlingen, Germany +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -21,14 +22,14 @@ int main() using format_t = column_major; using value_t = float; // std::complex; - using tensor_t = tensor; + using tensor_t = tensor,format_t>;; using matrix_t = matrix; using vector_t = vector; // Tensor-Vector-Multiplications - Including Transposition { - auto n = shape{3,4,2}; + auto n = dynamic_extents<>{3,4,2}; auto A = tensor_t(n,2); auto q = 0u; // contraction mode @@ -78,14 +79,14 @@ int main() // Tensor-Matrix-Multiplications - Including Transposition { - auto n = shape{3,4,2}; + auto n = dynamic_extents<>{3,4,2}; auto A = tensor_t(n,2); auto m = 5u; auto q = 0u; // contraction mode // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); q = 1u; - tensor_t C1 = tensor_t(shape{m,n[1],n[2]},2) + prod(A,matrix_t(m,n[q-1],1),q); + tensor_t C1 = tensor_t(dynamic_extents<>{m,n[1],n[2]},2) + prod(A,matrix_t(m,n[q-1],1),q); // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; q = 2u; @@ -144,14 +145,14 @@ int main() using perm_t = std::vector; - auto na = shape{3,4,5}; - auto nb = shape{4,6,3,2}; + auto na = dynamic_extents<>{3,4,5}; + auto nb = dynamic_extents<>{4,6,3,2}; auto A = tensor_t(na,2); auto B = tensor_t(nb,3); // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; - tensor_t C1 = tensor_t(shape{na[2],na[2]},2) + prod(A,A,perm_t{1,2}) + 5; + tensor_t C1 = tensor_t(dynamic_extents<>{na[2],na[2]},2) + prod(A,A,perm_t{1,2}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -161,7 +162,7 @@ int main() // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; - tensor_t C2 = tensor_t(shape{na[2],nb[1],nb[3]},2) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + tensor_t C2 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -171,7 +172,7 @@ int main() // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; - tensor_t C3 = tensor_t(shape{na[2],nb[1],nb[3]},2) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; + tensor_t C3 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; diff --git a/examples/tensor/simple_expressions.cpp b/examples/tensor/simple_expressions.cpp index fabb00f4b..54f3f6c38 100644 --- a/examples/tensor/simple_expressions.cpp +++ b/examples/tensor/simple_expressions.cpp @@ -1,12 +1,13 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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 IOSB, Ettlingen, Germany +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -36,7 +37,7 @@ int main() std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "A=" << A << ";" << std::endl << std::endl; - auto n = shape{3,4}; + auto n = dynamic_extents<>{3,4}; auto D = matrixf(n[0],n[1],1); auto e = vectorf(n[1],1); auto f = vectorf(n[0],2); diff --git a/examples/tensor/tensor_construction.cpp b/examples/tensor/tensor_construction.cpp new file mode 100644 index 000000000..36bc54a25 --- /dev/null +++ b/examples/tensor/tensor_construction.cpp @@ -0,0 +1,171 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#include +#include +#include + +namespace ub = boost::numeric::ublas; + +int main() { + + using value_type = float; + + /** tensor initialization using type deduction + * Storage Type: std::vector + * Layout: first_order + * Initial Value: 0 + **/ + auto tensor_dynamic_extents_and_dynamic_rank_0 = ub::tensor{1,2,3,4}; + + /** Dynamic extents but static rank + * Storage Type: std::array of static rank + * Layout: first_order + * Initial Value: 0 + **/ + auto tensor_dynamic_extents_and_static_rank_1 = ub::tensor>{ub::dynamic_extents<4>{1,2,3,4}}; + + /** Dynamic extents but dynamic rank + * Storage Type: std::vector + * Layout: first_order + * Initial Value: 0 + **/ + auto tensor_dynamic_extents_and_dynamic_rank_2 = ub::tensor>{ub::dynamic_extents<>{1,2,3,4}}; + + /** Dynamic extents but dynamic rank + * Storage Type: std::vector + * Layout: first_order + * Initial Value: 0.1f + **/ + auto tensor_dynamic_extents_and_dynamic_rank_3 = ub::tensor>{ub::dynamic_extents<>{1,2,3,4},0.1}; + + /** Static extents but static rank + * Storage Type: std::array + * Layout: first_order + * Initial Value: 0 + **/ + auto tensor_static_extents_and_static_rank_4 = ub::tensor>(); + + /** Static extents but static rank + * Storage Type: std::array + * Layout: first_order + * Initial Value: 0 + **/ + auto tensor_static_extents_and_static_rank_5 = ub::tensor,ub::first_order>(); + + /** Dynamic extents but dynamic rank + * Storage Type: std::array + * Layout: first_order + * Initial Value: 0 + **/ + auto tensor_dynamic_extents_and_dynamic_rank_6 = ub::tensor,ub::first_order>{1,2,3,4}; + + /** Dynamic extents but dynamic rank + * Storage Type: std::vector + * Layout: first_order + * Initial Value: 0 + **/ + auto tensor_dynamic_extents_and_dynamic_rank_7 = ub::tensor,ub::first_order,std::vector>{1,2,3,4}; + + /** Static extents but static rank + * Storage Type: std::array of size 24 + * Layout: first_order + * Initial Value: 0 + **/ + auto tensor_static_extents_and_static_rank_8 = ub::tensor,ub::first_order,std::array>(); + + auto t1_e = tensor_dynamic_extents_and_dynamic_rank_0.extents(); + auto t2_e = tensor_dynamic_extents_and_static_rank_1.extents(); + auto t3_e = tensor_dynamic_extents_and_dynamic_rank_2.extents(); + auto t4_e = tensor_static_extents_and_static_rank_4.extents(); + auto t5_e = tensor_dynamic_extents_and_dynamic_rank_3.extents(); + auto t6_e = tensor_static_extents_and_static_rank_5.extents(); + auto t7_e = tensor_dynamic_extents_and_dynamic_rank_6.extents(); + auto t8_e = tensor_dynamic_extents_and_dynamic_rank_7.extents(); + auto t9_e = tensor_static_extents_and_static_rank_8.extents(); + + auto t1_s = tensor_dynamic_extents_and_dynamic_rank_0.strides(); + auto t2_s = tensor_dynamic_extents_and_static_rank_1.strides(); + auto t3_s = tensor_dynamic_extents_and_dynamic_rank_2.strides(); + auto t4_s = tensor_static_extents_and_static_rank_4.strides(); + auto t5_s = tensor_dynamic_extents_and_dynamic_rank_3.strides(); + auto t6_s = tensor_static_extents_and_static_rank_5.strides(); + auto t7_s = tensor_dynamic_extents_and_dynamic_rank_6.strides(); + auto t8_s = tensor_dynamic_extents_and_dynamic_rank_7.strides(); + auto t9_s = tensor_static_extents_and_static_rank_8.strides(); + + std::cout<<"\nExtents: "<<(t1_e)<<'\n'; + std::cout<<"Strides: "<<(t1_s)<<'\n'; + + std::cout<<"\nExtents: "<<(t2_e)<<'\n'; + std::cout<<"Strides: "<<(t2_s)<<'\n'; + + std::cout<<"\nExtents: "<<(t3_e)<<'\n'; + std::cout<<"Strides: "<<(t3_s)<<'\n'; + + std::cout<<"\nExtents: "<<(t4_e)<<'\n'; + std::cout<<"Strides: "<<(t4_s)<<'\n'; + + std::cout<<"\nExtents: "<<(t5_e)<<'\n'; + std::cout<<"Strides: "<<(t5_s)<<'\n'; + + std::cout<<"\nExtents: "<<(t6_e)<<'\n'; + std::cout<<"Strides: "<<(t6_s)<<'\n'; + + std::cout<<"\nExtents: "<<(t7_e)<<'\n'; + std::cout<<"Strides: "<<(t7_s)<<'\n'; + + std::cout<<"\nExtents: "<<(t8_e)<<'\n'; + std::cout<<"Strides: "<<(t8_s)<<'\n'; + + std::cout<<"\nExtents: "<<(t9_e)<<'\n'; + std::cout<<"Strides: "<<(t9_s)<<'\n'; + + /** + * Checking if layout is first order or not + * Output: True + **/ + std::cout<::value<<'\n'; + + /** + * Checking if layout is first order or not + * Output: True + **/ + std::cout<::value<<'\n'; + + /** + * Checking if container is std::vector + * Output: True + **/ + std::cout< >::value<<'\n'; + + /** + * Checking if container is std::array + * Output: True + **/ + std::cout< >::value<<'\n'; + + /** + * Checking if extents is static + * Output: True + **/ + std::cout<::value<<'\n'; + + /** + * Checking if extents is dynamic + * Output: True + **/ + std::cout<::value<<'\n'; + + return 0; +} diff --git a/include/boost/numeric/ublas/tensor/algorithms.hpp b/include/boost/numeric/ublas/tensor/algorithms.hpp index c6b9dba48..b66f2344a 100644 --- a/include/boost/numeric/ublas/tensor/algorithms.hpp +++ b/include/boost/numeric/ublas/tensor/algorithms.hpp @@ -47,13 +47,13 @@ void copy(const SizeType p, SizeType const*const n, return; if(c == nullptr || a == nullptr) - throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); if(wc == nullptr || wa == nullptr) - throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); if(n == nullptr) - throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); std::function lambda; @@ -99,13 +99,13 @@ void transform(const SizeType p, return; if(c == nullptr || a == nullptr) - throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); if(wc == nullptr || wa == nullptr) - throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); if(n == nullptr) - throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); std::function lambda; @@ -147,13 +147,13 @@ ValueType accumulate(SizeType const p, SizeType const*const n, return k; if(a == nullptr) - throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); if(w == nullptr) - throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); if(n == nullptr) - throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); std::function lambda; @@ -197,13 +197,13 @@ ValueType accumulate(SizeType const p, SizeType const*const n, return k; if(a == nullptr) - throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); if(w == nullptr) - throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); if(n == nullptr) - throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); std::function lambda; @@ -256,13 +256,13 @@ void trans( SizeType const p, SizeType const*const na, SizeType const*const pi, throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null."); if(wc == nullptr || wa == nullptr) - throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); if(na == nullptr) - throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); if(pi == nullptr) - throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); std::function lambda; @@ -307,16 +307,16 @@ void trans( SizeType const p, return; if(c == nullptr || a == nullptr) - throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); if(wc == nullptr || wa == nullptr) - throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); if(na == nullptr) - throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); if(pi == nullptr) - throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); std::function* c, std::complex* a)> lambda; diff --git a/include/boost/numeric/ublas/tensor/detail/extents_functions.hpp b/include/boost/numeric/ublas/tensor/detail/extents_functions.hpp new file mode 100644 index 000000000..8e8fa9555 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/extents_functions.hpp @@ -0,0 +1,375 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP_ +#define _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP_ + +#include +#include +#include +#include +#include +#include + + +namespace boost::numeric::ublas::detail{ + + template + constexpr auto push_back(basic_static_extents) -> basic_static_extents; + + template + constexpr auto push_front(basic_static_extents) -> basic_static_extents; + + template + constexpr auto squeeze_impl_remove_one( basic_static_extents, basic_static_extents num = basic_static_extents{} ){ + // executed when basic_static_extents is size of 1 + // @code basic_static_extents @endcode + if constexpr( sizeof...(E) == 0ul ){ + // if element E0 is 1 we return number list but we do not append + // it to the list + if constexpr( E0 == T(1) ){ + return num; + }else{ + // if element E0 is 1 we return number list but we append + // it to the list + return decltype(push_back(num)){}; + } + }else{ + if constexpr( E0 == T(1) ){ + // if element E0 is 1 we return number list but we do not append + // it to the list + return squeeze_impl_remove_one(basic_static_extents{}, num); + }else{ + // if element E0 is 1 we return number list but we append + // it to the list + auto n_num_list = decltype(push_back(num)){}; + return squeeze_impl_remove_one(basic_static_extents{}, n_num_list); + } + } + } + + template + constexpr auto squeeze_impl( basic_static_extents const& e ){ + + using extents_type = basic_static_extents; + + if constexpr( extents_type::_size <= typename extents_type::size_type(2) ){ + return e; + } + + using value_type = typename extents_type::value_type; + using size_type = typename extents_type::size_type; + + auto one_free_static_extents = squeeze_impl_remove_one(e); + + // check after removing 1s from the list are they same + // if same that means 1s does not exist and no need to + // squeeze + if constexpr( decltype(one_free_static_extents)::_size != extents_type::_size ){ + + // after squeezing, all the extents are 1s we need to + // return extents of (1, 1) + if constexpr( decltype(one_free_static_extents)::_size == size_type(0) ){ + + return basic_static_extents{}; + + }else if constexpr( decltype(one_free_static_extents)::_size == (1) ){ + // to comply with GNU Octave this check is made + // if position 2 contains 1 we push at back + // else we push at front + if constexpr( extents_type::at(1) == value_type(1) ){ + return decltype( push_back(one_free_static_extents) ){}; + }else{ + return decltype( push_front(one_free_static_extents) ){}; + } + + }else{ + return one_free_static_extents; + } + + }else{ + return e; + } + + } + + template + inline + constexpr auto squeeze_impl( basic_extents const& e ){ + using extents_type = basic_extents; + using base_type = typename extents_type::base_type; + using value_type = typename extents_type::value_type; + using size_type = typename extents_type::size_type; + + if( e.size() <= size_type(2) ){ + return e; + } + + auto not_one = [](auto const& el){ + return el != value_type(1); + }; + + // count non one values + size_type size = std::count_if(e.begin(), e.end(), not_one); + + // reserve space + base_type n_extents( std::max(size, size_type(2)), 1 ); + + // copying non 1s to the new extents + std::copy_if(e.begin(), e.end(), n_extents.begin(), not_one); + + // checking if extents size goes blow 2 + // if size of extents goes to 1 + // complying with GNU Octave + // if position 2 contains 1 we + // swap the pos + if( size < size_type(2) && e[1] != value_type(1) ){ + std::swap(n_extents[0], n_extents[1]); + } + + return extents_type(n_extents); + } + + template + inline + constexpr auto squeeze_impl( basic_fixed_rank_extents const& e ){ + if constexpr( N <= 2 ){ + return e; + }else{ + return squeeze_impl(e.to_dynamic_extents()); + } + } + + + +} // namespace boost::numeric::ublas::detail + +namespace boost::numeric::ublas { + +/** @brief Returns true if size > 1 and all elements > 0 or size == 1 && e[0] == 1 */ +template +inline +constexpr bool valid(ExtentsType const &e) { + + static_assert(detail::is_extents::value, "boost::numeric::ublas::valid() : invalid type, type should be an extents"); + + using size_type = typename ExtentsType::size_type; + using value_type = typename ExtentsType::value_type; + + if ( e.size() == size_type(1) ){ + + return e[0] == value_type(1); + + } + if ( e.size() > size_type(1) ){ + + return std::all_of(e.begin(), e.end(), [](auto const &a) { return a > value_type(0); }); + + }else{ + + return false; + + } +} + +/** + * @code static_extents<4,1,2,3,4> s; + * std::cout< +inline +std::string to_string(T const &e) { + + static_assert(detail::is_extents::value || detail::is_strides::value, + "boost::numeric::ublas::to_string() : invalid type, type should be an extents or a strides"); + + if (e.empty()) { + return "[]"; + } + + std::stringstream ss; + + ss << "[ "; + + for (auto i = typename T::size_type(0); i < e.size() - 1; i++) { + ss << e[i] << ", "; + } + + ss << e.back() << " ]"; + + return ss.str(); +} + +/** @brief Returns true if this has a scalar shape + * + * @returns true if (1,1,[1,...,1]) + */ +template +inline +constexpr bool is_scalar(ExtentsType const &e) { + + static_assert(detail::is_extents::value, "boost::numeric::ublas::is_scalar() : invalid type, type should be an extents"); + + using size_type = typename ExtentsType::size_type; + using value_type = typename ExtentsType::value_type; + + if ( e.size() == size_type(0) ){ + return false; + }else{ + return std::all_of(e.begin(), e.end(), [](auto const &a) { return a == value_type(1); }); + } +} + +/** @brief Returns true if this has a vector shape + * + * @returns true if (1,n,[1,...,1]) or (n,1,[1,...,1]) with n > 1 + */ +template +inline +constexpr bool is_vector(ExtentsType const &e) { + + static_assert(detail::is_extents::value, "boost::numeric::ublas::is_vector() : invalid type, type should be an extents"); + + using size_type = typename ExtentsType::size_type; + using value_type = typename ExtentsType::value_type; + + if (e.size() == size_type(0)) { + + return false; + + } else if (e.size() == size_type(1)) { + + return e.at(0) > value_type(1); + + }else{ + + auto greater_one = [](auto const &a) { + return a > value_type(1); + }; + auto equal_one = [](auto const &a) { + return a == value_type(1); + }; + + return std::any_of(e.begin(), e.begin() + 2, greater_one) && + std::any_of(e.begin(), e.begin() + 2, equal_one) && + std::all_of(e.begin() + 2, e.end(), equal_one); + } + +} + +/** @brief Returns true if this has a matrix shape + * + * @returns true if (m,n,[1,...,1]) with m > 1 and n > 1 + */ +template +inline +constexpr bool is_matrix(ExtentsType const &e) { + + static_assert(detail::is_extents::value, "boost::numeric::ublas::is_matrix() : invalid type, type should be an extents"); + + using size_type = typename ExtentsType::size_type; + using value_type = typename ExtentsType::value_type; + + if (e.size() < size_type(2)) { + return false; + }else{ + + auto greater_one = [](auto const &a) { + return a > value_type(1); + }; + + auto equal_one = [](auto const &a) { + return a == value_type(1); + }; + + return std::all_of(e.begin(), e.begin() + 2, greater_one) && + std::all_of(e.begin() + 2, e.end(), equal_one); + } + +} + +/** @brief Returns true if this is has a tensor shape + * + * @returns true if !empty() && !is_scalar() && !is_vector() && !is_matrix() + */ +template +inline +constexpr bool is_tensor(ExtentsType const &e) { + + static_assert(detail::is_extents::value, "boost::numeric::ublas::is_tensor() : invalid type, type should be an extents"); + + using size_type = typename ExtentsType::size_type; + using value_type = typename ExtentsType::value_type; + + if (e.size() < size_type(3)) { + + return false; + + }else{ + + auto greater_one = [](auto const &a) { + return a > value_type(1); + }; + + return std::any_of(e.begin() + 2, e.end(), greater_one); + + } + +} + +/** @brief Eliminates singleton dimensions when size > 2 + * + * squeeze { 1,1} -> { 1,1} + * squeeze { 2,1} -> { 2,1} + * squeeze { 1,2} -> { 1,2} + * + * squeeze {1,2,3} -> { 2,3} + * squeeze {2,1,3} -> { 2,3} + * squeeze {1,3,1} -> { 1,3} + * + * @returns basic_extents with squeezed extents + */ +template +inline +auto squeeze(ExtentsType const &e) { + + static_assert(detail::is_extents::value, "boost::numeric::ublas::squeeze() : invalid type, type should be an extents"); + + return detail::squeeze_impl(e); +} + +/** @brief Returns the product of extents */ +template +inline +constexpr auto product(ExtentsType const &e) { + + static_assert(detail::is_extents::value, "boost::numeric::ublas::product() : invalid type, type should be an extents"); + + using value_type = typename ExtentsType::value_type; + + if (e.empty()) { + + return value_type(0); + + }else{ + + return value_type( std::accumulate(e.begin(), e.end(), value_type(1), std::multiplies<>()) ); + + } + +} + +} // namespace boost::numeric::ublas +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp b/include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp new file mode 100644 index 000000000..dfa6a4d94 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp @@ -0,0 +1,150 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef _BOOST_NUMERIC_UBLAS_TENSOR_STATIC_TRAITS_HPP_ +#define _BOOST_NUMERIC_UBLAS_TENSOR_STATIC_TRAITS_HPP_ + +#include + +namespace boost::numeric::ublas{ + + template struct basic_static_extents; + template struct basic_fixed_rank_extents; + template class basic_extents; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas::static_traits{ + + template + struct is_valid : std::integral_constant{}; + + template + inline static constexpr bool const is_valid_v = is_valid::value; + + template + struct is_valid< basic_static_extents >{ + static constexpr bool const value = ( E0 == ExtentsType(1) ); + }; + + template + struct is_valid< basic_static_extents >{ + static constexpr bool const value = ( E0 > ExtentsType(0) ) && ( E1 > ExtentsType(0) ); + }; + + template + struct is_valid< basic_static_extents >{ + static constexpr bool const value = ( E0 > ExtentsType(0) ) + && is_valid_v< basic_static_extents >; + }; + + + template + struct is_scalar : std::integral_constant{}; + + template + inline static constexpr bool const is_scalar_v = is_scalar::value; + + template + struct is_scalar< basic_static_extents >{ + static constexpr bool const value = is_scalar_v< basic_static_extents > && is_scalar_v< basic_static_extents >; + }; + + template + struct is_scalar< basic_static_extents >{ + static constexpr bool const value = (E0 == 1); + }; + + template + struct is_scalar< basic_static_extents > : std::false_type{}; + + template + struct is_vector : std::integral_constant{}; + + template + inline static constexpr bool const is_vector_v = is_vector::value; + + template + struct is_vector< basic_static_extents >{ + static constexpr bool const value = + is_vector_v< basic_static_extents > && + is_scalar_v< basic_static_extents >; + }; + + template + struct is_vector< basic_static_extents >{ + static constexpr bool const value = + ( E0 > ExtentsType(1) || E1 > ExtentsType(1) ) + && ( E0 == ExtentsType(1) || E1 == ExtentsType(1) ); + }; + + template + struct is_vector< basic_static_extents >{ + static constexpr bool const value = ( E0 > ExtentsType(1) ); + }; + + template + struct is_matrix : std::integral_constant{}; + + template + inline static constexpr bool const is_matrix_v = is_matrix::value; + + template + struct is_matrix< basic_static_extents > : std::false_type{}; + + template + struct is_matrix< basic_static_extents >{ + static constexpr bool const value = + is_matrix_v< basic_static_extents > && + is_scalar_v< basic_static_extents >; + }; + + template + struct is_matrix< basic_static_extents >{ + static constexpr bool const value = ( E0 > ExtentsType(1) && E1 > ExtentsType(1) ); + }; + + template + struct is_any_greater_than_one : std::integral_constant{}; + + template + inline static constexpr bool const is_any_greater_than_one_v = is_any_greater_than_one::value; + + template + struct is_any_greater_than_one< basic_static_extents > : std::false_type{}; + + template + struct is_any_greater_than_one< basic_static_extents > { + static constexpr bool const value = ( E0 > ExtentsType(1) ); + }; + + template + struct is_any_greater_than_one< basic_static_extents > { + static constexpr bool const value = is_any_greater_than_one_v< basic_static_extents > || is_any_greater_than_one_v< basic_static_extents >; + }; + + template + struct is_tensor : std::integral_constant{}; + + template + inline static constexpr bool const is_tensor_v = is_tensor::value; + + template + struct is_tensor< basic_static_extents > : std::false_type{}; + + template + struct is_tensor< basic_static_extents >{ + static constexpr bool const value = is_any_greater_than_one_v< basic_static_extents >; + }; + +} // namespace boost::numeric::ublas::static_traits +#endif diff --git a/include/boost/numeric/ublas/tensor/storage_traits.hpp b/include/boost/numeric/ublas/tensor/detail/storage_traits.hpp similarity index 92% rename from include/boost/numeric/ublas/tensor/storage_traits.hpp rename to include/boost/numeric/ublas/tensor/detail/storage_traits.hpp index 52840e968..5d2915580 100644 --- a/include/boost/numeric/ublas/tensor/storage_traits.hpp +++ b/include/boost/numeric/ublas/tensor/detail/storage_traits.hpp @@ -1,12 +1,13 @@ // -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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 IOSB, Ettlingen Germany +// Google and Fraunhofer IOSB, Ettlingen, Germany // diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits.hpp new file mode 100644 index 000000000..da379a158 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/type_traits.hpp @@ -0,0 +1,111 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_HPP + +#include +#include + +namespace boost::numeric::ublas::detail { + +/** @brief Checks if the extents or strides is dynamic + * + * @tparam E of type basic_extents or basic_static_extents + * + */ +template struct is_dynamic : std::false_type {}; + +template +inline static constexpr bool const is_dynamic_v = is_dynamic::value; + +/** @brief Checks if the extents or strides is static + * + * @tparam E of type basic_extents or basic_static_extents + * + */ +template struct is_static : std::false_type {}; + +template +inline static constexpr bool const is_static_v = is_static::value; + +/** @brief Checks if the extents or strides has dynamic rank + * + * @tparam E of type basic_extents or basic_static_extents + * + */ +template +struct is_dynamic_rank : std::false_type {}; + +template +inline static constexpr bool const is_dynamic_rank_v = is_dynamic_rank::value; + +/** @brief Checks if the extents or strides has static rank + * + * @tparam E of type basic_extents or basic_static_extents + * + */ +template +struct is_static_rank : std::false_type {}; + +template +inline static constexpr bool const is_static_rank_v = is_static_rank::value; + +/** @brief Checks if type has member function resize with + * prototype resize(size_type) and return type can be + * anything and type should have empty constructor. + * @code + * + * struct test1{ + * test1(){...} + * void resize(size_t){...} + * ... + * }; + * + * struct test2{ + * test2(){...} + * ... + * }; + * + * struct test3{ + * test2(int){...} + * void resize(size_t){...} + * }; + * + * auto v = std::vector{}; + * auto vec_val = is_resizable_v; // vec_val == true; + * + * auto a = std::array{}; + * auto arr_val = is_resizable_v; // arr_val == false; + * + * auto test1_val = is_resizable_v; // arr_val == true; + * auto test2_val = is_resizable_v; // arr_val == false; + * auto test3_val = is_resizable_v; // arr_val == false bacause test3 does not have empty constuctor. + * + * @endcode +*/ +template +struct is_resizable : std::false_type{}; + +template +struct is_resizable< T, std::void_t< decltype(T{}.resize(0)) > >: std::true_type{}; + +template +inline static constexpr bool const is_resizable_v = is_resizable::value; + +} // namespace boost::numeric::ublas::detail + +#include +#include +#include + +#endif \ No newline at end of file diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp new file mode 100644 index 000000000..1e188c647 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp @@ -0,0 +1,64 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_EXTENTS_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_EXTENTS_HPP + +namespace boost::numeric::ublas{ + + template struct basic_static_extents; + template struct basic_fixed_rank_extents; + template class basic_extents; + +} // namespace boost::numeric::ublas:: + + +namespace boost::numeric::ublas::detail { + +// checks if type is extents or not +template +struct is_extents : std::false_type {}; + +template +struct is_extents> : std::true_type {}; + +template +struct is_extents> : std::true_type {}; + +template +struct is_extents> : std::true_type {}; + +template +inline static constexpr bool const is_extents_v = is_extents::value; + +template +struct is_dynamic> : std::true_type {}; + +template +struct is_dynamic> : std::true_type {}; + +template +struct is_static> : std::true_type {}; + +template +struct is_dynamic_rank< basic_extents > : std::true_type {}; + +template +struct is_static_rank> : std::true_type {}; + +template +struct is_static_rank> : std::true_type {}; + +} // namespace boost::numeric::ublas::detail + + +#endif \ No newline at end of file diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp new file mode 100644 index 000000000..49b3e273c --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp @@ -0,0 +1,68 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_STRIDES_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_STRIDES_HPP + +namespace boost::numeric::ublas{ + + template struct basic_static_extents; + template struct basic_fixed_rank_extents; + template class basic_extents; + + template struct basic_static_strides; + template class basic_fixed_rank_strides; + template class basic_strides; + +} // namespace boost::numeric::ublas:: + + +namespace boost::numeric::ublas::detail { + +// checks if type is strides or not +template +struct is_strides : std::false_type {}; + +template +inline static constexpr bool const is_strides_v = is_strides::value; + +template +struct is_strides< basic_static_strides< basic_static_extents, L > > : std::true_type {}; + +template +struct is_strides< basic_fixed_rank_strides< T, R, L> > : std::true_type {}; + +template +struct is_strides> : std::true_type {}; + +template +struct is_dynamic< basic_strides > : std::true_type {}; + +template +struct is_dynamic< basic_fixed_rank_strides > : std::true_type {}; + +template +struct is_static< basic_static_strides< basic_static_extents, L > > : std::true_type {}; + +template +struct is_dynamic_rank< basic_strides > : std::true_type {}; + +template +struct is_static_rank< basic_static_strides< basic_static_extents, L > > : std::true_type {}; + +template +struct is_static_rank< basic_fixed_rank_strides > : std::true_type {}; + +} // namespace boost::numeric::ublas::detail + + +#endif \ No newline at end of file diff --git a/include/boost/numeric/ublas/tensor/dynamic_extents.hpp b/include/boost/numeric/ublas/tensor/dynamic_extents.hpp new file mode 100644 index 000000000..ae37f8f9f --- /dev/null +++ b/include/boost/numeric/ublas/tensor/dynamic_extents.hpp @@ -0,0 +1,449 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#ifndef _BOOST_NUMERIC_UBLAS_TENSOR_DYNAMIC_EXTENTS_HPP_ +#define _BOOST_NUMERIC_UBLAS_TENSOR_DYNAMIC_EXTENTS_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace numeric { +namespace ublas { + +/** @brief Template class for storing tensor extents with runtime variable size. + * + * Proxy template class of std::vector. + * + */ +template +class basic_extents +{ + static_assert( std::numeric_limits::value_type>::is_integer, "Static error in basic_layout: type must be of type integer."); + static_assert(!std::numeric_limits::value_type>::is_signed, "Static error in basic_layout: type must be of type unsigned integer."); + +public: + using base_type = std::vector; + using value_type = typename base_type::value_type; + using const_reference = typename base_type::const_reference; + using reference = typename base_type::reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + + + /** @brief Default constructs basic_extents + * + * @code auto ex = basic_extents{}; + */ + basic_extents() + : _base{} + { + } + + /** @brief Copy constructs basic_extents from a one-dimensional container + * + * @code auto ex = basic_extents( std::vector(3u,3u) ); + * + * @note checks if size > 1 and all elements > 0 + * + * @param b one-dimensional std::vector container + */ + explicit basic_extents(base_type const& b) + : _base(b) + { + if ( !valid(*this) ){ + throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + /** @brief Move constructs basic_extents from a one-dimensional container + * + * @code auto ex = basic_extents( std::vector(3u,3u) ); + * + * @note checks if size > 1 and all elements > 0 + * + * @param b one-dimensional container of type std::vector + */ + explicit basic_extents(base_type && b) + : _base(std::move(b)) + { + if (!valid(*this)){ + throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + /** @brief Constructs basic_extents from an initializer list + * + * @code auto ex = basic_extents{3,2,4}; + * + * @note checks if size > 1 and all elements > 0 + * + * @param l one-dimensional list of type std::initializer + */ + basic_extents(std::initializer_list l) + : basic_extents( base_type(std::move(l)) ) + { + } + + /** @brief Constructs basic_extents from a range specified by two iterators + * + * @code auto ex = basic_extents(a.begin(), a.end()); + * + * @note checks if size > 1 and all elements > 0 + * + * @param first iterator pointing to the first element + * @param last iterator pointing to the next position after the last element + */ + basic_extents(const_iterator first, const_iterator last) + : basic_extents ( base_type( first,last ) ) + { + } + + /** @brief Copy constructs basic_extents */ + basic_extents(basic_extents const& l ) + : _base(l._base) + { + } + + /** @brief Move constructs basic_extents */ + basic_extents(basic_extents && l ) noexcept + : _base(std::move(l._base)) + { + } + + + template::value + && ( !std::is_same_v ) + ,int > = 0 + > + basic_extents(OtherExtentsType const& e){ + _base.resize(e.size()); + for(auto i = size_type(0); i < size(); ++i){ + _base[i] = e[i]; + } + } + + ~basic_extents() = default; + + basic_extents& operator=(basic_extents other) noexcept + { + swap (*this, other); + return *this; + } + + friend void swap(basic_extents& lhs, basic_extents& rhs) { + std::swap(lhs._base , rhs._base ); + } + + const_pointer data() const + { + return this->_base.data(); + } + + const_reference operator[] (size_type p) const + { + return this->_base[p]; + } + + const_reference at (size_type p) const + { + return this->_base.at(p); + } + + reference operator[] (size_type p) + { + return this->_base[p]; + } + + reference at (size_type p) + { + return this->_base.at(p); + } + + const_reference back () const + { + return this->_base.back(); + } + + + bool empty() const + { + return this->_base.empty(); + } + + size_type size() const + { + return this->_base.size(); + } + + void clear() + { + this->_base.clear(); + } + + bool operator == (basic_extents const& b) const + { + return _base == b._base; + } + + bool operator != (basic_extents const& b) const + { + return !( _base == b._base ); + } + + const_iterator + begin() const + { + return _base.begin(); + } + + const_iterator + end() const + { + return _base.end(); + } + + base_type const& base() const { return _base; } + +private: + + base_type _base; + +}; + +// using shape = basic_extents; + + +/** @brief Template class for storing tensor extents for compile time. + * + * @code basic_static_extents<1,2,3,4> t @endcode + * @tparam E parameter pack of extents + * + */ +template +struct basic_fixed_rank_extents +{ + + + static constexpr std::size_t const _size = N; + + + using base_type = std::array; + using value_type = typename base_type::value_type; + using const_reference = typename base_type::const_reference; + using reference = typename base_type::reference; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + using size_type = typename base_type::size_type; + + static_assert( std::numeric_limits::is_integer, "Static error in basic_fixed_rank_extents: type must be of type integer."); + static_assert(!std::numeric_limits::is_signed, "Static error in basic_fixed_rank_extents: type must be of type unsigned integer."); + + //@returns the rank of basic_static_extents + [[nodiscard]] + static constexpr size_type size() noexcept { return _size; } + + [[nodiscard]] inline + constexpr const_reference at(size_type k) const{ + return _base.at(k); + } + + [[nodiscard]] inline + constexpr reference at(size_type k){ + return _base.at(k); + } + + [[nodiscard]] inline + constexpr const_reference operator[](size_type k) const noexcept{ + return _base[k]; + } + + [[nodiscard]] inline + constexpr reference operator[](size_type k) noexcept{ + return _base[k]; + } + + // default constructor + constexpr basic_fixed_rank_extents() = default; + + constexpr basic_fixed_rank_extents(std::initializer_list li){ + if( li.size() > _size ){ + throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than _size"); + } + + std::copy(li.begin(), li.end(), _base.begin()); + + if ( !valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + constexpr basic_fixed_rank_extents(const_iterator begin, const_iterator end){ + if( std::distance(begin,end) > _size ){ + throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than _size"); + } + + std::copy(begin, end, _base.begin()); + + if ( !valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + void fill( value_type value ){ + _base.fill(value); + } + + template::value + && ( !std::is_same_v ) + ,int > = 0 + > + constexpr basic_fixed_rank_extents(OtherExtentsType const& e){ + for(auto i = size_type(0); i < size(); ++i){ + _base[i] = e[i]; + } + } + + constexpr basic_fixed_rank_extents(base_type const& data) + : _base(data) + { + if ( !valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + constexpr basic_fixed_rank_extents(base_type&& data) + : _base(std::move(data)) + { + if ( !valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + /** @brief Returns the std::vector containing extents */ + [[nodiscard]] inline + auto to_vector() const { + return std::vector( _base.begin(), _base.end() ); + } + + /** @brief Returns the std::vector containing extents */ + [[nodiscard]] inline + constexpr base_type const& base() const { + return _base; + } + + /** @brief Returns the std::vector containing extents */ + [[nodiscard]] inline + constexpr base_type& base() { + return _base; + } + + /** @brief Returns the basic_extents containing extents */ + [[nodiscard]] inline + auto to_dynamic_extents() const { + return basic_extents(this->to_vector()); + } + + /** @brief Checks if extents is empty or not + * + * @returns true if rank is 0 else false + * + */ + [[nodiscard]] inline + constexpr bool empty() const noexcept { return _size == size_type{0}; } + + friend void swap(basic_fixed_rank_extents& lhs, basic_fixed_rank_extents& rhs) { + std::swap(lhs._base , rhs._base ); + } + + [[nodiscard]] inline + const_pointer data() const + { + return _base.data(); + } + + [[nodiscard]] inline + const_iterator + begin() const + { + return _base.begin(); + } + + [[nodiscard]] inline + const_iterator + end() const + { + return _base.end(); + } + + const_reference back () const + { + return _base.back(); + } + + /** @brief Returns true if both extents are equal else false */ + [[nodiscard]] inline + constexpr bool operator==(basic_fixed_rank_extents const &other) const { + return _base == other._base; + } + + /** @brief Returns false if both extents are equal else true */ + [[nodiscard]] inline + constexpr bool operator!=(basic_fixed_rank_extents const &other) const { + return !(*this == other); + } + + ~basic_fixed_rank_extents() = default; + +private: + base_type _base{}; +}; + + +namespace detail{ + template + struct dynamic_extents_impl; + + template struct dynamic_extents_impl { + using type = basic_fixed_rank_extents; + }; + + template <> struct dynamic_extents_impl<> { + using type = basic_extents; + }; + +} // namespace detail + + +template +using dynamic_extents = typename detail::dynamic_extents_impl::type; + +} // namespace ublas +} // namespace numeric +} // namespace boost + + +#endif diff --git a/include/boost/numeric/ublas/tensor/dynamic_strides.hpp b/include/boost/numeric/ublas/tensor/dynamic_strides.hpp new file mode 100644 index 000000000..5c025e0c8 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/dynamic_strides.hpp @@ -0,0 +1,363 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// +/// \file strides.hpp Definition for the basic_strides template class + + +#ifndef _BOOST_UBLAS_TENSOR_DYNAMIC_STRIDES_HPP_ +#define _BOOST_UBLAS_TENSOR_DYNAMIC_STRIDES_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace boost { +namespace numeric { +namespace ublas { + +using first_order = column_major; +using last_order = row_major; + +template +class basic_extents; + + +/** @brief Template class for storing tensor strides for iteration with runtime variable size. + * + * Proxy template class of std::vector. + * + */ +template +class basic_strides +{ +public: + + using base_type = std::vector<__int_type>; + + static_assert( std::numeric_limits::is_integer, + "Static error in boost::numeric::ublas::basic_strides: type must be of type integer."); + static_assert(!std::numeric_limits::is_signed, + "Static error in boost::numeric::ublas::basic_strides: type must be of type unsigned integer."); + static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value, + "Static error in boost::numeric::ublas::basic_strides: layout type must either first or last order"); + + + using layout_type = __layout; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + + + /** @brief Default constructs basic_strides + * + * @code auto ex = basic_strides{}; + */ + constexpr explicit basic_strides() + : _base{} + { + } + + /** @brief Constructs basic_strides from basic_extents for the first- and last-order storage formats + * + * @code auto strides = basic_strides( basic_extents{2,3,4} ); + * + */ + template + basic_strides(basic_extents const& s) + : _base(s.size(),1) + { + if( s.empty() ) + return; + + if( !valid(s) ) + throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : shape is not valid."); + + if( is_vector(s) || is_scalar(s) ) + return; + + if( this->size() < 2 ) + throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : size of strides must be greater or equal 2."); + + + if constexpr (std::is_same::value){ + size_type k = 1ul, kend = this->size(); + for(; k < kend; ++k) + _base[k] = _base[k-1] * s[k-1]; + } + else { + size_type k = this->size()-2, kend = 0ul; + for(; k > kend; --k) + _base[k] = _base[k+1] * s[k+1]; + _base[0] = _base[1] * s[1]; + } + } + + basic_strides(basic_strides const& l) + : _base(l._base) + {} + + basic_strides(basic_strides && l ) + : _base(std::move(l._base)) + {} + + basic_strides(base_type const& l ) + : _base(l) + {} + + basic_strides(base_type && l ) + : _base(std::move(l)) + {} + + ~basic_strides() = default; + + + basic_strides& operator=(basic_strides other) + { + swap (*this, other); + return *this; + } + + friend void swap(basic_strides& lhs, basic_strides& rhs) { + std::swap(lhs._base , rhs._base); + } + + const_reference operator[] (size_type p) const{ + return _base[p]; + } + + const_pointer data() const{ + return _base.data(); + } + + const_reference at (size_type p) const{ + return _base.at(p); + } + + const_reference back () const{ + return _base[_base.size() - 1]; + } + + reference back (){ + return _base[_base.size() - 1]; + } + + bool empty() const{ + return _base.empty(); + } + + size_type size() const{ + return _base.size(); + } + + template + bool operator == (basic_strides const& b) const{ + return b.base() == this->base(); + } + + template + bool operator != (basic_strides const& b) const{ + return b.base() != this->base(); + } + + bool operator == (basic_strides const& b) const{ + return b._base == _base; + } + + bool operator != (basic_strides const& b) const{ + return b._base != _base; + } + + const_iterator begin() const{ + return _base.begin(); + } + + const_iterator end() const{ + return _base.end(); + } + + void clear() { + this->_base.clear(); + } + + base_type const& base() const{ + return this->_base; + } + + +protected: + base_type _base; +}; + + +/** @brief Template class for storing tensor strides for iteration with runtime variable size. + * + * Proxy template class of std::array. + * + */ +template +class basic_fixed_rank_strides +{ +public: + + using base_type = std::array<__int_type, N>; + + static_assert( std::numeric_limits::is_integer, + "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type integer."); + static_assert(!std::numeric_limits::is_signed, + "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type unsigned integer."); + static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value, + "Static error in boost::numeric::ublas::basic_fixed_rank_strides: layout type must either first or last order"); + + + using layout_type = __layout; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + + + /** @brief Default constructs basic_fixed_rank_strides + * + * @code auto ex = basic_fixed_rank_strides{}; + */ + constexpr explicit basic_fixed_rank_strides() + : _base{} + { + } + + /** @brief Constructs basic_fixed_rank_strides from basic_extents for the first- and last-order storage formats + * + * @code auto strides = basic_fixed_rank_strides( basic_extents{2,3,4} ); + * + */ + template + basic_fixed_rank_strides(basic_fixed_rank_extents const& s) + { + _base.fill(value_type(1)); + + if( s.empty() ) + return; + + if( !valid(s) ) + throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides() : shape is not valid."); + + if( is_vector(s) || is_scalar(s) ) + return; + + if( this->size() < 2 ) + throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides() : size of strides must be greater or equal 2."); + + + if constexpr (std::is_same::value){ + size_type k = 1ul, kend = this->size(); + for(; k < kend; ++k) + _base[k] = _base[k-1] * s[k-1]; + } + else { + size_type k = this->size()-2, kend = 0ul; + for(; k > kend; --k) + _base[k] = _base[k+1] * s[k+1]; + _base[0] = _base[1] * s[1]; + } + } + + basic_fixed_rank_strides(basic_fixed_rank_strides const& l) + : _base(l._base) + {} + + basic_fixed_rank_strides(basic_fixed_rank_strides && l ) + : _base(std::move(l._base)) + {} + + basic_fixed_rank_strides(base_type const& l ) + : _base(l) + {} + + basic_fixed_rank_strides(base_type && l ) + : _base(std::move(l)) + {} + + ~basic_fixed_rank_strides() = default; + + + basic_fixed_rank_strides& operator=(basic_fixed_rank_strides other) + { + swap (*this, other); + return *this; + } + + friend void swap(basic_fixed_rank_strides& lhs, basic_fixed_rank_strides& rhs) { + std::swap(lhs._base , rhs._base); + } + + const_reference operator[] (size_type p) const{ + return _base[p]; + } + + const_pointer data() const{ + return _base.data(); + } + + const_reference at (size_type p) const{ + return _base.at(p); + } + + const_reference back () const{ + return _base[N - 1]; + } + + reference back (){ + return _base[N - 1]; + } + + bool empty() const{ + return _base.empty(); + } + + size_type size() const{ + return _base.size(); + } + + const_iterator begin() const{ + return _base.begin(); + } + + const_iterator end() const{ + return _base.end(); + } + + base_type const& base() const{ + return this->_base; + } + + +protected: + base_type _base; +}; + + +} +} +} + +#endif diff --git a/include/boost/numeric/ublas/tensor/expression.hpp b/include/boost/numeric/ublas/tensor/expression.hpp index 2677a0e6f..7b48a83d5 100644 --- a/include/boost/numeric/ublas/tensor/expression.hpp +++ b/include/boost/numeric/ublas/tensor/expression.hpp @@ -20,14 +20,6 @@ namespace boost { namespace numeric { namespace ublas { - -template -class tensor; - -template -class basic_extents; - - //TODO: put in fwd.hpp struct tensor_tag {}; @@ -57,7 +49,7 @@ struct tensor_expression using type_category = tensor_tag; using tensor_type = T; - BOOST_UBLAS_INLINE + inline auto const& operator()() const { return *static_cast (this); } protected : @@ -87,7 +79,7 @@ struct binary_tensor_expression binary_tensor_expression(binary_tensor_expression&& l) : el(l.el), er(l.er), op(l.op) {} - BOOST_UBLAS_INLINE + inline decltype(auto) operator()(size_type i) const { return op(el(i), er(i)); } expression_type_left const& el; @@ -147,7 +139,7 @@ struct unary_tensor_expression unary_tensor_expression(unary_tensor_expression&& l) : e(l.e), op(op.l) {} - BOOST_UBLAS_INLINE + inline decltype(auto) operator()(size_type i) const { return op(e(i)); } E const& e; diff --git a/include/boost/numeric/ublas/tensor/expression_evaluation.hpp b/include/boost/numeric/ublas/tensor/expression_evaluation.hpp index a7948639a..8d80aed28 100644 --- a/include/boost/numeric/ublas/tensor/expression_evaluation.hpp +++ b/include/boost/numeric/ublas/tensor/expression_evaluation.hpp @@ -1,12 +1,13 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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 IOSB, Ettlingen, Germany +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef _BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP_ @@ -18,7 +19,7 @@ namespace boost::numeric::ublas { -template +template class tensor; template @@ -74,8 +75,8 @@ namespace boost::numeric::ublas::detail { /** @brief Retrieves extents of the tensor * */ -template -auto retrieve_extents(tensor const& t) +template +auto retrieve_extents(tensor const& t) { return t.extents(); } @@ -100,6 +101,11 @@ auto retrieve_extents(tensor_expression const& expr) return retrieve_extents(cast_expr); } +// Disable warning for unreachable code for MSVC compiler +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning( disable : 4702 ) +#endif /** @brief Retrieves extents of the binary tensor expression * * @note tensor expression must be a binary tree with at least one tensor type @@ -125,6 +131,10 @@ auto retrieve_extents(binary_tensor_expression const& expr) return retrieve_extents(expr.er); } +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + /** @brief Retrieves extents of the binary tensor expression * * @note tensor expression must be a binary tree with at least one tensor type @@ -152,14 +162,14 @@ auto retrieve_extents(unary_tensor_expression const& expr) namespace boost::numeric::ublas::detail { -template -auto all_extents_equal(tensor const& t, basic_extents const& extents) +template +auto all_extents_equal(tensor const& t, E const& extents) { return extents == t.extents(); } -template -auto all_extents_equal(tensor_expression const& expr, basic_extents const& extents) +template +auto all_extents_equal(tensor_expression const& expr, typename T::extents_type const& extents) { static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); @@ -178,8 +188,8 @@ auto all_extents_equal(tensor_expression const& expr, basic_extents cons } -template -auto all_extents_equal(binary_tensor_expression const& expr, basic_extents const& extents) +template +auto all_extents_equal(binary_tensor_expression const& expr, typename T::extents_type const& extents) { static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); @@ -204,10 +214,9 @@ auto all_extents_equal(binary_tensor_expression const& expr, basic_e } -template -auto all_extents_equal(unary_tensor_expression const& expr, basic_extents const& extents) +template +auto all_extents_equal(unary_tensor_expression const& expr, typename T::extents_type const& extents) { - static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); diff --git a/include/boost/numeric/ublas/tensor/extents.hpp b/include/boost/numeric/ublas/tensor/extents.hpp index 5d4bf8e5c..a026434a0 100644 --- a/include/boost/numeric/ublas/tensor/extents.hpp +++ b/include/boost/numeric/ublas/tensor/extents.hpp @@ -1,335 +1,56 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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 IOSB, Ettlingen, Germany +// Google // - -#ifndef BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_HPP -#define BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_HPP +#ifndef _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_HPP_ +#define _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_HPP_ #include -#include -#include -#include -#include -#include - -#include - -namespace boost { -namespace numeric { -namespace ublas { - - -/** @brief Template class for storing tensor extents with runtime variable size. - * - * Proxy template class of std::vector. - * - */ -template -class basic_extents -{ - static_assert( std::numeric_limits::value_type>::is_integer, "Static error in basic_layout: type must be of type integer."); - static_assert(!std::numeric_limits::value_type>::is_signed, "Static error in basic_layout: type must be of type unsigned integer."); - -public: - using base_type = std::vector; - using value_type = typename base_type::value_type; - using const_reference = typename base_type::const_reference; - using reference = typename base_type::reference; - using size_type = typename base_type::size_type; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - - - /** @brief Default constructs basic_extents - * - * @code auto ex = basic_extents{}; - */ - constexpr explicit basic_extents() - : _base{} - { - } - - /** @brief Copy constructs basic_extents from a one-dimensional container - * - * @code auto ex = basic_extents( std::vector(3u,3u) ); - * - * @note checks if size > 1 and all elements > 0 - * - * @param b one-dimensional std::vector container - */ - explicit basic_extents(base_type const& b) - : _base(b) - { - if (!this->valid()){ - throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); - } - } - - /** @brief Move constructs basic_extents from a one-dimensional container - * - * @code auto ex = basic_extents( std::vector(3u,3u) ); - * - * @note checks if size > 1 and all elements > 0 - * - * @param b one-dimensional container of type std::vector - */ - explicit basic_extents(base_type && b) - : _base(std::move(b)) - { - if (!this->valid()){ - throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); - } - } - - /** @brief Constructs basic_extents from an initializer list - * - * @code auto ex = basic_extents{3,2,4}; - * - * @note checks if size > 1 and all elements > 0 - * - * @param l one-dimensional list of type std::initializer - */ - basic_extents(std::initializer_list l) - : basic_extents( base_type(std::move(l)) ) - { - } - - /** @brief Constructs basic_extents from a range specified by two iterators - * - * @code auto ex = basic_extents(a.begin(), a.end()); - * - * @note checks if size > 1 and all elements > 0 - * - * @param first iterator pointing to the first element - * @param last iterator pointing to the next position after the last element - */ - basic_extents(const_iterator first, const_iterator last) - : basic_extents ( base_type( first,last ) ) - { - } - - /** @brief Copy constructs basic_extents */ - basic_extents(basic_extents const& l ) - : _base(l._base) - { - } - - /** @brief Move constructs basic_extents */ - basic_extents(basic_extents && l ) noexcept - : _base(std::move(l._base)) - { - } - - ~basic_extents() = default; - - basic_extents& operator=(basic_extents other) noexcept - { - swap (*this, other); - return *this; - } - - friend void swap(basic_extents& lhs, basic_extents& rhs) { - std::swap(lhs._base , rhs._base ); - } - - - - /** @brief Returns true if this has a scalar shape - * - * @returns true if (1,1,[1,...,1]) - */ - bool is_scalar() const - { - return - _base.size() != 0 && - std::all_of(_base.begin(), _base.end(), - [](const_reference a){ return a == 1;}); - } - - /** @brief Returns true if this has a vector shape - * - * @returns true if (1,n,[1,...,1]) or (n,1,[1,...,1]) with n > 1 - */ - bool is_vector() const - { - if(_base.size() == 0){ - return false; - } - - if(_base.size() == 1){ - return _base.at(0) > 1; - } - - auto greater_one = [](const_reference a){ return a > 1;}; - auto equal_one = [](const_reference a){ return a == 1;}; - - return - std::any_of(_base.begin(), _base.begin()+2, greater_one) && - std::any_of(_base.begin(), _base.begin()+2, equal_one ) && - std::all_of(_base.begin()+2, _base.end(), equal_one); - } - - /** @brief Returns true if this has a matrix shape - * - * @returns true if (m,n,[1,...,1]) with m > 1 and n > 1 - */ - bool is_matrix() const - { - if(_base.size() < 2){ - return false; - } - - auto greater_one = [](const_reference a){ return a > 1;}; - auto equal_one = [](const_reference a){ return a == 1;}; - - return - std::all_of(_base.begin(), _base.begin()+2, greater_one) && - std::all_of(_base.begin()+2, _base.end(), equal_one ); - } - - /** @brief Returns true if this is has a tensor shape - * - * @returns true if !empty() && !is_scalar() && !is_vector() && !is_matrix() - */ - bool is_tensor() const - { - if(_base.size() < 3){ - return false; - } - - auto greater_one = [](const_reference a){ return a > 1;}; - - return std::any_of(_base.begin()+2, _base.end(), greater_one); - } - - const_pointer data() const - { - return this->_base.data(); - } - - const_reference operator[] (size_type p) const - { - return this->_base[p]; - } - - const_reference at (size_type p) const - { - return this->_base.at(p); - } - - reference operator[] (size_type p) - { - return this->_base[p]; - } - - reference at (size_type p) - { - return this->_base.at(p); - } - - - bool empty() const - { - return this->_base.empty(); - } - - size_type size() const - { - return this->_base.size(); - } - - /** @brief Returns true if size > 1 and all elements > 0 */ - bool valid() const - { - return - this->size() > 1 && - std::none_of(_base.begin(), _base.end(), - [](const_reference a){ return a == value_type(0); }); - } - - /** @brief Returns the number of elements a tensor holds with this */ - size_type product() const - { - if(_base.empty()){ - return 0; - } - - return std::accumulate(_base.begin(), _base.end(), 1ul, std::multiplies<>()); - - } - - - /** @brief Eliminates singleton dimensions when size > 2 - * - * squeeze { 1,1} -> { 1,1} - * squeeze { 2,1} -> { 2,1} - * squeeze { 1,2} -> { 1,2} - * - * squeeze {1,2,3} -> { 2,3} - * squeeze {2,1,3} -> { 2,3} - * squeeze {1,3,1} -> { 3,1} - * - */ - basic_extents squeeze() const - { - if(this->size() <= 2){ - return *this; - } - - auto new_extent = basic_extents{}; - auto insert_iter = std::back_insert_iterator(new_extent._base); - std::remove_copy(this->_base.begin(), this->_base.end(), insert_iter ,value_type{1}); - return new_extent; - - } - - void clear() - { - this->_base.clear(); - } - - bool operator == (basic_extents const& b) const - { - return _base == b._base; - } - - bool operator != (basic_extents const& b) const - { - return !( _base == b._base ); - } - - const_iterator - begin() const - { - return _base.begin(); - } - - const_iterator - end() const - { - return _base.end(); - } - - base_type const& base() const { return _base; } - -private: - - base_type _base; - -}; - -using shape = basic_extents; - -} // namespace ublas -} // namespace numeric -} // namespace boost +#include +#include +#include + +namespace boost::numeric::ublas { + + template && detail::is_extents_v, int> = 0 + > + constexpr bool operator==(LExtents const& lhs, RExtents const& rhs){ + static_assert(detail::is_extents_v && detail::is_extents_v, + "boost::numeric::ublas::operator==() : invalid type, type should be an extents"); + if( lhs.size() != rhs.size() ){ + return false; + }else{ + return std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + } + + template && detail::is_extents_v, int> = 0 + > + constexpr bool operator!=(LExtents const& lhs, RExtents const& rhs){ + static_assert(detail::is_extents_v && detail::is_extents_v, + "boost::numeric::ublas::operator!=() : invalid type, type should be an extents"); + return !(lhs == rhs); + } + + template , int> = 0 + > + std::ostream& operator<<(std::ostream& os, Extents const& e){ + static_assert(detail::is_extents_v, + "boost::numeric::ublas::operator<<() : invalid type, type should be an extents"); + return os< @@ -19,539 +20,819 @@ #include #include +#include +#include +#include +#include +#include +#include +#include -#include "multiplication.hpp" -#include "algorithms.hpp" -#include "expression.hpp" -#include "expression_evaluation.hpp" -#include "storage_traits.hpp" - -namespace boost { -namespace numeric { -namespace ublas { - -template -class tensor; - -template -class matrix; - -template -class vector; - - - - -/** @brief Computes the m-mode tensor-times-vector product - * - * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] - * - * @note calls ublas::ttv - * - * @param[in] m contraction dimension with 1 <= m <= p - * @param[in] a tensor object A with order p - * @param[in] b vector object B - * - * @returns tensor object C with order p-1, the same storage format and allocator type as A -*/ -template -auto prod(tensor const& a, vector const& b, const std::size_t m) +// dynamic_functions +namespace boost::numeric::ublas { - using tensor_type = tensor; - using extents_type = typename tensor_type::extents_type; - using ebase_type = typename extents_type::base_type; - using value_type = typename tensor_type::value_type; - using size_type = typename extents_type::value_type; - - auto const p = std::size_t(a.rank()); + namespace detail{ + // MSVC 14.1 bug + // cannot use ::_size inside constexpr function + // basic_extents does not contains _size member because of which + // it complains about it + + template + constexpr auto extents_result_type_tensor_times_vector( E const& ){ + static_assert(is_static_rank::value, + "boost::numeric::ublas::extents_result_type_tensor_times_vector() : invalid type, type should be an extents"); + using size_type = typename E::size_type; + auto ret = dynamic_extents< std::max( size_type( E::_size - 1 ), size_type(2) )>(); + ret.fill(typename E::value_type(1)); + return ret; + } + + template + constexpr auto extents_result_type_tensor_times_vector( basic_extents const& e ){ + using size_type = typename basic_extents::size_type; + return dynamic_extents<>{ typename dynamic_extents<>::base_type(std::max( size_type( e.size() - 1), size_type(2) ),1) } ; + } + + template + constexpr auto extents_result_type_tensor_times_matrix( E const& a ){ + static_assert(is_static_rank::value, + "boost::numeric::ublas::extents_result_type_tensor_times_matrix() : invalid type, type should be an extents"); + return dynamic_extents(a); + } + + template + constexpr auto extents_result_type_tensor_times_matrix( basic_extents const& e ){ + return dynamic_extents<>{ e } ; + } + + template + constexpr auto extents_result_type_outer_prod( basic_static_extents const&, basic_static_extents const& ){ + return dynamic_extents(); + } + + template + constexpr auto extents_result_type_outer_prod( basic_static_extents const&, basic_fixed_rank_extents const& ){ + return dynamic_extents(); + } + + template + constexpr auto extents_result_type_outer_prod( basic_fixed_rank_extents const&, basic_static_extents const& ){ + return dynamic_extents(); + } + + template + auto extents_result_type_outer_prod( E1 const& e1, E2 const& e2){ + return dynamic_extents<>( std::vector( e1.size() + e2.size(), 1 ) ); + } + + } // namespace detail - if( m == 0) - throw std::length_error("error in boost::numeric::ublas::prod(ttv): contraction mode must be greater than zero."); - - if( p < m ) - throw std::length_error("error in boost::numeric::ublas::prod(ttv): rank of tensor must be greater than or equal to the modus."); - - if( p == 0) - throw std::length_error("error in boost::numeric::ublas::prod(ttv): rank of tensor must be greater than zero."); - - if( a.empty() ) - throw std::length_error("error in boost::numeric::ublas::prod(ttv): first argument tensor should not be empty."); - - if( b.size() == 0) - throw std::length_error("error in boost::numeric::ublas::prod(ttv): second argument vector should not be empty."); - - - auto nc = ebase_type(std::max(p-1, size_type(2)) , size_type(1)); - auto nb = ebase_type{b.size(),1}; - - - for(auto i = 0u, j = 0u; i < p; ++i) - if(i != m-1) - nc[j++] = a.extents().at(i); - - auto c = tensor_type(extents_type(nc),value_type{}); - - auto bb = &(b(0)); - - ttv(m, p, - c.data(), c.extents().data(), c.strides().data(), - a.data(), a.extents().data(), a.strides().data(), - bb, nb.data(), nb.data()); + /** @brief Computes the m-mode tensor-times-vector product + * + * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] + * + * @note calls ublas::ttv + * + * @param[in] m contraction dimension with 1 <= m <= p + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p-1, the same storage format and allocator type as A + */ + template + inline decltype(auto) prod(tensor const &a, vector const &b, const std::size_t m) + { + + using tensor_type = tensor; + using extents_type = typename tensor_type::extents_type; + using value_type = typename tensor_type::value_type; + using size_type = typename extents_type::size_type; + + auto const p = std::size_t(a.rank()); + + if (m == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttv): " + "contraction mode must be greater than zero."); + + if (p < m) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttv): rank of tensor must be " + "greater than or equal to the modus."); + + if (a.empty()) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttv): first " + "argument tensor should not be empty."); + + if (b.size() == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttv): second " + "argument vector should not be empty."); + + auto nc = detail::extents_result_type_tensor_times_vector(a.extents()); + auto nb = std::vector{b.size(), 1}; + auto a_extents = a.extents(); + for (auto i = size_type(0), j = size_type(0); i < p; ++i) + if (i != m - 1) + nc[j++] = a_extents.at(i); + + + auto c = tensor >(nc, value_type{}); + auto bb = &(b(0)); + ttv(m, p, + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + bb, nb.data(), nb.data()); + return c; + } + + /** @brief Computes the m-mode tensor-times-matrix product + * + * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] + * + * @note calls ublas::ttm + * + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * @param[in] m contraction dimension with 1 <= m <= p + * + * @returns tensor object C with order p, the same storage format and allocator type as A + */ + template + inline decltype(auto) prod(tensor const &a, matrix const &b, const std::size_t m) + { + using tensor_type = tensor; + using dynamic_strides_type = strides_t,F>; + using value_type = typename tensor_type::value_type; + + auto const p = a.rank(); + + if (m == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttm): " + "contraction mode must be greater than zero."); + + if (p < m || m > a.extents().size()) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttm): rank " + "of the tensor must be greater equal the modus."); + + if (a.empty()) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttm): first " + "argument tensor should not be empty."); + + if (b.size1() * b.size2() == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttm): second " + "argument matrix should not be empty."); + + auto nc = detail::extents_result_type_tensor_times_matrix(a.extents()); + auto nb = dynamic_extents<>{b.size1(), b.size2()}; + + auto wb = dynamic_strides_type(nb); + + nc[m - 1] = nb[0]; + + auto c = tensor(nc, value_type{}); + + auto bb = &(b(0, 0)); + ttm(m, p, + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + bb, nb.data(), wb.data()); + + return c; + } + + /** @brief Computes the q-mode tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls ublas::ttt + * + * na[phia[x]] = nb[phib[x]] for 1 <= x <= q + * + * @param[in] phia one-based permutation tuple of length q for the first + * input tensor a + * @param[in] phib one-based permutation tuple of length q for the second + * input tensor b + * @param[in] a left-hand side tensor with order r+q + * @param[in] b right-hand side tensor with order s+q + * @result tensor with order r+s + */ + template + inline decltype(auto) prod(tensor const &a, tensor const &b, + std::vector const &phia, std::vector const &phib) + { + + using tensor_type = tensor; + using extents_type_1 = E1; + using value_type = typename tensor_type::value_type; + using size_type = typename extents_type_1::value_type; + + auto const pa = a.rank(); + auto const pb = b.rank(); + + auto const q = size_type(phia.size()); + + if (pa == 0ul) + throw std::runtime_error("error in ublas::prod: order of left-hand side tensor must be greater than 0."); + if (pb == 0ul) + throw std::runtime_error("error in ublas::prod: order of right-hand side tensor must be greater than 0."); + if (pa < q) + throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the left-hand side tensor."); + if (pb < q) + throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the right-hand side tensor."); + + if (q != phib.size()) + throw std::runtime_error("error in ublas::prod: permutation tuples must have the same length."); + + if (pa < phia.size()) + throw std::runtime_error("error in ublas::prod: permutation tuple for the left-hand side tensor cannot be greater than the corresponding order."); + if (pb < phib.size()) + throw std::runtime_error("error in ublas::prod: permutation tuple for the right-hand side tensor cannot be greater than the corresponding order."); + + auto const &na = a.extents(); + auto const &nb = b.extents(); + + for (auto i = 0ul; i < q; ++i) + if (na.at(phia.at(i) - 1) != nb.at(phib.at(i) - 1)) + throw std::runtime_error("error in ublas::prod: permutations of the extents are not correct."); + + auto const r = pa - q; + auto const s = pb - q; + + std::vector phia1(pa), phib1(pb); + std::iota(phia1.begin(), phia1.end(), 1ul); + std::iota(phib1.begin(), phib1.end(), 1ul); + + std::vector nc(std::max(r + s, size_type(2)), size_type(1)); + + for (auto i = 0ul; i < phia.size(); ++i) + *std::remove(phia1.begin(), phia1.end(), phia.at(i)) = phia.at(i); + + //phia1.erase( std::remove(phia1.begin(), phia1.end(), phia.at(i)), phia1.end() ) ; + + assert(phia1.size() == pa); + + for (auto i = 0ul; i < r; ++i) + nc[i] = na[phia1[i] - 1]; + + for (auto i = 0ul; i < phib.size(); ++i) + *std::remove(phib1.begin(), phib1.end(), phib.at(i)) = phib.at(i); + //phib1.erase( std::remove(phib1.begin(), phib1.end(), phia.at(i)), phib1.end() ) ; + + assert(phib1.size() == pb); + + for (auto i = 0ul; i < s; ++i) + nc[r + i] = nb[phib1[i] - 1]; + + // std::copy( phib.begin(), phib.end(), phib1.end() ); + + assert(phia1.size() == pa); + assert(phib1.size() == pb); + + auto c = tensor(dynamic_extents<>(nc), value_type{}); + + ttt(pa, pb, q, + phia1.data(), phib1.data(), + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + b.data(), b.extents().data(), b.strides().data()); + + return c; + } + + // template + // auto operator*( tensor_index const& lhs, tensor_index + // const& rhs) + + /** @brief Computes the q-mode tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls ublas::ttt + * + * na[phi[x]] = nb[phi[x]] for 1 <= x <= q + * + * @param[in] phi one-based permutation tuple of length q for bot input + * tensors + * @param[in] a left-hand side tensor with order r+q + * @param[in] b right-hand side tensor with order s+q + * @result tensor with order r+s + */ + template + inline decltype(auto) prod(tensor const &a, tensor const &b, + std::vector const &phi) + { + return prod(a, b, phi, phi); + } + + /** @brief Computes the inner product of two tensors + * + * Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,jp]) + * + * @note calls inner function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns a value type. + */ + template + inline decltype(auto) inner_prod(tensor const &a, tensor const &b) + { + using value_type = typename tensor::value_type; + + if (a.rank() != b.rank()) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Rank of both tensors must be the same."); + + if (a.empty() || b.empty()) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensors should not be empty."); + + if (a.extents() != b.extents()) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensor extents should be the same."); + + return inner(a.rank(), a.extents().data(), + a.data(), a.strides().data(), + b.data(), b.strides().data(), value_type{0}); + } + + /** @brief Computes the outer product of two tensors + * + * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] + * + * @note calls outer function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns tensor object C with the same storage format F and allocator type A1 + */ + template ::value && + detail::is_static::value ) + ,int> = 0 + > + inline decltype(auto) outer_prod(tensor const &a, tensor const &b) + { + + if (a.empty() || b.empty()) + throw std::runtime_error( + "error in boost::numeric::ublas::outer_prod: " + "tensors should not be empty."); + + auto nc = detail::extents_result_type_outer_prod(a.extents(), b.extents()); + + auto a_extents = a.extents(); + auto b_extents = b.extents(); + + for(auto i = 0u; i < a.rank(); ++i) + nc.at(i) = a_extents.at(i); + + for(auto i = 0u; i < b.rank(); ++i) + nc.at(a.rank()+i) = b_extents.at(i); + + auto c = tensor(nc, V{}); + + outer(c.data(), c.rank(), c.extents().data(), c.strides().data(), + a.data(), a.rank(), a_extents.data(), a.strides().data(), + b.data(), b.rank(), b_extents.data(), b.strides().data()); + + return c; + } + + /** @brief Transposes a tensor according to a permutation tuple + * + * Implements C[tau[i1],tau[i2]...,tau[ip]] = A[i1,i2,...,ip] + * + * @note calls trans function + * + * @param[in] a tensor object of rank p + * @param[in] tau one-based permutation tuple of length p + * @returns a transposed tensor object with the same storage format F and allocator type A + */ + template + inline decltype(auto) trans(tensor const &a, std::vector const &tau) + { + using result_tensor_type = tensor, F, std::vector>; + // using strides_type = typename tensor_type::strides_type; + + if (a.empty()) + return result_tensor_type{}; + + auto const p = a.rank(); + auto const &na = a.extents(); + + auto nc = typename dynamic_extents<>::base_type(p); + for (auto i = 0u; i < p; ++i) + nc.at(tau.at(i) - 1) = na.at(i); + + // auto wc = strides_type(extents_type(nc)); + auto c = result_tensor_type(dynamic_extents<>(nc)); + + trans(a.rank(), a.extents().data(), tau.data(), + c.data(), c.strides().data(), + a.data(), a.strides().data()); + + // auto wc_pi = typename strides_type::base_type (p); + // for(auto i = 0u; i < p; ++i) + // wc_pi.at(tau.at(i)-1) = c.strides().at(i); + + // copy(a.rank(), + // a.extents().data(), + // c.data(), wc_pi.data(), + // a.data(), a.strides().data() ); + + return c; + } + /** + * + * @brief Computes the frobenius nor of a tensor + * + * @note Calls accumulate on the tensor. + * + * implements + * k = sqrt( sum_(i1,...,ip) A(i1,...,ip)^2 ) + * + * @tparam V the data type of tensor + * @tparam F the format of tensor storage + * @tparam A the array_type of tensor + * @param a the tensor whose norm is expected of rank p. + * @return the frobenius norm of a tensor. + */ + template + inline decltype(auto) norm(tensor const &a) + { + using tensor_type = tensor; + using value_type = typename tensor_type::value_type; + + static_assert(std::is_default_constructible::value, + "Value type of tensor must be default construct able in order " + "to call boost::numeric::ublas::norm"); + if (a.empty()) + { + throw std::runtime_error( + "error in boost::numeric::ublas::norm: tensors should not be empty."); + } + + return std::sqrt(accumulate(a.order(), a.extents().data(), a.data(), a.strides().data(), value_type{}, + [](auto const &l, auto const &r) { return l + r * r; })); + } + + + /** @brief Computes the complex conjugate component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ + template + auto conj(detail::tensor_expression,E,F,A>,D> const& expr) + { + return detail::make_unary_tensor_expression,E,F,A>> (expr(), [] (auto const& l) { return std::conj( l ); } ); + } + + /** @brief Computes the complex conjugate component of tensor elements within a tensor expression + * + * @param[in] expr tensor expression + * @returns complex tensor + */ + template + auto conj(detail::tensor_expression const& expr) + { + using tensor_type = T; + using value_type = typename tensor_type::value_type; + using extents_type = typename tensor_type::extents_type; + using layout_type = typename tensor_type::layout_type; + using array_type = typename tensor_type::array_type; + + using new_value_type = std::complex; + using new_array_type = typename storage_traits::template rebind; + + using tensor_complex_type = tensor; + + if( detail::retrieve_extents( expr ).empty() ) + throw std::runtime_error("error in boost::numeric::ublas::conj: tensors should not be empty."); + + auto a = tensor_type( expr ); + auto c = tensor_complex_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::conj(l) ; } ); + + return c; + } + + /** @brief Extract the real component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ + template + auto real(detail::tensor_expression const& expr) { + return detail::make_unary_tensor_expression (expr(), [] (auto const& l) { return std::real( l ); } ); + } + + /** @brief Extract the real component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ + template + auto real(detail::tensor_expression,E,F,A>,D> const& expr) + { + using tensor_complex_type = tensor,E,F,A>; + using tensor_type = tensor::template rebind>; + + if( detail::retrieve_extents( expr ).empty() ) + throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); + + auto a = tensor_complex_type( expr ); + auto c = tensor_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::real(l) ; } ); + + return c; + } + + + /** @brief Extract the imaginary component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ + template + auto imag(detail::tensor_expression const& lhs) { + return detail::make_unary_tensor_expression (lhs(), [] (auto const& l) { return std::imag( l ); } ); + } + + + /** @brief Extract the imag component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ + template + auto imag(detail::tensor_expression,E,F,A>,D> const& expr) + { + using tensor_complex_type = tensor,E,F,A>; + using tensor_type = tensor::template rebind>; + + if( detail::retrieve_extents( expr ).empty() ) + throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); + + auto a = tensor_complex_type( expr ); + auto c = tensor_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::imag(l) ; } ); + + return c; + } - - return c; } - - -/** @brief Computes the m-mode tensor-times-matrix product - * - * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] - * - * @note calls ublas::ttm - * - * @param[in] a tensor object A with order p - * @param[in] b vector object B - * @param[in] m contraction dimension with 1 <= m <= p - * - * @returns tensor object C with order p, the same storage format and allocator type as A -*/ -template -auto prod(tensor const& a, matrix const& b, const std::size_t m) +// static functions +namespace boost::numeric::ublas { - using tensor_type = tensor; - using extents_type = typename tensor_type::extents_type; - using strides_type = typename tensor_type::strides_type; - using value_type = typename tensor_type::value_type; - - - auto const p = a.rank(); - - if( m == 0) - throw std::length_error("error in boost::numeric::ublas::prod(ttm): contraction mode must be greater than zero."); - - if( p < m || m > a.extents().size()) - throw std::length_error("error in boost::numeric::ublas::prod(ttm): rank of the tensor must be greater equal the modus."); - - if( p == 0) - throw std::length_error("error in boost::numeric::ublas::prod(ttm): rank of the tensor must be greater than zero."); - - if( a.empty() ) - throw std::length_error("error in boost::numeric::ublas::prod(ttm): first argument tensor should not be empty."); - - if( b.size1()*b.size2() == 0) - throw std::length_error("error in boost::numeric::ublas::prod(ttm): second argument matrix should not be empty."); - - - auto nc = a.extents().base(); - auto nb = extents_type {b.size1(),b.size2()}; - auto wb = strides_type (nb); - - nc[m-1] = nb[0]; - - auto c = tensor_type(extents_type(nc),value_type{}); - - auto bb = &(b(0,0)); - - ttm(m, p, - c.data(), c.extents().data(), c.strides().data(), - a.data(), a.extents().data(), a.strides().data(), - bb, nb.data(), wb.data()); - - - return c; -} - - - - -/** @brief Computes the q-mode tensor-times-tensor product - * - * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) - * - * @note calls ublas::ttt - * - * na[phia[x]] = nb[phib[x]] for 1 <= x <= q - * - * @param[in] phia one-based permutation tuple of length q for the first input tensor a - * @param[in] phib one-based permutation tuple of length q for the second input tensor b - * @param[in] a left-hand side tensor with order r+q - * @param[in] b right-hand side tensor with order s+q - * @result tensor with order r+s -*/ -template -auto prod(tensor const& a, tensor const& b, - std::vector const& phia, std::vector const& phib) -{ - - using tensor_type = tensor; - using extents_type = typename tensor_type::extents_type; - using value_type = typename tensor_type::value_type; - using size_type = typename extents_type::value_type; - - auto const pa = a.rank(); - auto const pb = b.rank(); - - auto const q = size_type(phia.size()); - - if(pa == 0ul) - throw std::runtime_error("error in ublas::prod: order of left-hand side tensor must be greater than 0."); - if(pb == 0ul) - throw std::runtime_error("error in ublas::prod: order of right-hand side tensor must be greater than 0."); - if(pa < q) - throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the left-hand side tensor."); - if(pb < q) - throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the right-hand side tensor."); - - if(q != phib.size()) - throw std::runtime_error("error in ublas::prod: permutation tuples must have the same length."); - - if(pa < phia.size()) - throw std::runtime_error("error in ublas::prod: permutation tuple for the left-hand side tensor cannot be greater than the corresponding order."); - if(pb < phib.size()) - throw std::runtime_error("error in ublas::prod: permutation tuple for the right-hand side tensor cannot be greater than the corresponding order."); - - - auto const& na = a.extents(); - auto const& nb = b.extents(); - - for(auto i = 0ul; i < q; ++i) - if( na.at(phia.at(i)-1) != nb.at(phib.at(i)-1)) - throw std::runtime_error("error in ublas::prod: permutations of the extents are not correct."); - - auto const r = pa - q; - auto const s = pb - q; - - - std::vector phia1(pa), phib1(pb); - std::iota(phia1.begin(), phia1.end(), 1ul); - std::iota(phib1.begin(), phib1.end(), 1ul); - - std::vector nc( std::max ( r+s , size_type(2) ), size_type(1) ); - - for(auto i = 0ul; i < phia.size(); ++i) - * std::remove(phia1.begin(), phia1.end(), phia.at(i)) = phia.at(i); - - //phia1.erase( std::remove(phia1.begin(), phia1.end(), phia.at(i)), phia1.end() ) ; - - assert(phia1.size() == pa); - - for(auto i = 0ul; i < r; ++i) - nc[ i ] = na[ phia1[ i ] - 1 ]; - - for(auto i = 0ul; i < phib.size(); ++i) - * std::remove(phib1.begin(), phib1.end(), phib.at(i)) = phib.at(i) ; - //phib1.erase( std::remove(phib1.begin(), phib1.end(), phia.at(i)), phib1.end() ) ; - - assert(phib1.size() == pb); - - for(auto i = 0ul; i < s; ++i) - nc[ r + i ] = nb[ phib1[ i ] - 1 ]; - - // std::copy( phib.begin(), phib.end(), phib1.end() ); - - assert( phia1.size() == pa ); - assert( phib1.size() == pb ); - - auto c = tensor_type(extents_type(nc), value_type{}); - - ttt(pa, pb, q, - phia1.data(), phib1.data(), - c.data(), c.extents().data(), c.strides().data(), - a.data(), a.extents().data(), a.strides().data(), - b.data(), b.extents().data(), b.strides().data()); - - return c; -} - -//template -//auto operator*( tensor_index const& lhs, tensor_index const& rhs) - - - - -/** @brief Computes the q-mode tensor-times-tensor product - * - * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) - * - * @note calls ublas::ttt - * - * na[phi[x]] = nb[phi[x]] for 1 <= x <= q - * - * @param[in] phi one-based permutation tuple of length q for bot input tensors - * @param[in] a left-hand side tensor with order r+q - * @param[in] b right-hand side tensor with order s+q - * @result tensor with order r+s -*/ -template -auto prod(tensor const& a, tensor const& b, - std::vector const& phi) -{ - return prod(a, b, phi, phi); -} - - -/** @brief Computes the inner product of two tensors - * - * Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,jp]) - * - * @note calls inner function - * - * @param[in] a tensor object A - * @param[in] b tensor object B - * - * @returns a value type. -*/ -template -auto inner_prod(tensor const& a, tensor const& b) -{ - using value_type = typename tensor::value_type; - - if( a.rank() != b.rank() ) - throw std::length_error("error in boost::numeric::ublas::inner_prod: Rank of both tensors must be the same."); - - if( a.empty() || b.empty()) - throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensors should not be empty."); - - if( a.extents() != b.extents()) - throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensor extents should be the same."); - - return inner(a.rank(), a.extents().data(), - a.data(), a.strides().data(), - b.data(), b.strides().data(), value_type{0}); -} - -/** @brief Computes the outer product of two tensors - * - * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] - * - * @note calls outer function - * - * @param[in] a tensor object A - * @param[in] b tensor object B - * - * @returns tensor object C with the same storage format F and allocator type A1 -*/ -template -auto outer_prod(tensor const& a, tensor const& b) -{ - using tensor_type = tensor; - using extents_type = typename tensor_type::extents_type; - - if( a.empty() || b.empty() ) - throw std::runtime_error("error in boost::numeric::ublas::outer_prod: tensors should not be empty."); - - auto nc = typename extents_type::base_type(a.rank() + b.rank()); - for(auto i = 0u; i < a.rank(); ++i) - nc.at(i) = a.extents().at(i); - - for(auto i = 0u; i < b.rank(); ++i) - nc.at(a.rank()+i) = b.extents().at(i); - - auto c = tensor_type(extents_type(nc)); - - outer(c.data(), c.rank(), c.extents().data(), c.strides().data(), - a.data(), a.rank(), a.extents().data(), a.strides().data(), - b.data(), b.rank(), b.extents().data(), b.strides().data()); - - return c; -} - - - -/** @brief Transposes a tensor according to a permutation tuple - * - * Implements C[tau[i1],tau[i2]...,tau[ip]] = A[i1,i2,...,ip] - * - * @note calls trans function - * - * @param[in] a tensor object of rank p - * @param[in] tau one-based permutation tuple of length p - * @returns a transposed tensor object with the same storage format F and allocator type A -*/ -template -auto trans(tensor const& a, std::vector const& tau) -{ - using tensor_type = tensor; - using extents_type = typename tensor_type::extents_type; - // using strides_type = typename tensor_type::strides_type; - - if( a.empty() ) - return tensor{}; - - auto const p = a.rank(); - auto const& na = a.extents(); - - auto nc = typename extents_type::base_type (p); - for(auto i = 0u; i < p; ++i) - nc.at(tau.at(i)-1) = na.at(i); - - // auto wc = strides_type(extents_type(nc)); - - auto c = tensor_type(extents_type(nc)); - - - trans( a.rank(), a.extents().data(), tau.data(), - c.data(), c.strides().data(), - a.data(), a.strides().data()); - - // auto wc_pi = typename strides_type::base_type (p); - // for(auto i = 0u; i < p; ++i) - // wc_pi.at(tau.at(i)-1) = c.strides().at(i); - - - //copy(a.rank(), - // a.extents().data(), - // c.data(), wc_pi.data(), - // a.data(), a.strides().data() ); - - return c; -} - -/** @brief Computes the frobenius norm of a tensor expression - * - * @note evaluates the tensor expression and calls the accumulate function - * - * - * Implements the two-norm with - * k = sqrt( sum_(i1,...,ip) A(i1,...,ip)^2 ) - * - * @param[in] a tensor object of rank p - * @returns the frobenius norm of the tensor -*/ -//template -//auto norm(tensor const& a) -template -auto norm(detail::tensor_expression const& expr) -{ - - using tensor_type = typename detail::tensor_expression::tensor_type; - using value_type = typename tensor_type::value_type; - - auto a = tensor_type( expr ); - - if( a.empty() ) - throw std::runtime_error("error in boost::numeric::ublas::norm: tensors should not be empty."); - - return std::sqrt( accumulate( a.order(), a.extents().data(), a.data(), a.strides().data(), value_type{}, - [](auto const& l, auto const& r){ return l + r*r; } ) ) ; -} - - - -/** @brief Extract the real component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression -*/ -template -auto real(detail::tensor_expression const& expr) { - return detail::make_unary_tensor_expression (expr(), [] (auto const& l) { return std::real( l ); } ); -} - -/** @brief Extract the real component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression -*/ -template -auto real(detail::tensor_expression,F,A>,D> const& expr) -{ - using tensor_complex_type = tensor,F,A>; - using tensor_type = tensor::template rebind>; - - if( detail::retrieve_extents( expr ).empty() ) - throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); - - auto a = tensor_complex_type( expr ); - auto c = tensor_type( a.extents() ); - - std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::real(l) ; } ); - - return c; -} - - -/** @brief Extract the imaginary component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression -*/ -template -auto imag(detail::tensor_expression const& lhs) { - return detail::make_unary_tensor_expression (lhs(), [] (auto const& l) { return std::imag( l ); } ); -} - - -/** @brief Extract the imag component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression -*/ -template -auto imag(detail::tensor_expression,F,A>,D> const& expr) -{ - using tensor_complex_type = tensor,F,A>; - using tensor_type = tensor::template rebind>; - - if( detail::retrieve_extents( expr ).empty() ) - throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); - - auto a = tensor_complex_type( expr ); - auto c = tensor_type( a.extents() ); - - std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::imag(l) ; } ); - - return c; -} - -/** @brief Computes the complex conjugate component of tensor elements within a tensor expression - * - * @param[in] expr tensor expression - * @returns complex tensor -*/ -template -auto conj(detail::tensor_expression const& expr) -{ - using tensor_type = T; - using value_type = typename tensor_type::value_type; - using layout_type = typename tensor_type::layout_type; - using array_type = typename tensor_type::array_type; - - using new_value_type = std::complex; - using new_array_type = typename storage_traits::template rebind; - - using tensor_complex_type = tensor; - - if( detail::retrieve_extents( expr ).empty() ) - throw std::runtime_error("error in boost::numeric::ublas::conj: tensors should not be empty."); - - auto a = tensor_type( expr ); - auto c = tensor_complex_type( a.extents() ); - - std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::conj(l) ; } ); - - return c; -} - - -/** @brief Computes the complex conjugate component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression -*/ -template -auto conj(detail::tensor_expression,F,A>,D> const& expr) -{ - return detail::make_unary_tensor_expression,F,A>> (expr(), [] (auto const& l) { return std::conj( l ); } ); -} - - + namespace detail{ + + template + inline + constexpr auto extents_result_type_tensor_times_vector(basic_static_extents, + basic_static_extents, basic_static_extents) + { + return basic_static_extents{}; + } + + template + inline + constexpr auto extents_result_type_tensor_times_vector(basic_static_extents, + basic_static_extents, basic_static_extents = basic_static_extents{}) + { + if constexpr(I != M - 1){ + return extents_result_type_tensor_times_vector + ( basic_static_extents{}, basic_static_extents{}, basic_static_extents{} ); + }else{ + return extents_result_type_tensor_times_vector + ( basic_static_extents{}, basic_static_extents{}, basic_static_extents{} ); + } + } + + + template + inline + constexpr auto extents_result_type_tensor_times_vector(basic_static_extents const& e) + { + using size_type = typename basic_static_extents::size_type; + auto ones = typename impl::make_sequence_of_ones_t< T, std::max( size_type(2), sizeof...(E) ) >::extents_type{}; + return extents_result_type_tensor_times_vector(e, ones); + } + + template + inline + constexpr auto static_extents_set_at + ( basic_static_extents const&, basic_static_extents = basic_static_extents{}){ + static_assert( I < sizeof...(E) + 1, "boost::numeric::ublas::detail::static_extents_set_at(): out of bound"); + if constexpr( sizeof...(E) == 0 ){ + if constexpr( I == 0 ){ + return basic_static_extents{}; + }else{ + return basic_static_extents{}; + } + }else{ + if constexpr(I == 0){ + return basic_static_extents{}; + }else{ + return static_extents_set_at( basic_static_extents{}, basic_static_extents{} ); + } + } + } + + namespace impl{ + template + struct concat< basic_static_extents, basic_static_extents >{ + using type = basic_static_extents; + }; + } + + } // namespace detail + + /** @brief Computes the m-mode tensor-times-vector product + * + * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] + * + * @note calls ublas::ttv + * + * @tparam m contraction dimension with 1 <= m <= p + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p-1, the same storage format and allocator type as A + */ + template ::value,int> = 0 + > + inline decltype(auto) prod(tensor const &a, vector const &b) + { + + using tensor_type = tensor; + using extents_type = typename tensor_type::extents_type; + using value_type = typename tensor_type::value_type; + + auto const p = std::size_t(a.rank()); + + static_assert( M != 0, + "error in boost::numeric::ublas::prod(ttv): " + "contraction mode must be greater than zero."); + + static_assert( extents_type::_size >= M, + "error in boost::numeric::ublas::prod(ttv): rank of tensor must be " + "greater than or equal to the modus."); + + static_assert(extents_type::_size != 0, + "error in boost::numeric::ublas::prod(ttv): first " + "argument tensor should not be empty."); + + if (b.size() == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttv): second " + "argument vector should not be empty."); + + auto nc = detail::extents_result_type_tensor_times_vector(a.extents()); + auto nb = std::vector{b.size(), 1}; + + auto c = tensor(nc, value_type{}); + auto bb = &(b(0)); + + auto& a_static_extents = a.extents().base(); + auto& c_static_extents = c.extents().base(); + + auto& a_static_strides = a.strides().base(); + auto& c_static_strides = c.strides().base(); + + ttv(M, p, + c.data(), c_static_extents.data(), c_static_strides.data(), + a.data(), a_static_extents.data(), a_static_strides.data(), + bb, nb.data(), nb.data()); + + return c; + } + + /** @brief Computes the m-mode tensor-times-matrix product + * + * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] + * + * @note calls ublas::ttm + * + * @tparam m contraction dimension with 1 <= m <= p + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p, the same storage format and allocator type as A + */ + template ::value,int> = 0 + > + inline decltype(auto) prod(tensor const &a, matrix const &b) + { + using tensor_type = tensor; + using dynamic_strides_type = strides_t,F>; + using value_type = typename tensor_type::value_type; + + auto const p = a.rank(); + + static_assert(M != 0, + "error in boost::numeric::ublas::prod(ttm): " + "contraction mode must be greater than zero."); + + static_assert( E::_size >= M , + "error in boost::numeric::ublas::prod(ttm): rank " + "of the tensor must be greater equal the modus."); + + static_assert(E::_size, + "error in boost::numeric::ublas::prod(ttm): first " + "argument tensor should not be empty."); + + if (b.size1() * b.size2() == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttm): second " + "argument matrix should not be empty."); + + auto nc = detail::static_extents_set_at< M - 1, MatricRow >( a.extents() ); + auto nb = dynamic_extents<>{b.size1(), b.size2()}; + + auto wb = dynamic_strides_type(nb); + + auto c = tensor(nc, value_type{}); + + auto bb = &(b(0, 0)); + + auto& a_static_extents = a.extents().base(); + auto& c_static_extents = c.extents().base(); + + auto& a_static_strides = a.strides().base(); + auto& c_static_strides = c.strides().base(); + ttm(M, p, + c.data(), c_static_extents.data(), c_static_strides.data(), + a.data(), a_static_extents.data(), a_static_strides.data(), + bb, nb.data(), wb.data()); + + return c; + } + + /** @brief Computes the outer product of two tensors + * + * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] + * + * @note calls outer function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns tensor object C with the same storage format F and allocator type A1 + */ + template ::value && + detail::is_static::value + ,int> = 0 + > + inline decltype(auto) outer_prod(tensor const &a, tensor const &b) + { + if (a.empty() || b.empty()) + throw std::runtime_error( + "error in boost::numeric::ublas::outer_prod: " + "tensors should not be empty."); + using extents_type1 = std::decay_t< decltype(a.extents()) >; + using extents_type2 = std::decay_t< decltype(b.extents()) >; + auto nc = detail::impl::concat_t{}; + + auto a_extents = a.extents(); + auto b_extents = b.extents(); + + + auto c = tensor(nc, V{}); + + auto& a_static_extents = a_extents.base(); + auto& a_static_strides = a.strides().base(); + + auto& b_static_extents = b_extents.base(); + auto& b_static_strides = b.strides().base(); + + auto c_static_extents = c.extents().base(); + auto c_static_strides = c.strides().base(); + + outer(c.data(), c.rank(), c_static_extents.data(), c_static_strides.data(), + a.data(), a.rank(), a_static_extents.data(), a_static_strides.data(), + b.data(), b.rank(), b_static_extents.data(), b_static_strides.data()); + + return c; + } -} -} } diff --git a/include/boost/numeric/ublas/tensor/multi_index.hpp b/include/boost/numeric/ublas/tensor/multi_index.hpp index 3cc86e2fd..ccafde21d 100644 --- a/include/boost/numeric/ublas/tensor/multi_index.hpp +++ b/include/boost/numeric/ublas/tensor/multi_index.hpp @@ -18,6 +18,7 @@ #include #include "multi_index_utility.hpp" +#include "index.hpp" namespace boost { namespace numeric { @@ -93,7 +94,7 @@ auto array_to_vector(multi_index const& lhs, multi_index const& rhs) for(auto i = 0u; i < N; ++i) for(auto j = 0u; j < M; ++j) if ( lhs.at(i) == rhs.at(j) && lhs.at(i) != boost::numeric::ublas::index::_()) - pair_of_vector.first .push_back( i+1 ), + (void)pair_of_vector.first .push_back( i+1 ), pair_of_vector.second.push_back( j+1 ); return pair_of_vector; diff --git a/include/boost/numeric/ublas/tensor/multi_index_utility.hpp b/include/boost/numeric/ublas/tensor/multi_index_utility.hpp index f04c0e867..82e1bf68b 100644 --- a/include/boost/numeric/ublas/tensor/multi_index_utility.hpp +++ b/include/boost/numeric/ublas/tensor/multi_index_utility.hpp @@ -268,7 +268,7 @@ template struct index_position_pairs_impl { template - static constexpr void run(array_type& out, tuple_left const& , tuple_right const& , std::size_t p) + static constexpr void run([[maybe_unused]] array_type& out, tuple_left const& , tuple_right const& , [[maybe_unused]] std::size_t p) { using index_type = std::tuple_element_t; using has_index_type = has_index; diff --git a/include/boost/numeric/ublas/tensor/multiplication.hpp b/include/boost/numeric/ublas/tensor/multiplication.hpp index f415a3e2f..625788374 100644 --- a/include/boost/numeric/ublas/tensor/multiplication.hpp +++ b/include/boost/numeric/ublas/tensor/multiplication.hpp @@ -180,10 +180,10 @@ void ttm(SizeType const m, SizeType const r, for(auto i0 = 0ul; i0 < nc[0]; c += wc[0], a += wa[0], ++i0) { auto cm = c; auto b0 = b; - for(auto i0 = 0ul; i0 < nc[m]; cm += wc[m], b0 += wb[0], ++i0){ + for(auto i1 = 0ul; i1 < nc[m]; cm += wc[m], b0 += wb[0], ++i1){ auto am = a; auto b1 = b0; - for(auto i1 = 0ul; i1 < nb[1]; am += wa[m], b1 += wb[1], ++i1) + for(auto i2 = 0ul; i2 < nb[1]; am += wa[m], b1 += wb[1], ++i2) *cm += *am * *b1; } } @@ -233,7 +233,7 @@ void ttm0( SizeType const r, auto am = a; auto b1 = b0; - for(auto i1 = 0u; i1 < nb[1]; am += wa[0], b1 += wb[1], ++i1){ + for(auto i2 = 0u; i2 < nb[1]; am += wa[0], b1 += wb[1], ++i2){ *cm += *am * *b1; } @@ -452,14 +452,14 @@ void outer_2x2(SizeType const pa, auto c2 = c; auto b0 = b; for(auto ib0 = 0u; ib0 < nb[0]; b0 += wb[0], c2 += wc[pa], ++ib0) { - const auto b = *b0; + const auto new_b = *b0; auto c1 = c2; auto a1 = a; for(auto ia1 = 0u; ia1 < na[1]; a1 += wa[1], c1 += wc[1], ++ia1) { auto a0 = a1; auto c0 = c1; for(SizeType ia0 = 0u; ia0 < na[0]; a0 += wa[0], c0 += wc[0], ++ia0) - *c0 = *a0 * b; + *c0 = *a0 * new_b; } } } diff --git a/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp b/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp index c9de6d30c..26bbbdf34 100644 --- a/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp +++ b/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp @@ -26,7 +26,7 @@ namespace numeric{ namespace ublas { -template +template class tensor; template @@ -163,26 +163,26 @@ auto& operator /= (T& lhs, const boost::numeric::ublas::detail::tensor_expressio -template -auto& operator += (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { +template +auto& operator += (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l+=r; } ); return lhs; } -template -auto& operator -= (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { +template +auto& operator -= (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l-=r; } ); return lhs; } -template -auto& operator *= (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { +template +auto& operator *= (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l*=r; } ); return lhs; } -template -auto& operator /= (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { +template +auto& operator /= (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l/=r; } ); return lhs; } diff --git a/include/boost/numeric/ublas/tensor/operators_comparison.hpp b/include/boost/numeric/ublas/tensor/operators_comparison.hpp index e54b47af4..c155a0727 100644 --- a/include/boost/numeric/ublas/tensor/operators_comparison.hpp +++ b/include/boost/numeric/ublas/tensor/operators_comparison.hpp @@ -16,16 +16,18 @@ #include #include #include +#include +#include namespace boost::numeric::ublas { -template +template class tensor; } namespace boost::numeric::ublas::detail { -template -bool compare(tensor const& lhs, tensor const& rhs, BinaryPred pred) +template +bool compare(tensor const& lhs, tensor const& rhs, BinaryPred pred) { if(lhs.extents() != rhs.extents()){ @@ -45,8 +47,8 @@ bool compare(tensor const& lhs, tensor const& rhs, BinaryPred pred return true; } -template -bool compare(tensor const& rhs, UnaryPred pred) +template +bool compare(tensor const& rhs, UnaryPred pred) { for(auto i = 0u; i < rhs.size(); ++i) if(!pred(rhs(i))) diff --git a/include/boost/numeric/ublas/tensor/ostream.hpp b/include/boost/numeric/ublas/tensor/ostream.hpp index 74ee77ea6..2a70d1e9b 100644 --- a/include/boost/numeric/ublas/tensor/ostream.hpp +++ b/include/boost/numeric/ublas/tensor/ostream.hpp @@ -14,6 +14,7 @@ #include #include +#include namespace boost { namespace numeric { @@ -79,7 +80,7 @@ namespace boost { namespace numeric { namespace ublas { -template +template class tensor; template @@ -93,16 +94,16 @@ class vector; } -template -std::ostream& operator << (std::ostream& out, boost::numeric::ublas::tensor const& t) +template +std::ostream& operator << (std::ostream& out, boost::numeric::ublas::tensor const& t) { - if(t.extents().is_scalar()){ + if(is_scalar(t.extents())){ out << '['; boost::numeric::ublas::detail::print(out,t[0]); out << ']'; } - else if(t.extents().is_vector()) { + else if(is_vector(t.extents())) { const auto& cat = t.extents().at(0) > t.extents().at(1) ? ';' : ','; out << '['; for(auto i = 0u; i < t.size()-1; ++i){ diff --git a/include/boost/numeric/ublas/tensor/static_extents.hpp b/include/boost/numeric/ublas/tensor/static_extents.hpp new file mode 100644 index 000000000..55281070a --- /dev/null +++ b/include/boost/numeric/ublas/tensor/static_extents.hpp @@ -0,0 +1,167 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef _BOOST_NUMERIC_UBLAS_TENSOR_STATIC_EXTENTS_HPP_ +#define _BOOST_NUMERIC_UBLAS_TENSOR_STATIC_EXTENTS_HPP_ + +#include +#include +#include + +namespace boost::numeric::ublas { + +template struct basic_static_extents; +template class basic_extents; + +/** @brief Template class for storing tensor extents for compile time. + * + * @code basic_static_extents<1,2,3,4> t @endcode + * @tparam E parameter pack of extents + * + */ +template +struct basic_static_extents{ + + static constexpr auto _size = sizeof...(E); + + using base_type = std::array; + using value_type = typename base_type::value_type; + using const_reference = typename base_type::const_reference; + using reference = typename base_type::reference; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + using size_type = typename base_type::size_type; + + static_assert( std::numeric_limits::is_integer, "Static error in basic_static_extents: type must be of type integer."); + static_assert(!std::numeric_limits::is_signed, "Static error in basic_static_extents: type must be of type unsigned integer."); + + //@returns the rank of basic_static_extents + [[nodiscard]] inline + constexpr size_type size() const noexcept { return _size; } + + /** + * @param k pos of extent + * @returns the element at given pos + */ + [[nodiscard]] inline + static constexpr const_reference at(size_type k){ + return m_data.at(k); + } + + [[nodiscard]] inline + constexpr const_reference operator[](size_type k) const noexcept{ + return m_data[k]; + } + + // default constructor + constexpr basic_static_extents() = default; + + /** @brief Returns the std::vector containing extents */ + [[nodiscard]] inline + auto to_vector() const { + std::vector temp(_size); + std::copy(begin(), end(), temp.begin()); + return temp; + } + + /** @brief Returns ref to the std::array containing extents */ + [[nodiscard]] inline + constexpr base_type const& base() const noexcept{ + return m_data; + } + + /** @brief Returns pointer to the std::array containing extents */ + [[nodiscard]] inline + constexpr const_pointer data() const noexcept{ + return m_data.data(); + } + + /** @brief Returns the basic_extents containing extents */ + [[nodiscard]] inline + auto to_dynamic_extents() const { + return basic_extents(this->to_vector()); + } + + /** @brief Checks if extents is empty or not + * + * @returns true if rank is 0 else false + * + */ + [[nodiscard]] inline + constexpr bool empty() const noexcept { return m_data.empty(); } + + constexpr value_type back() const noexcept{ + return m_data.back(); + } + + /** @brief Returns true if both extents are equal else false */ + template + [[nodiscard]] inline + constexpr bool operator==([[maybe_unused]] basic_static_extents const &rhs) const { + if constexpr( _size != basic_static_extents::_size ){ + return false; + }else{ + return std::equal(begin(), end(), rhs.begin()); + } + } + + /** @brief Returns false if both extents are equal else true */ + template + [[nodiscard]] inline + constexpr bool operator!=(basic_static_extents const &rhs) const { + return !(*this == rhs); + } + + [[nodiscard]] inline + constexpr const_iterator begin() const noexcept{ + return m_data.begin(); + } + + [[nodiscard]] inline + constexpr const_iterator end() const noexcept{ + return m_data.end(); + } + + ~basic_static_extents() = default; + + +private: + static constexpr base_type const m_data{E...}; +}; + +template +using static_extents = basic_static_extents; + + +template struct static_product; + +template +inline static constexpr auto const static_product_v = static_product::value; + +template +struct static_product< basic_static_extents >{ + static constexpr auto const value = E0 * static_product_v< basic_static_extents >; +}; + +template +struct static_product< basic_static_extents >{ + static constexpr auto const value = E0 ; +}; + +template +struct static_product< basic_static_extents >{ + static constexpr auto const value = ExtentsType(0) ; +}; + +} // namespace boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/static_strides.hpp b/include/boost/numeric/ublas/tensor/static_strides.hpp new file mode 100644 index 000000000..c7b673d02 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/static_strides.hpp @@ -0,0 +1,296 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// +/// \file strides.hpp Definition for the basic_strides template class + +#ifndef BOOST_UBLAS_TENSOR_STATIC_STRIDES_HPP +#define BOOST_UBLAS_TENSOR_STATIC_STRIDES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost::numeric::ublas{ + + using first_order = column_major; + using last_order = row_major; + + template struct basic_static_strides; + +} // boost::numeric::ublas + +namespace boost::numeric::ublas::detail{ + + // list for storing stides as types + template< typename T, T... P > + struct static_stride_list{ + using extents_type = basic_static_extents; + using type = std::array; + static constexpr type const value = {P...}; + }; + + namespace impl{ + + // concat two static_stride_list togather + // @code using type = typename concat< static_stride_list, static_stride_list >::type @endcode + template + struct concat; + + template + struct concat< static_stride_list, static_stride_list > { + using type = static_stride_list; + }; + + template + using concat_t = typename concat::type; + + // generates static_stride_list containing ones with specific size + template + struct make_sequence_of_ones; + + template + using make_sequence_of_ones_t = typename make_sequence_of_ones::type; + + template + struct make_sequence_of_ones { + using type = concat_t, make_sequence_of_ones_t>; + }; + + template + struct make_sequence_of_ones { + using type = static_stride_list; + }; + template + struct make_sequence_of_ones{ + using type = static_stride_list; + }; + + } // impl + + + template + using make_sequence_of_ones_t = impl::make_sequence_of_ones_t; + + // @returns the static_stride_list containing strides + // It is a helper function or implementation + template + constexpr auto make_static_strides_helper( static_stride_list, + static_stride_list, static_stride_list) + { + if constexpr(sizeof...(E) == 0ul ){ + + if constexpr( std::is_same_v ){ + + return static_stride_list{}; + + }else{ + + return static_stride_list{}; + + } + + }else{ + // add extent to the list, which will be used for + // taking the product for next iteration + auto n = static_stride_list{}; + + // result list containing the strides + // on each iteration calculate the product + if constexpr( std::is_same_v ){ + auto np = static_stride_list< T, P..., static_product_v< basic_static_extents > >{}; + return make_static_strides_helper( static_stride_list{}, n, np ); + }else{ + auto np = static_stride_list< T, P..., static_product_v< basic_static_extents > >{}; + return make_static_strides_helper( static_stride_list{}, n, np ); + } + } + + } + + + // @returns the static_stride_list containing strides for last order + template + constexpr auto make_static_strides( static_stride_list ) + { + using extents_type = typename static_stride_list::extents_type; + // checks if extents are vector or scalar + if constexpr( !( static_traits::is_scalar_v || static_traits::is_vector_v ) ){ + // if extent contains only one element return static_stride_list + if constexpr( sizeof...(E) == 0 ){ + + return static_stride_list{}; + + }else{ + + if constexpr( std::is_same_v ){ + + using ret_type = decltype( make_static_strides_helper(static_stride_list{}, static_stride_list{}, static_stride_list{}) ); + return impl::concat_t< static_stride_list, ret_type>{}; + + }else{ + + using ret_type = decltype( make_static_strides_helper(static_stride_list{}, static_stride_list{}, static_stride_list{}) ); + return impl::concat_t >{}; + + } + + } + }else{ + // @returns list contining ones if it is vector or scalar + return make_sequence_of_ones_t{}; + } + } + + // if extents are empty return empty list + template + constexpr auto make_static_strides( static_stride_list ) + { + return static_stride_list{}; + } + + // It is use for first order to + // get std::array containing strides + template + struct strides_helper{ + using type = decltype( make_static_strides(static_stride_list{}) ); + static constexpr auto value = type::value; + }; + + template + inline static constexpr auto strides_helper_v = strides_helper::value; + +} // namespace boost::numeric::ublas::detail + +namespace boost::numeric::ublas +{ +/** @brief Partial Specialization for first_order or column_major + * + * @code basic_static_strides, first_order> s @endcode + * + * @tparam R rank of basic_static_extents + * @tparam Extents paramerter pack of extents + * + */ +template +struct basic_static_strides, Layout> +{ + + static constexpr std::size_t const _size = sizeof...(Extents); + + using layout_type = Layout; + using extents_type = basic_static_extents; + using base_type = std::array; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + + /** + * @param k pos of extent + * @returns the element at given pos + */ + [[nodiscard]] inline + constexpr auto at(size_type k) const + { + return m_data.at(k); + } + + [[nodiscard]] inline + constexpr auto operator[](size_type k) const { return m_data[k]; } + + //@returns the rank of basic_static_extents + [[nodiscard]] inline + constexpr auto size() const noexcept { return _size; } + + value_type back () const{ + return m_data.back(); + } + + // default constructor + constexpr basic_static_strides(){ + if constexpr( _size == 0 ){ + return; + }else{ + static_assert( static_traits::is_valid_v, "Error in boost::numeric::ublas::basic_static_strides() : shape is not valid."); + + if constexpr( static_traits::is_vector_v || static_traits::is_scalar_v ){ + return; + }else{ + static_assert(_size >= 2, "Error in boost::numeric::ublas::basic_static_strides() : size of strides must be greater or equal 2."); + } + } + + + } + + constexpr basic_static_strides(extents_type const&) {}; + + // default copy constructor + constexpr basic_static_strides(basic_static_strides const &other) noexcept = default; + // default assign constructor + constexpr basic_static_strides & + operator=(basic_static_strides const &other) noexcept = default; + + /** @brief Returns ref to the std::array containing extents */ + [[nodiscard]] inline + constexpr auto const& base() const noexcept{ + return m_data; + } + + /** @brief Returns pointer to the std::array containing extents */ + [[nodiscard]] inline + constexpr const_pointer data() const noexcept{ + return m_data.data(); + } + + [[nodiscard]] inline + constexpr const_iterator begin() const noexcept{ + return m_data.begin(); + } + + [[nodiscard]] inline + constexpr const_iterator end() const noexcept{ + return m_data.end(); + } + + [[nodiscard]] inline + constexpr bool empty() const noexcept{ + return m_data.empty(); + } + + template + constexpr bool operator==(basic_static_strides const& rhs) const noexcept{ + if constexpr( _size != basic_static_strides::_size ){ + return false; + }else{ + return std::equal(begin(), end(), rhs.begin()); + } + } + + template + constexpr bool operator!=(basic_static_strides const& rhs) const noexcept{ + return !(*this == rhs); + } + +private: + static constexpr base_type const m_data{ detail::strides_helper_v }; +}; + +} // namespace boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/storage.hpp b/include/boost/numeric/ublas/tensor/storage.hpp new file mode 100644 index 000000000..036089c6f --- /dev/null +++ b/include/boost/numeric/ublas/tensor/storage.hpp @@ -0,0 +1,46 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_STORAGE_HPP +#define BOOST_UBLAS_TENSOR_STORAGE_HPP + +#include +#include +#include +#include + +namespace boost::numeric::ublas::storage { + +namespace dense_tensor { + + template + struct default_storage; + + template + struct default_storage>::type> { + using type = std::vector; + }; + + template + struct default_storage>::type> { + using type = std::array>; + }; + + template + using default_storage_t = typename default_storage::type; + +} // namespace dense_tensor + +} // namespace boost::numeric::ublas::storage + +#endif diff --git a/include/boost/numeric/ublas/tensor/strides.hpp b/include/boost/numeric/ublas/tensor/strides.hpp index 53de553bb..cf1139198 100644 --- a/include/boost/numeric/ublas/tensor/strides.hpp +++ b/include/boost/numeric/ublas/tensor/strides.hpp @@ -1,251 +1,164 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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 IOSB, Ettlingen, Germany +// Google // /// \file strides.hpp Definition for the basic_strides template class +#ifndef _BOOST_UBLAS_TENSOR_STRIDES_HPP_ +#define _BOOST_UBLAS_TENSOR_STRIDES_HPP_ -#ifndef BOOST_UBLAS_TENSOR_STRIDES_HPP -#define BOOST_UBLAS_TENSOR_STRIDES_HPP - -#include -#include -#include -#include -#include #include -#include - -#include - -namespace boost { -namespace numeric { -namespace ublas { - -using first_order = column_major; -using last_order = row_major; - -template -class basic_extents; - - -/** @brief Template class for storing tensor strides for iteration with runtime variable size. - * - * Proxy template class of std::vector. - * - */ -template -class basic_strides -{ -public: - - using base_type = std::vector<__int_type>; - - static_assert( std::numeric_limits::is_integer, - "Static error in boost::numeric::ublas::basic_strides: type must be of type integer."); - static_assert(!std::numeric_limits::is_signed, - "Static error in boost::numeric::ublas::basic_strides: type must be of type unsigned integer."); - static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value, - "Static error in boost::numeric::ublas::basic_strides: layout type must either first or last order"); - - - using layout_type = __layout; - using value_type = typename base_type::value_type; - using reference = typename base_type::reference; - using const_reference = typename base_type::const_reference; - using size_type = typename base_type::size_type; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - - - /** @brief Default constructs basic_strides - * - * @code auto ex = basic_strides{}; - */ - constexpr explicit basic_strides() - : _base{} - { - } - - /** @brief Constructs basic_strides from basic_extents for the first- and last-order storage formats - * - * @code auto strides = basic_strides( basic_extents{2,3,4} ); - * - */ - template - basic_strides(basic_extents const& s) - : _base(s.size(),1) - { - if(s.empty()) - return; - - if(!s.valid()) - throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : shape is not valid."); - - if(s.is_vector() || s.is_scalar()) - return; - - if(this->size() < 2) - throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : size of strides must be greater or equal 2."); - - - if constexpr (std::is_same::value){ - size_type k = 1ul, kend = this->size(); - for(; k < kend; ++k) - _base[k] = _base[k-1] * s[k-1]; - } - else { - size_type k = this->size()-2, kend = 0ul; - for(; k > kend; --k) - _base[k] = _base[k+1] * s[k+1]; - _base[0] = _base[1] * s[1]; - } - } - - basic_strides(basic_strides const& l) - : _base(l._base) - {} - - basic_strides(basic_strides && l ) - : _base(std::move(l._base)) - {} - - basic_strides(base_type const& l ) - : _base(l) - {} - - basic_strides(base_type && l ) - : _base(std::move(l)) - {} - - ~basic_strides() = default; - - - basic_strides& operator=(basic_strides other) - { - swap (*this, other); - return *this; - } - - friend void swap(basic_strides& lhs, basic_strides& rhs) { - std::swap(lhs._base , rhs._base); - } - - const_reference operator[] (size_type p) const{ - return _base[p]; - } - - const_pointer data() const{ - return _base.data(); - } - - const_reference at (size_type p) const{ - return _base.at(p); - } - - - bool empty() const{ - return _base.empty(); - } - - size_type size() const{ - return _base.size(); - } - - template - bool operator == (basic_strides const& b) const{ - return b.base() == this->base(); - } - - template - bool operator != (basic_strides const& b) const{ - return b.base() != this->base(); - } - - bool operator == (basic_strides const& b) const{ - return b._base == _base; - } - - bool operator != (basic_strides const& b) const{ - return b._base != _base; - } - - const_iterator begin() const{ - return _base.begin(); - } - - const_iterator end() const{ - return _base.end(); - } - - void clear() { - this->_base.clear(); - } - - base_type const& base() const{ - return this->_base; - } - - -protected: - base_type _base; -}; - -template -using strides = basic_strides; - -namespace detail { - - -/** @brief Returns relative memory index with respect to a multi-index - * - * @code auto j = access(std::vector{3,4,5}, strides{shape{4,2,3},first_order}); @endcode - * - * @param[in] i multi-index of length p - * @param[in] w stride vector of length p - * @returns relative memory location depending on \c i and \c w -*/ -BOOST_UBLAS_INLINE -template -auto access(std::vector const& i, basic_strides const& w) -{ - const auto p = i.size(); - size_type sum = 0u; - for(auto r = 0u; r < p; ++r) - sum += i[r]*w[r]; - return sum; -} - -/** @brief Returns relative memory index with respect to a multi-index - * - * @code auto j = access(0, strides{shape{4,2,3},first_order}, 2,3,4); @endcode - * - * @param[in] i first element of the partial multi-index - * @param[in] is the following elements of the partial multi-index - * @param[in] sum the current relative memory index - * @returns relative memory location depending on \c i and \c w -*/ -BOOST_UBLAS_INLINE -template -auto access(std::size_t sum, basic_strides const& w, std::size_t i, size_types ... is) -{ - sum+=i*w[r]; - if constexpr (sizeof...(is) == 0) - return sum; - else - return detail::access(sum,w,std::forward(is)...); -} - -} - -} -} -} +#include +#include + +namespace boost::numeric::ublas { + + template && detail::is_strides_v, int> = 0 + > + constexpr bool operator==(LStrides const &lhs, RStrides const &rhs) { + + static_assert(detail::is_strides_v && detail::is_strides_v, + "boost::numeric::ublas::operator==() : invalid type, type should be a strides"); + + if( lhs.size() != rhs.size() ){ + return false; + }else{ + return std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + } + + template && detail::is_strides_v, int> = 0 + > + constexpr bool operator!=(LStrides const &lhs, RStrides const &rhs) { + static_assert(detail::is_strides_v && detail::is_strides_v, + "boost::numeric::ublas::operator!=() : invalid type, type should be a strides"); + return !(lhs == rhs); + } + + template , int> = 0 + > + std::ostream& operator<<(std::ostream& os, Strides const& s){ + static_assert(detail::is_strides_v, + "boost::numeric::ublas::operator<<() : invalid type, type should be a strides"); + return os< struct strides; + + /** @brief Partial Specialization of strides for basic_static_extents + * + * + * @tparam Layout either first_order or last_order + * + * @tparam R rank of extents + * + * @tparam Extents parameter pack of extents + * + */ + template + struct strides, Layout> + { + using type = basic_static_strides, Layout>; + }; + + /** @brief Partial Specialization of strides for basic_extents + * + * + * @tparam Layout either first_order or last_order + * + * @tparam T extents type + * + */ + template + struct strides, Layout> + { + using type = basic_strides; + }; + + /** @brief Partial Specialization of strides for basic_fixed_rank_strides + * + * + * @tparam Layout either first_order or last_order + * + * @tparam T extents type + * + */ + template + struct strides, Layout> + { + using type = basic_fixed_rank_strides; + }; + + /** @brief type alias of result of strides::type + * + * @tparam E extents type either basic_extents or basic_static_extents + * + * @tparam Layout either first_order or last_order + * + */ + template + using strides_t = typename strides::type; + + namespace detail{ + + + /** @brief Returns relative memory index with respect to a multi-index + * + * @code auto j = access(std::vector{3,4,5}, strides{shape{4,2,3},first_order}); @endcode + * + * @param[in] i multi-index of length p + * @param[in] w stride vector of length p + * @returns relative memory location depending on \c i and \c w + */ + template + auto access(std::vector const& i, Stride const& w) + { + static_assert( is_strides_v, + "boost::numeric::ublas::detail::access() : invalid type, type should be a strides"); + + const auto p = i.size(); + size_type sum = 0u; + for(auto r = 0u; r < p; ++r) + sum += i[r]*w[r]; + return sum; + } + + /** @brief Returns relative memory index with respect to a multi-index + * + * @code auto j = access(0, strides{shape{4,2,3},first_order}, 2,3,4); @endcode + * + * @param[in] i first element of the partial multi-index + * @param[in] is the following elements of the partial multi-index + * @param[in] sum the current relative memory index + * @returns relative memory location depending on \c i and \c w + */ + template + auto access(std::size_t sum, Stride const& w, std::size_t i, size_types ... is) + { + static_assert( is_strides_v, + "boost::numeric::ublas::detail::access() : invalid type, type should be a strides"); + sum += i*w[r]; + if constexpr (sizeof...(is) == 0) + return sum; + else + return detail::access(sum,w,std::forward(is)...); + } + + +} // namespace detail + +} // namespace boost::numeric::ublas #endif diff --git a/include/boost/numeric/ublas/tensor/tensor.hpp b/include/boost/numeric/ublas/tensor/tensor.hpp index ea79b60cc..3f209d161 100644 --- a/include/boost/numeric/ublas/tensor/tensor.hpp +++ b/include/boost/numeric/ublas/tensor/tensor.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2018-2019 -// Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -16,28 +16,19 @@ #ifndef BOOST_UBLAS_TENSOR_IMPL_HPP #define BOOST_UBLAS_TENSOR_IMPL_HPP -#include - #include -#include "algorithms.hpp" -#include "expression.hpp" -#include "expression_evaluation.hpp" -#include "extents.hpp" -#include "strides.hpp" -#include "index.hpp" +#include +#include +#include +#include +#include +#include +#include +#include namespace boost { namespace numeric { namespace ublas { -template -class tensor; - -template -class matrix; - -template -class vector; - ///** \brief Base class for Tensor container models // * // * it does not model the Tensor concept but all derived types should. @@ -54,11 +45,11 @@ class vector; // typedef C container_type; // typedef tensor_tag type_category; -// BOOST_UBLAS_INLINE +// inline // const container_type &operator () () const { // return *static_cast (this); // } -// BOOST_UBLAS_INLINE +// inline // container_type &operator () () { // return *static_cast (this); // } @@ -75,16 +66,16 @@ class vector; * @tparam T type of the objects stored in the tensor (like int, double, complex,...) * @tparam A The type of the storage array of the tensor. Default is \c unbounded_array. \c and \c std::vector can also be used */ -template> > +template, class F = first_order, class A = storage::dense_tensor::default_storage_t< T, E ,std::allocator> > class tensor: - public detail::tensor_expression,tensor> + public detail::tensor_expression,tensor> { static_assert( std::is_same::value || std::is_same::value, "boost::numeric::tensor template class only supports first- or last-order storage formats."); - using self_type = tensor; + using self_type = tensor; public: @@ -100,7 +91,7 @@ class tensor: using super_type = tensor_expression_type; -// static_assert(std::is_same_v, detail::tensor_expression,tensor>>, "tensor_expression_type"); +// static_assert(std::is_same_v, detail::tensor_expression,tensor>>, "tensor_expression_type"); using array_type = A; using layout_type = F; @@ -125,11 +116,11 @@ class tensor: using tensor_temporary_type = self_type; using storage_category = dense_tag; - using strides_type = basic_strides; - using extents_type = shape; + using strides_type = strides_t; + using extents_type = E; - using matrix_type = matrix; - using vector_type = vector; + using matrix_type = matrix>; + using vector_type = vector>; /** @brief Constructs a tensor. @@ -138,17 +129,17 @@ class tensor: * @note the tensor needs to reshaped for further use. * */ - BOOST_UBLAS_INLINE + inline constexpr tensor () : tensor_expression_type() // container_type , extents_() , strides_() - , data_() { + resize(extents_); } - /** @brief Constructs a tensor with an initializer list + /** @brief Constructs a tensor with an initializer list for dynamic_extents * * By default, its elements are initialized to 0. * @@ -156,16 +147,15 @@ class tensor: * * @param l initializer list for setting the dimension extents of the tensor */ - explicit BOOST_UBLAS_INLINE + explicit inline tensor (std::initializer_list l) : tensor_expression_type() , extents_ (std::move(l)) , strides_ (extents_) - , data_ (extents_.product()) { + resize(extents_); } - /** @brief Constructs a tensor with a \c shape * * By default, its elements are initialized to 0. @@ -174,13 +164,14 @@ class tensor: * * @param s initial tensor dimension extents */ - explicit BOOST_UBLAS_INLINE + explicit inline tensor (extents_type const& s) : tensor_expression_type() //tensor_container() , extents_ (s) , strides_ (extents_) - , data_ (extents_.product()) - {} + { + resize(extents_); + } /** @brief Constructs a tensor with a \c shape and initiates it with one-dimensional data @@ -191,14 +182,14 @@ class tensor: * @param s initial tensor dimension extents * @param a container of \c array_type that is copied according to the storage layout */ - BOOST_UBLAS_INLINE + inline tensor (extents_type const& s, const array_type &a) : tensor_expression_type() //tensor_container() , extents_ (s) , strides_ (extents_) , data_ (a) { - if(this->extents_.product() != this->data_.size()) + if(product(extents_) != this->data_.size()) throw std::runtime_error("Error in boost::numeric::ublas::tensor: size of provided data and specified extents do not match."); } @@ -211,13 +202,31 @@ class tensor: * @param e initial tensor dimension extents * @param i initial value of all elements of type \c value_type */ - BOOST_UBLAS_INLINE + inline tensor (extents_type const& e, const value_type &i) : tensor_expression_type() //tensor_container () , extents_ (e) , strides_ (extents_) - , data_ (extents_.product(), i) - {} + { + resize(extents_); + std::fill(begin(),end(),i); + } + + // /** @brief Constructs a tensor using a shape tuple and initiates it with a value. + // * + // * @code tensor A{extents{4,2,3}, 1 }; @endcode + // * + // * @param e initial tensor dimension extents + // * @param i initial value of all elements of type \c value_type + // */ + // template + // inline + // tensor (shape_t const& e, const value_type &i, typename std::enable_if::value>::type* = nullptr) + // : tensor_expression_type() //tensor_container () + // , extents_ (e.begin(),e.end()) + // , strides_ (extents_) + // , data_ (product(extents_), i) + // {} @@ -225,7 +234,7 @@ class tensor: * * @param v tensor to be copied. */ - BOOST_UBLAS_INLINE + inline tensor (const tensor &v) : tensor_expression_type() , extents_ (v.extents_) @@ -239,7 +248,7 @@ class tensor: * * @param v tensor to be moved. */ - BOOST_UBLAS_INLINE + inline tensor (tensor &&v) : tensor_expression_type() //tensor_container () , extents_ (std::move(v.extents_)) @@ -247,23 +256,38 @@ class tensor: , data_ (std::move(v.data_ )) {} - /** @brief Constructs a tensor with a matrix * * \note Initially the tensor will be two-dimensional. * * @param v matrix to be copied. */ - BOOST_UBLAS_INLINE + inline tensor (const matrix_type &v) : tensor_expression_type() , extents_ () , strides_ () - , data_ (v.data()) { - if(!data_.empty()){ - extents_ = extents_type{v.size1(),v.size2()}; - strides_ = strides_type(extents_); + auto const sz = v.size1() * v.size2(); + if(sz){ + if constexpr (detail::is_static::value){ + static_assert(extents_type::_size == 2 + , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : invalid extents size"); + if( !( extents_[0] == v.size1() || extents_[1] == v.size2() ) ){ + throw std::runtime_error("Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : rank of extents not correct, please check!"); + } + }else { + if constexpr( detail::is_static_rank::value ){ + static_assert(extents_type::size() == 2, "Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : rank of extents not correct, please check!"); + } + resize(sz); + extents_ = extents_type{v.size1(),v.size2()}; + strides_ = strides_type(extents_); + } + std::copy(v.data().begin(), v.data().end(),data_.begin()); } } @@ -273,17 +297,37 @@ class tensor: * * @param v matrix to be moved. */ - BOOST_UBLAS_INLINE + inline tensor (matrix_type &&v) : tensor_expression_type() , extents_ {} , strides_ {} , data_ {} { - if(v.size1()*v.size2() != 0){ - extents_ = extents_type{v.size1(),v.size2()}; - strides_ = strides_type(extents_); - data_ = std::move(v.data()); + + auto const sz = v.size1() * v.size2(); + if(sz){ + if constexpr (detail::is_static::value){ + static_assert(extents_type::_size == 2 + , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : invalid extents size"); + if( !( extents_[0] == v.size1() || extents_[1] == v.size2() ) ){ + throw std::runtime_error("Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : rank of extents not correct, please check!"); + } + }else { + if constexpr( detail::is_static_rank::value ){ + static_assert(extents_type::size() == 2, "Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : rank of extents not correct, please check!"); + } + + resize(sz); + extents_ = extents_type{v.size1(),v.size2()}; + strides_ = strides_type(extents_); + } + for(auto i = size_type{}; i < sz; ++i){ + data_[i] = std::move(v.data()[i]); + } } } @@ -294,53 +338,93 @@ class tensor: * * @param v vector to be copied. */ - BOOST_UBLAS_INLINE + inline tensor (const vector_type &v) : tensor_expression_type() , extents_ () , strides_ () - , data_ (v.data()) { - if(!data_.empty()){ - extents_ = extents_type{data_.size(),1}; - strides_ = strides_type(extents_); + auto const sz = v.size(); + if(sz){ + if constexpr (detail::is_static::value){ + static_assert(extents_type::_size == 2 + , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : invalid extents size"); + if( !( extents_[0] == v.size() || extents_[1] == 1 ) ){ + throw std::runtime_error("Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : rank of extents not correct, please check!"); + } + }else{ + if constexpr( detail::is_static_rank::value ){ + static_assert(extents_type::size() == 2, "Error in boost::numeric::ublas::tensor(const vector &v)" + " : rank of extents not correct, please check!"); + } + + resize(sz); + extents_ = extents_type{v.size(),1}; + strides_ = strides_type(extents_); + } + std::copy(v.data().begin(), v.data().end(),data_.begin()); } + } /** @brief Constructs a tensor using a \c vector * * @param v vector to be moved. */ - BOOST_UBLAS_INLINE + inline tensor (vector_type &&v) : tensor_expression_type() , extents_ {} , strides_ {} , data_ {} { - if(v.size() != 0){ - extents_ = extents_type{v.size(),1}; - strides_ = strides_type(extents_); - data_ = std::move(v.data()); + auto const sz = v.size(); + if(sz){ + if constexpr (detail::is_static::value){ + static_assert(extents_type::_size == 2 + , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : invalid extents size"); + if( !( extents_[0] == v.size() || extents_[1] == 1 ) ){ + throw std::runtime_error("Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : rank of extents not correct, please check!"); + } + }else{ + if constexpr( detail::is_static_rank::value ){ + static_assert(extents_type::size() == 2, "Error in boost::numeric::ublas::tensor(const vector &v)" + " : rank of extents not correct, please check!"); + } + + resize(sz); + extents_ = extents_type{v.size(),1}; + strides_ = strides_type(extents_); + } + + for(auto i = size_type{}; i < sz; ++i){ + data_[i] = std::move(v.data()[i]); + } } } + + /** @brief Constructs a tensor with another tensor with a different layout * * @param other tensor with a different layout to be copied. */ - BOOST_UBLAS_INLINE - template - tensor (const tensor &other) + template + tensor (const tensor &other) : tensor_expression_type () , extents_ (other.extents()) , strides_ (other.extents()) - , data_ (other.extents().product()) - { + { + resize(extents_); copy(this->rank(), this->extents().data(), - this->data(), this->strides().data(), - other.data(), other.strides().data()); + this->data(), this->strides().data(), + other.data(), other.strides().data()); + } /** @brief Constructs a tensor with an tensor expression @@ -352,16 +436,15 @@ class tensor: * * @param expr tensor expression */ - BOOST_UBLAS_INLINE template tensor (const tensor_expression_type &expr) : tensor_expression_type () , extents_ ( detail::retrieve_extents(expr) ) , strides_ ( extents_ ) - , data_ ( extents_.product() ) { static_assert( detail::has_tensor_types>::value, "Error in boost::numeric::ublas::tensor: expression does not contain a tensor. cannot retrieve shape."); + resize(extents_); detail::eval( *this, expr ); } @@ -374,7 +457,6 @@ class tensor: * * @param expr matrix expression */ - BOOST_UBLAS_INLINE template tensor (const matrix_expression_type &expr) : tensor( matrix_type ( expr ) ) @@ -390,7 +472,6 @@ class tensor: * * @param expr vector expression */ - BOOST_UBLAS_INLINE template tensor (const vector_expression_type &expr) : tensor( vector_type ( expr ) ) @@ -405,7 +486,6 @@ class tensor: * * @param expr expression that is evaluated. */ - BOOST_UBLAS_INLINE template tensor &operator = (const tensor_expression_type &expr) { @@ -426,57 +506,57 @@ class tensor: } /** @brief Returns true if the tensor is empty (\c size==0) */ - BOOST_UBLAS_INLINE + inline bool empty () const { return this->data_.empty(); } /** @brief Returns the size of the tensor */ - BOOST_UBLAS_INLINE + inline size_type size () const { return this->data_.size (); } /** @brief Returns the size of the tensor */ - BOOST_UBLAS_INLINE + inline size_type size (size_type r) const { return this->extents_.at(r); } /** @brief Returns the number of dimensions/modes of the tensor */ - BOOST_UBLAS_INLINE + inline size_type rank () const { return this->extents_.size(); } /** @brief Returns the number of dimensions/modes of the tensor */ - BOOST_UBLAS_INLINE + inline size_type order () const { return this->extents_.size(); } /** @brief Returns the strides of the tensor */ - BOOST_UBLAS_INLINE + inline strides_type const& strides () const { return this->strides_; } /** @brief Returns the extents of the tensor */ - BOOST_UBLAS_INLINE + inline extents_type const& extents () const { return this->extents_; } /** @brief Returns a \c const reference to the container. */ - BOOST_UBLAS_INLINE + inline const_pointer data () const { return this->data_.data(); } /** @brief Returns a \c const reference to the container. */ - BOOST_UBLAS_INLINE + inline pointer data () { return this->data_.data(); } @@ -487,25 +567,22 @@ class tensor: * * @param i zero-based index where 0 <= i < this->size() */ - BOOST_UBLAS_INLINE + inline const_reference operator [] (size_type i) const { return this->data_[i]; } /** @brief Element access using a single index. * - * - * @code A[i] = a; @endcode + * @code auto a = A[i]; @endcode * * @param i zero-based index where 0 <= i < this->size() */ - BOOST_UBLAS_INLINE - reference operator [] (size_type i) - { + inline + reference operator [] (size_type i) { return this->data_[i]; } - /** @brief Element access using a multi-index or single-index. * * @@ -516,7 +593,7 @@ class tensor: * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() */ template - BOOST_UBLAS_INLINE + inline const_reference at (size_type i, size_types ... is) const { if constexpr (sizeof...(is) == 0) return this->data_[i]; @@ -533,18 +610,17 @@ class tensor: * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() */ - BOOST_UBLAS_INLINE template + inline reference at (size_type i, size_types ... is) { if constexpr (sizeof...(is) == 0) return this->data_[i]; - else - return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward(is)...)]; + else{ + auto temp = detail::access<0ul>(size_type(0),this->strides_,i,std::forward(is)...); + return this->data_[temp]; + } } - - - /** @brief Element access using a single index. * * @@ -552,7 +628,7 @@ class tensor: * * @param i zero-based index where 0 <= i < this->size() */ - BOOST_UBLAS_INLINE + inline const_reference operator()(size_type i) const { return this->data_[i]; } @@ -564,14 +640,11 @@ class tensor: * * @param i zero-based index where 0 <= i < this->size() */ - BOOST_UBLAS_INLINE + inline reference operator()(size_type i){ return this->data_[i]; } - - - /** @brief Generates a tensor index for tensor contraction * * @@ -580,8 +653,8 @@ class tensor: * @param i placeholder * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() */ - BOOST_UBLAS_INLINE template + inline decltype(auto) operator() (index::index_type p, index_types ... ps) const { constexpr auto N = sizeof...(ps)+1; @@ -609,20 +682,19 @@ class tensor: * @param e extents with which the tensor is reshaped. * @param v value which is appended if the tensor is enlarged. */ - BOOST_UBLAS_INLINE + inline void reshape (extents_type const& e, value_type v = value_type{}) { + static_assert(detail::is_dynamic_v, + "Error in boost::numeric::ublas::tensor: static extents cannot be reshaped"); this->extents_ = e; this->strides_ = strides_type(this->extents_); - if(e.product() != this->size()) - this->data_.resize (this->extents_.product(), v); + auto p = product(extents_); + if(p != this->size()) + this->data_.resize (p, v); } - - - - friend void swap(tensor& lhs, tensor& rhs) { std::swap(lhs.data_ , rhs.data_ ); std::swap(lhs.extents_, rhs.extents_); @@ -631,77 +703,92 @@ class tensor: /// \brief return an iterator on the first element of the tensor - BOOST_UBLAS_INLINE + inline const_iterator begin () const { return data_.begin (); } /// \brief return an iterator on the first element of the tensor - BOOST_UBLAS_INLINE + inline const_iterator cbegin () const { return data_.cbegin (); } /// \brief return an iterator after the last element of the tensor - BOOST_UBLAS_INLINE + inline const_iterator end () const { return data_.end(); } /// \brief return an iterator after the last element of the tensor - BOOST_UBLAS_INLINE + inline const_iterator cend () const { return data_.cend (); } /// \brief Return an iterator on the first element of the tensor - BOOST_UBLAS_INLINE + inline iterator begin () { return data_.begin(); } /// \brief Return an iterator at the end of the tensor - BOOST_UBLAS_INLINE + inline iterator end () { return data_.end(); } /// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor) - BOOST_UBLAS_INLINE + inline const_reverse_iterator rbegin () const { return data_.rbegin(); } /// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor) - BOOST_UBLAS_INLINE + inline const_reverse_iterator crbegin () const { return data_.crbegin(); } /// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor) - BOOST_UBLAS_INLINE + inline const_reverse_iterator rend () const { return data_.rend(); } /// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor) - BOOST_UBLAS_INLINE + inline const_reverse_iterator crend () const { return data_.crend(); } /// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor) - BOOST_UBLAS_INLINE + inline reverse_iterator rbegin () { return data_.rbegin(); } /// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor) - BOOST_UBLAS_INLINE + inline reverse_iterator rend () { return data_.rend(); } +private: + + inline + void resize( [[maybe_unused]] extents_type const& e ){ + if constexpr( detail::is_resizable_v){ + data_.resize(product(e)); + } + } + + inline + void resize( [[maybe_unused]] size_type sz ){ + if constexpr( detail::is_resizable_v){ + data_.resize(sz); + } + } #if 0 // ------------- @@ -726,6 +813,20 @@ class tensor: array_type data_; }; +#if __cpp_deduction_guides + +tensor() -> tensor>; + +template::value >::type* = nullptr> +tensor(E const&, T const& ) ->tensor; + +template::value >::type* = nullptr> +tensor(E const&) ->tensor; +#endif + + }}} // namespaces diff --git a/test/tensor/Jamfile b/test/tensor/Jamfile index 7d7b18ec6..84a1716c5 100644 --- a/test/tensor/Jamfile +++ b/test/tensor/Jamfile @@ -1,10 +1,15 @@ # Boost.uBLAS # -# Copyright (c) 2018 Cem Bassoy +# Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +# Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +# +# 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 +# Google and Fraunhofer IOSB, Ettlingen, Germany # -# 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 @@ -25,18 +30,38 @@ explicit unit_test_framework ; test-suite boost-ublas-tensor-test : - [ run test_tensor.cpp - test_strides.cpp + [ run test_tensor.cpp + test_strides.cpp + test_expression.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 ] + unit_test_framework + ] + [ run test_static_tensor.cpp + test_static_extents.cpp + test_static_strides.cpp + test_static_operators_arithmetic.cpp + test_static_operators_comparison.cpp + test_static_expression_evaluation.cpp + test_static_tensor_matrix_vector.cpp + unit_test_framework + ] + [ run test_fixed_rank_tensor.cpp + test_fixed_rank_operators_arithmetic.cpp + test_fixed_rank_operators_comparison.cpp + test_fixed_rank_expression_evaluation.cpp + test_fixed_rank_tensor_matrix_vector.cpp + unit_test_framework + ] + [ run test_functions.cpp + unit_test_framework + ] ; diff --git a/test/tensor/test_algorithms.cpp b/test/tensor/test_algorithms.cpp index 4215fc2a1..784bbe022 100644 --- a/test/tensor/test_algorithms.cpp +++ b/test/tensor/test_algorithms.cpp @@ -1,12 +1,13 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -25,13 +26,15 @@ BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms, * boost::unit_test::depends_on("test_extents") * boost::unit_test::depends_on("test_strides")) +// BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms) + -using test_types = zip>::with_t; +using test_types = zip>::with_t; using test_types2 = std::tuple>; struct fixture { - using extents_type = boost::numeric::ublas::shape; + using extents_type = boost::numeric::ublas::dynamic_extents<>; fixture() : extents { extents_type{1,1}, // 1 @@ -60,13 +63,13 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_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 a = vector_type(product(n)); + auto b = vector_type(product(n)); + auto c = vector_type(product(n)); - auto wa = ublas::strides(n); - auto wb = ublas::strides (n); - auto wc = ublas::strides(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wb = ublas::strides_t,ublas::last_order> (n); + auto wc = ublas::strides_t,ublas::first_order>(n); auto v = value_type{}; for(auto i = 0ul; i < a.size(); ++i, v+=1){ @@ -79,28 +82,28 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_type for(auto i = 1ul; i < c.size(); ++i) BOOST_CHECK_EQUAL( c[i], a[i] ); - using size_type = typename ublas::strides::value_type; + using size_type = typename ublas::strides_t,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 ); + BOOST_CHECK_THROW( ublas::copy( n.size(), p0, c.data(), wc.data(), b.data(), wb.data() ), std::runtime_error ); + BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), p0, b.data(), wb.data() ), std::runtime_error ); + BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), p0 ), std::runtime_error ); value_type* c0 = nullptr; - BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c0, wc.data(), b.data(), wb.data() ), std::length_error ); + BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c0, wc.data(), b.data(), wb.data() ), std::runtime_error ); } // special case rank == 0 { - auto n = ublas::shape{}; + auto n = ublas::dynamic_extents<>{}; - auto a = vector_type(n.product()); - auto b = vector_type(n.product()); - auto c = vector_type(n.product()); + auto a = vector_type(product(n)); + auto b = vector_type(product(n)); + auto c = vector_type(product(n)); - auto wa = ublas::strides(n); - auto wb = ublas::strides (n); - auto wc = ublas::strides(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wb = ublas::strides_t,ublas::last_order> (n); + auto wc = ublas::strides_t,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() ); @@ -118,6 +121,87 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_type } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, test_types2, fixture ) +{ + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector; + + for(auto const& n : extents) { + + value_type* a = nullptr; + auto c = vector_type(product(n)); + + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + value_type* a = nullptr; + value_type* c = nullptr; + + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + value_type* c = nullptr; + + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c, wc.data(), a.data(), wa.data() ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); + + size_t* wa = nullptr; + auto wc = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); + + size_t* wc = nullptr; + auto wa = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); + + size_t* m = nullptr; + auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::copy( n.size(), m, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + + } +} + + BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform, value, test_types2, fixture ) { @@ -128,13 +212,13 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform, value, test for(auto const& n : extents) { - auto a = vector_type(n.product()); - auto b = vector_type(n.product()); - auto c = vector_type(n.product()); + auto a = vector_type(product(n)); + auto b = vector_type(product(n)); + auto c = vector_type(product(n)); - auto wa = ublas::strides(n); - auto wb = ublas::strides (n); - auto wc = ublas::strides(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wb = ublas::strides_t,ublas::last_order> (n); + auto wc = ublas::strides_t,ublas::first_order>(n); auto v = value_type{}; for(auto i = 0ul; i < a.size(); ++i, v+=1){ @@ -144,13 +228,106 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform, value, test 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) + using size_type = typename ublas::strides_t,ublas::first_order>::value_type; + + size_type zero = 0; + ublas::transform(zero, n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a + value_type(1);} ); + + value_type* c0 = nullptr; + const size_type* s0 = nullptr; + size_type const*const p0 = nullptr; + + BOOST_CHECK_THROW(ublas::transform( n.size(), n.data(), c0, wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); + BOOST_CHECK_THROW(ublas::transform( n.size(), n.data(), b.data(), s0, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); + BOOST_CHECK_THROW(ublas::transform( n.size(), p0, b.data(), wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); + + + for(auto i = 1ul; i < c.size(); ++i) BOOST_CHECK_EQUAL( c[i], a[i] ); } } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform_exceptions, value, test_types2, fixture ) +{ + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector; + + for(auto const& n : extents) { + + value_type* a = nullptr; + auto c = vector_type(product(n)); + + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + value_type* a = nullptr; + value_type* c = nullptr; + + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c, wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + value_type* c = nullptr; + + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c, wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); + + size_t* wa = nullptr; + auto wc = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc.data(), a.data(), wa, [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); + + size_t* wc = nullptr; + auto wa = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); + + size_t* m = nullptr; + auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::transform( n.size(), m, c.data(), wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } +} BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, test_types2, fixture ) { @@ -161,15 +338,15 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, tes for(auto const& n : extents) { - auto const s = n.product(); + auto const s = product(n); - auto a = vector_type(n.product()); - // auto b = vector_type(n.product()); - // auto c = vector_type(n.product()); + auto a = vector_type(product(n)); + // auto b = vector_type(product(n)); + // auto c = vector_type(product(n)); - auto wa = ublas::strides(n); - // auto wb = ublas::strides (n); - // auto wc = ublas::strides(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + // auto wb = ublas::strides_t,ublas::last_order> (n); + // auto wc = ublas::strides_t,ublas::first_order>(n); auto v = value_type{}; for(auto i = 0ul; i < a.size(); ++i, v+=value_type(1)){ @@ -178,18 +355,104 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, tes auto acc = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v); - BOOST_CHECK_EQUAL( acc, value_type( s*(s+1) / 2 ) ); + BOOST_CHECK_EQUAL( acc, value_type( static_cast< inner_type_t >( s*(s+1) / 2 ) ) ); + + using size_type = typename ublas::strides_t,ublas::first_order>::value_type; + size_type zero = 0; + ublas::accumulate(zero, n.data(), a.data(), wa.data(),v); + + value_type* c0 = nullptr; + size_type const*const p0 = nullptr; + BOOST_CHECK_THROW(ublas::accumulate( n.size(), n.data(), c0, wa.data(), v), std::runtime_error); + BOOST_CHECK_THROW(ublas::accumulate( n.size(), n.data(), a.data(), p0, v), std::runtime_error); + BOOST_CHECK_THROW(ublas::accumulate( n.size(), p0, a.data(), wa.data(), v), std::runtime_error); - auto acc2 = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v, + + 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 ) ); + BOOST_CHECK_EQUAL( acc2, value_type( static_cast< inner_type_t >( s*(s+1) / 2 ) ) ); + + ublas::accumulate(zero, n.data(), a.data(), wa.data(), v, [](auto const& l, auto const& r){return l + r; }); + + BOOST_CHECK_THROW(ublas::accumulate( n.size(), n.data(), c0, wa.data(), v,[](auto const& l, auto const& r){return l + r; }), std::runtime_error); + BOOST_CHECK_THROW(ublas::accumulate( n.size(), n.data(), a.data(), p0, v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); + BOOST_CHECK_THROW(ublas::accumulate( n.size(), p0, a.data(), wa.data(),v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); } } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, value, test_types2, fixture ) +{ + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector; + + for(auto const& n : extents) { + + value_type* a = nullptr; + + auto wa = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0} ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + value_type* a = nullptr; + + auto wa = ublas::strides_t,ublas::first_order>(n); + + BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0},[](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + + auto wa = ublas::strides_t,ublas::first_order>(n); + size_t p = 0u; + BOOST_CHECK_EQUAL ( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0} ), value_type{0} ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + + auto wa = ublas::strides_t,ublas::first_order>(n); + size_t p = 0u; + BOOST_CHECK_EQUAL( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), value_type{0} ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + + size_t* wa = nullptr; + + BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a.data(), wa, value_type{0} ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto a = vector_type(product(n)); + + auto wa = ublas::strides_t,ublas::first_order>(n); + + size_t* m = nullptr; + + BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), m, a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); + + } + +} template @@ -219,16 +482,16 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans, value, test_typ using value_type = typename value::first_type; using layout_type = typename value::second_type; using vector_type = std::vector; - using strides_type = ublas::strides; - using extents_type = ublas::shape; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; using size_type = typename extents_type::value_type; using permutation_type = std::vector; - + for(auto const& n : extents) { auto p = n.size(); - auto s = n.product(); + auto s = product(n); auto pi = permutation_type(p); auto a = vector_type(s); @@ -281,7 +544,197 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans, value, test_typ for(auto i = 0ul; i < s; ++i) BOOST_CHECK_EQUAL( a[i], b2[i] ); + size_type zero = 0; + ublas::trans( zero, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() ); + ublas::trans( zero, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() ); + + value_type *c0 = nullptr; + size_type const*const s0 = nullptr; + + BOOST_CHECK_THROW(ublas::trans( p, n.data(), pi.data(), c0, wc.data(), a.data(), wa.data()), std::runtime_error); + BOOST_CHECK_THROW(ublas::trans( p, s0, pi.data(), c2.data(),wc.data(), a.data(), wa.data()), std::runtime_error); + BOOST_CHECK_THROW(ublas::trans( p, n.data(), pi.data(), c2.data(), s0, a.data(), wa.data()), std::runtime_error); + BOOST_CHECK_THROW(ublas::trans( p, n.data(), s0, c2.data(), wc.data(), a.data(), wa.data()), std::runtime_error); + + } +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans_exceptions, 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; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; + using size_type = typename extents_type::value_type; + using permutation_type = std::vector; + + for(auto const& n : extents) { + + auto p = n.size(); + auto s = product(n); + + auto pi = permutation_type(p); + value_type* a = nullptr; + auto c = vector_type(s); + + auto wa = strides_type(n); + + auto nc = typename extents_type::base_type (p); + auto wc = strides_type(n); + auto wc_pi = typename strides_type::base_type (p); + + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), a, wa.data(), c.data(), wc.data() ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto p = n.size(); + auto s = product(n); + + auto pi = permutation_type(p); + value_type* a = nullptr; + auto c = vector_type(s); + + auto wa = strides_type(n); + auto nc = typename extents_type::base_type (p); + + auto wc = strides_type(n); + + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto p = n.size(); + + auto pi = permutation_type(p); + value_type* a = nullptr; + value_type* c = nullptr; + + auto wa = strides_type(n); + auto nc = typename extents_type::base_type (p); + + auto wc = strides_type(n); + + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto p = n.size(); + auto s = product(n); + + auto pi = permutation_type(p); + auto a = vector_type(s); + auto c = vector_type(s); + + auto wa = strides_type(n); + + auto nc = typename extents_type::base_type (p); + + size_t* wc = nullptr; + + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto p = n.size(); + auto s = product(n); + + auto pi = permutation_type(p); + auto a = vector_type(s); + auto c = vector_type(s); + + auto wc = strides_type(n); + auto nc = typename extents_type::base_type (p); + + size_t* wa = nullptr; + + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto p = n.size(); + auto s = product(n); + + auto pi = permutation_type(p); + auto a = vector_type(s); + auto c = vector_type(s); + + size_t* wc = nullptr; + + auto nc = typename extents_type::base_type (p); + + size_t* wa = nullptr; + + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc, a.data(), wa ), std::runtime_error ); + } + + for(auto const& n : extents) { + + auto p = n.size(); + auto s = product(n); + + size_type* pi = nullptr; + auto a = vector_type(s); + auto c = vector_type(s); + + auto wa = strides_type(n); + + auto nc = typename extents_type::base_type (p); + auto wc = strides_type(n); + + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + auto p = n.size(); + auto s = product(n); + + auto pi = permutation_type(p); + auto a = vector_type(s); + auto c = vector_type(s); + + auto wa = strides_type(n); + size_t* nc = nullptr; + + auto wc = strides_type(n); + + BOOST_REQUIRE_THROW( ublas::trans( p, nc, pi.data(), c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + + } + + for(auto const& n : extents) { + + size_type p = 1; + auto s = product(n); + + auto pi = permutation_type(p); + auto a = vector_type(s); + auto c = vector_type(s); + + auto wa = strides_type(n); + auto nc = typename extents_type::base_type (p); + + auto wc = strides_type(n); + + ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a.data(), wa.data() ); + + } + } diff --git a/test/tensor/test_einstein_notation.cpp b/test/tensor/test_einstein_notation.cpp index b0326c80c..782d7b86d 100644 --- a/test/tensor/test_einstein_notation.cpp +++ b/test/tensor/test_einstein_notation.cpp @@ -1,12 +1,13 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // // And we acknowledge the support from all contributors. @@ -22,7 +23,7 @@ BOOST_AUTO_TEST_SUITE ( test_einstein_notation, * boost::unit_test::depends_on("test_multi_index") ) -using test_types = zip>::with_t; +using test_types = zip>::with_t; //using test_types = zip::with_t; @@ -31,9 +32,10 @@ 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; + using extents_type = dynamic_extents<>; + using tensor_type = tensor; using namespace boost::numeric::ublas::index; - + { auto A = tensor_type{5,3}; auto B = tensor_type{3,4}; @@ -41,11 +43,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_einstein_multiplication, value, test_types 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); + A.at( i,j ) = value_type( static_cast< inner_type_t >(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); + B.at( i,j ) = value_type( static_cast< inner_type_t >(i+1) ); @@ -70,12 +72,12 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_einstein_multiplication, value, test_types 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); + A.at( i,j,k ) = value_type( static_cast< inner_type_t >(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); + B.at( i,j,k ) = value_type( static_cast< inner_type_t >(i+1) ); auto AB = A(_d,_,_f) * B(_f,_d,_); @@ -88,7 +90,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_einstein_multiplication, value, test_types 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) ); + BOOST_CHECK_EQUAL( AB.at( i,j ) , value_type( static_cast< inner_type_t >(nf * nd) ) ); } @@ -99,12 +101,12 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_einstein_multiplication, value, test_types 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); + A.at( i,j ) = value_type( static_cast< inner_type_t >(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); + B.at( i,j,k ) = value_type( static_cast< inner_type_t >(i+1) ); auto AB = A(_d,_f) * B(_f,_d,_); @@ -113,7 +115,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_einstein_multiplication, value, test_types 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_CHECK_EQUAL ( AB.at( i ) , value_type( static_cast< inner_type_t >(nf * nd) ) ); } } diff --git a/test/tensor/test_expression.cpp b/test/tensor/test_expression.cpp index ae3ce2050..5cbe7ae65 100644 --- a/test/tensor/test_expression.cpp +++ b/test/tensor/test_expression.cpp @@ -22,12 +22,12 @@ -using test_types = zip>::with_t; +using test_types = zip>::with_t; struct fixture { - using extents_type = boost::numeric::ublas::shape; + using extents_type = boost::numeric::ublas::dynamic_extents<>; fixture() : extents { extents_type{}, // 0 @@ -57,7 +57,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_access, value, test_ty using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor, layout_type>; using tensor_expression_type = typename tensor_type::super_type; @@ -82,7 +82,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_expression, value, test_typ using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor, layout_type>; auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); @@ -120,7 +120,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_expression, value, test_ty using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor, layout_type>; auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); auto uplus2 = std::bind( std::plus{}, std::placeholders::_1, value_type(2) ); diff --git a/test/tensor/test_expression_evaluation.cpp b/test/tensor/test_expression_evaluation.cpp index 002d51a2b..ef43fdc59 100644 --- a/test/tensor/test_expression_evaluation.cpp +++ b/test/tensor/test_expression_evaluation.cpp @@ -1,12 +1,13 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -14,17 +15,19 @@ #include #include #include -#include #include "utility.hpp" +#include #include -using test_types = zip>::with_t; +BOOST_AUTO_TEST_SUITE(test_tensor_expression); + +using test_types = zip>::with_t; struct fixture { - using extents_type = boost::numeric::ublas::shape; + using extents_type = boost::numeric::ublas::dynamic_extents<>; fixture() : extents{ extents_type{}, // 0 @@ -55,7 +58,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_retrieve_extents, value using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using extents_type = ublas::dynamic_extents<>; + using tensor_type = ublas::tensor; auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); @@ -146,7 +150,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_all_extents_equal, valu using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor, layout_type>; auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); @@ -238,3 +242,5 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_all_extents_equal, valu } } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_extents.cpp b/test/tensor/test_extents.cpp index 9fbeee949..a02ec3386 100644 --- a/test/tensor/test_extents.cpp +++ b/test/tensor/test_extents.cpp @@ -1,8 +1,14 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// #include #include @@ -22,47 +28,92 @@ BOOST_AUTO_TEST_CASE(test_extents_ctor) auto e0 = extents{}; BOOST_CHECK( e0.empty()); - BOOST_CHECK_EQUAL ( e0.size(),0); + BOOST_CHECK ( e0.size() == 0 ); auto e1 = extents{1,1}; BOOST_CHECK(!e1.empty()); - BOOST_CHECK_EQUAL ( e1.size(),2); + BOOST_CHECK ( e1.size() == 2 ); auto e2 = extents{1,2}; BOOST_CHECK(!e2.empty()); - BOOST_CHECK_EQUAL ( e2.size(),2); + BOOST_CHECK ( e2.size() == 2 ); auto e3 = extents{2,1}; BOOST_CHECK (!e3.empty()); - BOOST_CHECK_EQUAL ( e3.size(),2); + BOOST_CHECK ( e3.size() == 2 ); auto e4 = extents{2,3}; BOOST_CHECK(!e4.empty()); - BOOST_CHECK_EQUAL ( e4.size(),2); + BOOST_CHECK ( e4.size() == 2 ); auto e5 = extents{2,3,1}; BOOST_CHECK (!e5.empty()); - BOOST_CHECK_EQUAL ( e5.size(),3); + BOOST_CHECK ( e5.size() == 3 ); auto e6 = extents{1,2,3}; // 6 BOOST_CHECK(!e6.empty()); - BOOST_CHECK_EQUAL ( e6.size(),3); + BOOST_CHECK ( e6.size() == 3 ); auto e7 = extents{4,2,3}; // 7 BOOST_CHECK(!e7.empty()); - BOOST_CHECK_EQUAL ( e7.size(),3); + BOOST_CHECK ( 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 ); + 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); } +BOOST_AUTO_TEST_CASE(test_static_rank_extents_ctor) +{ + namespace ub = boost::numeric::ublas; + + + auto e0 = ub::dynamic_extents<0>{}; + BOOST_CHECK( e0.empty()); + BOOST_CHECK ( e0.size() == 0); + + auto e1 = ub::dynamic_extents<2>{1,1}; + BOOST_CHECK(!e1.empty()); + BOOST_CHECK ( e1.size() == 2); + + auto e2 = ub::dynamic_extents<2>{1,2}; + BOOST_CHECK(!e2.empty()); + BOOST_CHECK ( e2.size() == 2); + + auto e3 = ub::dynamic_extents<2>{2,1}; + BOOST_CHECK (!e3.empty()); + BOOST_CHECK ( e3.size() == 2); + + auto e4 = ub::dynamic_extents<2>{2,3}; + BOOST_CHECK(!e4.empty()); + BOOST_CHECK ( e4.size() == 2); + + auto e5 = ub::dynamic_extents<3>{2,3,1}; + BOOST_CHECK (!e5.empty()); + BOOST_CHECK ( e5.size() == 3); + + auto e6 = ub::dynamic_extents<3>{1,2,3}; // 6 + BOOST_CHECK(!e6.empty()); + BOOST_CHECK ( e6.size() == 3); + + auto e7 = ub::dynamic_extents<3>{4,2,3}; // 7 + BOOST_CHECK(!e7.empty()); + BOOST_CHECK ( e7.size() == 3); + BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,0}), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<1>({0} ), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<1>({3} ), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<2>({0,1}), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,1,2}), std::out_of_range); +} struct fixture { - using extents_type = boost::numeric::ublas::basic_extents; + using extents_type = boost::numeric::ublas::dynamic_extents<>; + template + using static_rank_extents_type = boost::numeric::ublas::dynamic_extents; + fixture() : extents{ extents_type{}, // 0 @@ -80,16 +131,45 @@ struct fixture { 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 + + extents_type{1,4,1}, // 13 + extents_type{1,1,1,1}, // 14 + extents_type{1,4,1,1,1}, // 15 + extents_type{1,1,2,1,1,1}, // 16 + extents_type{1,1,2,3,1,1}, // 17 + } {} std::vector extents; + + static_rank_extents_type<0> de0{}; // 0 + + static_rank_extents_type<2> de1{1,1}; // 1 + static_rank_extents_type<2> de2{1,2}; // 2 + static_rank_extents_type<2> de3{2,1}; // 3 + + static_rank_extents_type<2> de4{2,3}; // 4 + static_rank_extents_type<3> de5{2,3,1}; // 5 + static_rank_extents_type<3> de6{1,2,3}; // 6 + static_rank_extents_type<4> de7{1,1,2,3}; // 7 + static_rank_extents_type<5> de8{1,2,3,1,1}; // 8 + + static_rank_extents_type<3> de9{4,2,3}; // 9 + static_rank_extents_type<4> de10{4,2,1,3}; // 10 + static_rank_extents_type<5> de11{4,2,1,3,1}; // 11 + static_rank_extents_type<6> de12{1,4,2,1,3,1};// 12 + + static_rank_extents_type<3> de13{1,4,1}; // 13 + static_rank_extents_type<4> de14{1,1,1,1}; // 14 + static_rank_extents_type<5> de15{1,4,1,1,1}; // 15 + static_rank_extents_type<6> de16{1,1,2,1,1,1};// 16 + static_rank_extents_type<6> de17{1,1,2,3,1,1};// 17 }; 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_REQUIRE_EQUAL(extents.size(),18); BOOST_CHECK_EQUAL (extents[ 0].size(), 0); BOOST_CHECK (extents[ 0].empty() ); @@ -106,6 +186,11 @@ BOOST_FIXTURE_TEST_CASE(test_extents_access, fixture, *boost::unit_test::label(" BOOST_REQUIRE_EQUAL(extents[10].size(), 4); BOOST_REQUIRE_EQUAL(extents[11].size(), 5); BOOST_REQUIRE_EQUAL(extents[12].size(), 6); + BOOST_REQUIRE_EQUAL(extents[13].size(), 3); + BOOST_REQUIRE_EQUAL(extents[14].size(), 4); + BOOST_REQUIRE_EQUAL(extents[15].size(), 5); + BOOST_REQUIRE_EQUAL(extents[16].size(), 6); + BOOST_REQUIRE_EQUAL(extents[17].size(), 6); BOOST_CHECK_EQUAL(extents[1][0],1); @@ -160,11 +245,149 @@ BOOST_FIXTURE_TEST_CASE(test_extents_access, fixture, *boost::unit_test::label(" BOOST_CHECK_EQUAL(extents[12][3],1); BOOST_CHECK_EQUAL(extents[12][4],3); BOOST_CHECK_EQUAL(extents[12][5],1); + + BOOST_CHECK_EQUAL(extents[13][0],1); + BOOST_CHECK_EQUAL(extents[13][1],4); + BOOST_CHECK_EQUAL(extents[13][2],1); + + BOOST_CHECK_EQUAL(extents[14][0],1); + BOOST_CHECK_EQUAL(extents[14][1],1); + BOOST_CHECK_EQUAL(extents[14][2],1); + BOOST_CHECK_EQUAL(extents[14][3],1); + + BOOST_CHECK_EQUAL(extents[15][0],1); + BOOST_CHECK_EQUAL(extents[15][1],4); + BOOST_CHECK_EQUAL(extents[15][2],1); + BOOST_CHECK_EQUAL(extents[15][3],1); + BOOST_CHECK_EQUAL(extents[15][4],1); + + BOOST_CHECK_EQUAL(extents[16][0],1); + BOOST_CHECK_EQUAL(extents[16][1],1); + BOOST_CHECK_EQUAL(extents[16][2],2); + BOOST_CHECK_EQUAL(extents[16][3],1); + BOOST_CHECK_EQUAL(extents[16][4],1); + BOOST_CHECK_EQUAL(extents[16][5],1); + + BOOST_CHECK_EQUAL(extents[17][0],1); + BOOST_CHECK_EQUAL(extents[17][1],1); + BOOST_CHECK_EQUAL(extents[17][2],2); + BOOST_CHECK_EQUAL(extents[17][3],3); + BOOST_CHECK_EQUAL(extents[17][4],1); + BOOST_CHECK_EQUAL(extents[17][5],1); +} + +BOOST_FIXTURE_TEST_CASE(test_static_rank_extents_access, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("access")) +{ + using namespace boost::numeric; + + BOOST_CHECK_EQUAL(de0.size(), 0); + BOOST_CHECK (de0.empty() ); + + BOOST_REQUIRE_EQUAL(de1.size(), 2); + BOOST_REQUIRE_EQUAL(de2.size(), 2); + BOOST_REQUIRE_EQUAL(de3.size(), 2); + BOOST_REQUIRE_EQUAL(de4.size(), 2); + BOOST_REQUIRE_EQUAL(de5.size(), 3); + BOOST_REQUIRE_EQUAL(de6.size(), 3); + BOOST_REQUIRE_EQUAL(de7.size(), 4); + BOOST_REQUIRE_EQUAL(de8.size(), 5); + BOOST_REQUIRE_EQUAL(de9.size(), 3); + BOOST_REQUIRE_EQUAL(de10.size(), 4); + BOOST_REQUIRE_EQUAL(de11.size(), 5); + BOOST_REQUIRE_EQUAL(de12.size(), 6); + BOOST_REQUIRE_EQUAL(de13.size(), 3); + BOOST_REQUIRE_EQUAL(de14.size(), 4); + BOOST_REQUIRE_EQUAL(de15.size(), 5); + BOOST_REQUIRE_EQUAL(de16.size(), 6); + BOOST_REQUIRE_EQUAL(de17.size(), 6); + + + BOOST_CHECK_EQUAL(de1[0],1); + BOOST_CHECK_EQUAL(de1[1],1); + + BOOST_CHECK_EQUAL(de2[0],1); + BOOST_CHECK_EQUAL(de2[1],2); + + BOOST_CHECK_EQUAL(de3[0],2); + BOOST_CHECK_EQUAL(de3[1],1); + + BOOST_CHECK_EQUAL(de4[0],2); + BOOST_CHECK_EQUAL(de4[1],3); + + BOOST_CHECK_EQUAL(de5[0],2); + BOOST_CHECK_EQUAL(de5[1],3); + BOOST_CHECK_EQUAL(de5[2],1); + + BOOST_CHECK_EQUAL(de6[0],1); + BOOST_CHECK_EQUAL(de6[1],2); + BOOST_CHECK_EQUAL(de6[2],3); + + BOOST_CHECK_EQUAL(de7[0],1); + BOOST_CHECK_EQUAL(de7[1],1); + BOOST_CHECK_EQUAL(de7[2],2); + BOOST_CHECK_EQUAL(de7[3],3); + + BOOST_CHECK_EQUAL(de8[0],1); + BOOST_CHECK_EQUAL(de8[1],2); + BOOST_CHECK_EQUAL(de8[2],3); + BOOST_CHECK_EQUAL(de8[3],1); + BOOST_CHECK_EQUAL(de8[4],1); + + BOOST_CHECK_EQUAL(de9[0],4); + BOOST_CHECK_EQUAL(de9[1],2); + BOOST_CHECK_EQUAL(de9[2],3); + + BOOST_CHECK_EQUAL(de10[0],4); + BOOST_CHECK_EQUAL(de10[1],2); + BOOST_CHECK_EQUAL(de10[2],1); + BOOST_CHECK_EQUAL(de10[3],3); + + BOOST_CHECK_EQUAL(de11[0],4); + BOOST_CHECK_EQUAL(de11[1],2); + BOOST_CHECK_EQUAL(de11[2],1); + BOOST_CHECK_EQUAL(de11[3],3); + BOOST_CHECK_EQUAL(de11[4],1); + + BOOST_CHECK_EQUAL(de12[0],1); + BOOST_CHECK_EQUAL(de12[1],4); + BOOST_CHECK_EQUAL(de12[2],2); + BOOST_CHECK_EQUAL(de12[3],1); + BOOST_CHECK_EQUAL(de12[4],3); + BOOST_CHECK_EQUAL(de12[5],1); + + BOOST_CHECK_EQUAL(de13[0],1); + BOOST_CHECK_EQUAL(de13[1],4); + BOOST_CHECK_EQUAL(de13[2],1); + + BOOST_CHECK_EQUAL(de14[0],1); + BOOST_CHECK_EQUAL(de14[1],1); + BOOST_CHECK_EQUAL(de14[2],1); + BOOST_CHECK_EQUAL(de14[3],1); + + BOOST_CHECK_EQUAL(de15[0],1); + BOOST_CHECK_EQUAL(de15[1],4); + BOOST_CHECK_EQUAL(de15[2],1); + BOOST_CHECK_EQUAL(de15[3],1); + BOOST_CHECK_EQUAL(de15[4],1); + + BOOST_CHECK_EQUAL(de16[0],1); + BOOST_CHECK_EQUAL(de16[1],1); + BOOST_CHECK_EQUAL(de16[2],2); + BOOST_CHECK_EQUAL(de16[3],1); + BOOST_CHECK_EQUAL(de16[4],1); + BOOST_CHECK_EQUAL(de16[5],1); + + BOOST_CHECK_EQUAL(de17[0],1); + BOOST_CHECK_EQUAL(de17[1],1); + BOOST_CHECK_EQUAL(de17[2],2); + BOOST_CHECK_EQUAL(de17[3],3); + BOOST_CHECK_EQUAL(de17[4],1); + BOOST_CHECK_EQUAL(de17[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); + BOOST_REQUIRE_EQUAL(extents.size(),18); auto e0 = extents[ 0]; // {} auto e1 = extents[ 1]; // {1,1} @@ -179,6 +402,139 @@ BOOST_FIXTURE_TEST_CASE(test_extents_copy_ctor, fixture, *boost::unit_test::labe 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} + auto e13 = extents[13]; // {1,4,1} + auto e14 = extents[14]; // {1,1,1,1} + auto e15 = extents[15]; // {1,4,1,1,1} + auto e16 = extents[16]; // {1,1,2,1,1,1} + auto e17 = extents[17]; // {1,1,2,3,1,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_REQUIRE_EQUAL(e13.size(), 3); + BOOST_REQUIRE_EQUAL(e14.size(), 4); + BOOST_REQUIRE_EQUAL(e15.size(), 5); + BOOST_REQUIRE_EQUAL(e16.size(), 6); + BOOST_REQUIRE_EQUAL(e17.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_CHECK_EQUAL(e13[0],1); + BOOST_CHECK_EQUAL(e13[1],4); + BOOST_CHECK_EQUAL(e13[2],1); + + BOOST_CHECK_EQUAL(e14[0],1); + BOOST_CHECK_EQUAL(e14[1],1); + BOOST_CHECK_EQUAL(e14[2],1); + BOOST_CHECK_EQUAL(e14[3],1); + + BOOST_CHECK_EQUAL(e15[0],1); + BOOST_CHECK_EQUAL(e15[1],4); + BOOST_CHECK_EQUAL(e15[2],1); + BOOST_CHECK_EQUAL(e15[3],1); + BOOST_CHECK_EQUAL(e15[4],1); + + BOOST_CHECK_EQUAL(e16[0],1); + BOOST_CHECK_EQUAL(e16[1],1); + BOOST_CHECK_EQUAL(e16[2],2); + BOOST_CHECK_EQUAL(e16[3],1); + BOOST_CHECK_EQUAL(e16[4],1); + BOOST_CHECK_EQUAL(e16[5],1); + + BOOST_CHECK_EQUAL(e17[0],1); + BOOST_CHECK_EQUAL(e17[1],1); + BOOST_CHECK_EQUAL(e17[2],2); + BOOST_CHECK_EQUAL(e17[3],3); + BOOST_CHECK_EQUAL(e17[4],1); + BOOST_CHECK_EQUAL(e17[5],1); + +} + +BOOST_FIXTURE_TEST_CASE(test_static_rank_extents_copy_ctor, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("copy_ctor")) +{ + + auto e0 = de0; // {} + auto e1 = de1; // {1,1} + auto e2 = de2; // {1,2} + auto e3 = de3; // {2,1} + auto e4 = de4; // {2,3} + auto e5 = de5; // {2,3,1} + auto e6 = de6; // {1,2,3} + auto e7 = de7; // {1,1,2,3} + auto e8 = de8; // {1,2,3,1,1} + auto e9 = de9; // {4,2,3} + auto e10 = de10; // {4,2,1,3} + auto e11 = de11; // {4,2,1,3,1} + auto e12 = de12; // {1,4,2,1,3,1} + auto e13 = de13; // {1,4,1} + auto e14 = de14; // {1,1,1,1} + auto e15 = de15; // {1,4,1,1,1} + auto e16 = de16; // {1,1,2,1,1,1} + auto e17 = de17; // {1,1,2,3,1,1} BOOST_CHECK_EQUAL (e0.size(), 0); BOOST_CHECK (e0.empty() ); @@ -195,6 +551,11 @@ BOOST_FIXTURE_TEST_CASE(test_extents_copy_ctor, fixture, *boost::unit_test::labe BOOST_REQUIRE_EQUAL(e10.size(), 4); BOOST_REQUIRE_EQUAL(e11.size(), 5); BOOST_REQUIRE_EQUAL(e12.size(), 6); + BOOST_REQUIRE_EQUAL(e13.size(), 3); + BOOST_REQUIRE_EQUAL(e14.size(), 4); + BOOST_REQUIRE_EQUAL(e15.size(), 5); + BOOST_REQUIRE_EQUAL(e16.size(), 6); + BOOST_REQUIRE_EQUAL(e17.size(), 6); BOOST_CHECK_EQUAL(e1[0],1); @@ -250,11 +611,40 @@ BOOST_FIXTURE_TEST_CASE(test_extents_copy_ctor, fixture, *boost::unit_test::labe BOOST_CHECK_EQUAL(e12[4],3); BOOST_CHECK_EQUAL(e12[5],1); + BOOST_CHECK_EQUAL(e13[0],1); + BOOST_CHECK_EQUAL(e13[1],4); + BOOST_CHECK_EQUAL(e13[2],1); + + BOOST_CHECK_EQUAL(e14[0],1); + BOOST_CHECK_EQUAL(e14[1],1); + BOOST_CHECK_EQUAL(e14[2],1); + BOOST_CHECK_EQUAL(e14[3],1); + + BOOST_CHECK_EQUAL(e15[0],1); + BOOST_CHECK_EQUAL(e15[1],4); + BOOST_CHECK_EQUAL(e15[2],1); + BOOST_CHECK_EQUAL(e15[3],1); + BOOST_CHECK_EQUAL(e15[4],1); + + BOOST_CHECK_EQUAL(e16[0],1); + BOOST_CHECK_EQUAL(e16[1],1); + BOOST_CHECK_EQUAL(e16[2],2); + BOOST_CHECK_EQUAL(e16[3],1); + BOOST_CHECK_EQUAL(e16[4],1); + BOOST_CHECK_EQUAL(e16[5],1); + + BOOST_CHECK_EQUAL(e17[0],1); + BOOST_CHECK_EQUAL(e17[1],1); + BOOST_CHECK_EQUAL(e17[2],2); + BOOST_CHECK_EQUAL(e17[3],3); + BOOST_CHECK_EQUAL(e17[4],1); + BOOST_CHECK_EQUAL(e17[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); + BOOST_REQUIRE_EQUAL(extents.size(),18); auto e0 = extents[ 0]; // {} auto e1 = extents[ 1]; // {1,1} @@ -269,106 +659,328 @@ BOOST_FIXTURE_TEST_CASE(test_extents_is, fixture, *boost::unit_test::label("exte 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} + auto e13 = extents[13]; // {1,4,1} + auto e14 = extents[14]; // {1,1,1,1} + auto e15 = extents[15]; // {1,4,1,1,1} + auto e16 = extents[16]; // {1,1,2,1,1,1} + auto e17 = extents[17]; // {1,1,2,3,1,1} + + BOOST_CHECK( e0.empty ( )); + BOOST_CHECK( ! is_scalar(e0)); + BOOST_CHECK( ! is_vector(e0)); + BOOST_CHECK( ! is_matrix(e0)); + BOOST_CHECK( ! is_tensor(e0)); + + BOOST_CHECK( ! e1.empty ( ) ); + BOOST_CHECK( is_scalar(e1) ); + BOOST_CHECK( ! is_vector(e1) ); + BOOST_CHECK( ! is_matrix(e1) ); + BOOST_CHECK( ! is_tensor(e1) ); + + BOOST_CHECK( ! e2.empty ( ) ); + BOOST_CHECK( ! is_scalar(e2) ); + BOOST_CHECK( is_vector(e2) ); + BOOST_CHECK( ! is_matrix(e2) ); + BOOST_CHECK( ! is_tensor(e2) ); + + BOOST_CHECK( ! e3.empty ( ) ); + BOOST_CHECK( ! is_scalar(e3) ); + BOOST_CHECK( is_vector(e3) ); + BOOST_CHECK( ! is_matrix(e3) ); + BOOST_CHECK( ! is_tensor(e3) ); + + BOOST_CHECK( ! e4.empty ( ) ); + BOOST_CHECK( ! is_scalar(e4) ); + BOOST_CHECK( ! is_vector(e4) ); + BOOST_CHECK( is_matrix(e4) ); + BOOST_CHECK( ! is_tensor(e4) ); + + BOOST_CHECK( ! e5.empty ( ) ); + BOOST_CHECK( ! is_scalar(e5) ); + BOOST_CHECK( ! is_vector(e5) ); + BOOST_CHECK( is_matrix(e5) ); + BOOST_CHECK( ! is_tensor(e5) ); + + BOOST_CHECK( ! e6.empty ( ) ); + BOOST_CHECK( ! is_scalar(e6) ); + BOOST_CHECK( ! is_vector(e6) ); + BOOST_CHECK( ! is_matrix(e6) ); + BOOST_CHECK( is_tensor(e6) ); + + BOOST_CHECK( ! e7.empty ( ) ); + BOOST_CHECK( ! is_scalar(e7) ); + BOOST_CHECK( ! is_vector(e7) ); + BOOST_CHECK( ! is_matrix(e7) ); + BOOST_CHECK( is_tensor(e7) ); + + BOOST_CHECK( ! e8.empty ( ) ); + BOOST_CHECK( ! is_scalar(e8) ); + BOOST_CHECK( ! is_vector(e8) ); + BOOST_CHECK( ! is_matrix(e8) ); + BOOST_CHECK( is_tensor(e8) ); + + BOOST_CHECK( ! e9.empty ( ) ); + BOOST_CHECK( ! is_scalar(e9) ); + BOOST_CHECK( ! is_vector(e9) ); + BOOST_CHECK( ! is_matrix(e9) ); + BOOST_CHECK( is_tensor(e9) ); + + BOOST_CHECK( ! e10.empty( ) ); + BOOST_CHECK( ! is_scalar(e10) ); + BOOST_CHECK( ! is_vector(e10) ); + BOOST_CHECK( ! is_matrix(e10) ); + BOOST_CHECK( is_tensor(e10) ); + + BOOST_CHECK( ! e11.empty( ) ); + BOOST_CHECK( ! is_scalar(e11) ); + BOOST_CHECK( ! is_vector(e11) ); + BOOST_CHECK( ! is_matrix(e11) ); + BOOST_CHECK( is_tensor(e11) ); + + BOOST_CHECK( ! e12.empty( ) ); + BOOST_CHECK( ! is_scalar(e12) ); + BOOST_CHECK( ! is_vector(e12) ); + BOOST_CHECK( ! is_matrix(e12) ); + BOOST_CHECK( is_tensor(e12) ); + + BOOST_CHECK( ! e13.empty( ) ); + BOOST_CHECK( ! is_scalar(e13) ); + BOOST_CHECK( is_vector(e13) ); + BOOST_CHECK( ! is_matrix(e13) ); + BOOST_CHECK( ! is_tensor(e13) ); + + BOOST_CHECK( ! e14.empty( ) ); + BOOST_CHECK( is_scalar(e14) ); + BOOST_CHECK( ! is_vector(e14) ); + BOOST_CHECK( ! is_matrix(e14) ); + BOOST_CHECK( ! is_tensor(e14) ); + + BOOST_CHECK( ! e15.empty( ) ); + BOOST_CHECK( ! is_scalar(e15) ); + BOOST_CHECK( is_vector(e15) ); + BOOST_CHECK( ! is_matrix(e15) ); + BOOST_CHECK( ! is_tensor(e15) ); + + BOOST_CHECK( ! e16.empty( ) ); + BOOST_CHECK( ! is_scalar(e16) ); + BOOST_CHECK( ! is_vector(e16) ); + BOOST_CHECK( ! is_matrix(e16) ); + BOOST_CHECK( is_tensor(e16) ); + + BOOST_CHECK( ! e17.empty( ) ); + BOOST_CHECK( ! is_scalar(e17) ); + BOOST_CHECK( ! is_vector(e17) ); + BOOST_CHECK( ! is_matrix(e17) ); + BOOST_CHECK( is_tensor(e17) ); +} + +BOOST_FIXTURE_TEST_CASE(test_static_rank_extents_is, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("query")) +{ - 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() ); + auto e0 = de0; // {} + auto e1 = de1; // {1,1} + auto e2 = de2; // {1,2} + auto e3 = de3; // {2,1} + auto e4 = de4; // {2,3} + auto e5 = de5; // {2,3,1} + auto e6 = de6; // {1,2,3} + auto e7 = de7; // {1,1,2,3} + auto e8 = de8; // {1,2,3,1,1} + auto e9 = de9; // {4,2,3} + auto e10 = de10; // {4,2,1,3} + auto e11 = de11; // {4,2,1,3,1} + auto e12 = de12; // {1,4,2,1,3,1} + auto e13 = de13; // {1,4,1} + auto e14 = de14; // {1,1,1,1} + auto e15 = de15; // {1,4,1,1,1} + auto e16 = de16; // {1,1,2,1,1,1} + auto e17 = de17; // {1,1,2,3,1,1} + + BOOST_CHECK( e0.empty ( )); + BOOST_CHECK( ! is_scalar(e0)); + BOOST_CHECK( ! is_vector(e0)); + BOOST_CHECK( ! is_matrix(e0)); + BOOST_CHECK( ! is_tensor(e0)); + + BOOST_CHECK( ! e1.empty ( ) ); + BOOST_CHECK( is_scalar(e1) ); + BOOST_CHECK( ! is_vector(e1) ); + BOOST_CHECK( ! is_matrix(e1) ); + BOOST_CHECK( ! is_tensor(e1) ); + + BOOST_CHECK( ! e2.empty ( ) ); + BOOST_CHECK( ! is_scalar(e2) ); + BOOST_CHECK( is_vector(e2) ); + BOOST_CHECK( ! is_matrix(e2) ); + BOOST_CHECK( ! is_tensor(e2) ); + + BOOST_CHECK( ! e3.empty ( ) ); + BOOST_CHECK( ! is_scalar(e3) ); + BOOST_CHECK( is_vector(e3) ); + BOOST_CHECK( ! is_matrix(e3) ); + BOOST_CHECK( ! is_tensor(e3) ); + + BOOST_CHECK( ! e4.empty ( ) ); + BOOST_CHECK( ! is_scalar(e4) ); + BOOST_CHECK( ! is_vector(e4) ); + BOOST_CHECK( is_matrix(e4) ); + BOOST_CHECK( ! is_tensor(e4) ); + + BOOST_CHECK( ! e5.empty ( ) ); + BOOST_CHECK( ! is_scalar(e5) ); + BOOST_CHECK( ! is_vector(e5) ); + BOOST_CHECK( is_matrix(e5) ); + BOOST_CHECK( ! is_tensor(e5) ); + + BOOST_CHECK( ! e6.empty ( ) ); + BOOST_CHECK( ! is_scalar(e6) ); + BOOST_CHECK( ! is_vector(e6) ); + BOOST_CHECK( ! is_matrix(e6) ); + BOOST_CHECK( is_tensor(e6) ); + + BOOST_CHECK( ! e7.empty ( ) ); + BOOST_CHECK( ! is_scalar(e7) ); + BOOST_CHECK( ! is_vector(e7) ); + BOOST_CHECK( ! is_matrix(e7) ); + BOOST_CHECK( is_tensor(e7) ); + + BOOST_CHECK( ! e8.empty ( ) ); + BOOST_CHECK( ! is_scalar(e8) ); + BOOST_CHECK( ! is_vector(e8) ); + BOOST_CHECK( ! is_matrix(e8) ); + BOOST_CHECK( is_tensor(e8) ); + + BOOST_CHECK( ! e9.empty ( ) ); + BOOST_CHECK( ! is_scalar(e9) ); + BOOST_CHECK( ! is_vector(e9) ); + BOOST_CHECK( ! is_matrix(e9) ); + BOOST_CHECK( is_tensor(e9) ); + + BOOST_CHECK( ! e10.empty( ) ); + BOOST_CHECK( ! is_scalar(e10) ); + BOOST_CHECK( ! is_vector(e10) ); + BOOST_CHECK( ! is_matrix(e10) ); + BOOST_CHECK( is_tensor(e10) ); + + BOOST_CHECK( ! e11.empty( ) ); + BOOST_CHECK( ! is_scalar(e11) ); + BOOST_CHECK( ! is_vector(e11) ); + BOOST_CHECK( ! is_matrix(e11) ); + BOOST_CHECK( is_tensor(e11) ); + + BOOST_CHECK( ! e12.empty( ) ); + BOOST_CHECK( ! is_scalar(e12) ); + BOOST_CHECK( ! is_vector(e12) ); + BOOST_CHECK( ! is_matrix(e12) ); + BOOST_CHECK( is_tensor(e12) ); + + BOOST_CHECK( ! e13.empty( ) ); + BOOST_CHECK( ! is_scalar(e13) ); + BOOST_CHECK( is_vector(e13) ); + BOOST_CHECK( ! is_matrix(e13) ); + BOOST_CHECK( ! is_tensor(e13) ); + + BOOST_CHECK( ! e14.empty( ) ); + BOOST_CHECK( is_scalar(e14) ); + BOOST_CHECK( ! is_vector(e14) ); + BOOST_CHECK( ! is_matrix(e14) ); + BOOST_CHECK( ! is_tensor(e14) ); + + BOOST_CHECK( ! e15.empty( ) ); + BOOST_CHECK( ! is_scalar(e15) ); + BOOST_CHECK( is_vector(e15) ); + BOOST_CHECK( ! is_matrix(e15) ); + BOOST_CHECK( ! is_tensor(e15) ); + + BOOST_CHECK( ! e16.empty( ) ); + BOOST_CHECK( ! is_scalar(e16) ); + BOOST_CHECK( ! is_vector(e16) ); + BOOST_CHECK( ! is_matrix(e16) ); + BOOST_CHECK( is_tensor(e16) ); + + BOOST_CHECK( ! e17.empty( ) ); + BOOST_CHECK( ! is_scalar(e17) ); + BOOST_CHECK( ! is_vector(e17) ); + BOOST_CHECK( ! is_matrix(e17) ); + BOOST_CHECK( is_tensor(e17) ); } BOOST_FIXTURE_TEST_CASE(test_extents_squeeze, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("squeeze")) { - BOOST_REQUIRE_EQUAL(extents.size(),13); + BOOST_REQUIRE_EQUAL(extents.size(),18); + + auto e0 = squeeze(extents[ 0]); // {} + auto e1 = squeeze(extents[ 1]); // {1,1} + auto e2 = squeeze(extents[ 2]); // {1,2} + auto e3 = squeeze(extents[ 3]); // {2,1} + + auto e4 = squeeze(extents[ 4]); // {2,3} + auto e5 = squeeze(extents[ 5]); // {2,3} + auto e6 = squeeze(extents[ 6]); // {2,3} + auto e7 = squeeze(extents[ 7]); // {2,3} + auto e8 = squeeze(extents[ 8]); // {2,3} + + auto e9 = squeeze(extents[ 9]); // {4,2,3} + auto e10 = squeeze(extents[10]); // {4,2,3} + auto e11 = squeeze(extents[11]); // {4,2,3} + auto e12 = squeeze(extents[12]); // {4,2,3} + + auto e13 = squeeze(extents[13]); // {1,4} + auto e14 = squeeze(extents[14]); // {1,1} + auto e15 = squeeze(extents[15]); // {1,4} + auto e16 = squeeze(extents[16]); // {2,1} + auto e17 = squeeze(extents[17]); // {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}) ); - 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} + BOOST_CHECK( (e13 == extents_type{1,4}) ); + BOOST_CHECK( (e14 == extents_type{1,1}) ); + BOOST_CHECK( (e15 == extents_type{1,4}) ); + BOOST_CHECK( (e16 == extents_type{2,1}) ); + BOOST_CHECK( (e17 == extents_type{2,3}) ); - 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_FIXTURE_TEST_CASE(test_static_rank_extents_squeeze, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("squeeze")) +{ + BOOST_REQUIRE_EQUAL(extents.size(),18); + + auto e0 = squeeze(de0); // {} + auto e1 = squeeze(de1); // {1,1} + auto e2 = squeeze(de2); // {1,2} + auto e3 = squeeze(de3); // {2,1} + + auto e4 = squeeze(de4); // {2,3} + auto e5 = squeeze(de5); // {2,3} + auto e6 = squeeze(de6); // {2,3} + auto e7 = squeeze(de7); // {2,3} + auto e8 = squeeze(de8); // {2,3} + + auto e9 = squeeze(de9); // {4,2,3} + auto e10 = squeeze(de10); // {4,2,3} + auto e11 = squeeze(de11); // {4,2,3} + auto e12 = squeeze(de12); // {4,2,3} + + auto e13 = squeeze(de13); // {1,4} + auto e14 = squeeze(de14); // {1,1} + auto e15 = squeeze(de15); // {1,4} + auto e16 = squeeze(de16); // {2,1} + auto e17 = squeeze(de17); // {2,3} BOOST_CHECK( (e0 == extents_type{} ) ); BOOST_CHECK( (e1 == extents_type{1,1}) ); @@ -386,6 +998,12 @@ BOOST_FIXTURE_TEST_CASE(test_extents_squeeze, fixture, *boost::unit_test::label( BOOST_CHECK( (e11 == extents_type{4,2,3}) ); BOOST_CHECK( (e12 == extents_type{4,2,3}) ); + BOOST_CHECK( (e13 == extents_type{1,4}) ); + BOOST_CHECK( (e14 == extents_type{1,1}) ); + BOOST_CHECK( (e15 == extents_type{1,4}) ); + BOOST_CHECK( (e16 == extents_type{2,1}) ); + BOOST_CHECK( (e17 == extents_type{2,3}) ); + } @@ -394,19 +1012,155 @@ BOOST_FIXTURE_TEST_CASE(test_extents_valid, fixture, *boost::unit_test::label("e using namespace boost::numeric; - BOOST_REQUIRE_EQUAL(extents.size(),13); + BOOST_REQUIRE_EQUAL(extents.size(),18); for(auto const& e : extents){ if(e.empty()) - BOOST_CHECK_EQUAL(e.valid(),false); + BOOST_CHECK_EQUAL(valid(e),false); else - BOOST_CHECK_EQUAL(e.valid(), true ); + BOOST_CHECK_EQUAL(valid(e), true ); } - BOOST_CHECK_EQUAL( extents_type{}.valid() , false ); + BOOST_CHECK_EQUAL( valid(extents_type{}) , false ); + + BOOST_CHECK_THROW( ublas::basic_extents({0,1}), std::length_error ); + BOOST_CHECK_THROW( ublas::basic_extents({1,0,1}), std::length_error ); + + BOOST_CHECK(!valid(de0)); + BOOST_CHECK(valid(de1)); + BOOST_CHECK(valid(de2)); + BOOST_CHECK(valid(de3)); + BOOST_CHECK(valid(de4)); + BOOST_CHECK(valid(de5)); + BOOST_CHECK(valid(de6)); + BOOST_CHECK(valid(de7)); + BOOST_CHECK(valid(de8)); + BOOST_CHECK(valid(de9)); + BOOST_CHECK(valid(de10)); + BOOST_CHECK(valid(de11)); + BOOST_CHECK(valid(de12)); + BOOST_CHECK(valid(de13)); + BOOST_CHECK(valid(de14)); + BOOST_CHECK(valid(de15)); + BOOST_CHECK(valid(de16)); + BOOST_CHECK(valid(de17)); + +} + +BOOST_FIXTURE_TEST_CASE(test_extents_comparison, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("compare")) +{ + + using namespace boost::numeric; - BOOST_CHECK_THROW( ublas::basic_extents({0,1}), std::length_error ); - BOOST_CHECK_THROW( ublas::basic_extents({1,0,1}), std::length_error ); + auto s0 = ublas::static_extents<>{}; + auto s1 = ublas::static_extents<1,1>{}; + auto s2 = ublas::static_extents<1,4,2,1,3,1>{}; + auto s3 = ublas::static_extents<1,4,2,1,1,1>{}; + + auto d0 = ublas::dynamic_extents<0>{}; + auto d1 = ublas::dynamic_extents<2>{1,1}; + auto d2 = ublas::dynamic_extents<6>{1,4,2,1,3,1}; + auto d3 = ublas::dynamic_extents<6>{1,4,2,1,1,1}; + + auto e0 = extents[ 0]; // {} + auto e1 = extents[ 1]; // {1,1} + auto e2 = extents[12]; // {1,4,2,1,3,1} + + // static_extents<...> == dynamic_extents<> + BOOST_TEST( s0 == e0 ); + BOOST_TEST( s1 == e1 ); + BOOST_TEST( s2 == e2 ); + + BOOST_TEST( e0 == s0 ); + BOOST_TEST( e1 == s1 ); + BOOST_TEST( e2 == s2 ); + + BOOST_TEST( s0 != e1 ); + BOOST_TEST( s0 != e2 ); + BOOST_TEST( s1 != e0 ); + BOOST_TEST( s1 != e2 ); + BOOST_TEST( s2 != e0 ); + BOOST_TEST( s2 != e1 ); + BOOST_TEST( s3 != e0 ); + BOOST_TEST( s3 != e1 ); + BOOST_TEST( s3 != e2 ); + + BOOST_TEST( e1 != s0 ); + BOOST_TEST( e2 != s0 ); + BOOST_TEST( e0 != s1 ); + BOOST_TEST( e2 != s1 ); + BOOST_TEST( e0 != s2 ); + BOOST_TEST( e1 != s2 ); + BOOST_TEST( e0 != s3 ); + BOOST_TEST( e1 != s3 ); + BOOST_TEST( e2 != s3 ); + + // dynamic_extents == dynamic_extents<> + BOOST_TEST( d0 == e0 ); + BOOST_TEST( d1 == e1 ); + BOOST_TEST( d2 == e2 ); + + BOOST_TEST( e0 == d0 ); + BOOST_TEST( e1 == d1 ); + BOOST_TEST( e2 == d2 ); + + BOOST_TEST( d0 != e1 ); + BOOST_TEST( d0 != e2 ); + BOOST_TEST( d1 != e0 ); + BOOST_TEST( d1 != e2 ); + BOOST_TEST( d2 != e0 ); + BOOST_TEST( d2 != e1 ); + BOOST_TEST( d3 != e0 ); + BOOST_TEST( d3 != e1 ); + BOOST_TEST( d3 != e2 ); + + BOOST_TEST( e1 != d0 ); + BOOST_TEST( e2 != d0 ); + BOOST_TEST( e0 != d1 ); + BOOST_TEST( e2 != d1 ); + BOOST_TEST( e0 != d2 ); + BOOST_TEST( e1 != d2 ); + BOOST_TEST( e0 != d3 ); + BOOST_TEST( e1 != d3 ); + BOOST_TEST( e2 != d3 ); + + // static_extents<...> == dynamic_extents + + BOOST_TEST( s0 == d0 ); + BOOST_TEST( s1 == d1 ); + BOOST_TEST( s2 == d2 ); + BOOST_TEST( s3 == d3 ); + + BOOST_TEST( d0 == s0 ); + BOOST_TEST( d1 == s1 ); + BOOST_TEST( d2 == s2 ); + BOOST_TEST( d3 == s3 ); + + BOOST_TEST( s0 != d1 ); + BOOST_TEST( s0 != d2 ); + BOOST_TEST( s0 != d3 ); + BOOST_TEST( s1 != d0 ); + BOOST_TEST( s1 != d2 ); + BOOST_TEST( s1 != d3 ); + BOOST_TEST( s2 != d0 ); + BOOST_TEST( s2 != d1 ); + BOOST_TEST( s2 != d3 ); + BOOST_TEST( s3 != d0 ); + BOOST_TEST( s3 != d1 ); + BOOST_TEST( s3 != d2 ); + + BOOST_TEST( d1 != s0 ); + BOOST_TEST( d2 != s0 ); + BOOST_TEST( d3 != s0 ); + BOOST_TEST( d0 != s1 ); + BOOST_TEST( d2 != s1 ); + BOOST_TEST( d3 != s1 ); + BOOST_TEST( d0 != s2 ); + BOOST_TEST( d1 != s2 ); + BOOST_TEST( d3 != s2 ); + BOOST_TEST( d0 != s3 ); + BOOST_TEST( d1 != s3 ); + BOOST_TEST( d2 != s3 ); } @@ -414,19 +1168,24 @@ BOOST_FIXTURE_TEST_CASE(test_extents_valid, fixture, *boost::unit_test::label("e 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} + auto e0 = product(extents[ 0]); // {} + auto e1 = product(extents[ 1]); // {1,1} + auto e2 = product(extents[ 2]); // {1,2} + auto e3 = product(extents[ 3]); // {2,1} + auto e4 = product(extents[ 4]); // {2,3} + auto e5 = product(extents[ 5]); // {2,3,1} + auto e6 = product(extents[ 6]); // {1,2,3} + auto e7 = product(extents[ 7]); // {1,1,2,3} + auto e8 = product(extents[ 8]); // {1,2,3,1,1} + auto e9 = product(extents[ 9]); // {4,2,3} + auto e10 = product(extents[10]); // {4,2,1,3} + auto e11 = product(extents[11]); // {4,2,1,3,1} + auto e12 = product(extents[12]); // {1,4,2,1,3,1} + auto e13 = product(extents[13]); // {1,4,1} + auto e14 = product(extents[14]); // {1,1,1,1} + auto e15 = product(extents[15]); // {1,4,1,1,1} + auto e16 = product(extents[16]); // {1,1,2,1,1,1} + auto e17 = product(extents[17]); // {1,1,2,3,1,1} BOOST_CHECK_EQUAL( e0 , 0 ); BOOST_CHECK_EQUAL( e1 , 1 ); @@ -441,9 +1200,58 @@ BOOST_FIXTURE_TEST_CASE(test_extents_product, fixture, *boost::unit_test::label( BOOST_CHECK_EQUAL( e10, 24 ); BOOST_CHECK_EQUAL( e11, 24 ); BOOST_CHECK_EQUAL( e12, 24 ); + BOOST_CHECK_EQUAL( e13, 4 ); + BOOST_CHECK_EQUAL( e14, 1 ); + BOOST_CHECK_EQUAL( e15, 4 ); + BOOST_CHECK_EQUAL( e16, 2 ); + BOOST_CHECK_EQUAL( e17, 6 ); } -BOOST_AUTO_TEST_SUITE_END() +BOOST_FIXTURE_TEST_CASE(test_static_rank_extents_product, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("product")) +{ + + auto e0 = product( de0 ); // {} + auto e1 = product( de1 ); // {1,1} + auto e2 = product( de2 ); // {1,2} + auto e3 = product( de3 ); // {2,1} + auto e4 = product( de4 ); // {2,3} + auto e5 = product( de5 ); // {2,3,1} + auto e6 = product( de6 ); // {1,2,3} + auto e7 = product( de7 ); // {1,1,2,3} + auto e8 = product( de8 ); // {1,2,3,1,1} + auto e9 = product( de9 ); // {4,2,3} + auto e10 = product( de10 ); // {4,2,1,3} + auto e11 = product( de11 ); // {4,2,1,3,1} + auto e12 = product( de12 ); // {1,4,2,1,3,1} + auto e13 = product( de13 ); // {1,4,1} + auto e14 = product( de14 ); // {1,1,1,1} + auto e15 = product( de15 ); // {1,4,1,1,1} + auto e16 = product( de16 ); // {1,1,2,1,1,1} + auto e17 = product( de17 ); // {1,1,2,3,1,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_CHECK_EQUAL( e13, 4 ); + BOOST_CHECK_EQUAL( e14, 1 ); + BOOST_CHECK_EQUAL( e15, 4 ); + BOOST_CHECK_EQUAL( e16, 2 ); + BOOST_CHECK_EQUAL( e17, 6 ); + + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_expression_evaluation.cpp b/test/tensor/test_fixed_rank_expression_evaluation.cpp new file mode 100644 index 000000000..7c50b087c --- /dev/null +++ b/test/tensor/test_fixed_rank_expression_evaluation.cpp @@ -0,0 +1,284 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + + +#include +#include +#include +#include "utility.hpp" +#include + +#include + +BOOST_AUTO_TEST_SUITE(test_fixed_rank_tensor_expression); + +using test_types = zip>::with_t; + + +struct fixture +{ + template + using extents_type = boost::numeric::ublas::dynamic_extents; + + std::tuple< + extents_type<0>, // 0 + extents_type<2>, // 1 + extents_type<2>, // 2 + extents_type<2>, // 3 + extents_type<2>, // 4 + extents_type<3>, // 5 + extents_type<3>, // 6 + extents_type<3>, // 7 + extents_type<3>, // 8 + extents_type<4> // 9 + > extents = { + extents_type<0>{}, + extents_type<2>{1,1}, + extents_type<2>{1,2}, + extents_type<2>{2,1}, + extents_type<2>{2,3}, + extents_type<3>{2,3,1}, + extents_type<3>{4,1,3}, + extents_type<3>{1,2,3}, + extents_type<3>{4,2,3}, + extents_type<4>{4,2,3,5} + }; +}; + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_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; + + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; + + for_each_tuple(extents, [&](auto const&, auto & e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); + + }); + + for_each_tuple(extents, [&](auto const& I, auto& e1){ + + if ( I >= std::tuple_size_v - 1 ){ + return; + } + + using extents_type1 = std::decay_t; + using tensor_type1 = ublas::tensor; + + for_each_tuple(extents, [&](auto const& J, auto& e2){ + if( J != I + 1 ){ + return; + } + + using extents_type2 = std::decay_t; + using tensor_type2 = ublas::tensor; + + auto v = value_type{}; + + tensor_type1 t1(e1); + for(auto& tt: t1){ tt = v; v+=value_type{1}; } + + tensor_type2 t2(e2); + 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( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 ) ); + + if constexpr( extents_type1::_size == extents_type2::_size ){ + // bexpr_uexpr = (t1+1) + (2+t2) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( 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( t2, bexpr_uexpr, bminus ); + + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); + } + + }); + }); +} + + + + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_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; + + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; + + for_each_tuple(extents, [&](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); + + }); + + + for_each_tuple(extents, [&](auto const& I, auto& e1){ + + if ( I >= std::tuple_size_v - 1){ + return; + } + + using extents_type1 = std::decay_t; + using tensor_type1 = ublas::tensor; + + for_each_tuple(extents, [&](auto const& J, auto& e2){ + if( J != I + 1 ){ + return; + } + + using extents_type2 = std::decay_t; + using tensor_type2 = ublas::tensor; + + auto v = value_type{}; + + tensor_type1 t1(e1); + for(auto& tt: t1){ tt = v; v+=value_type{1}; } + + tensor_type2 t2(e2); + 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( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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) ) ); + + if constexpr( extents_type1::_size == extents_type2::_size ){ + // bexpr_uexpr = (t1+1) + (2+t2) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( 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( 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( 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( 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( t1, bexpr_bexpr_uexpr3, bplus ); + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); + } + + }); + }); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_operators_arithmetic.cpp b/test/tensor/test_fixed_rank_operators_arithmetic.cpp new file mode 100644 index 000000000..715288be2 --- /dev/null +++ b/test/tensor/test_fixed_rank_operators_arithmetic.cpp @@ -0,0 +1,243 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + + +#include + +#include +#include +#include "utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_fixed_rank_tensor_arithmetic_operations) + +using double_extended = boost::multiprecision::cpp_bin_float_double_extended; + +using test_types = zip::with_t; + +struct fixture +{ + template + using extents_type = boost::numeric::ublas::dynamic_extents; + + std::tuple< + extents_type<2>, // 1 + extents_type<2>, // 2 + extents_type<3>, // 3 + extents_type<3>, // 4 + extents_type<4> // 5 + > extents = { + extents_type<2>{1,1}, + extents_type<2>{2,3}, + extents_type<3>{4,1,3}, + extents_type<3>{4,2,3}, + extents_type<4>{4,2,3,5} + }; +}; + +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; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + 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_each_tuple(extents,check); +} + + + +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; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + 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_each_tuple(extents,check); +} + + + + + +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; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + 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_each_tuple(extents,check); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_operators_comparison.cpp b/test/tensor/test_fixed_rank_operators_comparison.cpp new file mode 100644 index 000000000..33aea14c2 --- /dev/null +++ b/test/tensor/test_fixed_rank_operators_comparison.cpp @@ -0,0 +1,205 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + + +#include +#include +#include +#include +#include +#include "utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_fixed_rank_tensor_comparison) + +using double_extended = boost::multiprecision::cpp_bin_float_double_extended; + +using test_types = zip::with_t; + +struct fixture { + template + using extents_type = boost::numeric::ublas::dynamic_extents; + + std::tuple< + extents_type<2>, // 1 + extents_type<2>, // 2 + extents_type<3>, // 3 + extents_type<3>, // 4 + extents_type<4> // 5 + > extents = { + extents_type<2>{1,1}, + extents_type<2>{2,3}, + extents_type<3>{4,1,3}, + extents_type<3>{4,2,3}, + extents_type<4>{4,2,3,5} + }; +}; + + +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; + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + 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_each_tuple(extents,check); + +} + + +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; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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_each_tuple(extents,check); + +} + + + +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; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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_each_tuple(extents,check); + +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_tensor.cpp b/test/tensor/test_fixed_rank_tensor.cpp new file mode 100644 index 000000000..794a594b6 --- /dev/null +++ b/test/tensor/test_fixed_rank_tensor.cpp @@ -0,0 +1,511 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + + +#include +#include + +#ifndef BOOST_TEST_DYN_LINK +#define BOOST_TEST_DYN_LINK +#endif + +#define BOOST_TEST_MODULE TestFixedRankedTensor + +#include +#include "utility.hpp" + +BOOST_AUTO_TEST_SUITE ( test_fixed_rank_tensor ) + +using test_types = zip>::with_t; + + +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; + + auto a1 = ublas::tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a1.size() , 0ul ); + BOOST_CHECK( a1.empty() ); + BOOST_CHECK_EQUAL( a1.data() , nullptr); + + auto a2 = ublas::tensor,layout_type>{1,1}; + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + BOOST_CHECK_NE( a2.data() , nullptr); + + auto a3 = ublas::tensor,layout_type>{2,1}; + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + BOOST_CHECK_NE( a3.data() , nullptr); + + auto a4 = ublas::tensor,layout_type>{1,2}; + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + BOOST_CHECK_NE( a4.data() , nullptr); + + auto a5 = ublas::tensor,layout_type>{2,1}; + BOOST_CHECK_EQUAL( a5.size() , 2 ); + BOOST_CHECK( !a5.empty() ); + BOOST_CHECK_NE( a5.data() , nullptr); + + auto a6 = ublas::tensor,layout_type>{4,3,2}; + BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); + BOOST_CHECK( !a6.empty() ); + BOOST_CHECK_NE( a6.data() , nullptr); + + auto a7 = ublas::tensor,layout_type>{4,1,2}; + BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); + BOOST_CHECK( !a7.empty() ); + BOOST_CHECK_NE( a7.data() , nullptr); + +} + + +struct fixture +{ + template + using extents_type = boost::numeric::ublas::dynamic_extents; + + std::tuple< + extents_type<2>, // 1 + extents_type<2>, // 2 + extents_type<3>, // 3 + extents_type<3>, // 4 + extents_type<4> // 5 + > extents = { + extents_type<2>{1,1}, + extents_type<2>{2,3}, + extents_type<3>{4,1,3}, + extents_type<3>{4,2,3}, + extents_type<4>{4,2,3,5} + }; +}; + + +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; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + auto t = ublas::tensor{e}; + + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + 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); + } + }); + +} + + +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; + + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + auto r = ublas::tensor{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] ); + + }); +} + + +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 other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; + + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + auto r = tensor_type{e}; + ublas::tensor 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; + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + auto r = tensor_type{e}; + auto t = std::move(r); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + 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_each_tuple(extents,check); +} + + +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; + + std::random_device device{}; + std::minstd_rand0 generator(device()); + + using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; + auto distribution = distribution_type(1,6); + + for_each_tuple(extents, [&](auto const&, auto const& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + auto r = value_type( static_cast< inner_type_t >(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; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + using array_type = typename tensor_type::array_type; + + auto a = array_type(product(e)); + 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; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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; + + auto check1 = [](const auto& 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 auto& t) + { + std::array k; + auto r = std::is_same::value ? 1 : 0; + auto q = std::is_same::value ? 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 auto& t) + { + std::array k; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 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 auto& t) + { + std::array k; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 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&, auto const& e) { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + 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_each_tuple(extents,check); +} + + + + +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; + + for_each_tuple(extents,[&](auto const&, auto& efrom){ + + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + for_each_tuple(extents,[&](auto const&, auto& eto){ + + if ( efrom.size() == eto.size() ){ + + 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(product(efrom),product(eto)); ++i) + BOOST_CHECK_EQUAL( t[i], v ); + + BOOST_CHECK_EQUAL ( t.size() , product(eto) ); + BOOST_CHECK_EQUAL ( t.rank() , eto.size() ); + BOOST_CHECK ( t.extents() == eto ); + + if(efrom != eto){ + for(auto i = product(efrom); 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; + + for_each_tuple(extents,[&](auto const&, auto& e_t){ + + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + for_each_tuple(extents,[&](auto const&, auto& e_r){ + + if ( e_t.size() == e_r.size() ){ + + 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() , product(e_r) ); + 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() , product(e_t) ); + 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; + + for_each_tuple(extents,[](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, 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, layout_type>; + + std::vector vec(30); + BOOST_CHECK_THROW(tensor_type({5,5},vec), std::runtime_error); + + auto t = tensor_type{{5,5}}; + auto i = ublas::index::index_type<4>{}; + BOOST_CHECK_THROW(t.operator()(i,i,i), std::runtime_error); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp b/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp new file mode 100644 index 000000000..ade7f891e --- /dev/null +++ b/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp @@ -0,0 +1,482 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#include +#include +#include +#include +#include + +#include "utility.hpp" + +BOOST_AUTO_TEST_SUITE ( test_fixed_rank_tensor_matrix_interoperability ) ; + +using test_types = zip::with_t; + + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + ublas::tensor,layout_type> a1 = matrix_type(); + BOOST_CHECK_EQUAL( a1.size() , 0ul ); + BOOST_CHECK( a1.empty() ); + BOOST_CHECK_EQUAL( a1.data() , nullptr); + + ublas::tensor,layout_type> a2 = matrix_type(1,1); + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + BOOST_CHECK_NE( a2.data() , nullptr); + + ublas::tensor,layout_type> a3 = matrix_type(2,1); + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + BOOST_CHECK_NE( a3.data() , nullptr); + + ublas::tensor,layout_type> a4 = matrix_type(1,2); + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + BOOST_CHECK_NE( a4.data() , nullptr); + + ublas::tensor,layout_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,layout_type>; + using vector_type = typename tensor_type::vector_type; + + ublas::tensor,layout_type> a1 = vector_type(); + BOOST_CHECK_EQUAL( a1.size() , 0ul ); + BOOST_CHECK( a1.empty() ); + BOOST_CHECK_EQUAL( a1.data() , nullptr); + + ublas::tensor,layout_type> a2 = vector_type(1); + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + BOOST_CHECK_NE( a2.data() , nullptr); + + ublas::tensor,layout_type> a3 = vector_type(2); + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + BOOST_CHECK_NE( a3.data() , nullptr); + + ublas::tensor,layout_type> a4 = vector_type(2); + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + BOOST_CHECK_NE( a4.data() , nullptr); + + ublas::tensor,layout_type> a5 = vector_type(3); + BOOST_CHECK_EQUAL( a5.size() , 3 ); + BOOST_CHECK( !a5.empty() ); + BOOST_CHECK_NE( a5.data() , nullptr); +} + + +struct fixture +{ + template + using extents_type = boost::numeric::ublas::dynamic_extents; + + std::tuple< + extents_type<2>, // 0 + extents_type<2>, // 1 + extents_type<2>, // 2 + extents_type<2> // 3 + > extents = { + {1,2}, + {2,1}, + {9,7}, + {12,12}, + }; +}; + + + + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size()==2); + etensor_type t = matrix_type{e[0],e[1]}; + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + }; + + for_each_tuple(extents,check); +} + + +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,layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size()==2); + if(e.empty()) + return; + + etensor_type t = vector_type(product(e)); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + }; + + for_each_tuple(extents,check); +} + + + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + 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_each_tuple(extents,check); +} + + +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,layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + 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_each_tuple(extents,check); +} + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + 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_each_tuple(extents,check); +} + + + + +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,layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + 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_each_tuple(extents,check); +} + + + + + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + auto t = etensor_type{}; + auto r = matrix_type(e[0],e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r + 3*r; + etensor_type s = r + 3*r; + etensor_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() , product(e) ); + 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() , product(e) ); + 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() , product(e) ); + 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_each_tuple(extents,check); +} + + + + + + +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,layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + auto t = etensor_type{}; + auto r = vector_type(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r + 3*r; + etensor_type s = r + 3*r; + etensor_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() , product(e) ); + 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() , product(e) ); + 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() , product(e) ); + 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_each_tuple(extents,check); +} + + + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + if(product(e) <= 2) + return; + assert(e.size() == 2); + auto Q = etensor_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); + + etensor_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_each_tuple(extents,check); +} + + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/test/tensor/test_functions.cpp b/test/tensor/test_functions.cpp index 64ecda396..a328e94fa 100644 --- a/test/tensor/test_functions.cpp +++ b/test/tensor/test_functions.cpp @@ -1,12 +1,13 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // // And we acknowledge the support from all contributors. @@ -17,35 +18,66 @@ #include #include +#ifndef BOOST_TEST_DYN_LINK +#define BOOST_TEST_DYN_LINK +#endif + +#define BOOST_TEST_MODULE TestTensorFunctions + #include #include "utility.hpp" -BOOST_AUTO_TEST_SUITE ( test_tensor_functions, * boost::unit_test::depends_on("test_tensor_contraction") ) +// BOOST_AUTO_TEST_SUITE ( test_tensor_functions, * boost::unit_test::depends_on("test_tensor_contraction") ) +BOOST_AUTO_TEST_SUITE ( test_tensor_functions) -using test_types = zip>::with_t; +using test_types = zip>::with_t; //using test_types = zip::with_t; struct fixture { - using extents_type = boost::numeric::ublas::shape; + using dynamic_extents_type = boost::numeric::ublas::dynamic_extents<>; + template + using static_extents_type = boost::numeric::ublas::static_extents; + + template + using dynamic_rank_extents_type = boost::numeric::ublas::dynamic_extents; 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 + dynamic_extents_type{1,1}, // 1 + dynamic_extents_type{2,3}, // 2 + dynamic_extents_type{2,3,1}, // 3 + dynamic_extents_type{4,2,3}, // 4 + dynamic_extents_type{4,2,3,5}} // 5 { } - std::vector extents; + + std::tuple< + static_extents_type<1,1>, // 1 + static_extents_type<2,3>, // 2 + static_extents_type<2,3,1>, // 3 + static_extents_type<4,2,3>, // 4 + static_extents_type<4,2,3,5> // 5 + > static_extents{}; + + std::tuple< + dynamic_rank_extents_type<2>, + dynamic_rank_extents_type<2>, + dynamic_rank_extents_type<3>, + dynamic_rank_extents_type<3>, + dynamic_rank_extents_type<4> + > dynamic_rank_extents{ + {1,1}, // 1 + {2,3}, // 2 + {2,3,1}, // 3 + {4,2,3}, // 4 + {4,2,3,5} // 5 + }; + + std::vector extents; }; @@ -56,7 +88,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_vector, value, test_types, f using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using vector_type = typename tensor_type::vector_type; @@ -71,10 +103,99 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_vector, value, test_types, f 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_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(n[m]) ) * a[i] ); } } + auto n = extents[4]; + auto a = tensor_type(n, value_type{2}); + auto b = vector_type(n[0], value_type{1}); + + auto zero_rank_empty_tensor = tensor_type{}; + auto empty = vector_type{}; + + BOOST_CHECK_THROW(prod(a, b, 0), std::length_error); + BOOST_CHECK_THROW(prod(a, b, 9), std::length_error); + BOOST_CHECK_THROW(prod(zero_rank_empty_tensor, b, 1), std::length_error); + BOOST_CHECK_THROW(prod(a, empty, 2), std::length_error); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + for_each_tuple(static_extents,[](auto const&, auto& n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::tensor; + using vector_type = typename tensor_type::vector_type; + auto a = tensor_type(extents_type{}, 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( static_cast< inner_type_t >(n[m]) ) * a[i]); + } + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_dynamic_rank_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; + + for_each_tuple(dynamic_rank_extents,[](auto const&, auto & n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::tensor; + using vector_type = typename tensor_type::vector_type; + 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( static_cast< inner_type_t >(n[m]) ) * a[i]); + } + }); + +} + + + +BOOST_AUTO_TEST_CASE( test_tensor_prod_vector_exception ) +{ + using namespace boost::numeric; + using value_type = float; + using layout_type = ublas::first_order; + using d_extents_type = ublas::dynamic_extents<>; + using s_extents_type = ublas::static_extents<1,2,3>; + using d_tensor_type = ublas::tensor; + using s_tensor_type = ublas::tensor; + using vector_type = typename d_tensor_type::vector_type; + + auto t1 = d_tensor_type{d_extents_type{},1.f}; + auto v1 = vector_type{3,value_type{1}}; + + BOOST_REQUIRE_THROW(prod(t1,v1,0),std::length_error); + BOOST_REQUIRE_THROW(prod(t1,v1,1),std::length_error); + BOOST_REQUIRE_THROW(prod(t1,v1,3),std::length_error); + + auto t2 = s_tensor_type{}; + BOOST_REQUIRE_THROW(prod(t2,v1,2),std::length_error); + + auto t3 = s_tensor_type{s_extents_type{},value_type{1}}; + auto v2 = vector_type{0,value_type{1}}; + BOOST_REQUIRE_THROW(prod(t3,v2,2),std::length_error); } @@ -85,7 +206,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_matrix, value, test_types, f using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using matrix_type = typename tensor_type::matrix_type; @@ -100,20 +221,108 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_matrix, value, test_types, f 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_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(n[m]) ) * a[i] ); } } + + auto n = extents[4]; + auto a = tensor_type(n, value_type{2}); + auto b = matrix_type(n[0], n[0], value_type{1}); + + auto zero_rank_empty_tensor = tensor_type{}; + auto empty = matrix_type{}; + + BOOST_CHECK_THROW(prod(a, b, 0), std::length_error); + BOOST_CHECK_THROW(prod(a, b, 9), std::length_error); + BOOST_CHECK_THROW(prod(zero_rank_empty_tensor, b, 1), std::length_error); + BOOST_CHECK_THROW(prod(a, empty, 2), std::length_error); +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + for_each_tuple(static_extents,[](auto const&, auto & n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::tensor; + using matrix_type = typename tensor_type::matrix_type; + auto a = tensor_type(extents_type{}, 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( static_cast< inner_type_t >(n[m]) ) * a[i]); + } + }); + } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_dynamic_rank_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; + + for_each_tuple(dynamic_rank_extents,[](auto const&, auto & n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::tensor; + using matrix_type = typename tensor_type::matrix_type; + 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( static_cast< inner_type_t >(n[m]) ) * a[i]); + } + }); + +} + + +BOOST_AUTO_TEST_CASE( test_tensor_prod_matrix_exception ) +{ + using namespace boost::numeric; + using value_type = float; + using layout_type = ublas::first_order; + using d_extents_type = ublas::dynamic_extents<>; + using s_extents_type = ublas::static_extents<1,2,3>; + using d_tensor_type = ublas::tensor; + using s_tensor_type = ublas::tensor; + using matrix_type = typename d_tensor_type::matrix_type; + + auto t1 = d_tensor_type{d_extents_type{},1.f}; + auto m1 = matrix_type{3,3,value_type{1}}; + BOOST_REQUIRE_THROW(prod(t1,m1,0),std::length_error); + BOOST_REQUIRE_THROW(prod(t1,m1,1),std::length_error); + BOOST_REQUIRE_THROW(prod(t1,m1,3),std::length_error); + + auto t2 = s_tensor_type{}; + + BOOST_REQUIRE_THROW(prod(t2,m1,2),std::length_error); + + auto t3 = s_tensor_type{s_extents_type{},value_type{1}}; + auto m2 = matrix_type{0,0,value_type{1}}; + BOOST_REQUIRE_THROW(prod(t3,m2,2),std::length_error); +} + 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; + using tensor_type = ublas::tensor,layout_type>; // left-hand and right-hand side have the // the same number of elements @@ -136,7 +345,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_1, value, test_types, auto acc = value_type(1); for(auto i = 0ul; i < q; ++i) - acc *= a.extents().at(phi.at(i)-1); + acc *= value_type( static_cast< inner_type_t >( 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] ); @@ -146,12 +355,198 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_1, value, test_types, } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + auto const body = [](auto const& a, auto const& b){ + auto const pa = a.rank(); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phi = std::vector(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 *= value_type( static_cast< inner_type_t >( 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]); + } + }; + + + //static extents and static_extents + for_each_tuple(static_extents,[&](auto const&, auto & n){ + auto n1 = n; + auto n2 = n; + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = + ublas::tensor; + using tensor_type_2 = + ublas::tensor; + auto a = tensor_type_1(n1, value_type{2}); + auto b = tensor_type_2(n2, value_type{3}); + body(a,b); + }); + + for_each_tuple(static_extents,[&](auto const& I, auto & n){ + auto n1 = n; + auto n2 = extents[I]; + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = + ublas::tensor; + using tensor_type_2 = + ublas::tensor; + auto a = tensor_type_1(n1, value_type{2}); + auto b = tensor_type_2(n2, value_type{3}); + body(a,b); + }); + + for_each_tuple(static_extents,[&](auto const& I, auto & n){ + auto n1 = extents[I]; + auto n2 = n; + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = + ublas::tensor; + using tensor_type_2 = + ublas::tensor; + auto a = tensor_type_1(n1, value_type{2}); + auto b = tensor_type_2(n2, value_type{3}); + body(a,b); + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_dynamic_rank_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; + + auto const body = [](auto const& a, auto const& b){ + auto const pa = a.rank(); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phi = std::vector(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 *= value_type( static_cast< inner_type_t >( 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]); + } + }; + + + + for_each_tuple(dynamic_rank_extents,[&](auto const&, auto & n){ + auto n1 = n; + auto n2 = n; + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = + ublas::tensor; + using tensor_type_2 = + ublas::tensor; + auto a = tensor_type_1(n1, value_type{2}); + auto b = tensor_type_2(n2, value_type{3}); + body(a,b); + }); + + for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto & n){ + auto n1 = n; + auto n2 = extents[I]; + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = + ublas::tensor; + using tensor_type_2 = + ublas::tensor; + auto a = tensor_type_1(n1, value_type{2}); + auto b = tensor_type_2(n2, value_type{3}); + body(a,b); + }); + + for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto & n){ + auto n1 = extents[I]; + auto n2 = n; + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = + ublas::tensor; + using tensor_type_2 = + ublas::tensor; + auto a = tensor_type_1(n1, value_type{2}); + auto b = tensor_type_2(n2, value_type{3}); + body(a,b); + }); + +} + + + +BOOST_AUTO_TEST_CASE( test_tensor_prod_tensor_1_exception ) +{ + using namespace boost::numeric; + using value_type = float; + using layout_type = ublas::first_order; + using d_extents_type = ublas::dynamic_extents<>; + using s_extents_type = ublas::static_extents<1,2,3>; + using d_tensor_type = ublas::tensor; + using s_tensor_type = ublas::tensor; + + auto t1 = d_tensor_type{}; + auto t2 = s_tensor_type{s_extents_type{},1.f}; + std::vector phia = {1,2,3}; + std::vector phib = {1,2,3,4,5}; + + BOOST_REQUIRE_THROW(prod(t1,t2,phia,phib),std::runtime_error); + BOOST_REQUIRE_THROW(prod(t2,t1,phia,phib),std::runtime_error); + + + auto t3 = d_tensor_type{d_extents_type{1,2},1.f}; + auto t4 = d_tensor_type{d_extents_type{1,2},1.f}; + BOOST_REQUIRE_THROW(prod(t3,t4,phia,phib),std::runtime_error); + + + auto t5 = d_tensor_type{d_extents_type{1,2,3,4},1.f}; + auto t6 = d_tensor_type{d_extents_type{1,2},1.f}; + BOOST_REQUIRE_THROW(prod(t5,t6,phia,phib),std::runtime_error); + + + auto t7 = d_tensor_type{d_extents_type{1,2,3,4,5},1.f}; + auto t8 = d_tensor_type{d_extents_type{1,2,3,4,5},1.f}; + BOOST_REQUIRE_THROW(prod(t7,t8,phia,phib),std::runtime_error); + + std::vector phia_2 = {1,2,3,5,4}; + std::vector phib_2 = {1,2,3,4,5}; + auto t9 = d_tensor_type{d_extents_type{1,2,3,4,5,6},1.f}; + auto t10 = d_tensor_type{d_extents_type{1,2,3,4,5,6},1.f}; + BOOST_REQUIRE_THROW(prod(t9,t10,phia_2,phib_2),std::runtime_error); +} + 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; + using tensor_type = ublas::tensor,layout_type>; auto compute_factorial = [](auto const& p){ @@ -202,7 +597,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_2, value, test_types, auto acc = value_type(1); for(auto i = 0ul; i < q; ++i) - acc *= a.extents().at(phia.at(i)-1); + acc *= value_type( static_cast< inner_type_t >( 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] ); @@ -212,10 +607,344 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_2, value, test_types, std::next_permutation(pi.begin(), pi.end()); } } + + auto phia = std::vector(3); + auto sphia = std::vector(2); + + BOOST_CHECK_THROW(ublas::prod(tensor_type{}, tensor_type({2,1,2}), phia, phia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2,3}), tensor_type(), phia, phia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2,4}), tensor_type({2,1}), phia, phia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2}), tensor_type({2,1,2}), phia, phia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2}), tensor_type({2,1,3}), sphia, phia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2}), tensor_type({2,2}), phia, sphia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2}), tensor_type({4,4}), sphia, phia), std::runtime_error); } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + + + auto compute_factorial = [](auto const& p){ + auto f = 1ul; + for(auto i = 1u; i <= p; ++i) + f *= i; + return f; + }; + + auto permute_extents_d = [](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; + }; + + auto permute_extents_s_1 = [](auto const& pi, auto const& na){ + auto nb = na.to_dynamic_extents(); + assert(pi.size() == na.size()); + for(auto j = 0u; j < pi.size(); ++j) + nb[pi[j]-1] = na[j]; + return nb; + }; + auto permute_extents_s_2 = [](auto const& pi, auto const& na){ + auto tempn = na.base(); + assert(pi.size() == na.size()); + for(auto j = 0u; j < pi.size(); ++j) + tempn[pi[j]-1] = na[j]; + return ublas::dynamic_extents::type::_size>(tempn.begin(),tempn.end()); + }; + +// static and dynamic + for_each_tuple(static_extents,[&](auto const&, auto & n){ + auto na = n; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(na, value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_s_1(pi, na); + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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 *= value_type( static_cast< inner_type_t >( 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()); + } + }); + + //dynamic and static + for_each_tuple(static_extents,[&](auto const& I, auto & n){ + auto na = extents[I]; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(na, value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_d(pi, na); + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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 *= value_type( static_cast< inner_type_t >( 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()); + } + }); + //static and static + for_each_tuple(static_extents,[&](auto const&, auto & n){ + auto na = n; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(na, value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_s_2(pi, na); + + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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_dynamic_rank_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; + + + + auto compute_factorial = [](auto const& p){ + auto f = 1ul; + for(auto i = 1u; i <= p; ++i) + f *= i; + return f; + }; + + auto permute_extents_d = [](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; + }; + + auto permute_extents_s_1 = [](auto const& pi, auto const& na){ + auto nb = na.to_dynamic_extents(); + assert(pi.size() == na.size()); + for(auto j = 0u; j < pi.size(); ++j) + nb[pi[j]-1] = na[j]; + return nb; + }; + auto permute_extents_s_2 = [](auto const& pi, auto const& na){ + auto tempn = na.base(); + assert(pi.size() == na.size()); + for(auto j = 0u; j < pi.size(); ++j) + tempn[pi[j]-1] = na[j]; + return ublas::dynamic_extents::type::_size>(tempn.begin(),tempn.end()); + }; + + for_each_tuple(dynamic_rank_extents,[&](auto const&, auto & n){ + auto na = n; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(na, value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_s_1(pi, na); + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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 *= value_type( static_cast< inner_type_t >( 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()); + } + }); + + for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto & n){ + auto na = extents[I]; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(na, value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_d(pi, na); + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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 *= value_type( static_cast< inner_type_t >( 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()); + } + }); + + for_each_tuple(dynamic_rank_extents,[&](auto const&, auto & n){ + auto na = n; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(na, value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_s_2(pi, na); + + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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 *= value_type( static_cast< inner_type_t >( 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 ) @@ -223,7 +952,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_inner_prod, value, test_types, fi using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; for(auto const& n : extents) { @@ -237,6 +966,127 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_inner_prod, value, test_types, fi BOOST_CHECK_EQUAL( c , r ); } + BOOST_CHECK_THROW(ublas::inner_prod(tensor_type({1,2,3}), tensor_type({1,2,3,4})), std::length_error); // rank different + BOOST_CHECK_THROW(ublas::inner_prod(tensor_type(), tensor_type()), std::length_error); //empty tensor + BOOST_CHECK_THROW(ublas::inner_prod(tensor_type({1,2,3}), tensor_type({3,2,1})), std::length_error); // different extent +} + + +BOOST_AUTO_TEST_CASE( test_tensor_inner_prod_exception ) +{ + using namespace boost::numeric; + using value_type = float; + using layout_type = ublas::first_order; + using d_extents_type = ublas::dynamic_extents<>; + using s_extents_type = ublas::static_extents<1,2,3>; + using d_tensor_type = ublas::tensor; + using s_tensor_type = ublas::tensor; + + auto t1 = d_tensor_type{d_extents_type{1,2},1.f}; + auto t2 = d_tensor_type{d_extents_type{1,2,3},1.f}; + BOOST_REQUIRE_THROW( ublas::inner_prod(t1, t2), std::length_error); + + auto t3 = s_tensor_type{s_extents_type{},1.f}; + auto t4 = d_tensor_type{d_extents_type{1,2,4,5},1.f}; + BOOST_REQUIRE_THROW( ublas::inner_prod(t3, t4), std::length_error); +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + auto const body = [&](auto const& a, auto const& b){ + 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 ); + }; + + for_each_tuple(static_extents,[&](auto const&, auto & n){ + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + using tensor_type_2 = ublas::tensor; + auto a = tensor_type_1(n, value_type(2)); + auto b = tensor_type_2(n, value_type(1)); + body(a,b); + + }); + + for_each_tuple(static_extents,[&](auto const& I, auto & n){ + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + using tensor_type_2 = ublas::tensor; + auto a = tensor_type_1(n, value_type(2)); + auto b = tensor_type_2(extents[I], value_type(1)); + body(a,b); + + }); + + for_each_tuple(static_extents,[&](auto const& I, auto & n){ + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + using tensor_type_2 = ublas::tensor; + auto a = tensor_type_1(extents[I], value_type(2)); + auto b = tensor_type_2(n, value_type(1)); + body(a,b); + + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_dynamic_rank_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; + + auto const body = [&](auto const& a, auto const& b){ + 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 ); + }; + + for_each_tuple(dynamic_rank_extents,[&](auto const&, auto & n){ + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + using tensor_type_2 = ublas::tensor; + auto a = tensor_type_1(n, value_type(2)); + auto b = tensor_type_2(n, value_type(1)); + body(a,b); + + }); + + for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto & n){ + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + using tensor_type_2 = ublas::tensor; + auto a = tensor_type_1(n, value_type(2)); + auto b = tensor_type_2(extents[I], value_type(1)); + body(a,b); + + }); + + for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto & n){ + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + using tensor_type_2 = ublas::tensor; + auto a = tensor_type_1(extents[I], value_type(2)); + auto b = tensor_type_2(n, value_type(1)); + body(a,b); + + }); + } @@ -245,7 +1095,7 @@ 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; + using tensor_type = ublas::tensor,layout_type>; for(auto const& n : extents) { @@ -261,7 +1111,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_norm, value, test_types, fixture 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 ); + tensor_type var = (a+a)/2.0f; // std::complex/int not allowed as expression is captured + auto r2 = ublas::norm( var ); + + BOOST_CHECK_THROW(ublas::norm(tensor_type{}), std::runtime_error); BOOST_CHECK_EQUAL( c , r ); BOOST_CHECK_EQUAL( std::sqrt( c ) , r2 ); @@ -269,7 +1122,6 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_norm, value, test_types, fixture } } - BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) { using namespace boost::numeric; @@ -277,8 +1129,8 @@ BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) using complex_type = std::complex; using layout_type = ublas::first_order; - using tensor_complex_type = ublas::tensor; - using tensor_type = ublas::tensor; + using tensor_complex_type = ublas::tensor,layout_type>; + using tensor_type = ublas::tensor,layout_type>; for(auto const& n : extents) { @@ -295,23 +1147,20 @@ BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) 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 ); + BOOST_CHECK( (bool) (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 ); - + BOOST_CHECK( (bool) (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 ); + BOOST_CHECK( (bool) (r00 == r3) ); } for(auto const& n : extents) { - - - auto a = tensor_complex_type(n); auto r00 = tensor_complex_type(n); @@ -328,15 +1177,15 @@ BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) 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 ); + BOOST_CHECK( (bool) (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 ); + BOOST_CHECK( (bool) (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_CHECK( (bool) (r00 == r3) ); @@ -347,15 +1196,12 @@ BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) } - - - 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; + using tensor_type = ublas::tensor,layout_type>; for(auto const& n1 : extents) { auto a = tensor_type(n1, value_type(2)); @@ -371,6 +1217,119 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_outer_prod, value, test_types, fi } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + for_each_tuple(static_extents,[&](auto const&, auto const& n1){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(n1, value_type(2)); + for_each_tuple(static_extents,[&](auto const& J, auto const& n2){ + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(n2, value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + + }); + + }); + + for_each_tuple(static_extents,[&](auto const& I, auto const& n1){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(extents[I], value_type(2)); + for_each_tuple(static_extents,[&](auto const& J, auto const& n2){ + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(n2, value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + }); + + }); + + for_each_tuple(static_extents,[&](auto const&, auto const& n1){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(n1, value_type(2)); + for(auto n2 : extents){ + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(n2, value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + } + + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_dynamic_rank_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; + + for_each_tuple(static_extents,[&](auto const&, auto const& n1){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(n1, value_type(2)); + for_each_tuple(static_extents,[&](auto const& J, auto const& n2){ + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(n2, value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + + }); + + }); + + for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto const& n1){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(extents[I], value_type(2)); + for_each_tuple(dynamic_rank_extents,[&](auto const& J, auto const& n2){ + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(n2, value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + }); + + }); + + for_each_tuple(dynamic_rank_extents,[&](auto const&, auto const& n1){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::tensor; + auto a = tensor_type_1(n1, value_type(2)); + for(auto n2 : extents){ + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::tensor; + auto b = tensor_type_2(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 void init(std::vector& a) @@ -397,7 +1356,7 @@ 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; + using tensor_type = ublas::tensor,layout_type>; auto fak = [](auto const& p){ auto f = 1ul; @@ -416,7 +1375,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_trans, value, test_types, fixture for(auto const& n : extents) { auto const p = n.size(); - auto const s = n.product(); + auto const s = product(n); auto aref = tensor_type(n); auto v = value_type{}; for(auto i = 0u; i < s; ++i, v+=1) @@ -427,7 +1386,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_trans, value, test_types, fixture auto pi = std::vector(p); std::iota(pi.begin(), pi.end(), 1); a = ublas::trans( a, pi ); - BOOST_CHECK( a == aref ); + bool res1 = a == aref; + BOOST_CHECK( res1 ); auto const pfak = fak(p); @@ -442,12 +1402,71 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_trans, value, test_types, fixture auto pi_inv = inverse(pi); a = ublas::trans( a, pi_inv ); } - - BOOST_CHECK( a == aref ); + bool res2 = a == aref; // it was an expression. so evaluate into bool + BOOST_CHECK( res2 ); } } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_trans, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + auto fac = [](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_each_tuple(static_extents,[&](auto const&, auto & n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::tensor; + auto const p = n.size(); + auto const s = product(n); + auto aref = tensor_type(n); + auto v = value_type{}; + for(auto i = 0u; i < s; ++i, v+=1) + aref[i] = v; + + auto pi = std::vector(p); + std::iota(pi.begin(), pi.end(), 1); + + auto a = ublas::trans( aref, pi ); + + for(auto i = 0ul; i < a.size(); i++){ + BOOST_CHECK( a[i] == aref[i] ); + } + + + auto const pfac = fac(p); + auto i = 0u; + for(; i < pfac-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 ); + } + + for(auto j = 0ul; j < a.size(); j++){ + BOOST_CHECK( a[j] == aref[j] ); + } + }); + +} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_multi_index.cpp b/test/tensor/test_multi_index.cpp index d6448de22..59f82dc10 100644 --- a/test/tensor/test_multi_index.cpp +++ b/test/tensor/test_multi_index.cpp @@ -24,7 +24,7 @@ BOOST_AUTO_TEST_SUITE ( test_multi_index ) -using test_types = zip>::with_t; +using test_types = zip>::with_t; BOOST_AUTO_TEST_CASE ( test_index_classes ) @@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, using namespace boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = tensor; + using tensor_type = tensor,layout_type>; auto t = std::make_tuple ( index::_a, // 0 @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, ); { - auto a = tensor_type(shape{2,3}, value_type{2}); + auto a = tensor_type(dynamic_extents<>{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 ) ) ; @@ -110,7 +110,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, } { - auto a = tensor_type(shape{2,3}, value_type{2}); + auto a = tensor_type(dynamic_extents<>{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 ) ) ; @@ -120,7 +120,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, } { - auto a = tensor_type(shape{2,3}, value_type{2}); + auto a = tensor_type(dynamic_extents<>{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 ) ) ; @@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, } { - auto a = tensor_type(shape{2,3,4}, value_type{2}); + auto a = tensor_type(dynamic_extents<>{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 ) ) ; diff --git a/test/tensor/test_multiplication.cpp b/test/tensor/test_multiplication.cpp index 2f1570d15..b2249f136 100644 --- a/test/tensor/test_multiplication.cpp +++ b/test/tensor/test_multiplication.cpp @@ -1,12 +1,13 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -25,14 +26,14 @@ BOOST_AUTO_TEST_SUITE (test_tensor_contraction) -using test_types = zip>::with_t; +using test_types = zip>::with_t; //using test_types = zip::with_t; struct fixture { - using extents_type = boost::numeric::ublas::shape; + using extents_type = boost::numeric::ublas::dynamic_extents<>; fixture() : extents { extents_type{1,1}, // 1 @@ -57,9 +58,9 @@ 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; using vector_type = std::vector; - using extents_type = ublas::shape; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; using extents_type_base = typename extents_type::base_type; using size_type = typename extents_type_base::value_type; @@ -69,12 +70,12 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_mtv, value, test_types, fixture ) if(na.size() > 2) continue; - auto a = vector_type(na.product(), value_type{2}); + auto a = vector_type(product(na), 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 b = vector_type (product(nb), value_type{1} ); auto nc_base = extents_type_base(std::max(na.size()-1, size_type{2}), 1); @@ -84,7 +85,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_mtv, value, test_types, fixture ) auto nc = extents_type (nc_base); auto wc = strides_type (nc); - auto c = vector_type (nc.product(), value_type{0}); + auto c = vector_type (product(nc), value_type{0}); ublas::detail::recursive::mtv( size_type(m), @@ -94,7 +95,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_mtv, value, test_types, fixture ) for(auto i = 0u; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i] , value_type(na[m]) * a[i] ); + BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(na[m]) ) * a[i] ); } } @@ -106,9 +107,9 @@ 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; using vector_type = std::vector; - using extents_type = ublas::shape; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; // using extents_type_base = typename extents_type::base_type; @@ -117,16 +118,16 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_mtm, value, test_types, fixture ) if(na.size() != 2) continue; - auto a = vector_type (na.product(), value_type{2}); + auto a = vector_type (product(na), 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 b = vector_type (product(nb), value_type{1} ); auto nc = extents_type {na[0],nb[1]}; auto wc = strides_type (nc); -auto c = vector_type (nc.product()); +auto c = vector_type (product(nc)); ublas::detail::recursive::mtm( @@ -136,7 +137,7 @@ ublas::detail::recursive::mtm( for(auto i = 0u; i < c.size(); ++i) -BOOST_CHECK_EQUAL( c[i] , value_type(na[1]) * a[0] ); +BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(na[1]) ) * a[0] ); } @@ -148,16 +149,16 @@ 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; using vector_type = std::vector; - using extents_type = ublas::shape; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; 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 a = vector_type(product(na), 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} ); @@ -172,7 +173,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttv, value, test_types, fixture ) auto nc = extents_type (nc_base); auto wc = strides_type (nc); - auto c = vector_type (nc.product(), value_type{0}); + auto c = vector_type (product(nc), value_type{0}); ublas::ttv(size_type(m+1), na.size(), c.data(), nc.data(), wc.data(), @@ -193,25 +194,25 @@ 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; using vector_type = std::vector; - using extents_type = ublas::shape; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; using size_type = typename extents_type::value_type; for(auto const& na : extents) { - auto a = vector_type(na.product(), value_type{2}); + auto a = vector_type(product(na), 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 b = vector_type (product(nb), 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}); + auto c = vector_type (product(nc), value_type{0}); ublas::ttm(size_type(m+1), na.size(), c.data(), nc.data(), wc.data(), @@ -219,7 +220,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttm, value, test_types, fixture ) 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_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(na[m]) ) * a[i] ); } } @@ -232,9 +233,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt_permutation, value, test_type using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using strides_type = ublas::strides; using vector_type = std::vector; - using extents_type = ublas::shape; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; using size_type = typename strides_type::value_type; @@ -272,7 +273,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt_permutation, value, test_type for(auto const& na : extents) { auto wa = strides_type(na); - auto a = vector_type(na.product(), value_type{2}); + auto a = vector_type(product(na), value_type{2}); auto pa = na.size(); auto pia = std::vector(pa); std::iota( pia.begin(), pia.end(), 1 ); @@ -288,7 +289,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt_permutation, value, test_type auto nb = permute_extents( pib, na ); auto wb = strides_type(nb); - auto b = vector_type(nb.product(), value_type{3}); + auto b = vector_type(product(nb), value_type{3}); auto pb = nb.size(); // the number of contractions is changed. @@ -301,15 +302,15 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt_permutation, value, test_type auto nc_base = std::vector( pc , 1 ); - for(auto i = 0u; i < r; ++i) - nc_base[ i ] = na[ pia[i]-1 ]; + for(auto j = 0u; j < r; ++j) + nc_base[ j ] = na[ pia[j]-1 ]; - for(auto i = 0u; i < s; ++i) - nc_base[ r + i ] = nb[ pib_inv[i]-1 ]; + for(auto j = 0u; j < s; ++j) + nc_base[ r + j ] = nb[ pib_inv[j]-1 ]; auto nc = extents_type ( nc_base ); auto wc = strides_type ( nc ); - auto c = vector_type ( nc.product(), value_type(0) ); + auto c = vector_type ( product(nc), value_type(0) ); ublas::ttt(pa,pb,q, pia.data(), pib_inv.data(), @@ -319,11 +320,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt_permutation, value, test_type auto acc = value_type(1); - for(auto i = r; i < pa; ++i) - acc *= value_type(na[pia[i]-1]); + for(auto j = r; j < pa; ++j) + acc *= value_type( static_cast< inner_type_t >(na[pia[j]-1]) ); - for(auto i = 0ul; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); + for(auto j = 0ul; j < c.size(); ++j) + BOOST_CHECK_EQUAL( c[j] , acc * a[0] * b[0] ); } @@ -340,9 +341,9 @@ 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; using vector_type = std::vector; - using extents_type = ublas::shape; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; using size_type = typename strides_type::value_type; // left-hand and right-hand side have the @@ -355,12 +356,12 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt, value, test_types, fixture ) for(auto const& na : extents) { auto wa = strides_type(na); - auto a = vector_type(na.product(), value_type{2}); + auto a = vector_type(product(na), 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 b = vector_type(product(nb), value_type{3}); auto pb = nb.size(); // std::cout << "na = "; @@ -390,7 +391,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt, value, test_types, fixture ) auto nc = extents_type ( nc_base ); auto wc = strides_type ( nc ); - auto c = vector_type ( nc.product(), value_type{0} ); + auto c = vector_type ( product(nc), value_type{0} ); // std::cout << "nc = "; // std::copy(nc.begin(), nc.end(), std::ostream_iterator(std::cout, " ")); @@ -404,7 +405,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt, value, test_types, fixture ) auto acc = value_type(1); for(auto i = r; i < pa; ++i) - acc *= value_type(na[i]); + acc *= value_type( static_cast< inner_type_t >(na[i]) ); for(auto i = 0u; i < c.size(); ++i) BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); @@ -423,14 +424,14 @@ 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; + using strides_type = ublas::strides_t,layout_type>; using vector_type = std::vector; for(auto const& n : extents) { - auto a = vector_type(n.product(), value_type{2}); - auto b = vector_type(n.product(), value_type{3}); + auto a = vector_type(product(n), value_type{2}); + auto b = vector_type(product(n), 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)); @@ -449,22 +450,22 @@ 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; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; using vector_type = std::vector; for(auto const& na : extents) { - auto a = vector_type(na.product(), value_type{2}); + auto a = vector_type(product(na), value_type{2}); auto wa = strides_type(na); for(auto const& nb : extents) { - auto b = vector_type(nb.product(), value_type{3}); + auto b = vector_type(product(nb), value_type{3}); auto wb = strides_type(nb); - auto c = vector_type(nb.product()*na.product()); + auto c = vector_type(product(nb)*product(na)); auto nc = typename extents_type::base_type(na.size()+nb.size()); for(auto i = 0u; i < na.size(); ++i) diff --git a/test/tensor/test_operators_arithmetic.cpp b/test/tensor/test_operators_arithmetic.cpp index 8bab76192..797920469 100644 --- a/test/tensor/test_operators_arithmetic.cpp +++ b/test/tensor/test_operators_arithmetic.cpp @@ -17,10 +17,11 @@ #include #include "utility.hpp" +BOOST_AUTO_TEST_SUITE(test_tensor_arithmetic_operations, * boost::unit_test::depends_on("test_tensor")) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; -using test_types = zip::with_t; +using test_types = zip::with_t; struct fixture { @@ -42,7 +43,6 @@ struct fixture std::vector extents; }; -BOOST_AUTO_TEST_SUITE(test_tensor_arithmetic_operations, * boost::unit_test::depends_on("test_tensor")) @@ -51,7 +51,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, valu using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; auto check = [](auto const& e) @@ -120,7 +120,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; auto check = [](auto const& e) @@ -183,7 +183,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_assign_arithmetic_operations, valu using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; auto check = [](auto const& e) diff --git a/test/tensor/test_operators_comparison.cpp b/test/tensor/test_operators_comparison.cpp index f076e9c1e..337a20078 100644 --- a/test/tensor/test_operators_comparison.cpp +++ b/test/tensor/test_operators_comparison.cpp @@ -19,9 +19,11 @@ #include "utility.hpp" +BOOST_AUTO_TEST_SUITE(test_tensor_comparison, * boost::unit_test::depends_on("test_tensor")) + using double_extended = boost::multiprecision::cpp_bin_float_double_extended; -using test_types = zip::with_t; +using test_types = zip::with_t; struct fixture { using extents_type = boost::numeric::ublas::basic_extents; @@ -42,15 +44,13 @@ struct fixture { std::vector 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; + using tensor_type = ublas::tensor,layout_type>; auto check = [](auto const& e) @@ -107,7 +107,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; auto check = [](auto const& e) @@ -178,7 +178,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_scalar, value, te using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; auto check = [](auto const& e) diff --git a/test/tensor/test_static_expression_evaluation.cpp b/test/tensor/test_static_expression_evaluation.cpp new file mode 100644 index 000000000..98e652265 --- /dev/null +++ b/test/tensor/test_static_expression_evaluation.cpp @@ -0,0 +1,220 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + + +#include +#include +#include +#include "utility.hpp" +#include + +#include + +BOOST_AUTO_TEST_SUITE(test_static_tensor_expression) + +using test_types = zip>::with_t; + + +struct fixture +{ + template + using extents_type = boost::numeric::ublas::static_extents; + + fixture() {} + + std::tuple< + extents_type<1,1>, // 1 + extents_type<2,3>, // 2 + extents_type<4,1,3>, // 3 + extents_type<4,2,3>, // 4 + extents_type<4,2,3,5> // 5 + > extents; +}; + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; + + for_each_tuple(extents, [&](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); + + }); + + for_each_tuple(extents, [&](auto const& I, auto& e1){ + + if ( I >= std::tuple_size_v - 1){ + return; + } + + using extents_type1 = std::decay_t; + using tensor_type1 = ublas::tensor; + + for_each_tuple(extents, [&](auto const& J, auto& e2){ + if( J != I + 1 ){ + return; + } + + using extents_type2 = std::decay_t; + using tensor_type2 = ublas::tensor; + + auto v = value_type{}; + + tensor_type1 t1(e1); + for(auto& tt: t1){ tt = v; v+=value_type{1}; } + + tensor_type2 t2(e2); + 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( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 ) ); + + }); + }); +} + + + + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; + + for_each_tuple(extents, [&](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); + + }); + + + for_each_tuple(extents, [&](auto const& I, auto& e1){ + + if ( I >= std::tuple_size_v - 1){ + return; + } + + using extents_type1 = std::decay_t; + using tensor_type1 = ublas::tensor; + + for_each_tuple(extents, [&](auto const& J, auto& e2){ + if( J != I + 1 ){ + return; + } + + using extents_type2 = std::decay_t; + using tensor_type2 = ublas::tensor; + + auto v = value_type{}; + + tensor_type1 t1(e1); + for(auto& tt: t1){ tt = v; v+=value_type{1}; } + + tensor_type2 t2(e2); + 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( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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) ) ); + + }); + }); + +} + +BOOST_AUTO_TEST_SUITE_END(); \ No newline at end of file diff --git a/test/tensor/test_static_extents.cpp b/test/tensor/test_static_extents.cpp new file mode 100644 index 000000000..4d9d2a1e1 --- /dev/null +++ b/test/tensor/test_static_extents.cpp @@ -0,0 +1,519 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#include +#include +#include +#include +#include "utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_static_extents) + +template +using extents = boost::numeric::ublas::basic_static_extents; + +BOOST_AUTO_TEST_CASE(test_static_extents_ctor) { + using namespace boost::numeric; + + auto e0 = extents<>{}; + BOOST_CHECK(e0.empty()); + BOOST_CHECK_EQUAL(e0.size(), 0); + + auto e1 = extents<1, 2>{}; + BOOST_CHECK(!e1.empty()); + BOOST_CHECK_EQUAL(e1.size(), 2); + + auto e2 = extents<2, 3>{}; + BOOST_CHECK(!e2.empty()); + BOOST_CHECK_EQUAL(e2.size(), 2); + + auto e3 = extents<4, 2, 3>{}; // 7 + BOOST_CHECK(!e3.empty()); + BOOST_CHECK_EQUAL(e3.size(), 3); +} + +struct fixture { + fixture() = default; + extents<> e0{}; // 0 + extents<1, 2, 3, 4> e1{}; // 1 + extents<1, 2, 3> e2{}; // 2 + extents<4, 2, 3> e3{}; // 3 + extents<4, 2, 1, 3> e4{}; // 4 + extents<1, 4, 2, 1, 3, 1> e5{}; // 5 + + std::tuple< + extents<> + > rank_0_extents; + + std::tuple< + extents<1>, + extents<2> + > rank_1_extents; + + std::tuple< + extents<1,1>, + extents<2,2> + > rank_2_extents; + + std::tuple< + extents<1>, + extents<1,1>, + extents<1,1,1>, + extents<1,1,1,1> + > scalars; + + std::tuple< + extents<1,2>, + extents<1,3,1>, + extents<1,4,1,1>, + extents<5,1,1,1,1>, + extents<6,1,1,1,1,1> + > vectors; + + std::tuple< + extents<2,3>, + extents<3,2,1>, + extents<4,4,1,1>, + extents<6,6,1,1,1,1> + > matrices; + + std::tuple< + extents<3,3,3>, + extents<4,4,4,1>, + extents<5,5,5,1,1>, + extents<6,6,6,1,1,1>, + extents<6,6,1,1,1,6> + > tensors; +}; + +BOOST_FIXTURE_TEST_CASE(test_static_extents_product, fixture, + *boost::unit_test::label("static_extents") * + boost::unit_test::label("product")) { + + using namespace boost::numeric::ublas; + + auto p0 = product( e0); // {} + auto p1 = product( e1); // {1,2,3,4} + auto p2 = product( e2); // {1,2,3} + auto p3 = product( e3); // {4,2,3} + auto p4 = product( e4); // {4,2,1,3} + auto p5 = product( e5); // {1,4,2,1,3,1} + + auto sp0 = static_product_v< std::decay_t >; // {} + auto sp1 = static_product_v< std::decay_t >; // {1,2,3,4} + auto sp2 = static_product_v< std::decay_t >; // {1,2,3} + auto sp3 = static_product_v< std::decay_t >; // {4,2,3} + auto sp4 = static_product_v< std::decay_t >; // {4,2,1,3} + auto sp5 = static_product_v< std::decay_t >; // {1,4,2,1,3,1} + + BOOST_CHECK_EQUAL(p0, 0); + BOOST_CHECK_EQUAL(p1, 24); + BOOST_CHECK_EQUAL(p2, 6); + BOOST_CHECK_EQUAL(p3, 24); + BOOST_CHECK_EQUAL(p4, 24); + BOOST_CHECK_EQUAL(p5, 24); + + BOOST_CHECK_EQUAL(sp0, 0); + BOOST_CHECK_EQUAL(sp1, 24); + BOOST_CHECK_EQUAL(sp2, 6); + BOOST_CHECK_EQUAL(sp3, 24); + BOOST_CHECK_EQUAL(sp4, 24); + BOOST_CHECK_EQUAL(sp5, 24); +} + +BOOST_FIXTURE_TEST_CASE(test_static_extents_access, fixture, + *boost::unit_test::label("static_extents") * + boost::unit_test::label("access")) { + using namespace boost::numeric; + + BOOST_CHECK_EQUAL(e0.size(), 0); + BOOST_CHECK(e0.empty()); + + BOOST_REQUIRE_EQUAL(e1.size(), 4); + BOOST_REQUIRE_EQUAL(e2.size(), 3); + BOOST_REQUIRE_EQUAL(e3.size(), 3); + BOOST_REQUIRE_EQUAL(e4.size(), 4); + BOOST_REQUIRE_EQUAL(e5.size(), 6); + + BOOST_CHECK_EQUAL(e1[0], 1); + BOOST_CHECK_EQUAL(e1[1], 2); + BOOST_CHECK_EQUAL(e1[2], 3); + BOOST_CHECK_EQUAL(e1[3], 4); + + BOOST_CHECK_EQUAL(e2[0], 1); + BOOST_CHECK_EQUAL(e2[1], 2); + BOOST_CHECK_EQUAL(e2[2], 3); + + BOOST_CHECK_EQUAL(e3[0], 4); + BOOST_CHECK_EQUAL(e3[1], 2); + BOOST_CHECK_EQUAL(e3[2], 3); + + BOOST_CHECK_EQUAL(e4[0], 4); + BOOST_CHECK_EQUAL(e4[1], 2); + BOOST_CHECK_EQUAL(e4[2], 1); + BOOST_CHECK_EQUAL(e4[3], 3); + + BOOST_CHECK_EQUAL(e5[0], 1); + BOOST_CHECK_EQUAL(e5[1], 4); + BOOST_CHECK_EQUAL(e5[2], 2); + BOOST_CHECK_EQUAL(e5[3], 1); + BOOST_CHECK_EQUAL(e5[4], 3); + BOOST_CHECK_EQUAL(e5[5], 1); +} + +BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, + *boost::unit_test::label("static_extents") * + boost::unit_test::label("query")) { + + using namespace boost::numeric::ublas; + // e0 ==> {} + // e1 ==> {0,0,0,0} + // e2 ==> {1,2,3} + // e3 ==> {4,2,3} + // e4 ==> {4,2,1,3} + // e5 ==> {1,4,2,1,3,1} + + BOOST_CHECK( e0.empty( )); + BOOST_CHECK( !is_scalar( e0)); + BOOST_CHECK( !is_vector( e0)); + BOOST_CHECK( !is_matrix( e0)); + BOOST_CHECK( !is_tensor( e0)); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + + BOOST_CHECK( ! e1.empty( ) ); + BOOST_CHECK( !is_scalar( e1) ); + BOOST_CHECK( !is_vector( e1) ); + BOOST_CHECK( !is_matrix( e1) ); + BOOST_CHECK( is_tensor( e1) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + + BOOST_CHECK( ! e2.empty( ) ); + BOOST_CHECK( !is_scalar( e2) ); + BOOST_CHECK( !is_vector( e2) ); + BOOST_CHECK( !is_matrix( e2) ); + BOOST_CHECK( is_tensor( e2) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + + BOOST_CHECK( ! e3.empty( ) ); + BOOST_CHECK( !is_scalar( e3) ); + BOOST_CHECK( !is_vector( e3) ); + BOOST_CHECK( !is_matrix( e3) ); + BOOST_CHECK( is_tensor( e3) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + + BOOST_CHECK( ! e4.empty( ) ); + BOOST_CHECK( !is_scalar( e4) ); + BOOST_CHECK( !is_vector( e4) ); + BOOST_CHECK( !is_matrix( e4) ); + BOOST_CHECK( is_tensor( e4) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + + BOOST_CHECK( ! e5.empty( ) ); + BOOST_CHECK( !is_scalar( e5) ); + BOOST_CHECK( !is_vector( e5) ); + BOOST_CHECK( !is_matrix( e5) ); + BOOST_CHECK( is_tensor( e5) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + + boost::numeric::ublas::basic_static_extents e14; + BOOST_CHECK( ! e14.empty( ) ); + BOOST_CHECK( ! is_scalar(e14) ); + BOOST_CHECK( is_vector(e14) ); + BOOST_CHECK( ! is_matrix(e14) ); + BOOST_CHECK( ! is_tensor(e14) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + + + for_each_tuple(rank_0_extents,[](auto const&, auto& e){ + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + }); + + + for_each_tuple(rank_1_extents,[](auto const& I, auto const& e){ + if( I == 0 ){ + BOOST_CHECK( is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); + BOOST_CHECK( static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + }else{ + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + } + }); + + for_each_tuple(rank_2_extents,[](auto const& I, auto const& e){ + if( I == 0 ){ + BOOST_CHECK( is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); + BOOST_CHECK( static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + }else{ + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + } + }); + + for_each_tuple(scalars,[](auto const&, auto& e){ + BOOST_CHECK( is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); + BOOST_CHECK( static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + }); + + for_each_tuple(vectors,[](auto const&, auto& e){ + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + }); + + for_each_tuple(matrices,[](auto const&, auto& e){ + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + + }); + + for_each_tuple(tensors,[](auto const&, auto& e){ + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( is_tensor(e) ); + BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); + BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); + BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + }); + +} + +BOOST_FIXTURE_TEST_CASE(test_static_extents_to_functions, fixture, *boost::unit_test::label("static_extents") *boost::unit_test::label("to_functions")) +{ + + for_each_tuple(scalars,[](auto const&, auto& e){ + if (e.size() > 1){ + auto d = e.to_dynamic_extents(); + BOOST_CHECK(d == e); + } + }); + + for_each_tuple(vectors,[](auto const&, auto& e){ + auto d = e.to_dynamic_extents(); + BOOST_CHECK(d == e); + }); + + + for_each_tuple(matrices,[](auto const&, auto& e){ + auto d = e.to_dynamic_extents(); + BOOST_CHECK(d == e); + }); + + for_each_tuple(tensors,[](auto const&, auto& e){ + auto d = e.to_dynamic_extents(); + BOOST_CHECK(d == e); + }); + +} + +BOOST_FIXTURE_TEST_CASE(test_static_extents_valid, fixture, *boost::unit_test::label("static_extents") *boost::unit_test::label("valid")) +{ + using namespace boost::numeric::ublas; + for_each_tuple(rank_0_extents,[](auto const&, auto& e){ + BOOST_CHECK(!valid(e)); + BOOST_CHECK(!static_traits::is_valid_v< std::decay_t >); + }); + + for_each_tuple(rank_1_extents,[](auto const& I, auto const& e){ + if( I== 0 ){ + BOOST_CHECK(valid(e)); + BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + }else{ + BOOST_CHECK(!valid(e)); + BOOST_CHECK(!static_traits::is_valid_v< std::decay_t >); + } + }); + + for_each_tuple(rank_2_extents,[](auto const&, auto& e){ + BOOST_CHECK(valid(e)); + BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + }); + + for_each_tuple(scalars,[](auto const&, auto& e){ + BOOST_CHECK(valid(e)); + BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + }); + + for_each_tuple(vectors,[](auto const&, auto& e){ + BOOST_CHECK(valid(e)); + BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + }); + + for_each_tuple(matrices,[](auto const&, auto& e){ + BOOST_CHECK(valid(e)); + BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + }); + + for_each_tuple(tensors,[](auto const&, auto& e){ + BOOST_CHECK(valid(e)); + BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + }); +} + +BOOST_FIXTURE_TEST_CASE(test_static_extents_comparsion_operator, fixture, *boost::unit_test::label("static_extents") *boost::unit_test::label("comparsion_operator")) +{ + + auto const compare_extents = [](auto const& e1, auto const& e2){ + if(e1.size() != e2.size()) return false; + for(auto i = 0ul ; i < e1.size(); i++){ + if(e1[i] != e2[i]){ + return false; + } + } + return true; + }; + + for_each_tuple(rank_0_extents,[&](auto const&, auto const& e1){ + for_each_tuple(rank_1_extents,[&](auto const&, auto const& e2){ + BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); + }); + }); + + for_each_tuple(rank_1_extents,[&](auto const&, auto const& e1){ + for_each_tuple(rank_1_extents,[&](auto const&, auto const& e2){ + BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); + }); + }); + + for_each_tuple(rank_1_extents,[&](auto const&, auto const& e1){ + for_each_tuple(rank_2_extents,[&](auto const&, auto const& e2){ + BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); + }); + }); + + for_each_tuple(scalars,[&](auto const&, auto const& e1){ + for_each_tuple(scalars,[&](auto const&, auto const& e2){ + BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); + }); + }); + + for_each_tuple(scalars,[&](auto const&, auto const& e1){ + for_each_tuple(vectors,[&](auto const&, auto const& e2){ + BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); + }); + }); + + for_each_tuple(scalars,[&](auto const&, auto const& e1){ + for_each_tuple(matrices,[&](auto const&, auto const& e2){ + BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); + }); + }); + + for_each_tuple(scalars,[&](auto const&, auto const& e1){ + for_each_tuple(tensors,[&](auto const&, auto const& e2){ + BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); + }); + }); + +} + +BOOST_FIXTURE_TEST_CASE(test_static_extents_squeeze, fixture, *boost::unit_test::label("static_extents") *boost::unit_test::label("squeeze")) +{ + using extents_type = boost::numeric::ublas::basic_extents; + + auto e_sq2 = squeeze(e2 ) ;//==> {2,3} + auto e_sq3 = squeeze(e3 ) ;//==> {4,2,3} + auto e_sq4 = squeeze(e4 ) ;//==> {4,2,3} + auto e_sq5 = squeeze(e5 ) ;//==> {4,2,3} + + BOOST_CHECK( (e_sq2 == extents_type{2,3}) ); + BOOST_CHECK( (e_sq3 == extents_type{4,2,3}) ); + + BOOST_CHECK( (e_sq4 == extents_type{4,2,3}) ); + BOOST_CHECK( (e_sq5 == extents_type{4,2,3}) ); + +} + +BOOST_AUTO_TEST_CASE(test_static_extents_exception) +{ + using namespace boost::numeric::ublas; + + basic_static_extents e1; + for(auto i = e1.size(); i < 3; i++){ + BOOST_REQUIRE_THROW( (void)e1.at(i),std::out_of_range ); + } + + BOOST_REQUIRE_THROW((void)e1.at(std::numeric_limits::max()),std::out_of_range); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_operators_arithmetic.cpp b/test/tensor/test_static_operators_arithmetic.cpp new file mode 100644 index 000000000..6646a6aff --- /dev/null +++ b/test/tensor/test_static_operators_arithmetic.cpp @@ -0,0 +1,242 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + + +#include + +#include +#include +#include "utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_static_tensor_arithmetic_operations) + +using double_extended = boost::multiprecision::cpp_bin_float_double_extended; + +using test_types = zip::with_t; + +struct fixture +{ + template + using extents_type = boost::numeric::ublas::static_extents; + + fixture() {} + + std::tuple< + extents_type<1,1>, // 1 + extents_type<2,3>, // 2 + extents_type<4,1,3>, // 3 + extents_type<4,2,3>, // 4 + extents_type<4,2,3,5> // 5 + > extents; + +}; + + +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; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + 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_each_tuple(extents,check); +} + + + +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; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + 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_each_tuple(extents,check); +} + + + + + +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; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + 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_each_tuple(extents,check); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_operators_comparison.cpp b/test/tensor/test_static_operators_comparison.cpp new file mode 100644 index 000000000..e64ce1e25 --- /dev/null +++ b/test/tensor/test_static_operators_comparison.cpp @@ -0,0 +1,201 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + + +#include +#include +#include +#include +#include +#include "utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_static_tensor_comparison) + +using double_extended = boost::multiprecision::cpp_bin_float_double_extended; + +using test_types = zip::with_t; + +struct fixture { + template + using extents_type = boost::numeric::ublas::static_extents; + + fixture() {} + + std::tuple< + extents_type<1,1>, // 1 + extents_type<2,3>, // 2 + extents_type<4,1,3>, // 3 + extents_type<4,2,3>, // 4 + extents_type<4,2,3,5> // 5 + > extents; +}; + + +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; + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + 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_each_tuple(extents,check); + +} + + +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; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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_each_tuple(extents,check); + +} + + + +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; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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_each_tuple(extents,check); + +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_strides.cpp b/test/tensor/test_static_strides.cpp new file mode 100644 index 000000000..946dd60c9 --- /dev/null +++ b/test/tensor/test_static_strides.cpp @@ -0,0 +1,155 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#include +#include +#include + +BOOST_AUTO_TEST_SUITE(test_static_strides) + +using test_types = std::tuple; + +template +using extents_type = boost::numeric::ublas::basic_static_extents; +template +using strides_type = boost::numeric::ublas::strides_t; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_static_strides_ctor, value, test_types) { + using namespace boost::numeric; + + strides_type, ublas::first_order> s1{}; + BOOST_CHECK_EQUAL(s1.empty(), false); + BOOST_CHECK_EQUAL(s1.size(), 2); + + strides_type, ublas::first_order> s2{}; + BOOST_CHECK_EQUAL(s2.empty(), false); + BOOST_CHECK_EQUAL(s2.size(), 2); + + strides_type, ublas::first_order> s3{}; + BOOST_CHECK_EQUAL(s3.empty(), false); + BOOST_CHECK_EQUAL(s3.size(), 2); + + strides_type, ublas::first_order> s4{}; + BOOST_CHECK_EQUAL(s4.empty(), false); + BOOST_CHECK_EQUAL(s4.size(), 2); + + strides_type, ublas::first_order> s5{}; + BOOST_CHECK_EQUAL(s5.empty(), false); + BOOST_CHECK_EQUAL(s5.size(), 3); + + strides_type, ublas::first_order> s6{}; + BOOST_CHECK_EQUAL(s6.empty(), false); + BOOST_CHECK_EQUAL(s6.size(), 3); + + strides_type, ublas::first_order> s7{}; + BOOST_CHECK_EQUAL(s7.empty(), false); + BOOST_CHECK_EQUAL(s7.size(), 3); +} + +BOOST_AUTO_TEST_CASE(test_static_strides_ctor_access_first_order) { + using namespace boost::numeric; + + strides_type, ublas::first_order> s1{}; + BOOST_REQUIRE_EQUAL(s1.size(), 2); + BOOST_CHECK_EQUAL(s1[0], 1); + BOOST_CHECK_EQUAL(s1[1], 1); + + strides_type, ublas::first_order> s2{}; + BOOST_REQUIRE_EQUAL(s2.size(), 2); + BOOST_CHECK_EQUAL(s2[0], 1); + BOOST_CHECK_EQUAL(s2[1], 1); + + strides_type, ublas::first_order> s3{}; + BOOST_REQUIRE_EQUAL(s3.size(), 2); + BOOST_CHECK_EQUAL(s3[0], 1); + BOOST_CHECK_EQUAL(s3[1], 1); + + strides_type, ublas::first_order> s4{}; + BOOST_REQUIRE_EQUAL(s4.size(), 2); + BOOST_CHECK_EQUAL(s4[0], 1); + BOOST_CHECK_EQUAL(s4[1], 2); + + strides_type, ublas::first_order> s5{}; + 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, ublas::first_order> s6{}; + 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, ublas::first_order> s7{}; + 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, ublas::first_order> s8{}; + 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_static_strides_ctor_access_last_order) { + using namespace boost::numeric; + + strides_type, ublas::last_order> s1{}; + BOOST_REQUIRE_EQUAL(s1.size(), 2); + BOOST_CHECK_EQUAL(s1[0], 1); + BOOST_CHECK_EQUAL(s1[1], 1); + + strides_type, ublas::last_order> s2{}; + BOOST_REQUIRE_EQUAL(s2.size(), 2); + BOOST_CHECK_EQUAL(s2[0], 1); + BOOST_CHECK_EQUAL(s2[1], 1); + + strides_type, ublas::last_order> s3{}; + BOOST_REQUIRE_EQUAL(s3.size(), 2); + BOOST_CHECK_EQUAL(s3[0], 1); + BOOST_CHECK_EQUAL(s3[1], 1); + + strides_type, ublas::last_order> s4{}; + BOOST_REQUIRE_EQUAL(s4.size(), 2); + BOOST_CHECK_EQUAL(s4[0], 3); + BOOST_CHECK_EQUAL(s4[1], 1); + + strides_type, ublas::last_order> s5{}; + 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, ublas::last_order> s6{}; + 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, ublas::last_order> s7{}; + 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, ublas::last_order> s8{}; + BOOST_REQUIRE_EQUAL(s8.size(), 3); + BOOST_CHECK_EQUAL(s8[0], 6); + BOOST_CHECK_EQUAL(s8[1], 3); + BOOST_CHECK_EQUAL(s8[2], 1); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_tensor.cpp b/test/tensor/test_static_tensor.cpp new file mode 100644 index 000000000..8a93508a5 --- /dev/null +++ b/test/tensor/test_static_tensor.cpp @@ -0,0 +1,407 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + + +#include +#include + +#ifndef BOOST_TEST_DYN_LINK +#define BOOST_TEST_DYN_LINK +#endif + +#define BOOST_TEST_MODULE TestStaticTensor + +#include +#include "utility.hpp" + +BOOST_AUTO_TEST_SUITE ( test_static_tensor ) + +using test_types = zip>::with_t; + + +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; + + auto a1 = ublas::tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a1.size() , 0ul ); + BOOST_CHECK( a1.empty() ); + + auto a2 = ublas::tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + + auto a3 = ublas::tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + + auto a4 = ublas::tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + + auto a5 = ublas::tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a5.size() , 2 ); + BOOST_CHECK( !a5.empty() ); + + auto a6 = ublas::tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); + BOOST_CHECK( !a6.empty() ); + + auto a7 = ublas::tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); + BOOST_CHECK( !a7.empty() ); + +} + + +struct fixture +{ + template + using extents_type = boost::numeric::ublas::static_extents; + + fixture() {} + + std::tuple< + extents_type<1,1>, // 1 + extents_type<2,3>, // 2 + extents_type<4,1,3>, // 3 + extents_type<4,2,3>, // 4 + extents_type<4,2,3,5> // 5 + > 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; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + auto t = ublas::tensor{e}; + + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + if(e.empty()) { + BOOST_CHECK ( t.empty() ); + } + else{ + BOOST_CHECK ( !t.empty() ); + } + }); + +} + + +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; + + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + auto r = ublas::tensor{e,0}; + + 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() ); + } + else{ + BOOST_CHECK ( !t.empty() ); + } + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_TEST( t[i] == r[i]); + + }); +} + + +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 other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; + + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + auto r = tensor_type{e,0}; + ublas::tensor 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_TEST( 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; + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + auto r = tensor_type{e}; + auto t = std::move(r); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + + if(e.empty()) { + BOOST_CHECK ( t.empty() ); + } + else{ + BOOST_CHECK ( !t.empty() ); + } + + }; + + for_each_tuple(extents,check); +} + + +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; + + std::random_device device{}; + std::minstd_rand0 generator(device()); + + using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; + auto distribution = distribution_type(1,6); + + for_each_tuple(extents, [&](auto const&, auto const& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + auto r = value_type( static_cast< inner_type_t >(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; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + using array_type = typename tensor_type::array_type; + + auto a = array_type(); + 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; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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; + + auto check1 = [](const auto& 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 auto& t) + { + std::array k; + auto r = std::is_same::value ? 1 : 0; + auto q = std::is_same::value ? 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 auto& t) + { + std::array k; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 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 auto& t) + { + std::array k; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 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&, auto const& e) { + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + 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 constexpr ( extents_type::_size == 1) check1(t); + else if constexpr ( extents_type::_size == 2) check2(t); + else if constexpr ( extents_type::_size == 3) check3(t); + else if constexpr ( extents_type::_size == 4) check4(t); + + }; + + for_each_tuple(extents,check); +} + +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; + + for_each_tuple(extents,[](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::tensor; + + 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_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, 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, layout_type>; + + std::vector vec(30); + BOOST_CHECK_THROW(tensor_type({5,5},vec), std::runtime_error); + + auto t = tensor_type{{5,5}}; + auto i = ublas::index::index_type<4>{}; + BOOST_CHECK_THROW(t.operator()(i,i,i), std::runtime_error); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_tensor_matrix_vector.cpp b/test/tensor/test_static_tensor_matrix_vector.cpp new file mode 100644 index 000000000..dc15e1695 --- /dev/null +++ b/test/tensor/test_static_tensor_matrix_vector.cpp @@ -0,0 +1,460 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#include +#include +#include +#include +#include + +#include "utility.hpp" + + + +BOOST_AUTO_TEST_SUITE ( test_static_tensor_matrix_interoperability ) ; + +using test_types = zip::with_t; + + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + ublas::tensor,layout_type> a2 = matrix_type(1,1); + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + + ublas::tensor,layout_type> a3 = matrix_type(2,1); + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + + ublas::tensor,layout_type> a4 = matrix_type(1,2); + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + + ublas::tensor,layout_type> a5 = matrix_type(2,3); + BOOST_CHECK_EQUAL( a5.size() , 6 ); + BOOST_CHECK( !a5.empty() ); +} + + +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,layout_type>; + using vector_type = typename tensor_type::vector_type; + + ublas::tensor,layout_type> a2 = vector_type(1); + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + + ublas::tensor,layout_type> a3 = vector_type(2); + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + + ublas::tensor,layout_type> a4 = vector_type(2); + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + + ublas::tensor,layout_type> a5 = vector_type(3); + BOOST_CHECK_EQUAL( a5.size() , 3 ); + BOOST_CHECK( !a5.empty() ); +} + + +struct fixture +{ + template + using extents_type = boost::numeric::ublas::static_extents; + + fixture() {} + + std::tuple< + extents_type<1,1>, // 0 + extents_type<2,3>, // 1 + extents_type<9,7>, // 2 + extents_type<15,17> // 3 + > 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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size()==2); + etensor_type t = matrix_type{e[0],e[1]}; + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + }; + + for_each_tuple(extents,check); +} + + +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,layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + if constexpr( extents_type::at(1) == 1 ){ + assert(e.size()==2); + if(e.empty()) + return; + + etensor_type t = vector_type(product(e)); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + } + + }; + + for_each_tuple(extents,check); +} + + + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + 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_each_tuple(extents,check); +} + + +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,layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + + if constexpr( extents_type::at(1) == 1 ){ + auto t = etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_CHECK_EQUAL( t[i], r(i) ); + } + } + }; + + for_each_tuple(extents,check); +} + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + 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_each_tuple(extents,check); +} + + + + +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,layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + if constexpr( extents_type::at(1) == 1 ){ + auto t = etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_CHECK_EQUAL( t[i], q(i) ); + } + } + }; + + for_each_tuple(extents,check); +} + + + + + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + auto t = etensor_type{}; + auto r = matrix_type(e[0],e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r + 3*r; + etensor_type s = r + 3*r; + etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + 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() , product(e) ); + BOOST_CHECK_EQUAL ( s.rank() , e.size() ); + BOOST_CHECK ( !s.empty() ); + + 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() , product(e) ); + BOOST_CHECK_EQUAL ( q.rank() , e.size() ); + BOOST_CHECK ( !q.empty() ); + + + 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_each_tuple(extents,check); +} + + + + + + +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,layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::tensor; + + assert(e.size() == 2); + if constexpr( extents_type::at(1) == 1 ){ + auto t = etensor_type{}; + auto r = vector_type(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r + 3*r; + etensor_type s = r + 3*r; + etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + 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() , product(e) ); + BOOST_CHECK_EQUAL ( s.rank() , e.size() ); + BOOST_CHECK ( !s.empty() ); + + 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() , product(e) ); + BOOST_CHECK_EQUAL ( q.rank() , e.size() ); + BOOST_CHECK ( !q.empty() ); + + + + 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_each_tuple(extents,check); +} + + + +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,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + + if(product(e) <= 2) + return; + + assert(e.size() == 2); + auto Q = ublas::tensor,layout_type>{} ; + 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); + + decltype(Q) 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() ); + + 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_each_tuple(extents,check); +} + + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/test/tensor/test_strides.cpp b/test/tensor/test_strides.cpp index 3a29e660a..0623125f7 100644 --- a/test/tensor/test_strides.cpp +++ b/test/tensor/test_strides.cpp @@ -1,17 +1,17 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // - #include #include #include @@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_strides_ctor, value, test_types) using namespace boost::numeric; using extents_type = ublas::basic_extents; - using strides_type = ublas::strides; + using strides_type = ublas::strides_t; strides_type s0{}; BOOST_CHECK ( s0.empty()); @@ -62,6 +62,43 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_strides_ctor, value, test_types) BOOST_CHECK_EQUAL ( s7.size(), 3); } +BOOST_AUTO_TEST_CASE_TEMPLATE( test_static_rank_strides_ctor, value, test_types) +{ + namespace ub = boost::numeric::ublas; + + ub::basic_fixed_rank_strides s0{ub::dynamic_extents<0>{}}; + BOOST_CHECK ( s0.empty()); + BOOST_CHECK_EQUAL ( s0.size(), 0); + + ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; + BOOST_CHECK (!s1.empty()); + BOOST_CHECK_EQUAL ( s1.size(), 2); + + ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; + BOOST_CHECK (!s2.empty()); + BOOST_CHECK_EQUAL ( s2.size(), 2); + + ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; + BOOST_CHECK (!s3.empty()); + BOOST_CHECK_EQUAL ( s3.size(), 2); + + ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; + BOOST_CHECK (!s4.empty()); + BOOST_CHECK_EQUAL ( s4.size(), 2); + + ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{2,3,1}}; + BOOST_CHECK (!s5.empty()); + BOOST_CHECK_EQUAL ( s5.size(), 3); + + ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{1,2,3}}; + BOOST_CHECK (!s6.empty()); + BOOST_CHECK_EQUAL ( s6.size(), 3); + + ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{4,2,3}}; + BOOST_CHECK (!s7.empty()); + BOOST_CHECK_EQUAL ( s7.size(), 3); +} + BOOST_AUTO_TEST_CASE( test_strides_ctor_access_first_order) @@ -69,7 +106,7 @@ BOOST_AUTO_TEST_CASE( test_strides_ctor_access_first_order) using namespace boost::numeric; using extents_type = ublas::basic_extents; - using strides_type = ublas::strides; + using strides_type = ublas::strides_t; strides_type s1{extents_type{1,1}}; BOOST_REQUIRE_EQUAL( s1.size(),2); @@ -116,12 +153,61 @@ BOOST_AUTO_TEST_CASE( test_strides_ctor_access_first_order) BOOST_CHECK_EQUAL ( s8[2], 8); } +BOOST_AUTO_TEST_CASE( test_static_rank_strides_ctor_access_first_order) +{ + namespace ub = boost::numeric::ublas; + + ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; + BOOST_REQUIRE_EQUAL( s1.size(),2); + BOOST_CHECK_EQUAL ( s1[0], 1); + BOOST_CHECK_EQUAL ( s1[1], 1); + + ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; + BOOST_REQUIRE_EQUAL ( s2.size(),2); + BOOST_CHECK_EQUAL ( s2[0], 1); + BOOST_CHECK_EQUAL ( s2[1], 1); + + ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; + BOOST_REQUIRE_EQUAL ( s3.size(),2); + BOOST_CHECK_EQUAL ( s3[0], 1); + BOOST_CHECK_EQUAL ( s3[1], 1); + + ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; + BOOST_REQUIRE_EQUAL ( s4.size(),2); + BOOST_CHECK_EQUAL ( s4[0], 1); + BOOST_CHECK_EQUAL ( s4[1], 2); + + ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s8{ub::dynamic_extents<3>{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; - using strides_type = ublas::strides; + using strides_type = ublas::strides_t; strides_type s1{extents_type{1,1}}; BOOST_REQUIRE_EQUAL( s1.size(),2); @@ -168,5 +254,53 @@ BOOST_AUTO_TEST_CASE( test_strides_ctor_access_last_order) BOOST_CHECK_EQUAL ( s8[2], 1); } +BOOST_AUTO_TEST_CASE( test_static_rank_strides_ctor_access_last_order) +{ + namespace ub = boost::numeric::ublas; + + ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; + BOOST_REQUIRE_EQUAL( s1.size(),2); + BOOST_CHECK_EQUAL ( s1[0], 1); + BOOST_CHECK_EQUAL ( s1[1], 1); + + ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; + BOOST_REQUIRE_EQUAL ( s2.size(),2); + BOOST_CHECK_EQUAL ( s2[0], 1); + BOOST_CHECK_EQUAL ( s2[1], 1); + + ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; + BOOST_REQUIRE_EQUAL ( s3.size(),2); + BOOST_CHECK_EQUAL ( s3[0], 1); + BOOST_CHECK_EQUAL ( s3[1], 1); + + ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; + BOOST_REQUIRE_EQUAL ( s4.size(),2); + BOOST_CHECK_EQUAL ( s4[0], 3); + BOOST_CHECK_EQUAL ( s4[1], 1); + + ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s8{ub::dynamic_extents<3>{4,2,3}}; + BOOST_REQUIRE_EQUAL ( s8.size(),3); + BOOST_CHECK_EQUAL ( s8[0], 6); + BOOST_CHECK_EQUAL ( s8[1], 3); + BOOST_CHECK_EQUAL ( s8[2], 1); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_tensor.cpp b/test/tensor/test_tensor.cpp index 400e86245..0c7bd4cb9 100644 --- a/test/tensor/test_tensor.cpp +++ b/test/tensor/test_tensor.cpp @@ -1,12 +1,13 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -14,16 +15,20 @@ #include #include -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE TestTensor +#ifndef BOOST_TEST_DYN_LINK +#define BOOST_TEST_DYN_LINK +#endif + +#define BOOST_TEST_MODULE TestDynamicTensor + #include #include "utility.hpp" -//BOOST_AUTO_TEST_SUITE ( test_tensor, * boost::unit_test::depends_on("test_extents") ) ; +// BOOST_AUTO_TEST_SUITE ( test_tensor, * boost::unit_test::depends_on("test_extents") ) ; BOOST_AUTO_TEST_SUITE ( test_tensor ) -using test_types = zip>::with_t; +using test_types = zip>::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) @@ -31,7 +36,7 @@ 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; + using tensor_type = ublas::tensor,layout_type>; auto a1 = tensor_type{}; BOOST_CHECK_EQUAL( a1.size() , 0ul ); @@ -67,6 +72,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); BOOST_CHECK( !a7.empty() ); BOOST_CHECK_NE( a7.data() , nullptr); + + } @@ -96,11 +103,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents, 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; + using tensor_type = ublas::tensor,layout_type>; auto check = [](auto const& e) { auto t = tensor_type{e}; - BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); BOOST_CHECK_EQUAL ( t.rank() , e.size() ); if(e.empty()) { BOOST_CHECK ( t.empty() ); @@ -122,7 +129,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fix using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; auto check = [](auto const& e) { @@ -156,9 +163,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_typ using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; - using other_tensor_type = ublas::tensor; + using other_tensor_type = ublas::tensor, other_layout_type>; for(auto const& e : extents) @@ -187,13 +194,13 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_move_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; + using tensor_type = ublas::tensor,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.size() , product(e) ); BOOST_CHECK_EQUAL ( t.rank() , e.size() ); if(e.empty()) { @@ -217,7 +224,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_ty using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; std::random_device device{}; std::minstd_rand0 generator(device()); @@ -226,7 +233,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_ty auto distribution = distribution_type(1,6); for(auto const& e : extents){ - auto r = static_cast(distribution(generator)); + auto r = value_type( static_cast< inner_type_t >(distribution(generator)) ); auto t = tensor_type{e,r}; for(auto i = 0ul; i < t.size(); ++i) BOOST_CHECK_EQUAL( t[i], r ); @@ -240,11 +247,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_array, value, test_t using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using array_type = typename tensor_type::array_type; for(auto const& e : extents) { - auto a = array_type(e.product()); + auto a = array_type(product(e)); auto v = value_type {}; for(auto& aa : a){ @@ -266,7 +273,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_single_index_access, va using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; for(auto const& e : extents) { auto t = tensor_type{e}; @@ -288,8 +295,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; - + using tensor_type = ublas::tensor,layout_type>; auto check1 = [](const tensor_type& t) { auto v = value_type{}; @@ -302,8 +308,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check2 = [](const tensor_type& t) { std::array k; - auto r = std::is_same_v ? 1 : 0; - auto q = std::is_same_v ? 1 : 0; + auto r = std::is_same::value ? 1 : 0; + auto q = std::is_same::value ? 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]){ @@ -376,8 +382,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixtu using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; - + using tensor_type = ublas::tensor,layout_type>; for(auto const& efrom : extents){ for(auto const& eto : extents){ @@ -389,15 +394,15 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixtu BOOST_CHECK_EQUAL( t[i], v ); t.reshape(eto); - for(auto i = 0ul; i < std::min(efrom.product(),eto.product()); ++i) + for(auto i = 0ul; i < std::min(product(efrom),product(eto)); ++i) BOOST_CHECK_EQUAL( t[i], v ); - BOOST_CHECK_EQUAL ( t.size() , eto.product() ); + BOOST_CHECK_EQUAL ( t.size() , product(eto) ); BOOST_CHECK_EQUAL ( t.rank() , eto.size() ); BOOST_CHECK ( t.extents() == eto ); if(efrom != eto){ - for(auto i = efrom.product(); i < t.size(); ++i) + for(auto i = product(efrom); i < t.size(); ++i) BOOST_CHECK_EQUAL( t[i], value_type{} ); } } @@ -412,8 +417,7 @@ 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; - + using tensor_type = ublas::tensor,layout_type>; for(auto const& e_t : extents){ for(auto const& e_r : extents) { @@ -427,14 +431,14 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_swap, value, test_types, fixture) 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.size() , product(e_r) ); 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.size() , product(e_t) ); BOOST_CHECK_EQUAL ( r.rank() , e_t.size() ); BOOST_CHECK ( r.extents() == e_t ); @@ -450,7 +454,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_ty using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; for(auto const& e : extents) { @@ -470,4 +474,20 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_ty } } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, 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, layout_type>; + + std::vector vec(30); + BOOST_CHECK_THROW(tensor_type({5,5},vec), std::runtime_error); + + auto t = tensor_type{{5,5}}; + auto i = ublas::index::index_type<4>{}; + BOOST_CHECK_THROW(t.operator()(i,i,i), std::runtime_error); + +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_tensor_matrix_vector.cpp b/test/tensor/test_tensor_matrix_vector.cpp index 3e34047dd..d6f71f871 100644 --- a/test/tensor/test_tensor_matrix_vector.cpp +++ b/test/tensor/test_tensor_matrix_vector.cpp @@ -1,12 +1,13 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -22,7 +23,7 @@ BOOST_AUTO_TEST_SUITE ( test_tensor_matrix_interoperability ) -using test_types = zip::with_t; +using test_types = zip::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types) @@ -30,7 +31,7 @@ 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; + using tensor_type = ublas::tensor,layout_type>; using matrix_type = typename tensor_type::matrix_type; tensor_type a1 = matrix_type(); @@ -65,7 +66,7 @@ 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; + using tensor_type = ublas::tensor,layout_type>; using vector_type = typename tensor_type::vector_type; tensor_type a1 = vector_type(); @@ -97,17 +98,13 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, value, test_types) struct fixture { - using extents_type = boost::numeric::ublas::basic_extents; + using extents_type = boost::numeric::ublas::dynamic_extents<>; 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 + extents_type{2,3}, // 2 + extents_type{9,11}, // 2 + extents_type{15,17}} // 3 { } std::vector extents; @@ -121,13 +118,13 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, value, using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,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.size() , product(e) ); BOOST_CHECK_EQUAL ( t.rank() , e.size() ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); @@ -143,7 +140,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, value, using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using vector_type = typename tensor_type::vector_type; auto check = [](auto const& e) { @@ -151,8 +148,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, value, if(e.empty()) return; - tensor_type t = vector_type(e.product()); - BOOST_CHECK_EQUAL ( t.size() , e.product() ); + tensor_type t = vector_type(product(e)); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); BOOST_CHECK_EQUAL ( t.rank() , e.size() ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); @@ -169,7 +166,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, value, te using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using matrix_type = typename tensor_type::matrix_type; auto check = [](auto const& e) @@ -182,7 +179,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, value, te 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.size() , product(e) ); BOOST_CHECK_EQUAL ( t.rank() , e.size() ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); @@ -204,7 +201,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, value, te using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using vector_type = typename tensor_type::vector_type; auto check = [](auto const& e) @@ -217,7 +214,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, value, te 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.size() , product(e) ); BOOST_CHECK_EQUAL ( t.rank() , e.size() ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); @@ -236,7 +233,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, te using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using matrix_type = typename tensor_type::matrix_type; auto check = [](auto const& e) @@ -250,7 +247,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, te 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.size() , product(e) ); BOOST_CHECK_EQUAL ( t.rank() , e.size() ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); @@ -274,7 +271,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, te using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using vector_type = typename tensor_type::vector_type; auto check = [](auto const& e) @@ -288,7 +285,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, te 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.size() , product(e) ); BOOST_CHECK_EQUAL ( t.rank() , e.size() ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); @@ -311,7 +308,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_t using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using matrix_type = typename tensor_type::matrix_type; auto check = [](auto const& e) @@ -327,21 +324,21 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_t 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.size() , product(e) ); 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.size() , product(e) ); 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.size() , product(e) ); BOOST_CHECK_EQUAL ( q.rank() , e.size() ); BOOST_CHECK ( !q.empty() ); BOOST_CHECK_NE ( q.data() , nullptr); @@ -370,7 +367,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, value, test_t using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,layout_type>; using vector_type = typename tensor_type::vector_type; auto check = [](auto const& e) @@ -386,21 +383,21 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, value, test_t 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.size() , product(e) ); 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.size() , product(e) ); 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.size() , product(e) ); BOOST_CHECK_EQUAL ( q.rank() , e.size() ); BOOST_CHECK ( !q.empty() ); BOOST_CHECK_NE ( q.data() , nullptr); @@ -425,13 +422,13 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, value, using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::tensor; + using tensor_type = ublas::tensor,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) + if(product(e) <= 2) return; assert(e.size() == 2); auto Q = tensor_type{e[0],1}; diff --git a/test/tensor/utility.hpp b/test/tensor/utility.hpp index b2ef266e6..2f029f349 100644 --- a/test/tensor/utility.hpp +++ b/test/tensor/utility.hpp @@ -1,18 +1,20 @@ -// Copyright (c) 2018-2019 -// Cem Bassoy +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef _BOOST_UBLAS_TEST_TENSOR_UTILITY_ #define _BOOST_UBLAS_TEST_TENSOR_UTILITY_ +#include + template struct zip_helper; @@ -46,6 +48,68 @@ struct zip_helper, type1, types1...> template using zip = zip_helper,types...>; +template +struct for_each_tuple_impl{ + auto operator()(std::tuple& t, CallBack call_back){ + call_back(I,std::get(t)); + if constexpr(sizeof...(Ts) - 1 > I){ + for_each_tuple_impl it; + it(t,call_back); + } + } +}; + +template +auto for_each_tuple(std::tuple& t, CallBack call_back){ + for_each_tuple_impl<0,CallBack,Ts...> f; + f(t,call_back); +} + + +template +struct list{ + static constexpr size_t size = sizeof...(Ts); +}; + +template +struct for_each_list_impl{ + constexpr decltype(auto) operator()(list l, CallBack call_back){ + using new_list = list; + using value_type = T; + call_back(I,value_type{}); + + if constexpr(new_list::size != 0){ + for_each_list_impl it; + it(new_list{},call_back); + } + } +}; + + +template +auto for_each_list(list l, CallBack call_back){ + for_each_list_impl<0,CallBack,Ts...> f; + f(l,call_back); +} + +#include + +// To counter msvc warninig C4244 +template +struct inner_type{ + using type = T; +}; + +template +struct inner_type< std::complex >{ + using type = T; +}; + +template +using inner_type_t = typename inner_type::type; + + + // creates e.g. // using test_types = zip::with_t; // equals // using test_types = std::tuple< std::pair, std::pair, std::pair, std::pair From 8dc3f04ece305d057804a2645f44e8ea68b730a9 Mon Sep 17 00:00:00 2001 From: Cem Bassoy Date: Sat, 18 Apr 2020 13:26:27 +0200 Subject: [PATCH 11/36] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 2ba291c00..c435b8ca9 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Boost Linear and Multilinear Algebra Library ## Documentation uBLAS is documented at [boost.org](https://www.boost.org/doc/libs/1_69_0/libs/numeric/ublas/doc/index.html). -The tensor extension has a [wiki page](https://github.com/BoostGSoC18/tensor/wiki). +The tensor extension has also a [wiki page](https://github.com/BoostGSoC18/tensor/wiki). ## License Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). @@ -29,8 +29,6 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org Branch | Travis | Appveyor | Regression | codecov.io | Docs | :-----: | ------ | --------- | ----------- | ----------- | ----- | - [`expr_template`](https://github.com/BoostGSoC19/tensor/tree/expr_template) | [![Build Status](https://travis-ci.org/BoostGSoC19/tensor.svg?branch=expr_template)](https://travis-ci.org/BoostGSoC19/tensor) | [![Build status](https://ci.appveyor.com/api/projects/status/1aeqlamaymy3sas2/branch/expr_template?svg=true)](https://ci.appveyor.com/project/coder3101/tensor/branch/expr_template) | [![ublas](https://img.shields.io/badge/tensor-expr_template-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/BoostGSoC19/tensor/branch/expr_template/graph/badge.svg)](https://codecov.io/gh/BoostGSoC19/tensor) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | - [`framework`](https://github.com/BoostGSoC19/tensor/tree/framework) | [![Build Status](https://travis-ci.org/BoostGSoC19/tensor.svg?branch=framework)](https://travis-ci.org/BoostGSoC19/tensor) | [![Build status](https://ci.appveyor.com/api/projects/status/1aeqlamaymy3sas2/branch/framework?svg=true)](https://ci.appveyor.com/project/coder3101/tensor/branch/framwork) | [![ublas](https://img.shields.io/badge/tensor-framework-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/BoostGSoC19/tensor/branch/framework/graph/badge.svg)](https://codecov.io/gh/BoostGSoC19/tensor) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | [`master`](https://github.com/boostorg/ublas/tree/master) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=master)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/master?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/master) | [![ublas](https://img.shields.io/badge/ublas-master-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | [`develop`](https://github.com/boostorg/ublas/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=develop)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/develop?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/develop) | [![ublas](https://img.shields.io/badge/ublas-develop-blue.svg)](https://www.boost.org/development/tests/develop/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | From 8938db5ce586b842c0f740dd284f92ee057a40f0 Mon Sep 17 00:00:00 2001 From: amitsingh19975 Date: Sun, 3 May 2020 19:44:22 +0530 Subject: [PATCH 12/36] Decoupling the tensor into three tensor different tensor types (#81) * decomposing tensor class into seperate modules according to the extents type * stabilizing and updating test. Adding support for the operations b/w different types of tensor * updating examples * changing tabs to spaces * added constexpr, removed resize from tensor and changed the array_type to container_type * changing tag names and refactoring code * adding and updating examples * adding new line at the end of file * refactoring code, fixing bugs and adding few new examples * refactoring examples * fixing gcc-7 issue where it is unable to use deduction guide when initilized * adding constexpr and inline * adding noexcept * adding is_static_rank_v * removing extents.hpp and decoupling test_extents and test_strides * refactoring code and adding constexpr with [[nodiscard]] to the functions * refactoring code. * adding missing iterator header * changing helper function name --- examples/tensor/Jamfile | 7 +- examples/tensor/construction_access.cpp | 144 +- examples/tensor/dynamic_prod_expressions.cpp | 184 ++ examples/tensor/einstein_notation.cpp | 184 +- .../tensor/fixed_rank_prod_expressions.cpp | 171 ++ examples/tensor/fixed_rank_tensor.cpp | 92 + examples/tensor/prod_expressions_1.cpp | 424 ---- examples/tensor/prod_expressions_2.cpp | 184 -- examples/tensor/simple_expressions.cpp | 68 +- examples/tensor/static_prod_expressions.cpp | 120 ++ examples/tensor/static_tensor.cpp | 82 + examples/tensor/tensor_construction.cpp | 106 +- include/boost/numeric/ublas/tensor.hpp | 8 +- .../boost/numeric/ublas/tensor/algorithms.hpp | 268 +-- .../ublas/tensor/detail/basic_type_traits.hpp | 65 + .../ublas/tensor/detail/extents_functions.hpp | 190 +- .../tensor/detail/static_extents_traits.hpp | 2 +- .../ublas/tensor/detail/storage_traits.hpp | 56 +- .../ublas/tensor/detail/type_traits.hpp | 111 - .../detail/type_traits_dynamic_extents.hpp | 46 + .../detail/type_traits_dynamic_strides.hpp | 58 + .../tensor/detail/type_traits_extents.hpp | 49 +- .../detail/type_traits_fixed_rank_extents.hpp | 45 + .../detail/type_traits_fixed_rank_strides.hpp | 57 + .../detail/type_traits_static_extents.hpp | 37 + .../detail/type_traits_static_strides.hpp | 59 + .../tensor/detail/type_traits_strides.hpp | 71 +- .../tensor/detail/type_traits_tensor.hpp | 166 ++ .../numeric/ublas/tensor/dynamic_extents.hpp | 595 ++---- .../numeric/ublas/tensor/dynamic_strides.hpp | 469 ++--- .../numeric/ublas/tensor/dynamic_tensor.hpp | 203 ++ .../boost/numeric/ublas/tensor/expression.hpp | 126 +- .../ublas/tensor/expression_evaluation.hpp | 105 +- .../boost/numeric/ublas/tensor/extents.hpp | 56 - .../ublas/tensor/fixed_rank_extents.hpp | 190 ++ .../ublas/tensor/fixed_rank_strides.hpp | 189 ++ .../ublas/tensor/fixed_rank_tensor.hpp | 217 ++ .../boost/numeric/ublas/tensor/functions.hpp | 1686 +++++++-------- include/boost/numeric/ublas/tensor/index.hpp | 20 +- .../numeric/ublas/tensor/multi_index.hpp | 66 +- .../ublas/tensor/multi_index_utility.hpp | 124 +- .../numeric/ublas/tensor/multiplication.hpp | 624 +++--- .../ublas/tensor/operators_arithmetic.hpp | 279 ++- .../ublas/tensor/operators_comparison.hpp | 219 +- .../boost/numeric/ublas/tensor/ostream.hpp | 109 +- .../numeric/ublas/tensor/static_extents.hpp | 69 +- .../numeric/ublas/tensor/static_strides.hpp | 71 +- .../numeric/ublas/tensor/static_tensor.hpp | 212 ++ .../boost/numeric/ublas/tensor/storage.hpp | 46 - .../boost/numeric/ublas/tensor/strides.hpp | 127 +- include/boost/numeric/ublas/tensor/tensor.hpp | 1345 +++++------- .../numeric/ublas/tensor/type_traits.hpp | 22 + test/tensor/Jamfile | 8 +- test/tensor/test_algorithms.cpp | 850 ++++---- test/tensor/test_einstein_notation.cpp | 132 +- test/tensor/test_expression.cpp | 181 +- test/tensor/test_expression_evaluation.cpp | 275 +-- test/tensor/test_extents.cpp | 1816 ++++++----------- .../test_fixed_rank_expression_evaluation.cpp | 344 ++-- test/tensor/test_fixed_rank_extents.cpp | 556 +++++ test/tensor/test_fixed_rank_functions.cpp | 405 ++++ .../test_fixed_rank_operators_arithmetic.cpp | 280 +-- .../test_fixed_rank_operators_comparison.cpp | 294 ++- test/tensor/test_fixed_rank_strides.cpp | 161 ++ test/tensor/test_fixed_rank_tensor.cpp | 764 +++---- .../test_fixed_rank_tensor_matrix_vector.cpp | 759 ++++--- test/tensor/test_functions.cpp | 1573 ++++---------- test/tensor/test_multi_index.cpp | 163 +- test/tensor/test_multi_index_utility.cpp | 991 +++++---- test/tensor/test_multiplication.cpp | 583 +++--- test/tensor/test_operators_arithmetic.cpp | 307 +-- test/tensor/test_operators_comparison.cpp | 392 ++-- .../test_static_expression_evaluation.cpp | 256 +-- test/tensor/test_static_extents.cpp | 39 +- test/tensor/test_static_functions.cpp | 459 +++++ .../test_static_operators_arithmetic.cpp | 268 +-- .../test_static_operators_comparison.cpp | 286 ++- test/tensor/test_static_strides.cpp | 8 +- test/tensor/test_static_tensor.cpp | 567 +++-- .../test_static_tensor_matrix_vector.cpp | 697 ++++--- test/tensor/test_strides.cpp | 389 ++-- test/tensor/test_tensor.cpp | 730 +++---- test/tensor/test_tensor_matrix_vector.cpp | 729 ++++--- test/tensor/utility.hpp | 36 +- 84 files changed, 13162 insertions(+), 12359 deletions(-) create mode 100644 examples/tensor/dynamic_prod_expressions.cpp create mode 100644 examples/tensor/fixed_rank_prod_expressions.cpp create mode 100644 examples/tensor/fixed_rank_tensor.cpp delete mode 100644 examples/tensor/prod_expressions_1.cpp delete mode 100644 examples/tensor/prod_expressions_2.cpp create mode 100644 examples/tensor/static_prod_expressions.cpp create mode 100644 examples/tensor/static_tensor.cpp create mode 100644 include/boost/numeric/ublas/tensor/detail/basic_type_traits.hpp delete mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits.hpp create mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_extents.hpp create mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_strides.hpp create mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_extents.hpp create mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_strides.hpp create mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits_static_extents.hpp create mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits_static_strides.hpp create mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits_tensor.hpp create mode 100644 include/boost/numeric/ublas/tensor/dynamic_tensor.hpp delete mode 100644 include/boost/numeric/ublas/tensor/extents.hpp create mode 100644 include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp create mode 100644 include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp create mode 100644 include/boost/numeric/ublas/tensor/fixed_rank_tensor.hpp create mode 100644 include/boost/numeric/ublas/tensor/static_tensor.hpp delete mode 100644 include/boost/numeric/ublas/tensor/storage.hpp create mode 100644 include/boost/numeric/ublas/tensor/type_traits.hpp create mode 100644 test/tensor/test_fixed_rank_extents.cpp create mode 100644 test/tensor/test_fixed_rank_functions.cpp create mode 100644 test/tensor/test_fixed_rank_strides.cpp create mode 100644 test/tensor/test_static_functions.cpp diff --git a/examples/tensor/Jamfile b/examples/tensor/Jamfile index a3cff6da5..25e5f415f 100644 --- a/examples/tensor/Jamfile +++ b/examples/tensor/Jamfile @@ -21,7 +21,10 @@ project boost-ublas-tensor-example exe construction_access : construction_access.cpp ; exe simple_expressions : simple_expressions.cpp ; -exe prod_expressions_1 : prod_expressions_1.cpp ; -exe prod_expressions_2 : prod_expressions_2.cpp ; +exe dynamic_prod_expressions : dynamic_prod_expressions.cpp ; +exe fixed_rank_prod_expressions : fixed_rank_prod_expressions.cpp ; +exe static_prod_expressions : static_prod_expressions.cpp ; +exe fixed_rank_tensor : fixed_rank_tensor.cpp ; +exe static_tensor : static_tensor.cpp ; exe einstein_notation : einstein_notation.cpp ; exe tensor_construction : tensor_construction.cpp ; \ No newline at end of file diff --git a/examples/tensor/construction_access.cpp b/examples/tensor/construction_access.cpp index 8a4987a8d..cee695fa6 100644 --- a/examples/tensor/construction_access.cpp +++ b/examples/tensor/construction_access.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -17,74 +17,74 @@ int main() { - using namespace boost::numeric::ublas; - using namespace boost::multiprecision; - - - // creates a three-dimensional tensor with extents 3,4 and 2 - // tensor A stores single-precision floating-point number according - // to the first-order storage format - using ftype = float; - auto A = tensor{3,4,2}; - - // initializes the tensor with increasing values along the first-index - // using a single index. - auto vf = ftype(0); - for(auto i = 0u; i < A.size(); ++i, vf += ftype(1)) - A[i] = vf; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "A=" << A << ";" << std::endl << std::endl; - - // creates a four-dimensional tensor with extents 5,4,3 and 2 - // tensor A stores complex floating-point extended double precision numbers - // according to the last-order storage format - // and initializes it with the default value. - using ctype = std::complex; - auto B = tensor,last_order>(dynamic_extents<>{5,4,3,2},ctype{}); - - // initializes the tensor with increasing values along the last-index - // using a single-index - auto vc = ctype(0,0); - for(auto i = 0u; i < B.size(); ++i, vc += ctype(1,1)) - B[i] = vc; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "B=" << B << ";" << std::endl << std::endl; - - - - auto C = tensor,last_order>(B.extents()); - // computes the complex conjugate of elements of B - // using multi-index notation. - for(auto i = 0u; i < B.size(0); ++i) - for(auto j = 0u; j < B.size(1); ++j) - for(auto k = 0u; k < B.size(2); ++k) - for(auto l = 0u; l < B.size(3); ++l) - C.at(i,j,k,l) = std::conj(B.at(i,j,k,l)); - - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "C=" << C << ";" << std::endl << std::endl; - - - // computes the complex conjugate of elements of B - // using iterators. - auto D = tensor,last_order>(B.extents()); - std::transform(B.begin(), B.end(), D.begin(), [](auto const& b){ return std::conj(b); }); - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "D=" << D << ";" << std::endl << std::endl; - - // reshaping tensors. - auto new_extents = B.extents().base(); - std::next_permutation( new_extents.begin(), new_extents.end() ); - D.reshape( dynamic_extents<>(new_extents) ); - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "newD=" << D << ";" << std::endl << std::endl; + using namespace boost::numeric::ublas; + using namespace boost::multiprecision; + + + // creates a three-dimensional tensor with extents 3,4 and 2 + // tensor A stores single-precision floating-point number according + // to the first-order storage format + using ftype = float; + auto A = dynamic_tensor{3,4,2}; + + // initializes the tensor with increasing values along the first-index + // using a single index. + auto vf = ftype(0); + for(auto i = 0u; i < A.size(); ++i, vf += ftype(1)) + A[i] = vf; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "A=" << A << ";" << std::endl << std::endl; + + // creates a four-dimensional tensor with extents 5,4,3 and 2 + // tensor A stores complex floating-point extended double precision numbers + // according to the last-order storage format + // and initializes it with the default value. + using ctype = std::complex; + auto B = dynamic_tensor(dynamic_extents<>{5,4,3,2},ctype{}); + + // initializes the tensor with increasing values along the last-index + // using a single-index + auto vc = ctype(0,0); + for(auto i = 0u; i < B.size(); ++i, vc += ctype(1,1)) + B[i] = vc; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "B=" << B << ";" << std::endl << std::endl; + + + + auto C = dynamic_tensor(B.extents()); + // computes the complex conjugate of elements of B + // using multi-index notation. + for(auto i = 0u; i < B.size(0); ++i) + for(auto j = 0u; j < B.size(1); ++j) + for(auto k = 0u; k < B.size(2); ++k) + for(auto l = 0u; l < B.size(3); ++l) + C.at(i,j,k,l) = std::conj(B.at(i,j,k,l)); + + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "C=" << C << ";" << std::endl << std::endl; + + + // computes the complex conjugate of elements of B + // using iterators. + auto D = dynamic_tensor(B.extents()); + std::transform(B.begin(), B.end(), D.begin(), [](auto const& b){ return std::conj(b); }); + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "D=" << D << ";" << std::endl << std::endl; + + // reshaping tensors. + auto new_extents = B.extents().base(); + std::next_permutation( new_extents.begin(), new_extents.end() ); + D.reshape( dynamic_extents<>(new_extents) ); + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "newD=" << D << ";" << std::endl << std::endl; } diff --git a/examples/tensor/dynamic_prod_expressions.cpp b/examples/tensor/dynamic_prod_expressions.cpp new file mode 100644 index 000000000..e39ae62fd --- /dev/null +++ b/examples/tensor/dynamic_prod_expressions.cpp @@ -0,0 +1,184 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#include +#include +#include +#include + +int main() +{ + using namespace boost::numeric::ublas; + + using format_t = column_major; + using value_t = float; // std::complex; + using tensor_t = dynamic_tensor;; + using matrix_t = matrix; + using vector_t = vector; + + // Tensor-Vector-Multiplications - Including Transposition + { + + auto n = dynamic_extents<>{3,4,2}; + auto A = tensor_t(n,2); + auto q = 0u; // contraction mode + + // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); + q = 1u; + tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); + + // C2(i,k) = A(i,j,k)*T1(j) + 4; + q = 2u; + tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; + + // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); + tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); + + // C4(i,j) = A(k,i,j)*T1(k) + 4; + q = 1u; + tensor_t C4 = prod(trans(A,{2,3,1}),vector_t(n[2],1),q) + 4; + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; + std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,j) = A(k,i,j)*T1(k) + 4;" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + + } + + + // Tensor-Matrix-Multiplications - Including Transposition + { + + auto n = dynamic_extents<>{3,4,2}; + auto A = tensor_t(n,2); + auto m = 5u; + auto q = 0u; // contraction mode + + // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); + q = 1u; + tensor_t C1 = tensor_t(dynamic_extents<>{m,n[1],n[2]},2) + prod(A,matrix_t(m,n[q-1],1),q); + + // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; + q = 2u; + tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4; + + // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); + q = 3u; + tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q); + + // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); + tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1); + + // C5(i,k,l) = A(i,k,j)*T1(l,j) + 4; + q = 3u; + tensor_t C5 = prod(trans(A,{1,3,2}),matrix_t(m,n[1],1),q) + 4; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C5(i,k,l) = A(i,k,j)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C5=" << C5 << ";" << std::endl << std::endl; + } + + + + + + // Tensor-Tensor-Multiplications Including Transposition + { + + using perm_t = std::vector; + + auto na = dynamic_extents<>{3,4,5}; + auto nb = dynamic_extents<>{4,6,3,2}; + auto A = tensor_t(na,2); + auto B = tensor_t(nb,3); + + + // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; + tensor_t C1 = tensor_t(dynamic_extents<>{na[2],na[2]},2) + prod(A,A,perm_t{1,2}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + + // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; + tensor_t C2 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + + // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; + tensor_t C3 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + } +} diff --git a/examples/tensor/einstein_notation.cpp b/examples/tensor/einstein_notation.cpp index 90b637c17..b91f7a0ff 100644 --- a/examples/tensor/einstein_notation.cpp +++ b/examples/tensor/einstein_notation.cpp @@ -18,83 +18,83 @@ int main() { - using namespace boost::numeric::ublas; - - using format_t = column_major; - using value_t = float; - using tensor_t = tensor,format_t>; - using matrix_t = matrix; - using namespace boost::numeric::ublas::index; - - // Tensor-Vector-Multiplications - Including Transposition - { - - auto n = dynamic_extents<>{3,4,2}; - auto A = tensor_t(n,1); - auto B1 = matrix_t(n[1],n[2],2); - auto v1 = tensor_t(dynamic_extents<>{n[0],1},2); - auto v2 = tensor_t(dynamic_extents<>{n[1],1},2); -// auto v3 = tensor_t(shape{n[2],1},2); - - // C1(j,k) = B1(j,k) + A(i,j,k)*v1(i); - // tensor_t C1 = B1 + prod(A,vector_t(n[0],1),1); -// tensor_t C1 = B1 + A(_i,_,_) * v1(_i,_); - - // C2(i,k) = A(i,j,k)*v2(j) + 4; - //tensor_t C2 = prod(A,vector_t(n[1],1),2) + 4; -// tensor_t C2 = A(_,_i,_) * v2(_i,_) + 4; - - // not yet implemented! - // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - // tensor_t C3 = prod(prod(prod(A,v1,1),v2,1),v3,1); - // tensor_t C3 = A(_i,_j,_k) * v1(_i,_) * v2(_j,_) * v3(_k,_); - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(j,k) = B1(j,k) + A(i,j,k)*v1(i);" << std::endl << std::endl; -// std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,k) = A(i,j,k)*v2(j) + 4;" << std::endl << std::endl; -// std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - } - - - // Tensor-Matrix-Multiplications - Including Transposition - { - auto n = dynamic_extents<>{3,4,2}; - auto m = 5u; - auto A = tensor_t(n,2); - auto B = tensor_t(dynamic_extents<>{n[1],n[2],m},2); - auto B1 = tensor_t(dynamic_extents<>{m,n[0]},1); - auto B2 = tensor_t(dynamic_extents<>{m,n[1]},1); - - - // C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i); - // tensor_t C1 = B + prod(A,B1,1); + using namespace boost::numeric::ublas; + + using format_t = column_major; + using value_t = float; + using tensor_t = dynamic_tensor; + using matrix_t = matrix; + using namespace boost::numeric::ublas::index; + + // Tensor-Vector-Multiplications - Including Transposition + { + + auto n = dynamic_extents<>{3,4,2}; + auto A = tensor_t(n,1); + auto B1 = matrix_t(n[1],n[2],2); + auto v1 = tensor_t(dynamic_extents<>{n[0],1},2); + auto v2 = tensor_t(dynamic_extents<>{n[1],1},2); +// auto v3 = tensor_t(shape{n[2],1},2); + + // C1(j,k) = B1(j,k) + A(i,j,k)*v1(i); + // tensor_t C1 = B1 + prod(A,vector_t(n[0],1),1); +// tensor_t C1 = B1 + A(_i,_,_) * v1(_i,_); + + // C2(i,k) = A(i,j,k)*v2(j) + 4; + //tensor_t C2 = prod(A,vector_t(n[1],1),2) + 4; +// tensor_t C2 = A(_,_i,_) * v2(_i,_) + 4; + + // not yet implemented! + // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); + // tensor_t C3 = prod(prod(prod(A,v1,1),v2,1),v3,1); + // tensor_t C3 = A(_i,_j,_k) * v1(_i,_) * v2(_j,_) * v3(_k,_); + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(j,k) = B1(j,k) + A(i,j,k)*v1(i);" << std::endl << std::endl; +// std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,k) = A(i,j,k)*v2(j) + 4;" << std::endl << std::endl; +// std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + } + + + // Tensor-Matrix-Multiplications - Including Transposition + { + auto n = dynamic_extents<>{3,4,2}; + auto m = 5u; + auto A = tensor_t(n,2); + auto B = tensor_t(dynamic_extents<>{n[1],n[2],m},2); + auto B1 = tensor_t(dynamic_extents<>{m,n[0]},1); + auto B2 = tensor_t(dynamic_extents<>{m,n[1]},1); + + + // C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i); + // tensor_t C1 = B + prod(A,B1,1); // tensor_t C1 = B + A(_i,_,_) * B1(_,_i); - // C2(i,l,k) = A(i,j,k)*B2(l,j) + 4; - // tensor_t C2 = prod(A,B2) + 4; + // C2(i,l,k) = A(i,j,k)*B2(l,j) + 4; + // tensor_t C2 = prod(A,B2) + 4; // tensor_t C2 = A(_,_j,_) * B2(_,_j) + 4; - // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); - // not yet implemented. + // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); + // not yet implemented. - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i);" << std::endl << std::endl; + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i);" << std::endl << std::endl; // std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,l,k) = A(i,j,k)*B2(l,j) + 4;" << std::endl << std::endl; + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,l,k) = A(i,j,k)*B2(l,j) + 4;" << std::endl << std::endl; // std::cout << "C2=" << C2 << ";" << std::endl << std::endl; // // formatted output @@ -102,39 +102,39 @@ int main() // std::cout << "% --------------------------- " << std::endl << std::endl; // std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; // std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - } + } - // Tensor-Tensor-Multiplications Including Transposition - { - auto na = dynamic_extents<>{3,4,5}; - auto nb = dynamic_extents<>{4,6,3,2}; - auto A = tensor_t(na,2); - auto B = tensor_t(nb,3); - auto T1 = tensor_t(dynamic_extents<>{na[2],na[2]},2); - auto T2 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2); + // Tensor-Tensor-Multiplications Including Transposition + { + auto na = dynamic_extents<>{3,4,5}; + auto nb = dynamic_extents<>{4,6,3,2}; + auto A = tensor_t(na,2); + auto B = tensor_t(nb,3); + auto T1 = tensor_t(dynamic_extents<>{na[2],na[2]},2); + auto T2 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2); - // C1(j,l) = T1(j,l) + A(i,j,k)*A(i,j,l) + 5; - // tensor_t C1 = T1 + prod(A,A,perm_t{1,2}) + 5; + // C1(j,l) = T1(j,l) + A(i,j,k)*A(i,j,l) + 5; + // tensor_t C1 = T1 + prod(A,A,perm_t{1,2}) + 5; // tensor_t C1 = T1 + A(_i,_j,_m)*A(_i,_j,_l) + 5; - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(k,l) = T1(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(k,l) = T1(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; // std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - // C2(k,l,m) = T2(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; - //tensor_t C2 = T2 + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + // C2(k,l,m) = T2(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; + //tensor_t C2 = T2 + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; // tensor_t C2 = T2 + A(_i,_j,_k)*B(_j,_l,_i,_m) + 5; - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(k,l,m) = T2(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(k,l,m) = T2(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; // std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - } + } } diff --git a/examples/tensor/fixed_rank_prod_expressions.cpp b/examples/tensor/fixed_rank_prod_expressions.cpp new file mode 100644 index 000000000..78949035a --- /dev/null +++ b/examples/tensor/fixed_rank_prod_expressions.cpp @@ -0,0 +1,171 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#include +#include +#include +#include + +int main() +{ + using namespace boost::numeric::ublas; + + using format_t = column_major; + using value_t = float; // std::complex; + using matrix_t = matrix; + using vector_t = vector; + using extents_3_t = dynamic_extents<3>; + using extents_4_t = dynamic_extents<4>; + + // Tensor-Vector-Multiplications - Including Transposition + // dynamic_extents with static rank + { + + auto n = extents_3_t{3,4,2}; + auto A = fixed_rank_tensor(n,value_t(2)); + using tensor_t = fixed_rank_tensor< value_t, 2>; + auto q = 0u; // contraction mode + + // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); + q = 1u; + tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); + + // C2(i,k) = A(i,j,k)*T1(j) + 4; + q = 2u; + tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; + + // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); + tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; + std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; + + } + + // Tensor-Matrix-Multiplications - Including Transposition + // dynamic_extents with static rank + { + + auto n = extents_3_t{3,4,2}; + auto A = fixed_rank_tensor(n,value_t(2)); + using tensor_t = decltype(A); + auto m = 5u; + auto q = 0u; // contraction mode + + // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); + q = 1u; + tensor_t C1 = fixed_rank_tensor( extents_3_t{m,n[1],n[2]},value_t(2) ) + prod(A,matrix_t(m,n[q-1],1),q); + + // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; + q = 2u; + tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4 ; + + // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); + q = 3u; + tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q) ; + + // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); + tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1) ; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; + + } + + // Tensor-Tensor-Multiplications Including Transposition + // dynamic_extents with static rank + { + + using perm_t = std::vector; + + auto na = extents_3_t{3,4,5}; + auto nb = extents_4_t{4,6,3,2}; + auto A = fixed_rank_tensor(na,value_t(2)); + auto B = fixed_rank_tensor(nb,value_t(3)); + using tensor_t = dynamic_tensor< value_t >; + + + // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; + // Right now there exist no tensor other than dynamic_extents with + // dynamic rank so every tensor times tensor operator automatically + // to dynamic tensor + tensor_t C1 = dynamic_tensor(dynamic_extents<>{na[2],na[2]},value_t(2)) + prod(A,A,perm_t{1,2}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + + // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; + // Similar Problem as above + tensor_t C2 = dynamic_tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + + // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; + // Similar Problem as above + tensor_t C3 = dynamic_tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + } +} diff --git a/examples/tensor/fixed_rank_tensor.cpp b/examples/tensor/fixed_rank_tensor.cpp new file mode 100644 index 000000000..faa2a968a --- /dev/null +++ b/examples/tensor/fixed_rank_tensor.cpp @@ -0,0 +1,92 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#include +#include +#include + +namespace ub = boost::numeric::ublas; + +int main() { + + /** @brief How to create fixed_rank_tensor + * + * fixed_rank_tensor< / Value Type, / Extents Size /, / Layout Type / >( ... ); + * + **/ + + /** + * fixed rank tensor with + * Layout: first_order by default if not + * provided + * Value Type: float + * Extents Type: dynamic_extents<5>{1,2,3,4,5} + **/ + auto t11 = ub::fixed_rank_tensor{1,2,3,4,5}; + + /** + * fixed rank tensor using deduction guide + * Layout: last_order + * provided + * Value Type: float + * Extents Type: dynamic_extents<5>{1,2,2,3,4} + **/ + auto t12 = ub::fixed_rank_tensor{ ub::dynamic_extents<5>{1,2,2,3,4}, 5.f }; + + /** + * fixed rank tensor using deduction guide + * Layout: first_order by default if not + * provided + * Value Type: float + * Extents Type: dynamic_extents<5>{1,2,2,3,4} + **/ + auto t2 = ub::fixed_rank_tensor( ub::dynamic_extents<5>{1,2,2,3,4}, 5.f ); + + /*--------------------------Expressions------------------------------*/ + + using f_tensor = ub::fixed_rank_tensor; + using s_tensor = ub::static_tensor >; + + auto t3 = ub::fixed_rank_tensor( ub::dynamic_extents<5>{1,2,3,4,5}, 5.f ); + auto st1 = s_tensor{ 5.f }; + auto dt1 = ub::dynamic_tensor( ub::dynamic_extents<>{1,2,3,4,5}, 5.f ); + + f_tensor exp1 = t3 + t3 * 2 + t3*t3; + + // type of the expression will be whichever + // tensor type is present at the start of the + // expression + f_tensor exp2 = t3 + st1 * 2 + st1 * t3; + + f_tensor exp3 = t3 + dt1 * 2 + dt1 * t3; + + std::cout< "<<( exp1 == exp2 )< "<<( exp2 == exp3 )< t4 = st1; + + // Assigning dynamic_tensor into fixed_rank_tensor + ub::dynamic_tensor t5 = dt1; + + std::cout<<"( t4 == t3 ) => "<<( t4 == t3 )< "<<( t5 == dt1 )< -#include -#include -#include - -int main() -{ - using namespace boost::numeric::ublas; - - using format_t = column_major; - using value_t = float; // std::complex; - using matrix_t = matrix; - using vector_t = vector; - - // Tensor-Vector-Multiplications - Including Transposition - // dynamic_extents with dynamic rank - { - - auto n = dynamic_extents<>{3,4,2}; - auto A = tensor(n,value_t(2)); - using tensor_t = decltype(A); - auto q = 0u; // contraction mode - - // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); - q = 1u; - tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q) ; - - // C2(i,k) = A(i,j,k)*T1(j) + 4; - q = 2u; - tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4 ; - - // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); - - // C4(i,j) = A(k,i,j)*T1(k) + 4; - q = 1u; - tensor_t C4 = prod(trans(A,{2,3,1}),vector_t(n[2],1),q) + 4 ; - - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; - std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C4(i,j) = A(k,i,j)*T1(k) + 4;" << std::endl << std::endl; - std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - - } - - // Tensor-Vector-Multiplications - Including Transposition - // dynamic_extents with static rank - { - - auto n = dynamic_extents<3>{3,4,2}; - auto A = tensor(n,value_t(2)); - using tensor_t = tensor< value_t, dynamic_extents<2> >; - auto q = 0u; // contraction mode - - // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); - q = 1u; - tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); - - // C2(i,k) = A(i,j,k)*T1(j) + 4; - q = 2u; - tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; - - // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); - - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; - std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; - - } - - // Tensor-Vector-Multiplications - Including Transposition - // static_extents - { - - auto n = static_extents<3,4,2>{}; - auto A = tensor(n,value_t(2)); - auto q = 0u; // contraction mode - - // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); - q = 1u; - tensor< value_t, static_extents<4,2> > C1 = matrix_t(n[1],n[2],2) + prod<1ul /* q = 1 */ >(A,vector_t(n[q-1],1)); - - // C2(i,k) = A(i,j,k)*T1(j) + 4; - q = 2u; - tensor< value_t, static_extents<3,2> > C2 = prod<2ul /* q = 2 */ >(A,vector_t(n[q-1],1)) + 4; - - // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - auto C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); - - - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; - std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; - - } - - - // Tensor-Matrix-Multiplications - Including Transposition - // dynamic_extents with dynamic rank - { - - auto n = dynamic_extents<>{3,4,2}; - auto A = tensor(n,value_t(2)); - using tensor_t = decltype(A); - auto m = 5u; - auto q = 0u; // contraction mode - - // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); - q = 1u; - tensor_t C1 = tensor( dynamic_extents<>{m,n[1],n[2]},value_t(2) ) + prod(A,matrix_t(m,n[q-1],1),q); - - // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; - q = 2u; - tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4 ; - - // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); - q = 3u; - tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q) ; - - // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); - tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1) ; - - // C5(i,k,l) = A(i,k,j)*T1(l,j) + 4; - q = 3u; - tensor_t C5 = prod(trans(A,{1,3,2}),matrix_t(m,n[1],1),q) + 4 ; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; - std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; - - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C5(i,k,l) = A(i,k,j)*T1(l,j) + 4;" << std::endl << std::endl; - std::cout << "C5=" << C5 << ";" << std::endl << std::endl; - } - - // Tensor-Matrix-Multiplications - Including Transposition - // dynamic_extents with static rank - { - - auto n = dynamic_extents<3>{3,4,2}; - auto A = tensor(n,value_t(2)); - using tensor_t = decltype(A); - auto m = 5u; - auto q = 0u; // contraction mode - - // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); - q = 1u; - tensor_t C1 = tensor( dynamic_extents<3>{m,n[1],n[2]},value_t(2) ) + prod(A,matrix_t(m,n[q-1],1),q); - - // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; - q = 2u; - tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4 ; - - // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); - q = 3u; - tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q) ; - - // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); - tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1) ; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; - std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; - - } - - // Tensor-Matrix-Multiplications - Including Transposition - // static_extents - { - - auto n = static_extents<3,4,2>{}; - auto A = tensor(n,value_t(2)); - static constexpr auto m = 5u; - auto q = 0u; // contraction mode - - // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); - q = 1ul; - tensor< value_t, static_extents<5,4,2> > C1 = tensor( static_extents{},value_t(2) ) - + prod < 1ul /* q */, m /*n[q-1] => n[1-1] => n[0]*/ > (A, matrix_t(m,n[q-1],value_t(1) )) ; - - // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; - q = 2u; - tensor< value_t, static_extents<3,5,2> > C2 = prod<2ul/* q = 2 */, m>(A,matrix_t(m,n[q-1],1)) + 4 ; - - // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); - q = 3u; - auto C3 = prod<3ul, m + 2>( prod<2ul /* q(3) - 1 = 2 */, m + 1 >(A,matrix_t(m+1,n[q-2],1)), matrix_t(m+2,n[q-1],1) ) ; - - // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); - auto C4 = prod<2ul, m + 1>( prod<3ul, m + 2>(A,matrix_t(m+2,n[q-1],1)), matrix_t(m+1,n[q-2],1) ) ; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; - std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; - - } - - - - - - // Tensor-Tensor-Multiplications Including Transposition - // dynamic_extents with dynamic rank - { - - using perm_t = std::vector; - - auto na = dynamic_extents<>{3,4,5}; - auto nb = dynamic_extents<>{4,6,3,2}; - auto A = tensor(na,value_t(2)); - auto B = tensor(nb,value_t(3)); - using tensor_t = decltype(A); - - - // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; - tensor_t C1 = tensor(dynamic_extents<>{na[2],na[2]},value_t(2)) + prod(A,A,perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - - // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; - tensor_t C2 = tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - - // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; - tensor_t C3 = tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - } - - // Tensor-Tensor-Multiplications Including Transposition - // dynamic_extents with static rank - { - - using perm_t = std::vector; - - auto na = dynamic_extents<3>{3,4,5}; - auto nb = dynamic_extents<4>{4,6,3,2}; - auto A = tensor(na,value_t(2)); - auto B = tensor(nb,value_t(3)); - using tensor_t = tensor< value_t, dynamic_extents<> >; - - - // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; - // Right now there exist no tensor other than dynamic_extents with - // dynamic rank so every tensor times tensor operator automatically - // to dynamic tensor - tensor_t C1 = tensor(dynamic_extents<>{na[2],na[2]},value_t(2)) + prod(A,A,perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - - // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; - // Similar Problem as above - tensor_t C2 = tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - - // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; - // Similar Problem as above - tensor_t C3 = tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - } -} diff --git a/examples/tensor/prod_expressions_2.cpp b/examples/tensor/prod_expressions_2.cpp deleted file mode 100644 index 267fe40f0..000000000 --- a/examples/tensor/prod_expressions_2.cpp +++ /dev/null @@ -1,184 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#include -#include -#include -#include - -int main() -{ - using namespace boost::numeric::ublas; - - using format_t = column_major; - using value_t = float; // std::complex; - using tensor_t = tensor,format_t>;; - using matrix_t = matrix; - using vector_t = vector; - - // Tensor-Vector-Multiplications - Including Transposition - { - - auto n = dynamic_extents<>{3,4,2}; - auto A = tensor_t(n,2); - auto q = 0u; // contraction mode - - // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); - q = 1u; - tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); - - // C2(i,k) = A(i,j,k)*T1(j) + 4; - q = 2u; - tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; - - // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); - - // C4(i,j) = A(k,i,j)*T1(k) + 4; - q = 1u; - tensor_t C4 = prod(trans(A,{2,3,1}),vector_t(n[2],1),q) + 4; - - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; - std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C4(i,j) = A(k,i,j)*T1(k) + 4;" << std::endl << std::endl; - std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - - } - - - // Tensor-Matrix-Multiplications - Including Transposition - { - - auto n = dynamic_extents<>{3,4,2}; - auto A = tensor_t(n,2); - auto m = 5u; - auto q = 0u; // contraction mode - - // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); - q = 1u; - tensor_t C1 = tensor_t(dynamic_extents<>{m,n[1],n[2]},2) + prod(A,matrix_t(m,n[q-1],1),q); - - // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; - q = 2u; - tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4; - - // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); - q = 3u; - tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q); - - // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); - tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1); - - // C5(i,k,l) = A(i,k,j)*T1(l,j) + 4; - q = 3u; - tensor_t C5 = prod(trans(A,{1,3,2}),matrix_t(m,n[1],1),q) + 4; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; - std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; - - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C5(i,k,l) = A(i,k,j)*T1(l,j) + 4;" << std::endl << std::endl; - std::cout << "C5=" << C5 << ";" << std::endl << std::endl; - } - - - - - - // Tensor-Tensor-Multiplications Including Transposition - { - - using perm_t = std::vector; - - auto na = dynamic_extents<>{3,4,5}; - auto nb = dynamic_extents<>{4,6,3,2}; - auto A = tensor_t(na,2); - auto B = tensor_t(nb,3); - - - // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; - tensor_t C1 = tensor_t(dynamic_extents<>{na[2],na[2]},2) + prod(A,A,perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - - // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; - tensor_t C2 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - - // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; - tensor_t C3 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - } -} diff --git a/examples/tensor/simple_expressions.cpp b/examples/tensor/simple_expressions.cpp index 54f3f6c38..d5da90bfa 100644 --- a/examples/tensor/simple_expressions.cpp +++ b/examples/tensor/simple_expressions.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,47 +18,47 @@ int main() { - using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas; - using tensorf = tensor; - using matrixf = matrix; - using vectorf = vector; + using tensorf = dynamic_tensor; + using matrixf = matrix; + using vectorf = vector; - auto A = tensorf{3,4,2}; - auto B = A = 2; + auto A = tensorf{3,4,2}; + auto B = A = 2; - // Calling overloaded operators - // and using simple tensor expression templates. - if( A != (B+1) ) - A += 2*B - 1; + // Calling overloaded operators + // and using simple tensor expression templates. + if( A != (B+1) ) + A += 2*B - 1; - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "A=" << A << ";" << std::endl << std::endl; + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "A=" << A << ";" << std::endl << std::endl; - auto n = dynamic_extents<>{3,4}; - auto D = matrixf(n[0],n[1],1); - auto e = vectorf(n[1],1); - auto f = vectorf(n[0],2); + auto n = dynamic_extents<>{3,4}; + auto D = matrixf(n[0],n[1],1); + auto e = vectorf(n[1],1); + auto f = vectorf(n[0],2); - // Calling constructor with - // vector expression templates - tensorf C = 2*f; - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "C=" << C << ";" << std::endl << std::endl; + // Calling constructor with + // vector expression templates + tensorf C = 2*f; + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "C=" << C << ";" << std::endl << std::endl; - // Calling overloaded operators - // and mixing simple tensor and matrix expression templates - tensorf F = 3*C + 4*prod(2*D,e); + // Calling overloaded operators + // and mixing simple tensor and matrix expression templates + tensorf F = 3*C + 4*prod(2*D,e); - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "F=" << F << ";" << std::endl << std::endl; + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "F=" << F << ";" << std::endl << std::endl; } diff --git a/examples/tensor/static_prod_expressions.cpp b/examples/tensor/static_prod_expressions.cpp new file mode 100644 index 000000000..458fac22f --- /dev/null +++ b/examples/tensor/static_prod_expressions.cpp @@ -0,0 +1,120 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#include +#include +#include +#include + +int main() +{ + using namespace boost::numeric::ublas; + + using format_t = column_major; + using value_t = float; // std::complex; + using matrix_t = matrix; + using vector_t = vector; + + // Tensor-Vector-Multiplications - Including Transposition + // static_extents + { + auto n = static_extents<3,4,2>{}; + auto A = static_tensor>(value_t(2)); + auto q = 0u; // contraction mode + + // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); + q = 1u; + static_tensor< value_t, static_extents<4,2> > C1 = matrix_t(n[1],n[2],2) + prod<1ul /* q = 1 */ >(A,vector_t(n[q-1],1)); + + // C2(i,k) = A(i,j,k)*T1(j) + 4; + q = 2u; + static_tensor< value_t, static_extents<3,2> > C2 = prod<2ul /* q = 2 */ >(A,vector_t(n[q-1],1)) + 4; + + // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); + auto C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); + + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; + std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; + + } + + // Tensor-Matrix-Multiplications - Including Transposition + // static_extents + { + + auto n = static_extents<3,4,2>{}; + auto A = static_tensor>(value_t(2)); + static constexpr auto m = 5u; + auto q = 0u; // contraction mode + + // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); + q = 1ul; + static_tensor< value_t, static_extents<5,4,2> > C1 = static_tensor>( value_t(2) ) + + prod < 1ul /* q */, m /*n[q-1] => n[1-1] => n[0]*/ > (A, matrix_t(m,n[q-1],value_t(1) )) ; + + // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; + q = 2u; + static_tensor< value_t, static_extents<3,5,2> > C2 = prod<2ul/* q = 2 */, m>(A,matrix_t(m,n[q-1],1)) + 4 ; + + // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); + q = 3u; + auto C3 = prod<3ul, m + 2>( prod<2ul /* q(3) - 1 = 2 */, m + 1 >(A,matrix_t(m+1,n[q-2],1)), matrix_t(m+2,n[q-1],1) ) ; + + // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); + auto C4 = prod<2ul, m + 1>( prod<3ul, m + 2>(A,matrix_t(m+2,n[q-1],1)), matrix_t(m+1,n[q-2],1) ) ; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; + + } + +} diff --git a/examples/tensor/static_tensor.cpp b/examples/tensor/static_tensor.cpp new file mode 100644 index 000000000..7062c358c --- /dev/null +++ b/examples/tensor/static_tensor.cpp @@ -0,0 +1,82 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#include +#include +#include + +namespace ub = boost::numeric::ublas; + +int main() { + + /** @brief How to create static_tensor + * + * static_tensor< / Value Type, / Extents /, / Layout Type / >( ... ); + * + **/ + + /** + * static rank tensor with + * Layout: first_order by default if not + * provided + * Value Type: float + * Extents Type: dynamic_extents<5>{1,2,3,4,5} + **/ + auto t1 = ub::static_tensor >{5.f}; + + /** + * static rank tensor with + * Layout: first_order by default if not + * provided + * Value Type: float + * Extents Type: dynamic_extents<5>{1,2,3,4,5} + **/ + auto t2 = ub::static_tensor, ub::last_order >{5.f}; + + /*--------------------------Expressions------------------------------*/ + + using s_tensor = ub::static_tensor >; + + auto t3 = ub::fixed_rank_tensor( ub::dynamic_extents<5>{1,2,3,4,5}, 5.f ); + auto st1 = s_tensor{ 5.f }; + auto dt1 = ub::dynamic_tensor( ub::dynamic_extents<>{1,2,3,4,5}, 5.f ); + + s_tensor exp1 = st1 + st1 * 2 + st1*st1; + + // type of the expression will be whichever + // tensor type is present at the start of the + // expression + s_tensor exp2 = st1 + t3 * 2 + t3 * st1; + + s_tensor exp3 = st1 + dt1 * 2 + dt1 * t3; + + std::cout< "<<( exp1 == exp2)< "<<( exp2 == exp3)< "<<( t4 == t3)< "<<( t5 == dt1)<{1,2,3,4}; + auto tensor_dynamic_extents_and_dynamic_rank_0 = ub::dynamic_tensor{1,2,3,4}; /** Dynamic extents but static rank * Storage Type: std::array of static rank * Layout: first_order * Initial Value: 0 **/ - auto tensor_dynamic_extents_and_static_rank_1 = ub::tensor>{ub::dynamic_extents<4>{1,2,3,4}}; + auto tensor_dynamic_extents_and_static_rank_1 = ub::fixed_rank_tensor{ub::dynamic_extents<4>{1,2,3,4}}; /** Dynamic extents but dynamic rank * Storage Type: std::vector * Layout: first_order * Initial Value: 0 **/ - auto tensor_dynamic_extents_and_dynamic_rank_2 = ub::tensor>{ub::dynamic_extents<>{1,2,3,4}}; + auto tensor_dynamic_extents_and_dynamic_rank_2 = ub::dynamic_tensor{ub::dynamic_extents<>{1,2,3,4}}; /** Dynamic extents but dynamic rank * Storage Type: std::vector * Layout: first_order * Initial Value: 0.1f **/ - auto tensor_dynamic_extents_and_dynamic_rank_3 = ub::tensor>{ub::dynamic_extents<>{1,2,3,4},0.1}; + auto tensor_dynamic_extents_and_dynamic_rank_3 = ub::dynamic_tensor{ub::dynamic_extents<>{1,2,3,4},0.1}; /** Static extents but static rank * Storage Type: std::array * Layout: first_order * Initial Value: 0 **/ - auto tensor_static_extents_and_static_rank_4 = ub::tensor>(); + auto tensor_static_extents_and_static_rank_4 = ub::static_tensor>(); /** Static extents but static rank * Storage Type: std::array * Layout: first_order * Initial Value: 0 **/ - auto tensor_static_extents_and_static_rank_5 = ub::tensor,ub::first_order>(); + auto tensor_static_extents_and_static_rank_5 = ub::static_tensor,ub::first_order>(); /** Dynamic extents but dynamic rank * Storage Type: std::array * Layout: first_order * Initial Value: 0 **/ - auto tensor_dynamic_extents_and_dynamic_rank_6 = ub::tensor,ub::first_order>{1,2,3,4}; - - /** Dynamic extents but dynamic rank - * Storage Type: std::vector - * Layout: first_order - * Initial Value: 0 - **/ - auto tensor_dynamic_extents_and_dynamic_rank_7 = ub::tensor,ub::first_order,std::vector>{1,2,3,4}; - - /** Static extents but static rank - * Storage Type: std::array of size 24 - * Layout: first_order - * Initial Value: 0 - **/ - auto tensor_static_extents_and_static_rank_8 = ub::tensor,ub::first_order,std::array>(); + auto tensor_dynamic_extents_and_dynamic_rank_6 = ub::dynamic_tensor{1,2,3,4}; auto t1_e = tensor_dynamic_extents_and_dynamic_rank_0.extents(); auto t2_e = tensor_dynamic_extents_and_static_rank_1.extents(); @@ -91,8 +77,6 @@ int main() { auto t5_e = tensor_dynamic_extents_and_dynamic_rank_3.extents(); auto t6_e = tensor_static_extents_and_static_rank_5.extents(); auto t7_e = tensor_dynamic_extents_and_dynamic_rank_6.extents(); - auto t8_e = tensor_dynamic_extents_and_dynamic_rank_7.extents(); - auto t9_e = tensor_static_extents_and_static_rank_8.extents(); auto t1_s = tensor_dynamic_extents_and_dynamic_rank_0.strides(); auto t2_s = tensor_dynamic_extents_and_static_rank_1.strides(); @@ -101,71 +85,27 @@ int main() { auto t5_s = tensor_dynamic_extents_and_dynamic_rank_3.strides(); auto t6_s = tensor_static_extents_and_static_rank_5.strides(); auto t7_s = tensor_dynamic_extents_and_dynamic_rank_6.strides(); - auto t8_s = tensor_dynamic_extents_and_dynamic_rank_7.strides(); - auto t9_s = tensor_static_extents_and_static_rank_8.strides(); - std::cout<<"\nExtents: "<<(t1_e)<<'\n'; - std::cout<<"Strides: "<<(t1_s)<<'\n'; + std::cout<<"\nExtents: "<<(t1_e)<::value<<'\n'; - - /** - * Checking if layout is first order or not - * Output: True - **/ - std::cout<::value<<'\n'; - - /** - * Checking if container is std::vector - * Output: True - **/ - std::cout< >::value<<'\n'; - - /** - * Checking if container is std::array - * Output: True - **/ - std::cout< >::value<<'\n'; - - /** - * Checking if extents is static - * Output: True - **/ - std::cout<::value<<'\n'; - - /** - * Checking if extents is dynamic - * Output: True - **/ - std::cout<::value<<'\n'; + std::cout<<"\nExtents: "<<(t7_e)< +template void copy(const SizeType p, SizeType const*const n, PointerOut c, SizeType const*const wc, PointerIn a, SizeType const*const wa) { - static_assert( std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::copy: Argument types for pointers are not pointer types."); - if( p == 0 ) - return; + static_assert( std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::copy: Argument types for pointers are not pointer types."); + if( p == 0 ) + return; - if(c == nullptr || a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + if(c == nullptr || a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); - if(wc == nullptr || wa == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + if(wc == nullptr || wa == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); - if(n == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + if(n == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); - std::function lambda; + std::function lambda; - lambda = [&lambda, n, wc, wa](SizeType r, PointerOut c, PointerIn a) - { - if(r > 0) - for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d) - lambda(r-1, c, a ); - else - for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d) - *c = *a; - }; + lambda = [&lambda, n, wc, wa](SizeType r, PointerOut c, PointerIn a) + { + if(r > 0) + for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d) + lambda(r-1, c, a ); + else + for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d) + *c = *a; + }; - lambda( p-1, c, a ); + lambda( p-1, c, a ); } @@ -86,41 +86,41 @@ void copy(const SizeType p, SizeType const*const n, * @param[in] wa pointer to the strides of input tensor a * @param[in] op unary operation */ -template +template void transform(const SizeType p, SizeType const*const n, PointerOut c, SizeType const*const wc, PointerIn a, SizeType const*const wa, UnaryOp op) { - static_assert( std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); - if( p == 0 ) - return; + static_assert( std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); + if( p == 0 ) + return; - if(c == nullptr || a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(c == nullptr || a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(wc == nullptr || wa == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(wc == nullptr || wa == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(n == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(n == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - std::function lambda; + std::function lambda; - lambda = [&lambda, n, wc, wa, op](SizeType r, PointerOut c, PointerIn a) - { - if(r > 0) - for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d) - lambda(r-1, c, a); - else - for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d) - *c = op(*a); - }; + lambda = [&lambda, n, wc, wa, op](SizeType r, PointerOut c, PointerIn a) + { + if(r > 0) + for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d) + lambda(r-1, c, a); + else + for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d) + *c = op(*a); + }; - lambda( p-1, c, a ); + lambda( p-1, c, a ); } @@ -140,36 +140,36 @@ ValueType accumulate(SizeType const p, SizeType const*const n, PointerIn a, SizeType const*const w, ValueType k) { - static_assert(std::is_pointer::value, - "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); + static_assert(std::is_pointer::value, + "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); - if( p == 0 ) - return k; + if( p == 0 ) + return k; - if(a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(w == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(w == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(n == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(n == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - std::function lambda; + std::function lambda; - lambda = [&lambda, n, w](SizeType r, PointerIn a, ValueType k) - { - if(r > 0u) - for(auto d = 0u; d < n[r]; a += w[r], ++d) - k = lambda(r-1, a, k); - else - for(auto d = 0u; d < n[0]; a += w[0], ++d) - k += *a; - return k; - }; + lambda = [&lambda, n, w](SizeType r, PointerIn a, ValueType k) + { + if(r > 0u) + for(auto d = 0u; d < n[r]; a += w[r], ++d) + k = lambda(r-1, a, k); + else + for(auto d = 0u; d < n[0]; a += w[0], ++d) + k += *a; + return k; + }; - return lambda( p-1, a, k ); + return lambda( p-1, a, k ); } /** @brief Performs a reduce operation with all elements of the tensor and an initial value @@ -189,37 +189,37 @@ ValueType accumulate(SizeType const p, SizeType const*const n, PointerIn a, SizeType const*const w, ValueType k, BinaryOp op) { - static_assert(std::is_pointer::value, - "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); + static_assert(std::is_pointer::value, + "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); - if( p == 0 ) - return k; + if( p == 0 ) + return k; - if(a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(w == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(w == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(n == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(n == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - std::function lambda; + std::function lambda; - lambda = [&lambda, n, w, op](SizeType r, PointerIn a, ValueType k) - { - if(r > 0u) - for(auto d = 0u; d < n[r]; a += w[r], ++d) - k = lambda(r-1, a, k); - else - for(auto d = 0u; d < n[0]; a += w[0], ++d) - k = op ( k, *a ); - return k; - }; + lambda = [&lambda, n, w, op](SizeType r, PointerIn a, ValueType k) + { + if(r > 0u) + for(auto d = 0u; d < n[r]; a += w[r], ++d) + k = lambda(r-1, a, k); + else + for(auto d = 0u; d < n[0]; a += w[0], ++d) + k = op ( k, *a ); + return k; + }; - return lambda( p-1, a, k ); + return lambda( p-1, a, k ); } /** @brief Transposes a tensor @@ -243,41 +243,41 @@ void trans( SizeType const p, SizeType const*const na, SizeType const*const pi, PointerIn a, SizeType const*const wa) { - static_assert( std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::trans: Argument types for pointers are not pointer types."); + static_assert( std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::trans: Argument types for pointers are not pointer types."); - if( p < 2) - return; + if( p < 2) + return; - if(c == nullptr || a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(c == nullptr || a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - if(na == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null."); + if(na == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null."); - if(wc == nullptr || wa == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(wc == nullptr || wa == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - if(na == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(na == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - if(pi == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(pi == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - std::function lambda; + std::function lambda; - lambda = [&lambda, na, wc, wa, pi](SizeType r, PointerOut c, PointerIn a) - { - if(r > 0) - for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) - lambda(r-1, c, a); - else - for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) - *c = *a; - }; + lambda = [&lambda, na, wc, wa, pi](SizeType r, PointerOut c, PointerIn a) + { + if(r > 0) + for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) + lambda(r-1, c, a); + else + for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) + *c = *a; + }; - lambda( p-1, c, a ); + lambda( p-1, c, a ); } @@ -303,35 +303,35 @@ void trans( SizeType const p, std::complex* c, SizeType const*const wc, std::complex* a, SizeType const*const wa) { - if( p < 2) - return; + if( p < 2) + return; - if(c == nullptr || a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(c == nullptr || a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - if(wc == nullptr || wa == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(wc == nullptr || wa == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - if(na == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(na == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - if(pi == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(pi == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - std::function* c, std::complex* a)> lambda; + std::function* c, std::complex* a)> lambda; - lambda = [&lambda, na, wc, wa, pi](SizeType r, std::complex* c, std::complex* a) - { - if(r > 0) - for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) - lambda(r-1, c, a); - else - for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) - *c = std::conj(*a); - }; + lambda = [&lambda, na, wc, wa, pi](SizeType r, std::complex* c, std::complex* a) + { + if(r > 0) + for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) + lambda(r-1, c, a); + else + for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) + *c = std::conj(*a); + }; - lambda( p-1, c, a ); + lambda( p-1, c, a ); } diff --git a/include/boost/numeric/ublas/tensor/detail/basic_type_traits.hpp b/include/boost/numeric/ublas/tensor/detail/basic_type_traits.hpp new file mode 100644 index 000000000..eead93a0c --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/basic_type_traits.hpp @@ -0,0 +1,65 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_BASIC_TYPE_TRAITS_HPP +#define BOOST_UBLAS_TENSOR_BASIC_TYPE_TRAITS_HPP + +#include +#include + +namespace boost::numeric::ublas { + +/** @brief Checks if the extents or strides is dynamic + * + * @tparam E of type basic_extents or basic_static_extents + * + */ +template struct is_dynamic : std::false_type {}; + +template +inline static constexpr bool const is_dynamic_v = is_dynamic::value; + +/** @brief Checks if the extents or strides is static + * + * @tparam E of type basic_extents or basic_static_extents + * + */ +template struct is_static : std::false_type {}; + +template +inline static constexpr bool const is_static_v = is_static::value; + +/** @brief Checks if the extents or strides has dynamic rank + * + * @tparam E of type basic_extents or basic_static_extents + * + */ +template +struct is_dynamic_rank : std::false_type {}; + +template +inline static constexpr bool const is_dynamic_rank_v = is_dynamic_rank::value; + +/** @brief Checks if the extents or strides has static rank + * + * @tparam E of type basic_extents or basic_static_extents + * + */ +template +struct is_static_rank : std::false_type {}; + +template +inline static constexpr bool const is_static_rank_v = is_static_rank::value; + +} // namespace boost::numeric::ublas::detail + +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/extents_functions.hpp b/include/boost/numeric/ublas/tensor/detail/extents_functions.hpp index 8e8fa9555..0fbf28fd8 100644 --- a/include/boost/numeric/ublas/tensor/detail/extents_functions.hpp +++ b/include/boost/numeric/ublas/tensor/detail/extents_functions.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,13 +13,13 @@ #ifndef _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP_ #define _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP_ -#include +#include #include #include #include #include #include - +#include namespace boost::numeric::ublas::detail{ @@ -141,11 +141,11 @@ namespace boost::numeric::ublas::detail{ template inline - constexpr auto squeeze_impl( basic_fixed_rank_extents const& e ){ + auto squeeze_impl( basic_fixed_rank_extents const& e ){ if constexpr( N <= 2 ){ return e; }else{ - return squeeze_impl(e.to_dynamic_extents()); + return squeeze_impl(basic_extents(e)); } } @@ -157,28 +157,15 @@ namespace boost::numeric::ublas { /** @brief Returns true if size > 1 and all elements > 0 or size == 1 && e[0] == 1 */ template -inline +[[nodiscard]] inline constexpr bool valid(ExtentsType const &e) { - static_assert(detail::is_extents::value, "boost::numeric::ublas::valid() : invalid type, type should be an extents"); - - using size_type = typename ExtentsType::size_type; - using value_type = typename ExtentsType::value_type; - - if ( e.size() == size_type(1) ){ - - return e[0] == value_type(1); - - } - if ( e.size() > size_type(1) ){ - - return std::all_of(e.begin(), e.end(), [](auto const &a) { return a > value_type(0); }); - - }else{ + static_assert(is_extents_v, "boost::numeric::ublas::valid() : invalid type, type should be an extents"); - return false; + auto greater_than_zero = [](auto const& a){ return a > 0u; }; - } + if( e.size() == 1u ) return e[0] == 1u; + return !e.empty() && std::all_of(e.begin(), e.end(), greater_than_zero ); } /** @@ -189,23 +176,21 @@ constexpr bool valid(ExtentsType const &e) { */ template -inline +[[nodiscard]] inline std::string to_string(T const &e) { - static_assert(detail::is_extents::value || detail::is_strides::value, + using value_type = typename T::value_type; + + static_assert(is_extents_v ||is_strides_v, "boost::numeric::ublas::to_string() : invalid type, type should be an extents or a strides"); - if (e.empty()) { - return "[]"; - } + if ( e.empty() ) return "[]"; std::stringstream ss; ss << "[ "; - for (auto i = typename T::size_type(0); i < e.size() - 1; i++) { - ss << e[i] << ", "; - } + std::copy( e.begin(), e.end() - 1, std::ostream_iterator(ss,", ") ); ss << e.back() << " ]"; @@ -217,19 +202,14 @@ std::string to_string(T const &e) { * @returns true if (1,1,[1,...,1]) */ template -inline +[[nodiscard]] inline constexpr bool is_scalar(ExtentsType const &e) { - static_assert(detail::is_extents::value, "boost::numeric::ublas::is_scalar() : invalid type, type should be an extents"); - - using size_type = typename ExtentsType::size_type; - using value_type = typename ExtentsType::value_type; + static_assert(is_extents_v, "boost::numeric::ublas::is_scalar() : invalid type, type should be an extents"); + + auto equal_one = [](auto const &a) { return a == 1u; }; - if ( e.size() == size_type(0) ){ - return false; - }else{ - return std::all_of(e.begin(), e.end(), [](auto const &a) { return a == value_type(1); }); - } + return !e.empty() && std::all_of(e.begin(), e.end(), equal_one); } /** @brief Returns true if this has a vector shape @@ -237,35 +217,19 @@ constexpr bool is_scalar(ExtentsType const &e) { * @returns true if (1,n,[1,...,1]) or (n,1,[1,...,1]) with n > 1 */ template -inline +[[nodiscard]] inline constexpr bool is_vector(ExtentsType const &e) { - static_assert(detail::is_extents::value, "boost::numeric::ublas::is_vector() : invalid type, type should be an extents"); - - using size_type = typename ExtentsType::size_type; - using value_type = typename ExtentsType::value_type; - - if (e.size() == size_type(0)) { - - return false; + static_assert(is_extents_v, "boost::numeric::ublas::is_vector() : invalid type, type should be an extents"); - } else if (e.size() == size_type(1)) { + auto greater_one = [](auto const &a) { return a > 1u; }; + auto equal_one = [](auto const &a) { return a == 1u; }; - return e.at(0) > value_type(1); - - }else{ - - auto greater_one = [](auto const &a) { - return a > value_type(1); - }; - auto equal_one = [](auto const &a) { - return a == value_type(1); - }; - - return std::any_of(e.begin(), e.begin() + 2, greater_one) && - std::any_of(e.begin(), e.begin() + 2, equal_one) && - std::all_of(e.begin() + 2, e.end(), equal_one); - } + if (e.size() == 0u) return false; + else if (e.size() == 1u) return e[0] > 1u; + else return std::any_of(e.begin(), e.begin() + 2, greater_one) && + std::any_of(e.begin(), e.begin() + 2, equal_one) && + std::all_of(e.begin() + 2, e.end(), equal_one); } @@ -274,30 +238,16 @@ constexpr bool is_vector(ExtentsType const &e) { * @returns true if (m,n,[1,...,1]) with m > 1 and n > 1 */ template -inline +[[nodiscard]] inline constexpr bool is_matrix(ExtentsType const &e) { - static_assert(detail::is_extents::value, "boost::numeric::ublas::is_matrix() : invalid type, type should be an extents"); + static_assert(is_extents_v, "boost::numeric::ublas::is_matrix() : invalid type, type should be an extents"); - using size_type = typename ExtentsType::size_type; - using value_type = typename ExtentsType::value_type; - - if (e.size() < size_type(2)) { - return false; - }else{ - - auto greater_one = [](auto const &a) { - return a > value_type(1); - }; - - auto equal_one = [](auto const &a) { - return a == value_type(1); - }; - - return std::all_of(e.begin(), e.begin() + 2, greater_one) && - std::all_of(e.begin() + 2, e.end(), equal_one); - } + auto greater_one = [](auto const &a) { return a > 1u; }; + auto equal_one = [](auto const &a) { return a == 1u; }; + return ( e.size() >= 2u ) && std::all_of(e.begin(), e.begin() + 2, greater_one) && + std::all_of(e.begin() + 2, e.end(), equal_one); } /** @brief Returns true if this is has a tensor shape @@ -305,28 +255,14 @@ constexpr bool is_matrix(ExtentsType const &e) { * @returns true if !empty() && !is_scalar() && !is_vector() && !is_matrix() */ template -inline +[[nodiscard]] inline constexpr bool is_tensor(ExtentsType const &e) { - static_assert(detail::is_extents::value, "boost::numeric::ublas::is_tensor() : invalid type, type should be an extents"); + static_assert(is_extents_v, "boost::numeric::ublas::is_tensor() : invalid type, type should be an extents"); - using size_type = typename ExtentsType::size_type; - using value_type = typename ExtentsType::value_type; + auto greater_one = [](auto const &a) { return a > 1u;}; - if (e.size() < size_type(3)) { - - return false; - - }else{ - - auto greater_one = [](auto const &a) { - return a > value_type(1); - }; - - return std::any_of(e.begin() + 2, e.end(), greater_one); - - } - + return ( e.size() >= 3u ) && std::any_of(e.begin() + 2, e.end(), greater_one); } /** @brief Eliminates singleton dimensions when size > 2 @@ -342,34 +278,54 @@ constexpr bool is_tensor(ExtentsType const &e) { * @returns basic_extents with squeezed extents */ template -inline +[[nodiscard]] inline auto squeeze(ExtentsType const &e) { - static_assert(detail::is_extents::value, "boost::numeric::ublas::squeeze() : invalid type, type should be an extents"); + static_assert(is_extents_v, "boost::numeric::ublas::squeeze() : invalid type, type should be an extents"); return detail::squeeze_impl(e); } /** @brief Returns the product of extents */ template -inline +[[nodiscard]] inline constexpr auto product(ExtentsType const &e) { - static_assert(detail::is_extents::value, "boost::numeric::ublas::product() : invalid type, type should be an extents"); + static_assert(is_extents_v, "boost::numeric::ublas::product() : invalid type, type should be an extents"); - using value_type = typename ExtentsType::value_type; - - if (e.empty()) { + if ( e.empty() ) return 0u; + else return std::accumulate(e.begin(), e.end(), 1u, std::multiplies<>()) ; +} - return value_type(0); - - }else{ - return value_type( std::accumulate(e.begin(), e.end(), value_type(1), std::multiplies<>()) ); +template && is_extents_v + , int> = 0 +> +[[nodiscard]] inline +constexpr bool operator==(LExtents const& lhs, RExtents const& rhs) noexcept{ + + static_assert( std::is_same_v, + "boost::numeric::ublas::operator==(LExtents, RExtents) : LHS value type should be same as RHS value type"); - } + return ( lhs.size() == rhs.size() ) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} +template && is_extents_v + , int> = 0 +> +[[nodiscard]] inline +constexpr bool operator!=(LExtents const& lhs, RExtents const& rhs) noexcept{ + + static_assert( std::is_same_v, + "boost::numeric::ublas::operator!=(LExtents, RExtents) : LHS value type should be same as RHS value type"); + + return !( lhs == rhs ); } } // namespace boost::numeric::ublas + #endif diff --git a/include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp b/include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp index dfa6a4d94..36745e607 100644 --- a/include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp +++ b/include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com // Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/include/boost/numeric/ublas/tensor/detail/storage_traits.hpp b/include/boost/numeric/ublas/tensor/detail/storage_traits.hpp index 5d2915580..1b209e27c 100644 --- a/include/boost/numeric/ublas/tensor/detail/storage_traits.hpp +++ b/include/boost/numeric/ublas/tensor/detail/storage_traits.hpp @@ -29,52 +29,52 @@ struct storage_traits; template struct storage_traits> { - using array_type = std::vector; + using array_type = std::vector; - using size_type = typename array_type::size_type; - using difference_type = typename array_type::difference_type; - using value_type = typename array_type::value_type; + using size_type = typename array_type::size_type; + using difference_type = typename array_type::difference_type; + using value_type = typename array_type::value_type; - using reference = typename array_type::reference; - using const_reference = typename array_type::const_reference; + using reference = typename array_type::reference; + using const_reference = typename array_type::const_reference; - using pointer = typename array_type::pointer; - using const_pointer = typename array_type::const_pointer; + using pointer = typename array_type::pointer; + using const_pointer = typename array_type::const_pointer; - using iterator = typename array_type::iterator; - using const_iterator = typename array_type::const_iterator; + using iterator = typename array_type::iterator; + using const_iterator = typename array_type::const_iterator; - using reverse_iterator = typename array_type::reverse_iterator; - using const_reverse_iterator = typename array_type::const_reverse_iterator; + using reverse_iterator = typename array_type::reverse_iterator; + using const_reverse_iterator = typename array_type::const_reverse_iterator; - template - using rebind = std::vector::template rebind_alloc>; + template + using rebind = std::vector::template rebind_alloc>; }; template struct storage_traits> { - using array_type = std::array; + using array_type = std::array; - using size_type = typename array_type::size_type; - using difference_type = typename array_type::difference_type; - using value_type = typename array_type::value_type; + using size_type = typename array_type::size_type; + using difference_type = typename array_type::difference_type; + using value_type = typename array_type::value_type; - using reference = typename array_type::reference; - using const_reference = typename array_type::const_reference; + using reference = typename array_type::reference; + using const_reference = typename array_type::const_reference; - using pointer = typename array_type::pointer; - using const_pointer = typename array_type::const_pointer; + using pointer = typename array_type::pointer; + using const_pointer = typename array_type::const_pointer; - using iterator = typename array_type::iterator; - using const_iterator = typename array_type::const_iterator; + using iterator = typename array_type::iterator; + using const_iterator = typename array_type::const_iterator; - using reverse_iterator = typename array_type::reverse_iterator; - using const_reverse_iterator = typename array_type::const_reverse_iterator; + using reverse_iterator = typename array_type::reverse_iterator; + using const_reverse_iterator = typename array_type::const_reverse_iterator; - template - using rebind = std::array; + template + using rebind = std::array; }; } // ublas diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits.hpp deleted file mode 100644 index da379a158..000000000 --- a/include/boost/numeric/ublas/tensor/detail/type_traits.hpp +++ /dev/null @@ -1,111 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_HPP - -#include -#include - -namespace boost::numeric::ublas::detail { - -/** @brief Checks if the extents or strides is dynamic - * - * @tparam E of type basic_extents or basic_static_extents - * - */ -template struct is_dynamic : std::false_type {}; - -template -inline static constexpr bool const is_dynamic_v = is_dynamic::value; - -/** @brief Checks if the extents or strides is static - * - * @tparam E of type basic_extents or basic_static_extents - * - */ -template struct is_static : std::false_type {}; - -template -inline static constexpr bool const is_static_v = is_static::value; - -/** @brief Checks if the extents or strides has dynamic rank - * - * @tparam E of type basic_extents or basic_static_extents - * - */ -template -struct is_dynamic_rank : std::false_type {}; - -template -inline static constexpr bool const is_dynamic_rank_v = is_dynamic_rank::value; - -/** @brief Checks if the extents or strides has static rank - * - * @tparam E of type basic_extents or basic_static_extents - * - */ -template -struct is_static_rank : std::false_type {}; - -template -inline static constexpr bool const is_static_rank_v = is_static_rank::value; - -/** @brief Checks if type has member function resize with - * prototype resize(size_type) and return type can be - * anything and type should have empty constructor. - * @code - * - * struct test1{ - * test1(){...} - * void resize(size_t){...} - * ... - * }; - * - * struct test2{ - * test2(){...} - * ... - * }; - * - * struct test3{ - * test2(int){...} - * void resize(size_t){...} - * }; - * - * auto v = std::vector{}; - * auto vec_val = is_resizable_v; // vec_val == true; - * - * auto a = std::array{}; - * auto arr_val = is_resizable_v; // arr_val == false; - * - * auto test1_val = is_resizable_v; // arr_val == true; - * auto test2_val = is_resizable_v; // arr_val == false; - * auto test3_val = is_resizable_v; // arr_val == false bacause test3 does not have empty constuctor. - * - * @endcode -*/ -template -struct is_resizable : std::false_type{}; - -template -struct is_resizable< T, std::void_t< decltype(T{}.resize(0)) > >: std::true_type{}; - -template -inline static constexpr bool const is_resizable_v = is_resizable::value; - -} // namespace boost::numeric::ublas::detail - -#include -#include -#include - -#endif \ No newline at end of file diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_extents.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_extents.hpp new file mode 100644 index 000000000..745659903 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_extents.hpp @@ -0,0 +1,46 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_EXTENTS_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_EXTENTS_HPP + +#include + +namespace boost::numeric::ublas{ + +template class basic_extents; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas{ + + template + struct is_extents< basic_extents > : std::true_type {}; + + template + struct is_dynamic< basic_extents > : std::true_type {}; + + template + struct is_dynamic_rank< basic_extents > : std::true_type {}; + + + namespace detail{ + + template <> struct dynamic_extents_impl<> { + using type = basic_extents; + }; + + } // namespace detail + +} // namespace boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_strides.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_strides.hpp new file mode 100644 index 000000000..5a9a13174 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_strides.hpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_STRIDES_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_STRIDES_HPP + +#include + +namespace boost::numeric::ublas{ + +template class basic_extents; + +template +class basic_strides; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas{ + + template + struct is_strides> : std::true_type {}; + + template + struct is_dynamic< basic_strides > : std::true_type {}; + + template + struct is_dynamic_rank< basic_strides > : std::true_type {}; + + namespace detail{ + + /** @brief Partial Specialization of strides for basic_extents + * + * + * @tparam Layout either first_order or last_order + * + * @tparam T extents type + * + */ + template + struct strides_impl, Layout> + { + using type = basic_strides; + }; + + } // detail + +} // namespace boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp index 1e188c647..f7fc1927e 100644 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,52 +13,29 @@ #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_EXTENTS_HPP #define BOOST_UBLAS_TENSOR_TYPE_TRAITS_EXTENTS_HPP -namespace boost::numeric::ublas{ - - template struct basic_static_extents; - template struct basic_fixed_rank_extents; - template class basic_extents; - -} // namespace boost::numeric::ublas:: - - -namespace boost::numeric::ublas::detail { +namespace boost::numeric::ublas { // checks if type is extents or not template struct is_extents : std::false_type {}; -template -struct is_extents> : std::true_type {}; - -template -struct is_extents> : std::true_type {}; - -template -struct is_extents> : std::true_type {}; - template inline static constexpr bool const is_extents_v = is_extents::value; -template -struct is_dynamic> : std::true_type {}; - -template -struct is_dynamic> : std::true_type {}; - -template -struct is_static> : std::true_type {}; +namespace detail{ -template -struct is_dynamic_rank< basic_extents > : std::true_type {}; + template + struct dynamic_extents_impl; -template -struct is_static_rank> : std::true_type {}; +} // detail -template -struct is_static_rank> : std::true_type {}; +template +using dynamic_extents = typename detail::dynamic_extents_impl::type; } // namespace boost::numeric::ublas::detail +#include +#include +#include -#endif \ No newline at end of file +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_extents.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_extents.hpp new file mode 100644 index 000000000..e299f5d81 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_extents.hpp @@ -0,0 +1,45 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_EXTENTS_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_EXTENTS_HPP + +#include + +namespace boost::numeric::ublas{ + +template struct basic_fixed_rank_extents; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas{ + + template + struct is_extents< basic_fixed_rank_extents > : std::true_type {}; + + template + struct is_dynamic< basic_fixed_rank_extents > : std::true_type {}; + + template + struct is_static_rank< basic_fixed_rank_extents > : std::true_type {}; + + namespace detail{ + + template struct dynamic_extents_impl { + using type = basic_fixed_rank_extents; + }; + + } // namespace detail + +} // namespace boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_strides.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_strides.hpp new file mode 100644 index 000000000..bb56052e4 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_strides.hpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_STRIDES_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_STRIDES_HPP + +#include + +namespace boost::numeric::ublas{ + +template struct basic_fixed_rank_extents; + +template class basic_fixed_rank_strides; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas{ + + template + struct is_strides< basic_fixed_rank_strides< T, R, L> > : std::true_type {}; + + template + struct is_dynamic< basic_fixed_rank_strides > : std::true_type {}; + + template + struct is_static_rank< basic_fixed_rank_strides > : std::true_type {}; + + namespace detail{ + + /** @brief Partial Specialization of strides for basic_fixed_rank_strides + * + * + * @tparam Layout either first_order or last_order + * + * @tparam T extents type + * + */ + template + struct strides_impl, Layout> + { + using type = basic_fixed_rank_strides; + }; + + } // detail + +} // namespace boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_static_extents.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_static_extents.hpp new file mode 100644 index 000000000..54b13ae08 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_static_extents.hpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_EXTENTS_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_EXTENTS_HPP + +#include + +namespace boost::numeric::ublas{ + +template struct basic_static_extents; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas{ + +template +struct is_extents< basic_static_extents > : std::true_type {}; + +template +struct is_static< basic_static_extents > : std::true_type {}; + +template +struct is_static_rank< basic_static_extents > : std::true_type {}; + +} // namespace boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_static_strides.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_static_strides.hpp new file mode 100644 index 000000000..bf8ce0604 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_static_strides.hpp @@ -0,0 +1,59 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_STRIDES_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_STRIDES_HPP + +#include + +namespace boost::numeric::ublas{ + +template struct basic_static_extents; + +template struct basic_static_strides; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas{ + + template + struct is_strides< basic_static_strides< basic_static_extents, L > > : std::true_type {}; + + template + struct is_static< basic_static_strides< basic_static_extents, L > > : std::true_type {}; + + template + struct is_static_rank< basic_static_strides< basic_static_extents, L > > : std::true_type {}; + + namespace detail{ + + /** @brief Partial Specialization of strides for basic_static_extents + * + * + * @tparam Layout either first_order or last_order + * + * @tparam R rank of extents + * + * @tparam Extents parameter pack of extents + * + */ + template + struct strides_impl, Layout> + { + using type = basic_static_strides, Layout>; + }; + + } // detail + +} // namespace boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp index 49b3e273c..1b7c1381f 100644 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,56 +13,33 @@ #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_STRIDES_HPP #define BOOST_UBLAS_TENSOR_TYPE_TRAITS_STRIDES_HPP -namespace boost::numeric::ublas{ - - template struct basic_static_extents; - template struct basic_fixed_rank_extents; - template class basic_extents; +namespace boost::numeric::ublas { - template struct basic_static_strides; - template class basic_fixed_rank_strides; - template class basic_strides; + // checks if type is strides or not + template + struct is_strides : std::false_type {}; -} // namespace boost::numeric::ublas:: + template + inline static constexpr bool const is_strides_v = is_strides::value; + namespace detail{ + template struct strides_impl; + } // detail -namespace boost::numeric::ublas::detail { - -// checks if type is strides or not -template -struct is_strides : std::false_type {}; - -template -inline static constexpr bool const is_strides_v = is_strides::value; - -template -struct is_strides< basic_static_strides< basic_static_extents, L > > : std::true_type {}; - -template -struct is_strides< basic_fixed_rank_strides< T, R, L> > : std::true_type {}; - -template -struct is_strides> : std::true_type {}; - -template -struct is_dynamic< basic_strides > : std::true_type {}; - -template -struct is_dynamic< basic_fixed_rank_strides > : std::true_type {}; - -template -struct is_static< basic_static_strides< basic_static_extents, L > > : std::true_type {}; - -template -struct is_dynamic_rank< basic_strides > : std::true_type {}; - -template -struct is_static_rank< basic_static_strides< basic_static_extents, L > > : std::true_type {}; - -template -struct is_static_rank< basic_fixed_rank_strides > : std::true_type {}; + /** @brief type alias of result of strides::type + * + * @tparam E extents type either basic_extents or basic_static_extents + * + * @tparam Layout either first_order or last_order + * + */ + template + using strides_t = typename detail::strides_impl::type; } // namespace boost::numeric::ublas::detail +#include +#include +#include -#endif \ No newline at end of file +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_tensor.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_tensor.hpp new file mode 100644 index 000000000..563bbc326 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/detail/type_traits_tensor.hpp @@ -0,0 +1,166 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_TENSOR_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_TENSOR_HPP + +#include +#include + +namespace boost::numeric::ublas{ + template class basic_tensor; + + template< typename T, typename F > struct dynamic_tensor; + + template< typename T, std::size_t R, typename F > struct fixed_rank_tensor; + + template< typename T, typename E, typename F > struct static_tensor; +} // namespace boost::numeric::ublas + + +namespace boost::numeric::ublas { + + template + struct tensor_traits; + + template + struct is_valid_tensor: std::is_base_of< basic_tensor, T >{}; + + template + inline static constexpr bool is_valid_tensor_v = is_valid_tensor::value; + + template + struct tensor_rebind; + + template + using tensor_rebind_t = typename tensor_rebind::type; + + template + struct result_tensor; + + template + using result_tensor_t = typename result_tensor::type; + + struct tensor_tag {}; + + struct dynamic_tensor_tag : tensor_tag{}; + struct static_tensor_tag : tensor_tag{}; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas{ + + template + struct tensor_rebind< dynamic_tensor, NewValue > { + using type = dynamic_tensor< NewValue, F >; + }; + + template + struct tensor_rebind< dynamic_tensor, NewValue, NewLayout > { + using type = dynamic_tensor< NewValue, NewLayout >; + }; + + template + struct is_static< dynamic_tensor > : std::false_type{}; + + template + struct is_static_rank< dynamic_tensor > : std::false_type{}; + + template + struct is_dynamic< dynamic_tensor > : std::true_type{}; + + template + struct is_dynamic_rank< dynamic_tensor > : std::true_type{}; + + template + struct result_tensor< V, dynamic_extents<>, F >{ + using type = dynamic_tensor< V, F >; + }; + +} // namespace boost::numeric::ublas::detail + + +namespace boost::numeric::ublas{ + + template + struct tensor_rebind< fixed_rank_tensor, NewValue > { + using type = fixed_rank_tensor< NewValue, R, F >; + }; + + template + struct tensor_rebind< fixed_rank_tensor, NewValue, NewExtents > { + using type = fixed_rank_tensor< NewValue, NewExtents::_size, F >; + }; + + template + struct tensor_rebind< fixed_rank_tensor, NewValue, NewExtents, NewLayout > { + using type = fixed_rank_tensor< NewValue, NewExtents::_size, NewLayout >; + }; + + template + struct is_static< fixed_rank_tensor > : std::false_type{}; + + template + struct is_static_rank< fixed_rank_tensor > : std::true_type{}; + + template + struct is_dynamic< fixed_rank_tensor > : std::true_type{}; + + template + struct is_dynamic_rank< fixed_rank_tensor > : std::false_type{}; + + template + struct result_tensor< V, basic_fixed_rank_extents, F >{ + using type = fixed_rank_tensor< V, R, F >; + }; + +} // namespace boost::numeric::ublas::detail + +namespace boost::numeric::ublas{ + + template + struct tensor_rebind< static_tensor, NewValue > { + using type = static_tensor< NewValue, E, F >; + }; + + template + struct tensor_rebind< static_tensor, NewValue, NewExtents > { + using type = static_tensor< NewValue, NewExtents, F >; + }; + + template + struct tensor_rebind< static_tensor, NewValue, NewExtents, NewLayout > { + using type = static_tensor< NewValue, NewExtents, NewLayout >; + }; + + + template + struct is_static< static_tensor > : std::true_type{}; + + template + struct is_static_rank< static_tensor > : std::true_type{}; + + template + struct is_dynamic< static_tensor > : std::false_type{}; + + template + struct is_dynamic_rank< static_tensor > : std::false_type{}; + + template + struct result_tensor< V, basic_static_extents, F >{ + using type = static_tensor< V, basic_static_extents, F >; + }; + +} // namespace boost::numeric::ublas::detail + + +#endif diff --git a/include/boost/numeric/ublas/tensor/dynamic_extents.hpp b/include/boost/numeric/ublas/tensor/dynamic_extents.hpp index ae37f8f9f..77446976e 100644 --- a/include/boost/numeric/ublas/tensor/dynamic_extents.hpp +++ b/include/boost/numeric/ublas/tensor/dynamic_extents.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -14,16 +14,12 @@ #ifndef _BOOST_NUMERIC_UBLAS_TENSOR_DYNAMIC_EXTENTS_HPP_ #define _BOOST_NUMERIC_UBLAS_TENSOR_DYNAMIC_EXTENTS_HPP_ -#include -#include #include #include -#include #include #include -#include - -#include +#include +#include namespace boost { namespace numeric { @@ -37,410 +33,201 @@ namespace ublas { template class basic_extents { - static_assert( std::numeric_limits::value_type>::is_integer, "Static error in basic_layout: type must be of type integer."); - static_assert(!std::numeric_limits::value_type>::is_signed, "Static error in basic_layout: type must be of type unsigned integer."); + static_assert( std::numeric_limits::value_type>::is_integer, "Static error in basic_layout: type must be of type integer."); + static_assert(!std::numeric_limits::value_type>::is_signed, "Static error in basic_layout: type must be of type unsigned integer."); public: - using base_type = std::vector; - using value_type = typename base_type::value_type; - using const_reference = typename base_type::const_reference; - using reference = typename base_type::reference; - using size_type = typename base_type::size_type; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - - - /** @brief Default constructs basic_extents - * - * @code auto ex = basic_extents{}; - */ - basic_extents() - : _base{} - { - } - - /** @brief Copy constructs basic_extents from a one-dimensional container - * - * @code auto ex = basic_extents( std::vector(3u,3u) ); - * - * @note checks if size > 1 and all elements > 0 - * - * @param b one-dimensional std::vector container - */ - explicit basic_extents(base_type const& b) - : _base(b) - { - if ( !valid(*this) ){ - throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); - } - } - - /** @brief Move constructs basic_extents from a one-dimensional container - * - * @code auto ex = basic_extents( std::vector(3u,3u) ); - * - * @note checks if size > 1 and all elements > 0 - * - * @param b one-dimensional container of type std::vector - */ - explicit basic_extents(base_type && b) - : _base(std::move(b)) - { - if (!valid(*this)){ - throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); - } - } - - /** @brief Constructs basic_extents from an initializer list - * - * @code auto ex = basic_extents{3,2,4}; - * - * @note checks if size > 1 and all elements > 0 - * - * @param l one-dimensional list of type std::initializer - */ - basic_extents(std::initializer_list l) - : basic_extents( base_type(std::move(l)) ) - { - } - - /** @brief Constructs basic_extents from a range specified by two iterators - * - * @code auto ex = basic_extents(a.begin(), a.end()); - * - * @note checks if size > 1 and all elements > 0 - * - * @param first iterator pointing to the first element - * @param last iterator pointing to the next position after the last element - */ - basic_extents(const_iterator first, const_iterator last) - : basic_extents ( base_type( first,last ) ) - { - } - - /** @brief Copy constructs basic_extents */ - basic_extents(basic_extents const& l ) - : _base(l._base) - { - } - - /** @brief Move constructs basic_extents */ - basic_extents(basic_extents && l ) noexcept - : _base(std::move(l._base)) - { - } - - - template::value - && ( !std::is_same_v ) - ,int > = 0 - > - basic_extents(OtherExtentsType const& e){ - _base.resize(e.size()); - for(auto i = size_type(0); i < size(); ++i){ - _base[i] = e[i]; - } - } - - ~basic_extents() = default; - - basic_extents& operator=(basic_extents other) noexcept - { - swap (*this, other); - return *this; - } - - friend void swap(basic_extents& lhs, basic_extents& rhs) { - std::swap(lhs._base , rhs._base ); - } - - const_pointer data() const - { - return this->_base.data(); - } - - const_reference operator[] (size_type p) const - { - return this->_base[p]; - } - - const_reference at (size_type p) const - { - return this->_base.at(p); - } - - reference operator[] (size_type p) - { - return this->_base[p]; - } - - reference at (size_type p) - { - return this->_base.at(p); - } - - const_reference back () const - { - return this->_base.back(); - } - - - bool empty() const - { - return this->_base.empty(); - } - - size_type size() const - { - return this->_base.size(); - } - - void clear() - { - this->_base.clear(); - } - - bool operator == (basic_extents const& b) const - { - return _base == b._base; - } - - bool operator != (basic_extents const& b) const - { - return !( _base == b._base ); - } - - const_iterator - begin() const - { - return _base.begin(); - } - - const_iterator - end() const - { - return _base.end(); - } - - base_type const& base() const { return _base; } + using base_type = std::vector; + using value_type = typename base_type::value_type; + using const_reference = typename base_type::const_reference; + using reference = typename base_type::reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + + + /** @brief Default constructs basic_extents + * + * @code auto ex = basic_extents{}; + */ + basic_extents() + : _base{} + { + } + + /** @brief Copy constructs basic_extents from a one-dimensional container + * + * @code auto ex = basic_extents( std::vector(3u,3u) ); + * + * @note checks if size > 1 and all elements > 0 + * + * @param b one-dimensional std::vector container + */ + explicit basic_extents(base_type const& b) + : _base(b) + { + if ( !valid(*this) ){ + throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + /** @brief Move constructs basic_extents from a one-dimensional container + * + * @code auto ex = basic_extents( std::vector(3u,3u) ); + * + * @note checks if size > 1 and all elements > 0 + * + * @param b one-dimensional container of type std::vector + */ + explicit basic_extents(base_type && b) + : _base(std::move(b)) + { + if (!valid(*this)){ + throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + /** @brief Constructs basic_extents from an initializer list + * + * @code auto ex = basic_extents{3,2,4}; + * + * @note checks if size > 1 and all elements > 0 + * + * @param l one-dimensional list of type std::initializer + */ + basic_extents(std::initializer_list l) + : basic_extents( base_type(std::move(l)) ) + { + } + + /** @brief Constructs basic_extents from a range specified by two iterators + * + * @code auto ex = basic_extents(a.begin(), a.end()); + * + * @note checks if size > 1 and all elements > 0 + * + * @param first iterator pointing to the first element + * @param last iterator pointing to the next position after the last element + */ + basic_extents(const_iterator first, const_iterator last) + : basic_extents ( base_type( first,last ) ) + { + } + + /** @brief Copy constructs basic_extents */ + basic_extents(basic_extents const& l ) + : _base(l._base) + { + } + + /** @brief Move constructs basic_extents */ + basic_extents(basic_extents && l ) noexcept + : _base(std::move(l._base)) + { + } + + + template::value + ,int > = 0 + > + basic_extents(OtherExtentsType const& e) + : _base(e.size()) + { + std::copy(e.begin(),e.end(), _base.begin()); + } + + ~basic_extents() = default; + + basic_extents& operator=(basic_extents other) noexcept + { + swap (*this, other); + return *this; + } + + friend void swap(basic_extents& lhs, basic_extents& rhs) { + std::swap(lhs._base , rhs._base ); + } + + [[nodiscard]] inline + constexpr const_pointer data() const + { + return this->_base.data(); + } + + [[nodiscard]] inline + constexpr const_reference operator[] (size_type p) const noexcept + { + return this->_base[p]; + } + + [[nodiscard]] inline + constexpr const_reference at (size_type p) const + { + return this->_base.at(p); + } + + [[nodiscard]] inline + constexpr reference operator[] (size_type p) + { + return this->_base[p]; + } + + [[nodiscard]] inline + constexpr reference at (size_type p) + { + return this->_base.at(p); + } + + [[nodiscard]] inline + constexpr const_reference back () const + { + return this->_base.back(); + } + + + [[nodiscard]] inline + constexpr bool empty() const + { + return this->_base.empty(); + } + + [[nodiscard]] inline + constexpr size_type size() const + { + return this->_base.size(); + } + + inline + constexpr void clear() + { + this->_base.clear(); + } + + [[nodiscard]] inline + constexpr const_iterator + begin() const + { + return _base.begin(); + } + + [[nodiscard]] inline + constexpr const_iterator + end() const + { + return _base.end(); + } + + [[nodiscard]] inline + constexpr base_type const& base() const { return _base; } private: - base_type _base; - -}; - -// using shape = basic_extents; - - -/** @brief Template class for storing tensor extents for compile time. - * - * @code basic_static_extents<1,2,3,4> t @endcode - * @tparam E parameter pack of extents - * - */ -template -struct basic_fixed_rank_extents -{ - - - static constexpr std::size_t const _size = N; - - - using base_type = std::array; - using value_type = typename base_type::value_type; - using const_reference = typename base_type::const_reference; - using reference = typename base_type::reference; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - using size_type = typename base_type::size_type; - - static_assert( std::numeric_limits::is_integer, "Static error in basic_fixed_rank_extents: type must be of type integer."); - static_assert(!std::numeric_limits::is_signed, "Static error in basic_fixed_rank_extents: type must be of type unsigned integer."); - - //@returns the rank of basic_static_extents - [[nodiscard]] - static constexpr size_type size() noexcept { return _size; } - - [[nodiscard]] inline - constexpr const_reference at(size_type k) const{ - return _base.at(k); - } - - [[nodiscard]] inline - constexpr reference at(size_type k){ - return _base.at(k); - } - - [[nodiscard]] inline - constexpr const_reference operator[](size_type k) const noexcept{ - return _base[k]; - } - - [[nodiscard]] inline - constexpr reference operator[](size_type k) noexcept{ - return _base[k]; - } - - // default constructor - constexpr basic_fixed_rank_extents() = default; - - constexpr basic_fixed_rank_extents(std::initializer_list li){ - if( li.size() > _size ){ - throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than _size"); - } - - std::copy(li.begin(), li.end(), _base.begin()); - - if ( !valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); - } - } - - constexpr basic_fixed_rank_extents(const_iterator begin, const_iterator end){ - if( std::distance(begin,end) > _size ){ - throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than _size"); - } - - std::copy(begin, end, _base.begin()); - - if ( !valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); - } - } - - void fill( value_type value ){ - _base.fill(value); - } - - template::value - && ( !std::is_same_v ) - ,int > = 0 - > - constexpr basic_fixed_rank_extents(OtherExtentsType const& e){ - for(auto i = size_type(0); i < size(); ++i){ - _base[i] = e[i]; - } - } - - constexpr basic_fixed_rank_extents(base_type const& data) - : _base(data) - { - if ( !valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); - } - } - - constexpr basic_fixed_rank_extents(base_type&& data) - : _base(std::move(data)) - { - if ( !valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); - } - } - - /** @brief Returns the std::vector containing extents */ - [[nodiscard]] inline - auto to_vector() const { - return std::vector( _base.begin(), _base.end() ); - } - - /** @brief Returns the std::vector containing extents */ - [[nodiscard]] inline - constexpr base_type const& base() const { - return _base; - } - - /** @brief Returns the std::vector containing extents */ - [[nodiscard]] inline - constexpr base_type& base() { - return _base; - } - - /** @brief Returns the basic_extents containing extents */ - [[nodiscard]] inline - auto to_dynamic_extents() const { - return basic_extents(this->to_vector()); - } - - /** @brief Checks if extents is empty or not - * - * @returns true if rank is 0 else false - * - */ - [[nodiscard]] inline - constexpr bool empty() const noexcept { return _size == size_type{0}; } - - friend void swap(basic_fixed_rank_extents& lhs, basic_fixed_rank_extents& rhs) { - std::swap(lhs._base , rhs._base ); - } - - [[nodiscard]] inline - const_pointer data() const - { - return _base.data(); - } - - [[nodiscard]] inline - const_iterator - begin() const - { - return _base.begin(); - } - - [[nodiscard]] inline - const_iterator - end() const - { - return _base.end(); - } - - const_reference back () const - { - return _base.back(); - } - - /** @brief Returns true if both extents are equal else false */ - [[nodiscard]] inline - constexpr bool operator==(basic_fixed_rank_extents const &other) const { - return _base == other._base; - } - - /** @brief Returns false if both extents are equal else true */ - [[nodiscard]] inline - constexpr bool operator!=(basic_fixed_rank_extents const &other) const { - return !(*this == other); - } - - ~basic_fixed_rank_extents() = default; + base_type _base; -private: - base_type _base{}; }; - -namespace detail{ - template - struct dynamic_extents_impl; - - template struct dynamic_extents_impl { - using type = basic_fixed_rank_extents; - }; - - template <> struct dynamic_extents_impl<> { - using type = basic_extents; - }; - -} // namespace detail - - -template -using dynamic_extents = typename detail::dynamic_extents_impl::type; - } // namespace ublas } // namespace numeric } // namespace boost diff --git a/include/boost/numeric/ublas/tensor/dynamic_strides.hpp b/include/boost/numeric/ublas/tensor/dynamic_strides.hpp index 5c025e0c8..d8e6ba94b 100644 --- a/include/boost/numeric/ublas/tensor/dynamic_strides.hpp +++ b/include/boost/numeric/ublas/tensor/dynamic_strides.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -15,16 +15,9 @@ #ifndef _BOOST_UBLAS_TENSOR_DYNAMIC_STRIDES_HPP_ #define _BOOST_UBLAS_TENSOR_DYNAMIC_STRIDES_HPP_ -#include -#include -#include -#include -#include -#include -#include - #include -#include +#include +#include namespace boost { namespace numeric { @@ -47,315 +40,157 @@ class basic_strides { public: - using base_type = std::vector<__int_type>; - - static_assert( std::numeric_limits::is_integer, - "Static error in boost::numeric::ublas::basic_strides: type must be of type integer."); - static_assert(!std::numeric_limits::is_signed, - "Static error in boost::numeric::ublas::basic_strides: type must be of type unsigned integer."); - static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value, - "Static error in boost::numeric::ublas::basic_strides: layout type must either first or last order"); - - - using layout_type = __layout; - using value_type = typename base_type::value_type; - using reference = typename base_type::reference; - using const_reference = typename base_type::const_reference; - using size_type = typename base_type::size_type; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - - - /** @brief Default constructs basic_strides - * - * @code auto ex = basic_strides{}; - */ - constexpr explicit basic_strides() - : _base{} - { - } - - /** @brief Constructs basic_strides from basic_extents for the first- and last-order storage formats - * - * @code auto strides = basic_strides( basic_extents{2,3,4} ); - * - */ - template - basic_strides(basic_extents const& s) - : _base(s.size(),1) - { - if( s.empty() ) - return; - - if( !valid(s) ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : shape is not valid."); - - if( is_vector(s) || is_scalar(s) ) - return; - - if( this->size() < 2 ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : size of strides must be greater or equal 2."); - - - if constexpr (std::is_same::value){ - size_type k = 1ul, kend = this->size(); - for(; k < kend; ++k) - _base[k] = _base[k-1] * s[k-1]; - } - else { - size_type k = this->size()-2, kend = 0ul; - for(; k > kend; --k) - _base[k] = _base[k+1] * s[k+1]; - _base[0] = _base[1] * s[1]; - } - } - - basic_strides(basic_strides const& l) - : _base(l._base) - {} - - basic_strides(basic_strides && l ) - : _base(std::move(l._base)) - {} - - basic_strides(base_type const& l ) - : _base(l) - {} - - basic_strides(base_type && l ) - : _base(std::move(l)) - {} - - ~basic_strides() = default; - - - basic_strides& operator=(basic_strides other) - { - swap (*this, other); - return *this; - } - - friend void swap(basic_strides& lhs, basic_strides& rhs) { - std::swap(lhs._base , rhs._base); - } - - const_reference operator[] (size_type p) const{ - return _base[p]; - } - - const_pointer data() const{ - return _base.data(); - } - - const_reference at (size_type p) const{ - return _base.at(p); - } - - const_reference back () const{ - return _base[_base.size() - 1]; - } - - reference back (){ - return _base[_base.size() - 1]; - } - - bool empty() const{ - return _base.empty(); - } - - size_type size() const{ - return _base.size(); - } - - template - bool operator == (basic_strides const& b) const{ - return b.base() == this->base(); - } - - template - bool operator != (basic_strides const& b) const{ - return b.base() != this->base(); - } - - bool operator == (basic_strides const& b) const{ - return b._base == _base; - } - - bool operator != (basic_strides const& b) const{ - return b._base != _base; - } - - const_iterator begin() const{ - return _base.begin(); - } - - const_iterator end() const{ - return _base.end(); - } - - void clear() { - this->_base.clear(); - } - - base_type const& base() const{ - return this->_base; - } - - -protected: - base_type _base; -}; - - -/** @brief Template class for storing tensor strides for iteration with runtime variable size. - * - * Proxy template class of std::array. - * - */ -template -class basic_fixed_rank_strides -{ -public: - - using base_type = std::array<__int_type, N>; - - static_assert( std::numeric_limits::is_integer, - "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type integer."); - static_assert(!std::numeric_limits::is_signed, - "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type unsigned integer."); - static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value, - "Static error in boost::numeric::ublas::basic_fixed_rank_strides: layout type must either first or last order"); - - - using layout_type = __layout; - using value_type = typename base_type::value_type; - using reference = typename base_type::reference; - using const_reference = typename base_type::const_reference; - using size_type = typename base_type::size_type; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - - - /** @brief Default constructs basic_fixed_rank_strides - * - * @code auto ex = basic_fixed_rank_strides{}; - */ - constexpr explicit basic_fixed_rank_strides() - : _base{} - { - } - - /** @brief Constructs basic_fixed_rank_strides from basic_extents for the first- and last-order storage formats - * - * @code auto strides = basic_fixed_rank_strides( basic_extents{2,3,4} ); - * - */ - template - basic_fixed_rank_strides(basic_fixed_rank_extents const& s) - { - _base.fill(value_type(1)); - - if( s.empty() ) - return; - - if( !valid(s) ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides() : shape is not valid."); - - if( is_vector(s) || is_scalar(s) ) - return; - - if( this->size() < 2 ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides() : size of strides must be greater or equal 2."); - - - if constexpr (std::is_same::value){ - size_type k = 1ul, kend = this->size(); - for(; k < kend; ++k) - _base[k] = _base[k-1] * s[k-1]; - } - else { - size_type k = this->size()-2, kend = 0ul; - for(; k > kend; --k) - _base[k] = _base[k+1] * s[k+1]; - _base[0] = _base[1] * s[1]; - } - } - - basic_fixed_rank_strides(basic_fixed_rank_strides const& l) - : _base(l._base) - {} - - basic_fixed_rank_strides(basic_fixed_rank_strides && l ) - : _base(std::move(l._base)) - {} - - basic_fixed_rank_strides(base_type const& l ) - : _base(l) - {} - - basic_fixed_rank_strides(base_type && l ) - : _base(std::move(l)) - {} - - ~basic_fixed_rank_strides() = default; - - - basic_fixed_rank_strides& operator=(basic_fixed_rank_strides other) - { - swap (*this, other); - return *this; - } - - friend void swap(basic_fixed_rank_strides& lhs, basic_fixed_rank_strides& rhs) { - std::swap(lhs._base , rhs._base); - } - - const_reference operator[] (size_type p) const{ - return _base[p]; - } - - const_pointer data() const{ - return _base.data(); - } - - const_reference at (size_type p) const{ - return _base.at(p); - } - - const_reference back () const{ - return _base[N - 1]; - } - - reference back (){ - return _base[N - 1]; - } - - bool empty() const{ - return _base.empty(); - } - - size_type size() const{ - return _base.size(); - } - - const_iterator begin() const{ - return _base.begin(); - } - - const_iterator end() const{ - return _base.end(); - } - - base_type const& base() const{ - return this->_base; - } - - + using base_type = std::vector<__int_type>; + + static_assert( std::numeric_limits::is_integer, + "Static error in boost::numeric::ublas::basic_strides: type must be of type integer."); + static_assert(!std::numeric_limits::is_signed, + "Static error in boost::numeric::ublas::basic_strides: type must be of type unsigned integer."); + static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value, + "Static error in boost::numeric::ublas::basic_strides: layout type must either first or last order"); + + + using layout_type = __layout; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + + + /** @brief Default constructs basic_strides + * + * @code auto ex = basic_strides{}; + */ + constexpr explicit basic_strides() + : _base{} + { + } + + /** @brief Constructs basic_strides from basic_extents for the first- and last-order storage formats + * + * @code auto strides = basic_strides( basic_extents{2,3,4} ); + * + */ + template + basic_strides(basic_extents const& s) + : _base(s.size(),1) + { + if( s.empty() ) + return; + + if( !valid(s) ) + throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : shape is not valid."); + + if( is_vector(s) || is_scalar(s) ) + return; + + if( this->size() < 2 ) + throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : size of strides must be greater or equal 2."); + + + if constexpr (std::is_same::value){ + size_type k = 1ul, kend = this->size(); + for(; k < kend; ++k) + _base[k] = _base[k-1] * s[k-1]; + } + else { + size_type k = this->size()-2, kend = 0ul; + for(; k > kend; --k) + _base[k] = _base[k+1] * s[k+1]; + _base[0] = _base[1] * s[1]; + } + } + + basic_strides(basic_strides const& l) + : _base(l._base) + {} + + basic_strides(basic_strides && l ) + : _base(std::move(l._base)) + {} + + basic_strides(base_type const& l ) + : _base(l) + {} + + basic_strides(base_type && l ) + : _base(std::move(l)) + {} + + ~basic_strides() = default; + + + basic_strides& operator=(basic_strides other) + { + swap (*this, other); + return *this; + } + + friend void swap(basic_strides& lhs, basic_strides& rhs) { + std::swap(lhs._base , rhs._base); + } + + [[nodiscard]] inline + constexpr const_reference operator[] (size_type p) const{ + return _base[p]; + } + + [[nodiscard]] inline + constexpr const_pointer data() const{ + return _base.data(); + } + + [[nodiscard]] inline + constexpr const_reference at (size_type p) const{ + return _base.at(p); + } + + [[nodiscard]] inline + constexpr const_reference back () const{ + return _base[_base.size() - 1]; + } + + [[nodiscard]] inline + constexpr reference back (){ + return _base[_base.size() - 1]; + } + + [[nodiscard]] inline + constexpr bool empty() const{ + return _base.empty(); + } + + [[nodiscard]] inline + constexpr size_type size() const{ + return _base.size(); + } + + [[nodiscard]] inline + constexpr const_iterator begin() const{ + return _base.begin(); + } + + [[nodiscard]] inline + constexpr const_iterator end() const{ + return _base.end(); + } + + inline + constexpr void clear() { + this->_base.clear(); + } + + [[nodiscard]] inline + constexpr base_type const& base() const{ + return this->_base; + } + protected: - base_type _base; + base_type _base; }; - } } } diff --git a/include/boost/numeric/ublas/tensor/dynamic_tensor.hpp b/include/boost/numeric/ublas/tensor/dynamic_tensor.hpp new file mode 100644 index 000000000..273db7c12 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/dynamic_tensor.hpp @@ -0,0 +1,203 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#ifndef BOOST_UBLAS_DYNAMIC_TENSOR_IMPL_HPP +#define BOOST_UBLAS_DYNAMIC_TENSOR_IMPL_HPP + +#include + +namespace boost::numeric::ublas { + + template< typename T = float, typename F = first_order > + struct dynamic_tensor: + public basic_tensor< dynamic_tensor< T, F > > + { + using self_type = dynamic_tensor< T, F >; + using super_type = basic_tensor< self_type >; + + template + using tensor_expression_type = typename super_type::template tensor_expression_type; + + template + using matrix_expression_type = typename super_type::template matrix_expression_type; + + template + using vector_expression_type = typename super_type::template vector_expression_type; + + using array_type = typename tensor_traits::container_type; + using layout_type = typename tensor_traits::layout_type; + + using size_type = typename array_type::size_type; + using difference_type = typename array_type::difference_type; + using value_type = typename array_type::value_type; + + using reference = typename array_type::reference; + using const_reference = typename array_type::const_reference; + + using pointer = typename array_type::pointer; + using const_pointer = typename array_type::const_pointer; + + using iterator = typename array_type::iterator; + using const_iterator = typename array_type::const_iterator; + + using reverse_iterator = typename array_type::reverse_iterator; + using const_reverse_iterator = typename array_type::const_reverse_iterator; + + using tensor_temporary_type = self_type; + using storage_category = dense_tag; + + using extents_type = typename tensor_traits::extents_type; + using strides_type = strides_t; + + using matrix_type = typename super_type::matrix_type; + using vector_type = typename super_type::vector_type; + + constexpr dynamic_tensor() = default; + + dynamic_tensor( std::initializer_list< size_type > li ) + : super_type( std::move(li) ) + {} + + constexpr dynamic_tensor( extents_type const& e, value_type const& i ) + : super_type(e,i) + {} + + constexpr dynamic_tensor( extents_type const& e, array_type const& a ) + : super_type(e,a) + {} + + constexpr dynamic_tensor( extents_type const& e ) + : super_type(e) + {} + + constexpr dynamic_tensor( matrix_type const& v ) + : super_type( extents_type{v.size1(), v.size2()} ) + { + std::copy(v.data().begin(), v.data().end(),super_type::data_.begin()); + } + + constexpr dynamic_tensor( matrix_type && v ) + : super_type( extents_type{v.size1(), v.size2()} ) + { + std::move(v.data().begin(), v.data().end(),super_type::begin()); + } + + constexpr dynamic_tensor (const vector_type &v) + : super_type( extents_type{ v.size(), typename extents_type::value_type{1} } ) + { + std::copy(v.data().begin(), v.data().end(),super_type::data_.begin()); + } + + constexpr dynamic_tensor (vector_type &&v) + : super_type( extents_type{ v.size(), typename extents_type::value_type{1} } ) + { + std::move(v.data().begin(), v.data().end(),super_type::begin()); + } + + template + constexpr dynamic_tensor (const dynamic_tensor &expr) + : super_type(expr) + { + + } + + template + constexpr dynamic_tensor (const tensor_expression_type &expr) + : super_type(expr) + {} + + template + inline + constexpr dynamic_tensor& operator= (const tensor_expression_type &expr) + { + dynamic_tensor temp( expr ); + swap(*this,temp); + return *this; + } + + template + constexpr dynamic_tensor (const matrix_expression_type &expr) + : dynamic_tensor( matrix_type(expr) ) + {} + + template + constexpr dynamic_tensor (const vector_expression_type &expr) + : dynamic_tensor( vector_type(expr) ) + {} + + + template + constexpr dynamic_tensor (const basic_tensor & other) + : super_type(other.extents()) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::dynamic_tensor( const OtherTensor& ) : The OtherTensor should have a tensor type" + ); + + static_assert( std::is_same_v, + "boost::numeric::ublas::dynamic_tensor( const OtherTensor& ) : The tensor should have same value type" + ); + + std::copy(other.begin(), other.end(), super_type::begin()); + } + + template + constexpr dynamic_tensor (basic_tensor && other) + : super_type(other.extents()) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::dynamic_tensor( OtherTensor&& ) : The OtherTensor should have a tensor type" + ); + + static_assert( std::is_same_v, + "boost::numeric::ublas::dynamic_tensor( OtherTensor&& ) : The tensor should have same value type" + ); + + std::move(other.begin(), other.end(), super_type::begin()); + + } + + inline + constexpr dynamic_tensor& operator=(const_reference v) noexcept{ + std::fill(super_type::begin(), super_type::end(), v); + return *this; + } + + }; + + template + dynamic_tensor(dynamic_extents<> const&, V const&) -> dynamic_tensor; + + dynamic_tensor(dynamic_extents<> const&) -> dynamic_tensor; + + template + dynamic_tensor(basic_tensor const&) -> dynamic_tensor< typename T::value_type, typename T::layout_type >; + + template + dynamic_tensor(basic_tensor &&) -> dynamic_tensor< typename T::value_type, typename T::layout_type >; + +} // boost::numeric::ublas + +namespace boost::numeric::ublas{ + + template + struct tensor_traits< dynamic_tensor > { + using container_type= std::vector< T >; + using extents_type = dynamic_extents<>; + using layout_type = F; + using container_tag = dynamic_tensor_tag; + }; + +} // boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/expression.hpp b/include/boost/numeric/ublas/tensor/expression.hpp index 7b48a83d5..821a7f2b0 100644 --- a/include/boost/numeric/ublas/tensor/expression.hpp +++ b/include/boost/numeric/ublas/tensor/expression.hpp @@ -14,18 +14,7 @@ #include #include - - -namespace boost { -namespace numeric { -namespace ublas { - -//TODO: put in fwd.hpp -struct tensor_tag {}; - -} -} -} +#include namespace boost { namespace numeric { @@ -44,18 +33,18 @@ template struct tensor_expression : public ublas_expression { - // static const unsigned complexity = 0; - using expression_type = E; - using type_category = tensor_tag; - using tensor_type = T; + // static const unsigned complexity = 0; + using expression_type = E; + using type_category = tensor_tag; + using tensor_type = T; - inline - auto const& operator()() const { return *static_cast (this); } + inline + auto const& operator()() const { return *static_cast (this); } protected : - explicit tensor_expression() = default; - tensor_expression(const tensor_expression&) = delete; - tensor_expression& operator=(const tensor_expression&) = delete; + explicit tensor_expression() = default; + tensor_expression(const tensor_expression&) = delete; + tensor_expression& operator=(const tensor_expression&) = delete; }; @@ -63,59 +52,62 @@ template struct binary_tensor_expression : public tensor_expression > { - using self_type = binary_tensor_expression; - using tensor_type = T; - using binary_operation = OP; - using expression_type_left = EL; - using expression_type_right = ER; - using derived_type = tensor_expression ; - - using size_type = typename tensor_type::size_type; - - explicit binary_tensor_expression(expression_type_left const& l, expression_type_right const& r, binary_operation o) - : el(l) , er(r) , op(o) {} - binary_tensor_expression() = delete; - binary_tensor_expression(const binary_tensor_expression& l) = delete; - binary_tensor_expression(binary_tensor_expression&& l) - : el(l.el), er(l.er), op(l.op) {} - - inline - decltype(auto) operator()(size_type i) const { return op(el(i), er(i)); } - - expression_type_left const& el; - expression_type_right const& er; - binary_operation op; + using self_type = binary_tensor_expression; + using tensor_type = T; + using binary_operation = OP; + using expression_type_left = EL; + using expression_type_right = ER; + using derived_type = tensor_expression ; + + using size_type = typename tensor_type::size_type; + + explicit binary_tensor_expression(expression_type_left const& l, expression_type_right const& r, binary_operation o) + : el(l) , er(r) , op(o) {} + binary_tensor_expression() = delete; + binary_tensor_expression(const binary_tensor_expression& l) = delete; + binary_tensor_expression(binary_tensor_expression&& l) + : el(l.el), er(l.er), op(l.op) {} + + inline + decltype(auto) operator()(size_type i) const { return op(el(i), er(i)); } + + expression_type_left const& el; + expression_type_right const& er; + binary_operation op; }; /// @brief helper function to simply instantiation of lambda proxy class -template -auto make_binary_tensor_expression( tensor_expression const& el, tensor_expression const& er, OP op) +template +auto make_binary_tensor_expression( tensor_expression const& el, tensor_expression const& er, OP op) { - return binary_tensor_expression( el(), er(), op) ; + static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, + "boost::numeric::ublas::make_binary_tensor_expression(T1,T2) : LHS tensor and RHS tensor should have same value type" + ); + return binary_tensor_expression( el(), er(), op) ; } template auto make_binary_tensor_expression( matrix_expression const& el, tensor_expression const& er, OP op) { - return binary_tensor_expression( el(), er(), op) ; + return binary_tensor_expression( el(), er(), op) ; } template auto make_binary_tensor_expression( tensor_expression const& el, matrix_expression const& er, OP op) { - return binary_tensor_expression( el(), er(), op) ; + return binary_tensor_expression( el(), er(), op) ; } template auto make_binary_tensor_expression( vector_expression const& el, tensor_expression const& er, OP op) { - return binary_tensor_expression( el(), er(), op) ; + return binary_tensor_expression( el(), er(), op) ; } template auto make_binary_tensor_expression( tensor_expression const& el, vector_expression const& er, OP op) { - return binary_tensor_expression( el(), er(), op) ; + return binary_tensor_expression( el(), er(), op) ; } @@ -125,44 +117,44 @@ struct unary_tensor_expression : public tensor_expression > { - using self_type = unary_tensor_expression; - using tensor_type = T; - using expression_type = E; + using self_type = unary_tensor_expression; + using tensor_type = T; + using expression_type = E; - using derived_type = tensor_expression >; + using derived_type = tensor_expression >; - using size_type = typename tensor_type::size_type; + using size_type = typename tensor_type::size_type; - explicit unary_tensor_expression(E const& ee, OP o) : e(ee) , op(o) {} - unary_tensor_expression() = delete; - unary_tensor_expression(const unary_tensor_expression& l) = delete; - unary_tensor_expression(unary_tensor_expression&& l) - : e(l.e), op(op.l) {} + explicit unary_tensor_expression(E const& ee, OP o) : e(ee) , op(o) {} + unary_tensor_expression() = delete; + unary_tensor_expression(const unary_tensor_expression& l) = delete; + unary_tensor_expression(unary_tensor_expression&& l) + : e(l.e), op(op.l) {} - inline - decltype(auto) operator()(size_type i) const { return op(e(i)); } + inline + decltype(auto) operator()(size_type i) const { return op(e(i)); } - E const& e; - OP op; + E const& e; + OP op; }; // \brief helper function to simply instantiation of lambda proxy class template auto make_unary_tensor_expression( tensor_expression const& e, OP op) { - return unary_tensor_expression( e() , op); + return unary_tensor_expression( e() , op); } template auto make_unary_tensor_expression( matrix_expression const& e, OP op) { - return unary_tensor_expression( e() , op); + return unary_tensor_expression( e() , op); } template auto make_unary_tensor_expression( vector_expression const& e, OP op) { - return unary_tensor_expression( e() , op); + return unary_tensor_expression( e() , op); } diff --git a/include/boost/numeric/ublas/tensor/expression_evaluation.hpp b/include/boost/numeric/ublas/tensor/expression_evaluation.hpp index 8d80aed28..90e1fa829 100644 --- a/include/boost/numeric/ublas/tensor/expression_evaluation.hpp +++ b/include/boost/numeric/ublas/tensor/expression_evaluation.hpp @@ -15,12 +15,13 @@ #include #include +#include namespace boost::numeric::ublas { -template -class tensor; +template +class basic_tensor; template class basic_extents; @@ -72,23 +73,28 @@ namespace boost::numeric::ublas::detail { -/** @brief Retrieves extents of the tensor +/** @brief Retrieves extents of the basic_tensor * */ -template -auto retrieve_extents(tensor const& t) +template +[[nodiscard]] +constexpr auto& retrieve_extents(basic_tensor const& t) { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::detailretrieve_extents() : tensor type should be valid tensor" + ); return t.extents(); } -/** @brief Retrieves extents of the tensor expression +/** @brief Retrieves extents of the basic_tensor expression * - * @note tensor expression must be a binary tree with at least one tensor type + * @note basic_tensor expression must be a binary tree with at least one basic_tensor type * - * @returns extents of the child expression if it is a tensor or extents of one child of its child. + * @returns extents of the child expression if it is a basic_tensor or extents of one child of its child. */ template -auto retrieve_extents(tensor_expression const& expr) +[[nodiscard]] +constexpr auto& retrieve_extents(tensor_expression const& expr) { static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::retrieve_extents: Expression to evaluate should contain tensors."); @@ -106,14 +112,15 @@ auto retrieve_extents(tensor_expression const& expr) #pragma warning( push ) #pragma warning( disable : 4702 ) #endif -/** @brief Retrieves extents of the binary tensor expression +/** @brief Retrieves extents of the binary basic_tensor expression * - * @note tensor expression must be a binary tree with at least one tensor type + * @note basic_tensor expression must be a binary tree with at least one basic_tensor type * - * @returns extents of the (left and if necessary then right) child expression if it is a tensor or extents of a child of its (left and if necessary then right) child. + * @returns extents of the (left and if necessary then right) child expression if it is a basic_tensor or extents of a child of its (left and if necessary then right) child. */ template -auto retrieve_extents(binary_tensor_expression const& expr) +[[nodiscard]] +constexpr auto& retrieve_extents(binary_tensor_expression const& expr) { static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::retrieve_extents: Expression to evaluate should contain tensors."); @@ -135,14 +142,15 @@ auto retrieve_extents(binary_tensor_expression const& expr) #pragma warning( pop ) #endif -/** @brief Retrieves extents of the binary tensor expression +/** @brief Retrieves extents of the binary basic_tensor expression * - * @note tensor expression must be a binary tree with at least one tensor type + * @note basic_tensor expression must be a binary tree with at least one basic_tensor type * - * @returns extents of the child expression if it is a tensor or extents of a child of its child. + * @returns extents of the child expression if it is a basic_tensor or extents of a child of its child. */ template -auto retrieve_extents(unary_tensor_expression const& expr) +[[nodiscard]] +constexpr auto& retrieve_extents(unary_tensor_expression const& expr) { static_assert(detail::has_tensor_types>::value, @@ -162,17 +170,32 @@ auto retrieve_extents(unary_tensor_expression const& expr) namespace boost::numeric::ublas::detail { -template -auto all_extents_equal(tensor const& t, E const& extents) +template +[[nodiscard]] inline +constexpr auto all_extents_equal(basic_tensor const& t, Extents const& extents) { + static_assert(is_extents_v, + "Error in boost::numeric::ublas::detail::all_extents_equal: extents passed should be of extents type." + ); + + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::all_extents_equal() : tensor type should be valid tensor" + ); + return extents == t.extents(); } -template -auto all_extents_equal(tensor_expression const& expr, typename T::extents_type const& extents) +template +[[nodiscard]] +constexpr auto all_extents_equal(tensor_expression const& expr, Extents const& extents) { + static_assert(is_extents_v, + "Error in boost::numeric::ublas::detail::all_extents_equal: extents passed should be of extents type." + ); + static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); + auto const& cast_expr = static_cast(expr); @@ -188,9 +211,14 @@ auto all_extents_equal(tensor_expression const& expr, typename T::extents_t } -template -auto all_extents_equal(binary_tensor_expression const& expr, typename T::extents_type const& extents) +template +[[nodiscard]] +constexpr auto all_extents_equal(binary_tensor_expression const& expr, Extents const& extents) { + static_assert(is_extents_v, + "Error in boost::numeric::ublas::detail::all_extents_equal: extents passed should be of extents type." + ); + static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); @@ -214,19 +242,24 @@ auto all_extents_equal(binary_tensor_expression const& expr, typenam } -template -auto all_extents_equal(unary_tensor_expression const& expr, typename T::extents_type const& extents) +template +[[nodiscard]] +constexpr auto all_extents_equal(unary_tensor_expression const& expr, Extents const& extents) { + static_assert(is_extents_v, + "Error in boost::numeric::ublas::detail::all_extents_equal: extents passed should be of extents type." + ); + static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); if constexpr ( std::is_same::value ) if(extents != expr.e.extents()) - return false; + return false; if constexpr ( detail::has_tensor_types::value ) if(!all_extents_equal(expr.e, extents)) - return false; + return false; return true; } @@ -237,30 +270,30 @@ auto all_extents_equal(unary_tensor_expression const& expr, typename T:: namespace boost::numeric::ublas::detail { -/** @brief Evaluates expression for a tensor +/** @brief Evaluates expression for a basic_tensor * - * Assigns the results of the expression to the tensor. + * Assigns the results of the expression to the basic_tensor. * - * \note Checks if shape of the tensor matches those of all tensors within the expression. + * \note Checks if shape of the basic_tensor matches those of all tensors within the expression. */ template void eval(tensor_type& lhs, tensor_expression const& expr) { if constexpr (detail::has_tensor_types >::value ) if(!detail::all_extents_equal(expr, lhs.extents() )) - throw std::runtime_error("Error in boost::numeric::ublas::tensor: expression contains tensors with different shapes."); + throw std::runtime_error("Error in boost::numeric::ublas::basic_tensor: expression contains tensors with different shapes."); #pragma omp parallel for for(auto i = 0u; i < lhs.size(); ++i) lhs(i) = expr()(i); } -/** @brief Evaluates expression for a tensor +/** @brief Evaluates expression for a basic_tensor * * Applies a unary function to the results of the expressions before the assignment. * Usually applied needed for unary operators such as A += C; * - * \note Checks if shape of the tensor matches those of all tensors within the expression. + * \note Checks if shape of the basic_tensor matches those of all tensors within the expression. */ template void eval(tensor_type& lhs, tensor_expression const& expr, unary_fn const fn) @@ -268,7 +301,7 @@ void eval(tensor_type& lhs, tensor_expression const& if constexpr (detail::has_tensor_types< tensor_type, tensor_expression >::value ) if(!detail::all_extents_equal( expr, lhs.extents() )) - throw std::runtime_error("Error in boost::numeric::ublas::tensor: expression contains tensors with different shapes."); + throw std::runtime_error("Error in boost::numeric::ublas::basic_tensor: expression contains tensors with different shapes."); #pragma omp parallel for for(auto i = 0u; i < lhs.size(); ++i) @@ -277,12 +310,12 @@ void eval(tensor_type& lhs, tensor_expression const& -/** @brief Evaluates expression for a tensor +/** @brief Evaluates expression for a basic_tensor * * Applies a unary function to the results of the expressions before the assignment. * Usually applied needed for unary operators such as A += C; * - * \note Checks if shape of the tensor matches those of all tensors within the expression. + * \note Checks if shape of the basic_tensor matches those of all tensors within the expression. */ template void eval(tensor_type& lhs, unary_fn const fn) diff --git a/include/boost/numeric/ublas/tensor/extents.hpp b/include/boost/numeric/ublas/tensor/extents.hpp deleted file mode 100644 index a026434a0..000000000 --- a/include/boost/numeric/ublas/tensor/extents.hpp +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - -#ifndef _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_HPP_ -#define _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_HPP_ - -#include -#include -#include -#include - -namespace boost::numeric::ublas { - - template && detail::is_extents_v, int> = 0 - > - constexpr bool operator==(LExtents const& lhs, RExtents const& rhs){ - static_assert(detail::is_extents_v && detail::is_extents_v, - "boost::numeric::ublas::operator==() : invalid type, type should be an extents"); - if( lhs.size() != rhs.size() ){ - return false; - }else{ - return std::equal(lhs.begin(), lhs.end(), rhs.begin()); - } - } - - template && detail::is_extents_v, int> = 0 - > - constexpr bool operator!=(LExtents const& lhs, RExtents const& rhs){ - static_assert(detail::is_extents_v && detail::is_extents_v, - "boost::numeric::ublas::operator!=() : invalid type, type should be an extents"); - return !(lhs == rhs); - } - - template , int> = 0 - > - std::ostream& operator<<(std::ostream& os, Extents const& e){ - static_assert(detail::is_extents_v, - "boost::numeric::ublas::operator<<() : invalid type, type should be an extents"); - return os< +#include +#include +#include +#include +#include + +namespace boost { +namespace numeric { +namespace ublas { + +/** @brief Template class for storing tensor extents for compile time. + * + * @code basic_static_extents<1,2,3,4> t @endcode + * @tparam E parameter pack of extents + * + */ +template +struct basic_fixed_rank_extents +{ + + + static constexpr std::size_t const _size = N; + + + using base_type = std::array; + using value_type = typename base_type::value_type; + using const_reference = typename base_type::const_reference; + using reference = typename base_type::reference; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + using size_type = typename base_type::size_type; + + static_assert( std::numeric_limits::is_integer, "Static error in basic_fixed_rank_extents: type must be of type integer."); + static_assert(!std::numeric_limits::is_signed, "Static error in basic_fixed_rank_extents: type must be of type unsigned integer."); + + //@returns the rank of basic_static_extents + [[nodiscard]] + static constexpr size_type size() noexcept { return _size; } + + [[nodiscard]] inline + constexpr const_reference at(size_type k) const{ + return _base.at(k); + } + + [[nodiscard]] inline + constexpr reference at(size_type k){ + return _base.at(k); + } + + [[nodiscard]] inline + constexpr const_reference operator[](size_type k) const noexcept{ + return _base[k]; + } + + [[nodiscard]] inline + constexpr reference operator[](size_type k) noexcept{ + return _base[k]; + } + + // default constructor + constexpr basic_fixed_rank_extents() = default; + + constexpr basic_fixed_rank_extents(std::initializer_list li){ + if( li.size() > _size ){ + throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than _size"); + } + + std::copy(li.begin(), li.end(), _base.begin()); + + if ( !valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + constexpr basic_fixed_rank_extents(const_iterator begin, const_iterator end){ + if( std::distance(begin,end) > _size ){ + throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than _size"); + } + + std::copy(begin, end, _base.begin()); + + if ( !valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + inline + constexpr void fill( value_type value ){ + _base.fill(value); + } + + template::value + ,int > = 0 + > + constexpr basic_fixed_rank_extents(OtherExtentsType const& e){ + std::copy_n(e.begin(),_size, _base.begin()); + } + + constexpr basic_fixed_rank_extents(base_type const& data) + : _base(data) + { + if ( !valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + constexpr basic_fixed_rank_extents(base_type&& data) + : _base(std::move(data)) + { + if ( !valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + /** @brief Returns the std::vector containing extents */ + [[nodiscard]] inline + constexpr base_type const& base() const { + return _base; + } + + /** @brief Checks if extents is empty or not + * + * @returns true if rank is 0 else false + * + */ + [[nodiscard]] inline + constexpr bool empty() const noexcept { return _size == size_type{0}; } + + friend void swap(basic_fixed_rank_extents& lhs, basic_fixed_rank_extents& rhs) { + std::swap(lhs._base , rhs._base ); + } + + [[nodiscard]] inline + constexpr const_pointer data() const + { + return _base.data(); + } + + [[nodiscard]] inline + constexpr const_iterator + begin() const + { + return _base.begin(); + } + + [[nodiscard]] inline + constexpr const_iterator + end() const + { + return _base.end(); + } + + [[nodiscard]] inline + constexpr const_reference back () const + { + return _base.back(); + } + + ~basic_fixed_rank_extents() = default; + +private: + base_type _base{}; +}; + +} // namespace ublas +} // namespace numeric +} // namespace boost + + + +#endif diff --git a/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp b/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp new file mode 100644 index 000000000..43eb79c8a --- /dev/null +++ b/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp @@ -0,0 +1,189 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// +/// \file strides.hpp Definition for the basic_strides template class + + +#ifndef _BOOST_UBLAS_TENSOR_FIXED_RANK_STRIDES_HPP_ +#define _BOOST_UBLAS_TENSOR_FIXED_RANK_STRIDES_HPP_ + +#include +#include + +namespace boost { +namespace numeric { +namespace ublas { + +using first_order = column_major; +using last_order = row_major; + +/** @brief Template class for storing tensor strides for iteration with runtime variable size. + * + * Proxy template class of std::array. + * + */ +template +class basic_fixed_rank_strides +{ +public: + + using base_type = std::array; + + static_assert( std::numeric_limits::is_integer, + "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type integer."); + static_assert(!std::numeric_limits::is_signed, + "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type unsigned integer."); + static_assert(std::is_same::value || std::is_same::value, + "Static error in boost::numeric::ublas::basic_fixed_rank_strides: layout type must either first or last order"); + + + using layout_type = L; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + + + /** @brief Default constructs basic_fixed_rank_strides + * + * @code auto ex = basic_fixed_rank_strides{}; + */ + constexpr explicit basic_fixed_rank_strides() + : _base{} + { + } + + /** @brief Constructs basic_fixed_rank_strides from basic_extents for the first- and last-order storage formats + * + * @code auto strides = basic_fixed_rank_strides( basic_extents{2,3,4} ); + * + */ + basic_fixed_rank_strides(basic_fixed_rank_extents const& s) + { + _base.fill(value_type(1)); + + if( s.empty() ) + return; + + if( !valid(s) ) + throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides() : shape is not valid."); + + if( is_vector(s) || is_scalar(s) ) + return; + + if( this->size() < 2 ) + throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides() : size of strides must be greater or equal 2."); + + + if constexpr (std::is_same::value){ + size_type k = 1ul, kend = this->size(); + for(; k < kend; ++k) + _base[k] = _base[k-1] * s[k-1]; + } + else { + size_type k = this->size()-2, kend = 0ul; + for(; k > kend; --k) + _base[k] = _base[k+1] * s[k+1]; + _base[0] = _base[1] * s[1]; + } + } + + basic_fixed_rank_strides(basic_fixed_rank_strides const& l) + : _base(l._base) + {} + + basic_fixed_rank_strides(basic_fixed_rank_strides && l ) + : _base(std::move(l._base)) + {} + + basic_fixed_rank_strides(base_type const& l ) + : _base(l) + {} + + basic_fixed_rank_strides(base_type && l ) + : _base(std::move(l)) + {} + + ~basic_fixed_rank_strides() = default; + + + basic_fixed_rank_strides& operator=(basic_fixed_rank_strides other) + { + swap (*this, other); + return *this; + } + + friend void swap(basic_fixed_rank_strides& lhs, basic_fixed_rank_strides& rhs) { + std::swap(lhs._base , rhs._base); + } + + [[nodiscard]] inline + constexpr const_reference operator[] (size_type p) const{ + return _base[p]; + } + + [[nodiscard]] inline + constexpr const_pointer data() const{ + return _base.data(); + } + + [[nodiscard]] inline + constexpr const_reference at (size_type p) const{ + return _base.at(p); + } + + [[nodiscard]] inline + constexpr const_reference back () const{ + return _base[N - 1]; + } + + [[nodiscard]] inline + constexpr reference back (){ + return _base[N - 1]; + } + + [[nodiscard]] inline + constexpr bool empty() const{ + return _base.empty(); + } + + [[nodiscard]] inline + constexpr size_type size() const{ + return _base.size(); + } + + [[nodiscard]] inline + constexpr const_iterator begin() const{ + return _base.begin(); + } + + [[nodiscard]] inline + constexpr const_iterator end() const{ + return _base.end(); + } + + [[nodiscard]] inline + constexpr base_type const& base() const{ + return this->_base; + } + +protected: + base_type _base; +}; + + +} +} +} + +#endif diff --git a/include/boost/numeric/ublas/tensor/fixed_rank_tensor.hpp b/include/boost/numeric/ublas/tensor/fixed_rank_tensor.hpp new file mode 100644 index 000000000..b364fbc93 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/fixed_rank_tensor.hpp @@ -0,0 +1,217 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#ifndef BOOST_UBLAS_FIXED_RANK_TENSOR_IMPL_HPP +#define BOOST_UBLAS_FIXED_RANK_TENSOR_IMPL_HPP + +#include + +namespace boost::numeric::ublas { + + template< typename T, std::size_t R, typename F = first_order > + struct fixed_rank_tensor: + public basic_tensor< fixed_rank_tensor< T, R, F > > + { + using self_type = fixed_rank_tensor< T, R, F >; + using super_type = basic_tensor< self_type >; + + template + using tensor_expression_type = typename super_type::template tensor_expression_type; + + template + using matrix_expression_type = typename super_type::template matrix_expression_type; + + template + using vector_expression_type = typename super_type::template vector_expression_type; + + using array_type = typename tensor_traits::container_type; + using layout_type = typename tensor_traits::layout_type; + + using size_type = typename array_type::size_type; + using difference_type = typename array_type::difference_type; + using value_type = typename array_type::value_type; + + using reference = typename array_type::reference; + using const_reference = typename array_type::const_reference; + + using pointer = typename array_type::pointer; + using const_pointer = typename array_type::const_pointer; + + using iterator = typename array_type::iterator; + using const_iterator = typename array_type::const_iterator; + + using reverse_iterator = typename array_type::reverse_iterator; + using const_reverse_iterator = typename array_type::const_reverse_iterator; + + using tensor_temporary_type = self_type; + using storage_category = dense_tag; + + using extents_type = typename tensor_traits::extents_type; + using strides_type = strides_t; + + using matrix_type = typename super_type::matrix_type; + using vector_type = typename super_type::vector_type; + + constexpr fixed_rank_tensor() = default; + + constexpr fixed_rank_tensor( extents_type const& e, value_type const& i ) + : super_type(e,i) + {} + + constexpr fixed_rank_tensor( extents_type const& e, array_type const& a ) + : super_type(e,a) + {} + + constexpr fixed_rank_tensor( extents_type const& e ) + : super_type(e) + {} + + fixed_rank_tensor( std::initializer_list< size_type > li ) + : super_type( std::move(li) ) + {} + + constexpr fixed_rank_tensor( matrix_type const& v ) + : super_type( extents_type{v.size1(), v.size2()} ) + { + static_assert( R == 2, "Error in boost::numeric::ublas::tensor(const matrix &v)" + " : rank of extents are not correct, please check!"); + + std::copy(v.data().begin(), v.data().end(), super_type::begin()); + } + + constexpr fixed_rank_tensor( matrix_type && v ) + : super_type( extents_type{v.size1(), v.size2()} ) + { + + static_assert( R == 2, "Error in boost::numeric::ublas::tensor(matrix &&v)" + " : rank of extents are not correct, please check!"); + + std::move(v.data().begin(), v.data().end(),super_type::begin()); + } + + constexpr fixed_rank_tensor (const vector_type &v) + : super_type( extents_type{ v.size(), typename extents_type::value_type{1} } ) + { + static_assert( R == 2, "Error in boost::numeric::ublas::tensor(const vector &v)" + " : rank of extents are not correct, please check!"); + + std::copy(v.data().begin(), v.data().end(), super_type::begin()); + + } + + constexpr fixed_rank_tensor (vector_type &&v) + : super_type( extents_type{ v.size(), typename extents_type::value_type{1} } ) + { + + static_assert( R == 2, "Error in boost::numeric::ublas::tensor(vector &&v)" + " : rank of extents are not correct, please check!"); + + std::move(v.data().begin(), v.data().end(),super_type::begin()); + + } + + template + constexpr fixed_rank_tensor (const fixed_rank_tensor &expr) + : super_type(static_cast(expr)) + {} + + template + constexpr fixed_rank_tensor (const tensor_expression_type &expr) + : super_type(expr) + {} + + template + inline + constexpr fixed_rank_tensor& operator= (const tensor_expression_type &expr) + { + fixed_rank_tensor temp( expr ); + swap(*this,temp); + return *this; + } + + template + constexpr fixed_rank_tensor (const matrix_expression_type &expr) + : fixed_rank_tensor( matrix_type(expr) ) + {} + + template + constexpr fixed_rank_tensor (const vector_expression_type &expr) + : fixed_rank_tensor( vector_type(expr) ) + {} + + template + constexpr fixed_rank_tensor (const basic_tensor & other) + : super_type(other.extents()) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::fixed_rank_tensor( const OtherTensor& ) : The OtherTensor should have a tensor type" + ); + + static_assert( std::is_same_v, + "boost::numeric::ublas::fixed_rank_tensor( const OtherTensor& ) : The tensor should have same value type" + ); + + if ( other.extents().size() != R ){ + throw std::runtime_error("boost::numeric::ublas::static_tensor( const OtherTensor& ) : The tensor should have equal number of extents"); + } + + std::copy(other.begin(), other.end(), super_type::begin()); + } + + template + constexpr fixed_rank_tensor (basic_tensor && other) + : super_type(other.extents()) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::fixed_rank_tensor( OtherTensor&& ) : The OtherTensor should have a tensor type" + ); + + static_assert( std::is_same_v, + "boost::numeric::ublas::fixed_rank_tensor( OtherTensor&& ) : The tensor should have same value type" + ); + + if ( other.extents().size() != R ){ + throw std::runtime_error("boost::numeric::ublas::static_tensor( OtherTensor&& ) : The tensor should have equal number of extents"); + } + + std::move(other.begin(), other.end(), super_type::begin()); + } + + inline + constexpr fixed_rank_tensor& operator=(const_reference v) noexcept{ + std::fill(super_type::begin(), super_type::end(), v); + return *this; + } + }; + + template + fixed_rank_tensor( E const&, V const& ) -> fixed_rank_tensor; + + template + fixed_rank_tensor( E const& ) -> fixed_rank_tensor; + +} // boost::numeric::ublas + +namespace boost::numeric::ublas{ + + template + struct tensor_traits< fixed_rank_tensor > { + using container_type= std::vector< T >; + using extents_type = dynamic_extents; + using layout_type = F; + using container_tag = dynamic_tensor_tag; + }; + +} // boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/functions.hpp b/include/boost/numeric/ublas/tensor/functions.hpp index a0f37c41b..0d8c34e7f 100644 --- a/include/boost/numeric/ublas/tensor/functions.hpp +++ b/include/boost/numeric/ublas/tensor/functions.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -24,573 +24,645 @@ #include #include #include -#include -#include +#include +#include +#include +#include #include +namespace boost::numeric::ublas{ + + template + struct dynamic_tensor; + + template + struct static_tensor; + + template + struct fixed_rank_tensor; + +} // namespace boost::numeric::ublas + + // dynamic_functions namespace boost::numeric::ublas { - - namespace detail{ - // MSVC 14.1 bug - // cannot use ::_size inside constexpr function - // basic_extents does not contains _size member because of which - // it complains about it - - template - constexpr auto extents_result_type_tensor_times_vector( E const& ){ - static_assert(is_static_rank::value, - "boost::numeric::ublas::extents_result_type_tensor_times_vector() : invalid type, type should be an extents"); - using size_type = typename E::size_type; - auto ret = dynamic_extents< std::max( size_type( E::_size - 1 ), size_type(2) )>(); - ret.fill(typename E::value_type(1)); - return ret; - } - - template - constexpr auto extents_result_type_tensor_times_vector( basic_extents const& e ){ - using size_type = typename basic_extents::size_type; - return dynamic_extents<>{ typename dynamic_extents<>::base_type(std::max( size_type( e.size() - 1), size_type(2) ),1) } ; - } - - template - constexpr auto extents_result_type_tensor_times_matrix( E const& a ){ - static_assert(is_static_rank::value, - "boost::numeric::ublas::extents_result_type_tensor_times_matrix() : invalid type, type should be an extents"); - return dynamic_extents(a); - } - - template - constexpr auto extents_result_type_tensor_times_matrix( basic_extents const& e ){ - return dynamic_extents<>{ e } ; - } - - template - constexpr auto extents_result_type_outer_prod( basic_static_extents const&, basic_static_extents const& ){ - return dynamic_extents(); - } - - template - constexpr auto extents_result_type_outer_prod( basic_static_extents const&, basic_fixed_rank_extents const& ){ - return dynamic_extents(); - } - - template - constexpr auto extents_result_type_outer_prod( basic_fixed_rank_extents const&, basic_static_extents const& ){ - return dynamic_extents(); - } - - template - auto extents_result_type_outer_prod( E1 const& e1, E2 const& e2){ - return dynamic_extents<>( std::vector( e1.size() + e2.size(), 1 ) ); - } - - } // namespace detail - - /** @brief Computes the m-mode tensor-times-vector product - * - * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] - * - * @note calls ublas::ttv - * - * @param[in] m contraction dimension with 1 <= m <= p - * @param[in] a tensor object A with order p - * @param[in] b vector object B - * - * @returns tensor object C with order p-1, the same storage format and allocator type as A - */ - template - inline decltype(auto) prod(tensor const &a, vector const &b, const std::size_t m) - { - - using tensor_type = tensor; - using extents_type = typename tensor_type::extents_type; - using value_type = typename tensor_type::value_type; - using size_type = typename extents_type::size_type; - - auto const p = std::size_t(a.rank()); - - if (m == 0) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttv): " - "contraction mode must be greater than zero."); - - if (p < m) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttv): rank of tensor must be " - "greater than or equal to the modus."); - - if (a.empty()) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttv): first " - "argument tensor should not be empty."); - - if (b.size() == 0) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttv): second " - "argument vector should not be empty."); - - auto nc = detail::extents_result_type_tensor_times_vector(a.extents()); - auto nb = std::vector{b.size(), 1}; - auto a_extents = a.extents(); - for (auto i = size_type(0), j = size_type(0); i < p; ++i) - if (i != m - 1) - nc[j++] = a_extents.at(i); - - - auto c = tensor >(nc, value_type{}); - auto bb = &(b(0)); - ttv(m, p, - c.data(), c.extents().data(), c.strides().data(), - a.data(), a.extents().data(), a.strides().data(), - bb, nb.data(), nb.data()); - return c; - } - - /** @brief Computes the m-mode tensor-times-matrix product - * - * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] - * - * @note calls ublas::ttm - * - * @param[in] a tensor object A with order p - * @param[in] b vector object B - * @param[in] m contraction dimension with 1 <= m <= p - * - * @returns tensor object C with order p, the same storage format and allocator type as A - */ - template - inline decltype(auto) prod(tensor const &a, matrix const &b, const std::size_t m) - { - using tensor_type = tensor; - using dynamic_strides_type = strides_t,F>; - using value_type = typename tensor_type::value_type; - - auto const p = a.rank(); - - if (m == 0) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttm): " - "contraction mode must be greater than zero."); - - if (p < m || m > a.extents().size()) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttm): rank " - "of the tensor must be greater equal the modus."); - - if (a.empty()) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttm): first " - "argument tensor should not be empty."); - - if (b.size1() * b.size2() == 0) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttm): second " - "argument matrix should not be empty."); - - auto nc = detail::extents_result_type_tensor_times_matrix(a.extents()); - auto nb = dynamic_extents<>{b.size1(), b.size2()}; - - auto wb = dynamic_strides_type(nb); - - nc[m - 1] = nb[0]; - - auto c = tensor(nc, value_type{}); - - auto bb = &(b(0, 0)); - ttm(m, p, - c.data(), c.extents().data(), c.strides().data(), - a.data(), a.extents().data(), a.strides().data(), - bb, nb.data(), wb.data()); - - return c; - } - - /** @brief Computes the q-mode tensor-times-tensor product - * - * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) - * - * @note calls ublas::ttt - * - * na[phia[x]] = nb[phib[x]] for 1 <= x <= q - * - * @param[in] phia one-based permutation tuple of length q for the first - * input tensor a - * @param[in] phib one-based permutation tuple of length q for the second - * input tensor b - * @param[in] a left-hand side tensor with order r+q - * @param[in] b right-hand side tensor with order s+q - * @result tensor with order r+s - */ - template - inline decltype(auto) prod(tensor const &a, tensor const &b, - std::vector const &phia, std::vector const &phib) - { - - using tensor_type = tensor; - using extents_type_1 = E1; - using value_type = typename tensor_type::value_type; - using size_type = typename extents_type_1::value_type; - - auto const pa = a.rank(); - auto const pb = b.rank(); - - auto const q = size_type(phia.size()); - - if (pa == 0ul) - throw std::runtime_error("error in ublas::prod: order of left-hand side tensor must be greater than 0."); - if (pb == 0ul) - throw std::runtime_error("error in ublas::prod: order of right-hand side tensor must be greater than 0."); - if (pa < q) - throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the left-hand side tensor."); - if (pb < q) - throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the right-hand side tensor."); - - if (q != phib.size()) - throw std::runtime_error("error in ublas::prod: permutation tuples must have the same length."); - - if (pa < phia.size()) - throw std::runtime_error("error in ublas::prod: permutation tuple for the left-hand side tensor cannot be greater than the corresponding order."); - if (pb < phib.size()) - throw std::runtime_error("error in ublas::prod: permutation tuple for the right-hand side tensor cannot be greater than the corresponding order."); - - auto const &na = a.extents(); - auto const &nb = b.extents(); - - for (auto i = 0ul; i < q; ++i) - if (na.at(phia.at(i) - 1) != nb.at(phib.at(i) - 1)) - throw std::runtime_error("error in ublas::prod: permutations of the extents are not correct."); - - auto const r = pa - q; - auto const s = pb - q; - - std::vector phia1(pa), phib1(pb); - std::iota(phia1.begin(), phia1.end(), 1ul); - std::iota(phib1.begin(), phib1.end(), 1ul); - - std::vector nc(std::max(r + s, size_type(2)), size_type(1)); - - for (auto i = 0ul; i < phia.size(); ++i) - *std::remove(phia1.begin(), phia1.end(), phia.at(i)) = phia.at(i); - - //phia1.erase( std::remove(phia1.begin(), phia1.end(), phia.at(i)), phia1.end() ) ; - - assert(phia1.size() == pa); - - for (auto i = 0ul; i < r; ++i) - nc[i] = na[phia1[i] - 1]; - - for (auto i = 0ul; i < phib.size(); ++i) - *std::remove(phib1.begin(), phib1.end(), phib.at(i)) = phib.at(i); - //phib1.erase( std::remove(phib1.begin(), phib1.end(), phia.at(i)), phib1.end() ) ; - - assert(phib1.size() == pb); - - for (auto i = 0ul; i < s; ++i) - nc[r + i] = nb[phib1[i] - 1]; - - // std::copy( phib.begin(), phib.end(), phib1.end() ); - - assert(phia1.size() == pa); - assert(phib1.size() == pb); - - auto c = tensor(dynamic_extents<>(nc), value_type{}); - - ttt(pa, pb, q, - phia1.data(), phib1.data(), - c.data(), c.extents().data(), c.strides().data(), - a.data(), a.extents().data(), a.strides().data(), - b.data(), b.extents().data(), b.strides().data()); - - return c; - } - - // template - // auto operator*( tensor_index const& lhs, tensor_index - // const& rhs) - - /** @brief Computes the q-mode tensor-times-tensor product - * - * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) - * - * @note calls ublas::ttt - * - * na[phi[x]] = nb[phi[x]] for 1 <= x <= q - * - * @param[in] phi one-based permutation tuple of length q for bot input - * tensors - * @param[in] a left-hand side tensor with order r+q - * @param[in] b right-hand side tensor with order s+q - * @result tensor with order r+s - */ - template - inline decltype(auto) prod(tensor const &a, tensor const &b, - std::vector const &phi) - { - return prod(a, b, phi, phi); - } - - /** @brief Computes the inner product of two tensors - * - * Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,jp]) - * - * @note calls inner function - * - * @param[in] a tensor object A - * @param[in] b tensor object B - * - * @returns a value type. - */ - template - inline decltype(auto) inner_prod(tensor const &a, tensor const &b) - { - using value_type = typename tensor::value_type; - - if (a.rank() != b.rank()) - throw std::length_error("error in boost::numeric::ublas::inner_prod: Rank of both tensors must be the same."); - - if (a.empty() || b.empty()) - throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensors should not be empty."); - - if (a.extents() != b.extents()) - throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensor extents should be the same."); - - return inner(a.rank(), a.extents().data(), - a.data(), a.strides().data(), - b.data(), b.strides().data(), value_type{0}); - } - - /** @brief Computes the outer product of two tensors - * - * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] - * - * @note calls outer function - * - * @param[in] a tensor object A - * @param[in] b tensor object B - * - * @returns tensor object C with the same storage format F and allocator type A1 - */ - template ::value && - detail::is_static::value ) - ,int> = 0 - > - inline decltype(auto) outer_prod(tensor const &a, tensor const &b) - { - - if (a.empty() || b.empty()) - throw std::runtime_error( - "error in boost::numeric::ublas::outer_prod: " - "tensors should not be empty."); - - auto nc = detail::extents_result_type_outer_prod(a.extents(), b.extents()); - - auto a_extents = a.extents(); - auto b_extents = b.extents(); - - for(auto i = 0u; i < a.rank(); ++i) - nc.at(i) = a_extents.at(i); - - for(auto i = 0u; i < b.rank(); ++i) - nc.at(a.rank()+i) = b_extents.at(i); - - auto c = tensor(nc, V{}); - - outer(c.data(), c.rank(), c.extents().data(), c.strides().data(), - a.data(), a.rank(), a_extents.data(), a.strides().data(), - b.data(), b.rank(), b_extents.data(), b.strides().data()); - - return c; - } - - /** @brief Transposes a tensor according to a permutation tuple - * - * Implements C[tau[i1],tau[i2]...,tau[ip]] = A[i1,i2,...,ip] - * - * @note calls trans function - * - * @param[in] a tensor object of rank p - * @param[in] tau one-based permutation tuple of length p - * @returns a transposed tensor object with the same storage format F and allocator type A - */ - template - inline decltype(auto) trans(tensor const &a, std::vector const &tau) - { - using result_tensor_type = tensor, F, std::vector>; - // using strides_type = typename tensor_type::strides_type; - - if (a.empty()) - return result_tensor_type{}; - - auto const p = a.rank(); - auto const &na = a.extents(); - - auto nc = typename dynamic_extents<>::base_type(p); - for (auto i = 0u; i < p; ++i) - nc.at(tau.at(i) - 1) = na.at(i); - - // auto wc = strides_type(extents_type(nc)); - auto c = result_tensor_type(dynamic_extents<>(nc)); - - trans(a.rank(), a.extents().data(), tau.data(), - c.data(), c.strides().data(), - a.data(), a.strides().data()); - - // auto wc_pi = typename strides_type::base_type (p); - // for(auto i = 0u; i < p; ++i) - // wc_pi.at(tau.at(i)-1) = c.strides().at(i); - - // copy(a.rank(), - // a.extents().data(), - // c.data(), wc_pi.data(), - // a.data(), a.strides().data() ); - - return c; - } - /** - * - * @brief Computes the frobenius nor of a tensor - * - * @note Calls accumulate on the tensor. - * - * implements - * k = sqrt( sum_(i1,...,ip) A(i1,...,ip)^2 ) - * - * @tparam V the data type of tensor - * @tparam F the format of tensor storage - * @tparam A the array_type of tensor - * @param a the tensor whose norm is expected of rank p. - * @return the frobenius norm of a tensor. - */ - template - inline decltype(auto) norm(tensor const &a) - { - using tensor_type = tensor; - using value_type = typename tensor_type::value_type; - - static_assert(std::is_default_constructible::value, - "Value type of tensor must be default construct able in order " - "to call boost::numeric::ublas::norm"); - if (a.empty()) - { - throw std::runtime_error( - "error in boost::numeric::ublas::norm: tensors should not be empty."); - } - - return std::sqrt(accumulate(a.order(), a.extents().data(), a.data(), a.strides().data(), value_type{}, - [](auto const &l, auto const &r) { return l + r * r; })); - } - - - /** @brief Computes the complex conjugate component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression - */ - template - auto conj(detail::tensor_expression,E,F,A>,D> const& expr) - { - return detail::make_unary_tensor_expression,E,F,A>> (expr(), [] (auto const& l) { return std::conj( l ); } ); - } - - /** @brief Computes the complex conjugate component of tensor elements within a tensor expression - * - * @param[in] expr tensor expression - * @returns complex tensor - */ - template - auto conj(detail::tensor_expression const& expr) - { - using tensor_type = T; - using value_type = typename tensor_type::value_type; - using extents_type = typename tensor_type::extents_type; - using layout_type = typename tensor_type::layout_type; - using array_type = typename tensor_type::array_type; - - using new_value_type = std::complex; - using new_array_type = typename storage_traits::template rebind; - - using tensor_complex_type = tensor; - - if( detail::retrieve_extents( expr ).empty() ) - throw std::runtime_error("error in boost::numeric::ublas::conj: tensors should not be empty."); - - auto a = tensor_type( expr ); - auto c = tensor_complex_type( a.extents() ); - - std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::conj(l) ; } ); - - return c; - } - - /** @brief Extract the real component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression - */ - template - auto real(detail::tensor_expression const& expr) { - return detail::make_unary_tensor_expression (expr(), [] (auto const& l) { return std::real( l ); } ); - } - - /** @brief Extract the real component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression - */ - template - auto real(detail::tensor_expression,E,F,A>,D> const& expr) - { - using tensor_complex_type = tensor,E,F,A>; - using tensor_type = tensor::template rebind>; - - if( detail::retrieve_extents( expr ).empty() ) - throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); - - auto a = tensor_complex_type( expr ); - auto c = tensor_type( a.extents() ); - - std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::real(l) ; } ); - - return c; - } - - - /** @brief Extract the imaginary component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression - */ - template - auto imag(detail::tensor_expression const& lhs) { - return detail::make_unary_tensor_expression (lhs(), [] (auto const& l) { return std::imag( l ); } ); - } - - - /** @brief Extract the imag component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression - */ - template - auto imag(detail::tensor_expression,E,F,A>,D> const& expr) - { - using tensor_complex_type = tensor,E,F,A>; - using tensor_type = tensor::template rebind>; - - if( detail::retrieve_extents( expr ).empty() ) - throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); - - auto a = tensor_complex_type( expr ); - auto c = tensor_type( a.extents() ); - - std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::imag(l) ; } ); - - return c; - } + namespace detail{ + + template + constexpr auto extents_result_tensor_times_vector( E const& ){ + static_assert(is_static_rank::value, + "boost::numeric::ublas::extents_result_tensor_times_vector() : invalid type, type should be an extents"); + using size_type = typename E::size_type; + auto ret = dynamic_extents< std::max( size_type( E::_size - 1 ), size_type(2) )>(); + ret.fill(typename E::value_type(1)); + return ret; + } + + template + constexpr auto extents_result_tensor_times_vector( basic_extents const& e ){ + using size_type = typename basic_extents::size_type; + return dynamic_extents<>{ typename dynamic_extents<>::base_type(std::max( size_type( e.size() - 1), size_type(2) ),1) } ; + } + + template + constexpr auto extents_result_tensor_times_matrix( E const& a ){ + static_assert(is_static_rank::value, + "boost::numeric::ublas::extents_result_tensor_times_matrix() : invalid type, type should be an extents"); + return dynamic_extents(a); + } + + template + constexpr auto extents_result_tensor_times_matrix( basic_extents const& e ){ + return dynamic_extents<>{ e } ; + } + + template + constexpr auto extents_result_type_outer_prod( basic_static_extents const&, basic_static_extents const& ){ + return dynamic_extents(); + } + + template + constexpr auto extents_result_type_outer_prod( basic_static_extents const&, basic_fixed_rank_extents const& ){ + return dynamic_extents(); + } + + template + constexpr auto extents_result_type_outer_prod( basic_fixed_rank_extents const&, basic_static_extents const& ){ + return dynamic_extents(); + } + + template + auto extents_result_type_outer_prod( E1 const& e1, E2 const& e2){ + return dynamic_extents<>( std::vector( e1.size() + e2.size(), 1 ) ); + } + + template + struct is_complex : std::false_type{}; + + template + struct is_complex< std::complex > : std::true_type{}; + + template + inline static constexpr bool is_complex_v = is_complex::value; + + } // namespace detail + + /** @brief Computes the m-mode tensor-times-vector product + * + * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] + * + * @note calls ublas::ttv + * + * @param[in] m contraction dimension with 1 <= m <= p + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p-1, the same storage format and allocator type as A + */ + template + inline decltype(auto) prod( basic_tensor< TensorType > const &a, + vector const &b, + const std::size_t m) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::prod(ttv) : tensor type should be valid tensor" + ); + using tensor_type = TensorType; + using extents_type = typename tensor_type::extents_type; + using layout_type = typename tensor_type::layout_type; + using value_type = typename tensor_type::value_type; + using size_type = typename extents_type::size_type; + + auto const p = std::size_t(a.rank()); + + if (m == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttv): " + "contraction mode must be greater than zero."); + + if (p < m) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttv): rank of tensor must be " + "greater than or equal to the modus."); + + if (a.empty()) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttv): first " + "argument tensor should not be empty."); + + if (b.size() == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttv): second " + "argument vector should not be empty."); + + auto nc = detail::extents_result_tensor_times_vector(a.extents()); + auto nb = std::vector{b.size(), 1}; + + auto a_extents = a.extents(); + for (auto i = size_type(0), j = size_type(0); i < p; ++i) + if (i != m - 1) + nc[j++] = a_extents.at(i); + + + auto c = result_tensor_t( nc, value_type{} ); + auto bb = &(b(0)); + ttv(m, p, + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + bb, nb.data(), nb.data()); + return c; + } + + /** @brief Computes the m-mode tensor-times-matrix product + * + * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] + * + * @note calls ublas::ttm + * + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * @param[in] m contraction dimension with 1 <= m <= p + * + * @returns tensor object C with order p, the same storage format and allocator type as A + */ + template + inline decltype(auto) prod( basic_tensor< TensorType > const &a, + matrix const &b, + const std::size_t m) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::prod(ttm) : tensor type should be valid tensor" + ); + + using tensor_type = TensorType; + using dynamic_strides_type = strides_t, typename tensor_type::layout_type>; + using value_type = typename tensor_type::value_type; + using layout_type = typename tensor_type::layout_type; + + auto const p = a.rank(); + + if (m == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttm): " + "contraction mode must be greater than zero."); + + if (p < m || m > a.extents().size()) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttm): rank " + "of the tensor must be greater equal the modus."); + + if (a.empty()) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttm): first " + "argument tensor should not be empty."); + + if (b.size1() * b.size2() == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttm): second " + "argument matrix should not be empty."); + + auto nc = detail::extents_result_tensor_times_matrix(a.extents()); + auto nb = dynamic_extents<>{b.size1(), b.size2()}; + + auto wb = dynamic_strides_type(nb); + + nc[m - 1] = nb[0]; + + auto c = result_tensor_t(nc, value_type{}); + + auto bb = &(b(0, 0)); + ttm(m, p, + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + bb, nb.data(), wb.data()); + + return c; + } + + /** @brief Computes the q-mode tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls ublas::ttt + * + * na[phia[x]] = nb[phib[x]] for 1 <= x <= q + * + * @param[in] phia one-based permutation tuple of length q for the first + * input tensor a + * @param[in] phib one-based permutation tuple of length q for the second + * input tensor b + * @param[in] a left-hand side tensor with order r+q + * @param[in] b right-hand side tensor with order s+q + * @result tensor with order r+s + */ + template + inline decltype(auto) prod(basic_tensor< TensorType1 > const &a, basic_tensor< TensorType2 > const &b, + std::vector const &phia, std::vector const &phib) + { + + static_assert( is_valid_tensor_v && is_valid_tensor_v, + "boost::numeric::ublas::prod(ttt) : tensor type should be valid tensor" + ); + + using tensor_type = TensorType1; + using extents_type_1 = typename tensor_type::extents_type; + using value_type = typename tensor_type::value_type; + using layout_type = typename tensor_type::layout_type; + using size_type = typename extents_type_1::size_type; + + auto const pa = a.rank(); + auto const pb = b.rank(); + + auto const q = size_type(phia.size()); + + if (pa == 0ul) + throw std::runtime_error("error in ublas::prod: order of left-hand side tensor must be greater than 0."); + if (pb == 0ul) + throw std::runtime_error("error in ublas::prod: order of right-hand side tensor must be greater than 0."); + if (pa < q) + throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the left-hand side tensor."); + if (pb < q) + throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the right-hand side tensor."); + + if (q != phib.size()) + throw std::runtime_error("error in ublas::prod: permutation tuples must have the same length."); + + if (pa < phia.size()) + throw std::runtime_error("error in ublas::prod: permutation tuple for the left-hand side tensor cannot be greater than the corresponding order."); + if (pb < phib.size()) + throw std::runtime_error("error in ublas::prod: permutation tuple for the right-hand side tensor cannot be greater than the corresponding order."); + + auto const &na = a.extents(); + auto const &nb = b.extents(); + + for (auto i = 0ul; i < q; ++i) + if (na.at(phia.at(i) - 1) != nb.at(phib.at(i) - 1)) + throw std::runtime_error("error in ublas::prod: permutations of the extents are not correct."); + + auto const r = pa - q; + auto const s = pb - q; + + std::vector phia1(pa), phib1(pb); + std::iota(phia1.begin(), phia1.end(), 1ul); + std::iota(phib1.begin(), phib1.end(), 1ul); + + std::vector nc(std::max(r + s, size_type(2)), size_type(1)); + + for (auto i = 0ul; i < phia.size(); ++i) + *std::remove(phia1.begin(), phia1.end(), phia.at(i)) = phia.at(i); + + //phia1.erase( std::remove(phia1.begin(), phia1.end(), phia.at(i)), phia1.end() ) ; + + assert(phia1.size() == pa); + + for (auto i = 0ul; i < r; ++i) + nc[i] = na[phia1[i] - 1]; + + for (auto i = 0ul; i < phib.size(); ++i) + *std::remove(phib1.begin(), phib1.end(), phib.at(i)) = phib.at(i); + //phib1.erase( std::remove(phib1.begin(), phib1.end(), phia.at(i)), phib1.end() ) ; + + assert(phib1.size() == pb); + + for (auto i = 0ul; i < s; ++i) + nc[r + i] = nb[phib1[i] - 1]; + + // std::copy( phib.begin(), phib.end(), phib1.end() ); + + assert(phia1.size() == pa); + assert(phib1.size() == pb); + + auto c = dynamic_tensor( dynamic_extents<>(nc), value_type{} );//tensor(dynamic_extents<>(nc), value_type{}); + + ttt(pa, pb, q, + phia1.data(), phib1.data(), + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + b.data(), b.extents().data(), b.strides().data()); + + return c; + } + + // template + // auto operator*( tensor_index const& lhs, tensor_index + // const& rhs) + + /** @brief Computes the q-mode tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls ublas::ttt + * + * na[phi[x]] = nb[phi[x]] for 1 <= x <= q + * + * @param[in] phi one-based permutation tuple of length q for bot input + * tensors + * @param[in] a left-hand side tensor with order r+q + * @param[in] b right-hand side tensor with order s+q + * @result tensor with order r+s + */ + template + inline decltype(auto) prod(basic_tensor< TensorType1 > const &a, basic_tensor< TensorType2 > const &b, + std::vector const &phi) + { + static_assert( is_valid_tensor_v && is_valid_tensor_v, + "boost::numeric::ublas::prod(ttt) : tensor type should be valid tensor" + ); + + return prod(a, b, phi, phi); + } + + /** @brief Computes the inner product of two tensors + * + * Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,jp]) + * + * @note calls inner function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns a value type. + */ + template + inline decltype(auto) inner_prod(basic_tensor< TensorType1 > const &a, basic_tensor< TensorType2 > const &b) + { + static_assert( is_valid_tensor_v && is_valid_tensor_v, + "boost::numeric::ublas::prod(ttt) : tensor type should be valid tensor" + ); + + using value_type = typename TensorType1::value_type; + + if (a.rank() != b.rank()) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Rank of both tensors must be the same."); + + if (a.empty() || b.empty()) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensors should not be empty."); + + if (a.extents() != b.extents()) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensor extents should be the same."); + + return inner(a.rank(), a.extents().data(), + a.data(), a.strides().data(), + b.data(), b.strides().data(), value_type{0}); + } + + /** @brief Computes the outer product of two tensors + * + * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] + * + * @note calls outer function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns tensor object C with the same storage format F and allocator type A1 + */ + template ::value && + is_static::value ) + ,int> = 0 + > + inline decltype(auto) outer_prod(basic_tensor< TensorType1 > const &a, basic_tensor< TensorType2 > const &b) + { + using value_type = typename TensorType1::value_type; + using layout_type = typename TensorType1::layout_type; + + static_assert( is_valid_tensor_v && is_valid_tensor_v, + "boost::numeric::ublas::outer_prod() : tensor type should be valid tensor" + ); + + if (a.empty() || b.empty()) + throw std::runtime_error( + "error in boost::numeric::ublas::outer_prod: " + "tensors should not be empty."); + + auto nc = detail::extents_result_type_outer_prod(a.extents(), b.extents()); + + auto a_extents = a.extents(); + auto b_extents = b.extents(); + + for(auto i = 0u; i < a.rank(); ++i) + nc.at(i) = a_extents.at(i); + + for(auto i = 0u; i < b.rank(); ++i) + nc.at(a.rank()+i) = b_extents.at(i); + + auto c = result_tensor_t( nc, value_type{} ); + + outer(c.data(), c.rank(), c.extents().data(), c.strides().data(), + a.data(), a.rank(), a_extents.data(), a.strides().data(), + b.data(), b.rank(), b_extents.data(), b.strides().data()); + + return c; + } + + /** @brief Transposes a tensor according to a permutation tuple + * + * Implements C[tau[i1],tau[i2]...,tau[ip]] = A[i1,i2,...,ip] + * + * @note calls trans function + * + * @param[in] a tensor object of rank p + * @param[in] tau one-based permutation tuple of length p + * @returns a transposed tensor object with the same storage format F and allocator type A + */ + template + inline decltype(auto) trans(basic_tensor< TensorType > const &a, std::vector const &tau) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::trans() : tensor type should be valid tensor" + ); + + using value_type = typename TensorType::value_type; + using layout_type = typename TensorType::layout_type; + using result_tensor_type = dynamic_tensor; + // using strides_type = typename tensor_type::strides_type; + + if (a.empty()) + return result_tensor_type{}; + + auto const p = a.rank(); + auto const &na = a.extents(); + + auto nc = typename dynamic_extents<>::base_type(p); + for (auto i = 0u; i < p; ++i) + nc.at(tau.at(i) - 1) = na.at(i); + + // auto wc = strides_type(extents_type(nc)); + auto c = result_tensor_type(dynamic_extents<>(nc)); + + trans(a.rank(), a.extents().data(), tau.data(), + c.data(), c.strides().data(), + a.data(), a.strides().data()); + + // auto wc_pi = typename strides_type::base_type (p); + // for(auto i = 0u; i < p; ++i) + // wc_pi.at(tau.at(i)-1) = c.strides().at(i); + + // copy(a.rank(), + // a.extents().data(), + // c.data(), wc_pi.data(), + // a.data(), a.strides().data() ); + + return c; + } + /** + * + * @brief Computes the frobenius nor of a tensor + * + * @note Calls accumulate on the tensor. + * + * implements + * k = sqrt( sum_(i1,...,ip) A(i1,...,ip)^2 ) + * + * @tparam V the data type of tensor + * @tparam F the format of tensor storage + * @tparam A the array_type of tensor + * @param a the tensor whose norm is expected of rank p. + * @return the frobenius norm of a tensor. + */ + template + inline decltype(auto) norm(basic_tensor< TensorType > const &a) + { + + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::norm() : tensor type should be valid tensor" + ); + + using tensor_type = TensorType; + using value_type = typename tensor_type::value_type; + + static_assert(std::is_default_constructible::value, + "Value type of tensor must be default construct able in order " + "to call boost::numeric::ublas::norm"); + if (a.empty()) + { + throw std::runtime_error( + "error in boost::numeric::ublas::norm: tensors should not be empty."); + } + + return std::sqrt(accumulate(a.order(), a.extents().data(), a.data(), a.strides().data(), value_type{}, + [](auto const &l, auto const &r) { return l + r * r; })); + } + + + /** @brief Computes the complex conjugate component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ + template, int > = 0 + > + auto conj(detail::tensor_expression< basic_tensor, D > const& expr) + { + return detail::make_unary_tensor_expression< basic_tensor > (expr(), [] (auto const& l) { return std::conj( l ); } ); + } + + /** @brief Computes the complex conjugate component of tensor elements within a tensor expression + * + * @param[in] expr tensor expression + * @returns complex tensor + */ + template + auto conj(detail::tensor_expression const& expr) + { + using tensor_type = T ; + using value_type = typename tensor_type::value_type; + + using new_value_type = std::complex; + + using tensor_complex_type = tensor_rebind_t;//decltype(ret); + + if( detail::retrieve_extents( expr ).empty() ) + throw std::runtime_error("error in boost::numeric::ublas::conj: tensors should not be empty."); + + auto a = tensor_type( expr ); + auto c = tensor_complex_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::conj(l) ; } ); + + return c; + } + + /** @brief Extract the real component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ + template + auto real(detail::tensor_expression const& expr) { + return detail::make_unary_tensor_expression (expr(), [] (auto const& l) { return std::real( l ); } ); + } + + /** @brief Extract the real component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ + template, int > = 0 + > + auto real(detail::tensor_expression< basic_tensor< TensorType > ,D > const& expr) + { + using tensor_complex_type = TensorType; + using complex_type = typename tensor_complex_type::value_type; + using value_type = typename complex_type::value_type; + + using tensor_type = tensor_rebind_t; + + if( detail::retrieve_extents( expr ).empty() ) + throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); + + auto a = tensor_complex_type( expr ); + auto c = tensor_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::real(l) ; } ); + + return c; + } + + + /** @brief Extract the imaginary component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ + template + auto imag(detail::tensor_expression const& lhs) { + return detail::make_unary_tensor_expression (lhs(), [] (auto const& l) { return std::imag( l ); } ); + } + + + /** @brief Extract the imag component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ + template, int > = 0 + > + auto imag(detail::tensor_expression< basic_tensor< TensorType > ,D> const& expr) + { + using tensor_complex_type = TensorType; + using complex_type = typename tensor_complex_type::value_type; + using value_type = typename complex_type::value_type; + + using tensor_complex_type = TensorType; + using tensor_type = tensor_rebind_t; + + if( detail::retrieve_extents( expr ).empty() ) + throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); + + auto a = tensor_complex_type( expr ); + auto c = tensor_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::imag(l) ; } ); + + return c; + } } @@ -598,240 +670,258 @@ namespace boost::numeric::ublas namespace boost::numeric::ublas { - namespace detail{ - - template - inline - constexpr auto extents_result_type_tensor_times_vector(basic_static_extents, - basic_static_extents, basic_static_extents) - { - return basic_static_extents{}; - } - - template - inline - constexpr auto extents_result_type_tensor_times_vector(basic_static_extents, - basic_static_extents, basic_static_extents = basic_static_extents{}) - { - if constexpr(I != M - 1){ - return extents_result_type_tensor_times_vector - ( basic_static_extents{}, basic_static_extents{}, basic_static_extents{} ); - }else{ - return extents_result_type_tensor_times_vector - ( basic_static_extents{}, basic_static_extents{}, basic_static_extents{} ); - } - } - - - template - inline - constexpr auto extents_result_type_tensor_times_vector(basic_static_extents const& e) - { - using size_type = typename basic_static_extents::size_type; - auto ones = typename impl::make_sequence_of_ones_t< T, std::max( size_type(2), sizeof...(E) ) >::extents_type{}; - return extents_result_type_tensor_times_vector(e, ones); - } - - template - inline - constexpr auto static_extents_set_at - ( basic_static_extents const&, basic_static_extents = basic_static_extents{}){ - static_assert( I < sizeof...(E) + 1, "boost::numeric::ublas::detail::static_extents_set_at(): out of bound"); - if constexpr( sizeof...(E) == 0 ){ - if constexpr( I == 0 ){ - return basic_static_extents{}; - }else{ - return basic_static_extents{}; - } - }else{ - if constexpr(I == 0){ - return basic_static_extents{}; - }else{ - return static_extents_set_at( basic_static_extents{}, basic_static_extents{} ); - } - } - } - - namespace impl{ - template - struct concat< basic_static_extents, basic_static_extents >{ - using type = basic_static_extents; - }; - } - - } // namespace detail - - /** @brief Computes the m-mode tensor-times-vector product - * - * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] - * - * @note calls ublas::ttv - * - * @tparam m contraction dimension with 1 <= m <= p - * @param[in] a tensor object A with order p - * @param[in] b vector object B - * - * @returns tensor object C with order p-1, the same storage format and allocator type as A - */ - template ::value,int> = 0 - > - inline decltype(auto) prod(tensor const &a, vector const &b) - { - - using tensor_type = tensor; - using extents_type = typename tensor_type::extents_type; - using value_type = typename tensor_type::value_type; - - auto const p = std::size_t(a.rank()); - - static_assert( M != 0, - "error in boost::numeric::ublas::prod(ttv): " - "contraction mode must be greater than zero."); - - static_assert( extents_type::_size >= M, - "error in boost::numeric::ublas::prod(ttv): rank of tensor must be " - "greater than or equal to the modus."); - - static_assert(extents_type::_size != 0, - "error in boost::numeric::ublas::prod(ttv): first " - "argument tensor should not be empty."); - - if (b.size() == 0) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttv): second " - "argument vector should not be empty."); - - auto nc = detail::extents_result_type_tensor_times_vector(a.extents()); - auto nb = std::vector{b.size(), 1}; - - auto c = tensor(nc, value_type{}); - auto bb = &(b(0)); - - auto& a_static_extents = a.extents().base(); - auto& c_static_extents = c.extents().base(); - - auto& a_static_strides = a.strides().base(); - auto& c_static_strides = c.strides().base(); - - ttv(M, p, - c.data(), c_static_extents.data(), c_static_strides.data(), - a.data(), a_static_extents.data(), a_static_strides.data(), - bb, nb.data(), nb.data()); - - return c; - } - - /** @brief Computes the m-mode tensor-times-matrix product - * - * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] - * - * @note calls ublas::ttm - * - * @tparam m contraction dimension with 1 <= m <= p - * @param[in] a tensor object A with order p - * @param[in] b vector object B - * - * @returns tensor object C with order p, the same storage format and allocator type as A - */ - template ::value,int> = 0 - > - inline decltype(auto) prod(tensor const &a, matrix const &b) - { - using tensor_type = tensor; - using dynamic_strides_type = strides_t,F>; - using value_type = typename tensor_type::value_type; - - auto const p = a.rank(); - - static_assert(M != 0, - "error in boost::numeric::ublas::prod(ttm): " - "contraction mode must be greater than zero."); - - static_assert( E::_size >= M , - "error in boost::numeric::ublas::prod(ttm): rank " - "of the tensor must be greater equal the modus."); - - static_assert(E::_size, - "error in boost::numeric::ublas::prod(ttm): first " - "argument tensor should not be empty."); - - if (b.size1() * b.size2() == 0) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttm): second " - "argument matrix should not be empty."); - - auto nc = detail::static_extents_set_at< M - 1, MatricRow >( a.extents() ); - auto nb = dynamic_extents<>{b.size1(), b.size2()}; - - auto wb = dynamic_strides_type(nb); - - auto c = tensor(nc, value_type{}); - - auto bb = &(b(0, 0)); - - auto& a_static_extents = a.extents().base(); - auto& c_static_extents = c.extents().base(); - - auto& a_static_strides = a.strides().base(); - auto& c_static_strides = c.strides().base(); - ttm(M, p, - c.data(), c_static_extents.data(), c_static_strides.data(), - a.data(), a_static_extents.data(), a_static_strides.data(), - bb, nb.data(), wb.data()); - - return c; - } - - /** @brief Computes the outer product of two tensors - * - * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] - * - * @note calls outer function - * - * @param[in] a tensor object A - * @param[in] b tensor object B - * - * @returns tensor object C with the same storage format F and allocator type A1 - */ - template ::value && - detail::is_static::value - ,int> = 0 - > - inline decltype(auto) outer_prod(tensor const &a, tensor const &b) - { - if (a.empty() || b.empty()) - throw std::runtime_error( - "error in boost::numeric::ublas::outer_prod: " - "tensors should not be empty."); - using extents_type1 = std::decay_t< decltype(a.extents()) >; - using extents_type2 = std::decay_t< decltype(b.extents()) >; - auto nc = detail::impl::concat_t{}; - - auto a_extents = a.extents(); - auto b_extents = b.extents(); - - - auto c = tensor(nc, V{}); - - auto& a_static_extents = a_extents.base(); - auto& a_static_strides = a.strides().base(); - - auto& b_static_extents = b_extents.base(); - auto& b_static_strides = b.strides().base(); - - auto c_static_extents = c.extents().base(); - auto c_static_strides = c.strides().base(); - - outer(c.data(), c.rank(), c_static_extents.data(), c_static_strides.data(), - a.data(), a.rank(), a_static_extents.data(), a_static_strides.data(), - b.data(), b.rank(), b_static_extents.data(), b_static_strides.data()); - - return c; - } + namespace detail{ + + template + inline + constexpr auto extents_result_tensor_times_vector(basic_static_extents, + basic_static_extents, basic_static_extents) + { + return basic_static_extents{}; + } + + template + inline + constexpr auto extents_result_tensor_times_vector(basic_static_extents, + basic_static_extents, basic_static_extents = basic_static_extents{}) + { + if constexpr(I != M - 1){ + return extents_result_tensor_times_vector + ( basic_static_extents{}, basic_static_extents{}, basic_static_extents{} ); + }else{ + return extents_result_tensor_times_vector + ( basic_static_extents{}, basic_static_extents{}, basic_static_extents{} ); + } + } + + + template + inline + constexpr auto extents_result_tensor_times_vector(basic_static_extents const& e) + { + using size_type = typename basic_static_extents::size_type; + auto ones = typename impl::make_sequence_of_ones_t< T, std::max( size_type(2), sizeof...(E) ) >::extents_type{}; + return extents_result_tensor_times_vector(e, ones); + } + + template + inline + constexpr auto static_extents_set_at + ( basic_static_extents const&, basic_static_extents = basic_static_extents{}){ + static_assert( I < sizeof...(E) + 1, "boost::numeric::ublas::detail::static_extents_set_at(): out of bound"); + if constexpr( sizeof...(E) == 0 ){ + if constexpr( I == 0 ){ + return basic_static_extents{}; + }else{ + return basic_static_extents{}; + } + }else{ + if constexpr(I == 0){ + return basic_static_extents{}; + }else{ + return static_extents_set_at( basic_static_extents{}, basic_static_extents{} ); + } + } + } + + namespace impl{ + template + struct concat< basic_static_extents, basic_static_extents >{ + using type = basic_static_extents; + }; + } + + } // namespace detail + + /** @brief Computes the m-mode tensor-times-vector product + * + * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] + * + * @note calls ublas::ttv + * + * @tparam m contraction dimension with 1 <= m <= p + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p-1, the same storage format and allocator type as A + */ + template ::value,int> = 0 + > + inline decltype(auto) prod(basic_tensor< TensorType > const &a, vector const &b) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::prod(ttv) : tensor type should be valid tensor" + ); + + using tensor_type = TensorType; + using extents_type = typename tensor_type::extents_type; + using value_type = typename tensor_type::value_type; + using layout_type = typename tensor_type::layout_type; + + auto const p = std::size_t(a.rank()); + + static_assert( M != 0, + "error in boost::numeric::ublas::prod(ttv): " + "contraction mode must be greater than zero."); + + static_assert( extents_type::_size >= M, + "error in boost::numeric::ublas::prod(ttv): rank of tensor must be " + "greater than or equal to the modus."); + + static_assert(extents_type::_size != 0, + "error in boost::numeric::ublas::prod(ttv): first " + "argument tensor should not be empty."); + + if (b.size() == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttv): second " + "argument vector should not be empty."); + + auto nc = detail::extents_result_tensor_times_vector(a.extents()); + auto nb = std::vector{b.size(), 1}; + + auto c = static_tensor(value_type{}); + auto bb = &(b(0)); + + auto& a_static_extents = a.extents().base(); + auto& c_static_extents = c.extents().base(); + + auto& a_static_strides = a.strides().base(); + auto& c_static_strides = c.strides().base(); + + ttv(M, p, + c.data(), c_static_extents.data(), c_static_strides.data(), + a.data(), a_static_extents.data(), a_static_strides.data(), + bb, nb.data(), nb.data()); + + return c; + } + + /** @brief Computes the m-mode tensor-times-matrix product + * + * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] + * + * @note calls ublas::ttm + * + * @tparam m contraction dimension with 1 <= m <= p + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p, the same storage format and allocator type as A + */ + template ::value,int> = 0 + > + inline decltype(auto) prod(basic_tensor< TensorType > const &a, + matrix const &b) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::prod(ttm) : tensor type should be valid tensor" + ); + + using tensor_type = TensorType; + using extents_type = typename tensor_type::extents_type; + using layout_type = typename tensor_type::layout_type; + using dynamic_strides_type = strides_t, layout_type>; + using value_type = typename tensor_type::value_type; + + auto const p = a.rank(); + + static_assert(M != 0, + "error in boost::numeric::ublas::prod(ttm): " + "contraction mode must be greater than zero."); + + static_assert( extents_type::_size >= M , + "error in boost::numeric::ublas::prod(ttm): rank " + "of the tensor must be greater equal the modus."); + + static_assert( extents_type::_size, + "error in boost::numeric::ublas::prod(ttm): first " + "argument tensor should not be empty."); + + if (b.size1() * b.size2() == 0) + throw std::length_error( + "error in boost::numeric::ublas::prod(ttm): second " + "argument matrix should not be empty."); + + auto nc = detail::static_extents_set_at< M - 1, MatricRow >( a.extents() ); + auto nb = dynamic_extents<>{b.size1(), b.size2()}; + + auto wb = dynamic_strides_type(nb); + + auto c = static_tensor(value_type{}); + + auto bb = &(b(0, 0)); + + auto& a_static_extents = a.extents().base(); + auto& c_static_extents = c.extents().base(); + + auto& a_static_strides = a.strides().base(); + auto& c_static_strides = c.strides().base(); + ttm(M, p, + c.data(), c_static_extents.data(), c_static_strides.data(), + a.data(), a_static_extents.data(), a_static_strides.data(), + bb, nb.data(), wb.data()); + + return c; + } + + /** @brief Computes the outer product of two tensors + * + * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] + * + * @note calls outer function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns tensor object C with the same storage format F and allocator type A1 + */ + template ::value && + is_static< typename TensorType2::extents_type >::value + ,int> = 0 + > + inline decltype(auto) outer_prod(basic_tensor< TensorType1 > const &a, basic_tensor< TensorType2 > const &b) + { + static_assert( is_valid_tensor_v && is_valid_tensor_v, + "boost::numeric::ublas::outer_prod() : tensor type should be valid tensor" + ); + + if (a.empty() || b.empty()) + throw std::runtime_error( + "error in boost::numeric::ublas::outer_prod: " + "tensors should not be empty."); + using extents_type1 = std::decay_t< decltype(a.extents()) >; + using extents_type2 = std::decay_t< decltype(b.extents()) >; + using value_type = typename TensorType1::value_type; + using layout_type = typename TensorType1::layout_type; + + auto nc = detail::impl::concat_t{}; + + auto a_extents = a.extents(); + auto b_extents = b.extents(); + + + auto c = static_tensor(value_type{}); + + auto& a_static_extents = a_extents.base(); + auto& a_static_strides = a.strides().base(); + + auto& b_static_extents = b_extents.base(); + auto& b_static_strides = b.strides().base(); + + auto c_static_extents = c.extents().base(); + auto c_static_strides = c.strides().base(); + + outer(c.data(), c.rank(), c_static_extents.data(), c_static_strides.data(), + a.data(), a.rank(), a_static_extents.data(), a_static_strides.data(), + b.data(), b.rank(), b_static_extents.data(), b_static_strides.data()); + + return c; + } } diff --git a/include/boost/numeric/ublas/tensor/index.hpp b/include/boost/numeric/ublas/tensor/index.hpp index a8a40deb8..7de9e52e7 100644 --- a/include/boost/numeric/ublas/tensor/index.hpp +++ b/include/boost/numeric/ublas/tensor/index.hpp @@ -31,20 +31,20 @@ namespace index { template struct index_type { - static constexpr std::size_t value = I; + static constexpr std::size_t value = I; - constexpr bool operator == (std::size_t other) const { return value == other; } - constexpr bool operator != (std::size_t other) const { return value != other; } + constexpr bool operator == (std::size_t other) const { return value == other; } + constexpr bool operator != (std::size_t other) const { return value != other; } - template - constexpr bool operator == (index_type /*other*/) const { return I==K; } - template - constexpr bool operator != (index_type /*other*/) const { return I!=K; } + template + constexpr bool operator == (index_type /*other*/) const { return I==K; } + template + constexpr bool operator != (index_type /*other*/) const { return I!=K; } - constexpr bool operator == (index_type /*other*/) const { return true; } - constexpr bool operator != (index_type /*other*/) const { return false; } + constexpr bool operator == (index_type /*other*/) const { return true; } + constexpr bool operator != (index_type /*other*/) const { return false; } - constexpr std::size_t operator()() const { return I; } + constexpr std::size_t operator()() const { return I; } }; /** @brief Proxy classes for the einstein summation notation diff --git a/include/boost/numeric/ublas/tensor/multi_index.hpp b/include/boost/numeric/ublas/tensor/multi_index.hpp index ccafde21d..3a375de87 100644 --- a/include/boost/numeric/ublas/tensor/multi_index.hpp +++ b/include/boost/numeric/ublas/tensor/multi_index.hpp @@ -46,39 +46,39 @@ template class multi_index { public: - multi_index() = delete; + multi_index() = delete; - template - constexpr multi_index(index::index_type const& i, indexes ... is ) - : _base{i(), is()... } - { - static_assert( sizeof...(is)+1 == N, - "Static assert in boost::numeric::ublas::multi_index: number of constructor arguments is not equal to the template parameter." ); + template + constexpr multi_index(index::index_type const& i, indexes ... is ) + : _base{i(), is()... } + { + static_assert( sizeof...(is)+1 == N, + "Static assert in boost::numeric::ublas::multi_index: number of constructor arguments is not equal to the template parameter." ); - static_assert( valid_multi_index, indexes ...> >::value, - "Static assert in boost::numeric::ublas::multi_index: indexes occur twice in multi-index." ); - } + static_assert( valid_multi_index, indexes ...> >::value, + "Static assert in boost::numeric::ublas::multi_index: indexes occur twice in multi-index." ); + } - multi_index(multi_index const& other) - : _base(other._base) - { - } + multi_index(multi_index const& other) + : _base(other._base) + { + } - multi_index& operator=(multi_index const& other) - { - this->_base = other._base; - return *this; - } + multi_index& operator=(multi_index const& other) + { + this->_base = other._base; + return *this; + } - ~multi_index() = default; + ~multi_index() = default; - auto const& base() const { return _base; } - constexpr auto size() const { return _base.size(); } - constexpr auto at(std::size_t i) const { return _base.at(i); } - constexpr auto operator[](std::size_t i) const { return _base.at(i); } + auto const& base() const { return _base; } + constexpr auto size() const { return _base.size(); } + constexpr auto at(std::size_t i) const { return _base.at(i); } + constexpr auto operator[](std::size_t i) const { return _base.at(i); } private: - std::array _base; + std::array _base; }; template @@ -87,17 +87,17 @@ constexpr auto get(multi_index const& m) { return std::get(m.base()); } template auto array_to_vector(multi_index const& lhs, multi_index const& rhs) { - using vtype = std::vector; + using vtype = std::vector; - auto pair_of_vector = std::make_pair( vtype {}, vtype{} ); + auto pair_of_vector = std::make_pair( vtype {}, vtype{} ); - for(auto i = 0u; i < N; ++i) - for(auto j = 0u; j < M; ++j) - if ( lhs.at(i) == rhs.at(j) && lhs.at(i) != boost::numeric::ublas::index::_()) - (void)pair_of_vector.first .push_back( i+1 ), - pair_of_vector.second.push_back( j+1 ); + for(auto i = 0u; i < N; ++i) + for(auto j = 0u; j < M; ++j) + if ( lhs.at(i) == rhs.at(j) && lhs.at(i) != boost::numeric::ublas::index::_()) + (void)pair_of_vector.first .push_back( i+1 ), + pair_of_vector.second.push_back( j+1 ); - return pair_of_vector; + return pair_of_vector; } diff --git a/include/boost/numeric/ublas/tensor/multi_index_utility.hpp b/include/boost/numeric/ublas/tensor/multi_index_utility.hpp index 82e1bf68b..168f29773 100644 --- a/include/boost/numeric/ublas/tensor/multi_index_utility.hpp +++ b/include/boost/numeric/ublas/tensor/multi_index_utility.hpp @@ -29,26 +29,26 @@ struct has_index_impl; template struct has_index_impl { - static constexpr bool value = itype_left::value == itype_right::value; + static constexpr bool value = itype_left::value == itype_right::value; }; template struct has_index_impl > { - static constexpr bool value = false; + static constexpr bool value = false; }; template struct has_index_impl > { - static constexpr bool value = has_index_impl::value; + static constexpr bool value = has_index_impl::value; }; template struct has_index_impl > { - using next_type = has_index_impl>; - static constexpr bool value = has_index_impl::value || next_type::value; + using next_type = has_index_impl>; + static constexpr bool value = has_index_impl::value || next_type::value; }; } // namespace detail @@ -66,7 +66,7 @@ struct has_index_impl > template struct has_index { - static constexpr bool value = detail::has_index_impl,std::decay_t>::value; + static constexpr bool value = detail::has_index_impl,std::decay_t>::value; }; } // namespace ublas @@ -88,25 +88,25 @@ struct valid_multi_index_impl; template<> struct valid_multi_index_impl> { - static constexpr bool value = true; + static constexpr bool value = true; }; template struct valid_multi_index_impl> { - static constexpr bool value = true; + static constexpr bool value = true; }; template struct valid_multi_index_impl> { - using ttype = std::tuple; - using has_index_type = has_index; + using ttype = std::tuple; + using has_index_type = has_index; - static constexpr bool is_index_zero = itype::value==0ul; - static constexpr bool has_index_value = has_index_type::value && !is_index_zero; - static constexpr bool value = !has_index_value && valid_multi_index_impl::value; + static constexpr bool is_index_zero = itype::value==0ul; + static constexpr bool has_index_value = has_index_type::value && !is_index_zero; + static constexpr bool value = !has_index_value && valid_multi_index_impl::value; }; } // namespace detail @@ -122,7 +122,7 @@ struct valid_multi_index_impl> template struct valid_multi_index { - static constexpr bool value = detail::valid_multi_index_impl>::value; + static constexpr bool value = detail::valid_multi_index_impl>::value; }; } // namespace ublas @@ -143,21 +143,21 @@ struct number_equal_indexes_impl; template struct number_equal_indexes_impl < std::tuple<>, std::tuple> { - static constexpr unsigned value = 0; + static constexpr unsigned value = 0; }; template struct number_equal_indexes_impl < std::tuple, std::tuple> { - using tuple_right = std::tuple; - using has_index_type = has_index; + using tuple_right = std::tuple; + using has_index_type = has_index; - static constexpr bool is_index_zero = itype::value==0ul; - static constexpr bool has_index_value = has_index_type::value && !is_index_zero; + static constexpr bool is_index_zero = itype::value==0ul; + static constexpr bool has_index_value = has_index_type::value && !is_index_zero; - using next_type = number_equal_indexes_impl< std::tuple, tuple_right >; - static constexpr unsigned v = has_index_value ? 1 : 0; - static constexpr unsigned value = v + next_type::value; + using next_type = number_equal_indexes_impl< std::tuple, tuple_right >; + static constexpr unsigned v = has_index_value ? 1 : 0; + static constexpr unsigned value = v + next_type::value; }; } // namespace detail @@ -178,8 +178,8 @@ struct number_equal_indexes_impl < std::tuple, std::tuple< template struct number_equal_indexes { - static constexpr unsigned value = - detail::number_equal_indexes_impl< std::decay_t, std::decay_t>::value; + static constexpr unsigned value = + detail::number_equal_indexes_impl< std::decay_t, std::decay_t>::value; }; } // namespace ublas @@ -199,8 +199,8 @@ namespace detail { template struct index_position_impl { - static constexpr auto is_same = std::is_same< std::decay_t, std::decay_t> >::value; - static constexpr auto value = is_same ? r : index_position_impl::value; + static constexpr auto is_same = std::is_same< std::decay_t, std::decay_t> >::value; + static constexpr auto value = is_same ? r : index_position_impl::value; }; @@ -208,7 +208,7 @@ struct index_position_impl template struct index_position_impl < m, m, itype, ttype> { - static constexpr auto value = std::tuple_size::value; + static constexpr auto value = std::tuple_size::value; }; } // namespace detail @@ -232,7 +232,7 @@ struct index_position_impl < m, m, itype, ttype> template struct index_position { - static constexpr auto value = detail::index_position_impl<0ul,std::tuple_size::value,std::decay_t,std::decay_t>::value; + static constexpr auto value = detail::index_position_impl<0ul,std::tuple_size::value,std::decay_t,std::decay_t>::value; }; } // namespace ublas @@ -251,39 +251,39 @@ namespace detail { template struct index_position_pairs_impl { - template - static constexpr void run(array_type& out, tuple_left const& lhs, tuple_right const& rhs, std::size_t p) - { - using index_type = std::tuple_element_t; - using has_index_type = has_index; - using get_index_type = index_position; - using next_type = index_position_pairs_impl; - if constexpr ( has_index_type::value && index_type::value != 0) - out[p++] = std::make_pair(r-1,get_index_type::value); - next_type::run( out, lhs, rhs, p ); - } + template + static constexpr void run(array_type& out, tuple_left const& lhs, tuple_right const& rhs, std::size_t p) + { + using index_type = std::tuple_element_t; + using has_index_type = has_index; + using get_index_type = index_position; + using next_type = index_position_pairs_impl; + if constexpr ( has_index_type::value && index_type::value != 0) + out[p++] = std::make_pair(r-1,get_index_type::value); + next_type::run( out, lhs, rhs, p ); + } }; template struct index_position_pairs_impl { - template - static constexpr void run([[maybe_unused]] array_type& out, tuple_left const& , tuple_right const& , [[maybe_unused]] std::size_t p) - { - using index_type = std::tuple_element_t; - using has_index_type = has_index; - using get_index_type = index_position; - if constexpr ( has_index_type::value && index_type::value != 0 ) - out[p] = std::make_pair(m-1,get_index_type::value); - } + template + static constexpr void run([[maybe_unused]] array_type& out, tuple_left const& , tuple_right const& , [[maybe_unused]] std::size_t p) + { + using index_type = std::tuple_element_t; + using has_index_type = has_index; + using get_index_type = index_position; + if constexpr ( has_index_type::value && index_type::value != 0 ) + out[p] = std::make_pair(m-1,get_index_type::value); + } }; template struct index_position_pairs_impl { - template - static constexpr void run(array_type&, tuple_left const& , tuple_right const& , std::size_t) - {} + template + static constexpr void run(array_type&, tuple_left const& , tuple_right const& , std::size_t) + {} }; @@ -305,12 +305,12 @@ struct index_position_pairs_impl template auto index_position_pairs(tuple_left const& lhs, tuple_right const& rhs) { - using pair_type = std::pair; - constexpr auto m = std::tuple_size::value; - constexpr auto p = number_equal_indexes::value; - auto array = std::array{}; - detail::index_position_pairs_impl<1,m>::run(array, lhs, rhs,0); - return array; + using pair_type = std::pair; + constexpr auto m = std::tuple_size::value; + constexpr auto p = number_equal_indexes::value; + auto array = std::array{}; + detail::index_position_pairs_impl<1,m>::run(array, lhs, rhs,0); + return array; } } // namespace ublas @@ -331,9 +331,9 @@ namespace detail { template constexpr auto array_to_vector_impl( array_type const& array, std::index_sequence ) { - return std::make_pair( - std::vector{std::get<0>( std::get(array) )+1 ...} , - std::vector{std::get<1>( std::get(array) )+1 ...} ); + return std::make_pair( + std::vector{std::get<0>( std::get(array) )+1 ...} , + std::vector{std::get<1>( std::get(array) )+1 ...} ); } } // namespace detail @@ -351,8 +351,8 @@ constexpr auto array_to_vector_impl( array_type const& array, std::index_sequenc template constexpr auto array_to_vector( std::array const& array) { - constexpr auto sequence = std::make_index_sequence{}; - return detail::array_to_vector_impl( array, sequence ); + constexpr auto sequence = std::make_index_sequence{}; + return detail::array_to_vector_impl( array, sequence ); } diff --git a/include/boost/numeric/ublas/tensor/multiplication.hpp b/include/boost/numeric/ublas/tensor/multiplication.hpp index 625788374..9ffc775ea 100644 --- a/include/boost/numeric/ublas/tensor/multiplication.hpp +++ b/include/boost/numeric/ublas/tensor/multiplication.hpp @@ -57,30 +57,30 @@ void ttt(SizeType const k, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(k < r) - { - assert(nc[k] == na[phia[k]-1]); - for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) - ttt(k+1, r, s, q, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(k < r+s) - { - assert(nc[k] == nb[phib[k-r]-1]); - for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) - ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(k < r+s+q-1) - { - assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); - for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) - ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); - } - else - { - assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); - for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) - *c += *a * *b; - } + if(k < r) + { + assert(nc[k] == na[phia[k]-1]); + for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) + ttt(k+1, r, s, q, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(k < r+s) + { + assert(nc[k] == nb[phib[k-r]-1]); + for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) + ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(k < r+s+q-1) + { + assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); + for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) + ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); + } + else + { + assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); + for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) + *c += *a * *b; + } } @@ -120,30 +120,30 @@ void ttt(SizeType const k, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(k < r) - { - assert(nc[k] == na[k]); - for(size_t ic = 0u; ic < nc[k]; a += wa[k], c += wc[k], ++ic) - ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(k < r+s) - { - assert(nc[k] == nb[k-r]); - for(size_t ic = 0u; ic < nc[k]; b += wb[k-r], c += wc[k], ++ic) - ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(k < r+s+q-1) - { - assert(na[k-s] == nb[k-r]); - for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) - ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); - } - else - { - assert(na[k-s] == nb[k-r]); - for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) - *c += *a * *b; - } + if(k < r) + { + assert(nc[k] == na[k]); + for(size_t ic = 0u; ic < nc[k]; a += wa[k], c += wc[k], ++ic) + ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(k < r+s) + { + assert(nc[k] == nb[k-r]); + for(size_t ic = 0u; ic < nc[k]; b += wb[k-r], c += wc[k], ++ic) + ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(k < r+s+q-1) + { + assert(na[k-s] == nb[k-r]); + for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) + ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); + } + else + { + assert(na[k-s] == nb[k-r]); + for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) + *c += *a * *b; + } } @@ -173,26 +173,26 @@ void ttm(SizeType const m, SizeType const r, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(r == m) { - ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(r == 0){ - for(auto i0 = 0ul; i0 < nc[0]; c += wc[0], a += wa[0], ++i0) { - auto cm = c; - auto b0 = b; - for(auto i1 = 0ul; i1 < nc[m]; cm += wc[m], b0 += wb[0], ++i1){ - auto am = a; - auto b1 = b0; - for(auto i2 = 0ul; i2 < nb[1]; am += wa[m], b1 += wb[1], ++i2) - *cm += *am * *b1; - } - } - } - - else{ - for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i) - ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb); - } + if(r == m) { + ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(r == 0){ + for(auto i0 = 0ul; i0 < nc[0]; c += wc[0], a += wa[0], ++i0) { + auto cm = c; + auto b0 = b; + for(auto i1 = 0ul; i1 < nc[m]; cm += wc[m], b0 += wb[0], ++i1){ + auto am = a; + auto b1 = b0; + for(auto i2 = 0ul; i2 < nb[1]; am += wa[m], b1 += wb[1], ++i2) + *cm += *am * *b1; + } + } + } + + else{ + for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i) + ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb); + } } /** @brief Computes the tensor-times-matrix product for the contraction mode m = 0 @@ -220,26 +220,26 @@ void ttm0( SizeType const r, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(r > 1){ - for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i) - ttm0(r-1, c, nc, wc, a, na, wa, b, nb, wb); - } - else{ - for(auto i1 = 0ul; i1 < nc[1]; c += wc[1], a += wa[1], ++i1) { - auto cm = c; - auto b0 = b; - // r == m == 0 - for(auto i0 = 0ul; i0 < nc[0]; cm += wc[0], b0 += wb[0], ++i0){ - - auto am = a; - auto b1 = b0; - for(auto i2 = 0u; i2 < nb[1]; am += wa[0], b1 += wb[1], ++i2){ - - *cm += *am * *b1; - } - } - } - } + if(r > 1){ + for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i) + ttm0(r-1, c, nc, wc, a, na, wa, b, nb, wb); + } + else{ + for(auto i1 = 0ul; i1 < nc[1]; c += wc[1], a += wa[1], ++i1) { + auto cm = c; + auto b0 = b; + // r == m == 0 + for(auto i0 = 0ul; i0 < nc[0]; cm += wc[0], b0 += wb[0], ++i0){ + + auto am = a; + auto b1 = b0; + for(auto i2 = 0u; i2 < nb[1]; am += wa[0], b1 += wb[1], ++i2){ + + *cm += *am * *b1; + } + } + } + } } @@ -274,20 +274,20 @@ void ttv( SizeType const m, SizeType const r, SizeType const q, PointerIn2 b) { - if(r == m) { - ttv(m, r-1, q, c, nc, wc, a, na, wa, b); - } - else if(r == 0){ - for(auto i0 = 0u; i0 < na[0]; c += wc[0], a += wa[0], ++i0) { - auto c1 = c; auto a1 = a; auto b1 = b; - for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im) - *c1 += *a1 * *b1; - } - } - else{ - for(auto i = 0u; i < na[r]; c += wc[q], a += wa[r], ++i) - ttv(m, r-1, q-1, c, nc, wc, a, na, wa, b); - } + if(r == m) { + ttv(m, r-1, q, c, nc, wc, a, na, wa, b); + } + else if(r == 0){ + for(auto i0 = 0u; i0 < na[0]; c += wc[0], a += wa[0], ++i0) { + auto c1 = c; auto a1 = a; auto b1 = b; + for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im) + *c1 += *a1 * *b1; + } + } + else{ + for(auto i = 0u; i < na[r]; c += wc[q], a += wa[r], ++i) + ttv(m, r-1, q-1, c, nc, wc, a, na, wa, b); + } } @@ -314,18 +314,18 @@ void ttv0(SizeType const r, PointerIn2 b) { - if(r > 1){ - for(auto i = 0u; i < na[r]; c += wc[r-1], a += wa[r], ++i) - ttv0(r-1, c, nc, wc, a, na, wa, b); - } - else{ - for(auto i1 = 0u; i1 < na[1]; c += wc[0], a += wa[1], ++i1) - { - auto c1 = c; auto a1 = a; auto b1 = b; - for(auto i0 = 0u; i0 < na[0]; a1 += wa[0], ++b1, ++i0) - *c1 += *a1 * *b1; - } - } + if(r > 1){ + for(auto i = 0u; i < na[r]; c += wc[r-1], a += wa[r], ++i) + ttv0(r-1, c, nc, wc, a, na, wa, b); + } + else{ + for(auto i1 = 0u; i1 < na[1]; c += wc[0], a += wa[1], ++i1) + { + auto c1 = c; auto a1 = a; auto b1 = b; + for(auto i0 = 0u; i0 < na[0]; a1 += wa[0], ++b1, ++i0) + *c1 += *a1 * *b1; + } + } } @@ -350,14 +350,14 @@ void mtv(SizeType const m, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b) { - // decides whether matrix multiplied with vector or vector multiplied with matrix - const auto o = (m == 0) ? 1 : 0; - - for(auto io = 0u; io < na[o]; c += wc[o], a += wa[o], ++io) { - auto c1 = c; auto a1 = a; auto b1 = b; - for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im) - *c1 += *a1 * *b1; - } + // decides whether matrix multiplied with vector or vector multiplied with matrix + const auto o = (m == 0) ? 1 : 0; + + for(auto io = 0u; io < na[o]; c += wc[o], a += wa[o], ++io) { + auto c1 = c; auto a1 = a; auto b1 = b; + for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im) + *c1 += *a1 * *b1; + } } @@ -383,26 +383,26 @@ void mtm(PointerOut c, SizeType const*const nc, SizeType const*const wc, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - // C(i,j) = A(i,k) * B(k,j) + // C(i,j) = A(i,k) * B(k,j) - assert(nc[0] == na[0]); - assert(nc[1] == nb[1]); - assert(na[1] == nb[0]); + assert(nc[0] == na[0]); + assert(nc[1] == nb[1]); + assert(na[1] == nb[0]); - auto cj = c; auto bj = b; - for(auto j = 0u; j < nc[1]; cj += wc[1], bj += wb[1], ++j) { + auto cj = c; auto bj = b; + for(auto j = 0u; j < nc[1]; cj += wc[1], bj += wb[1], ++j) { - auto bk = bj; auto ak = a; - for(auto k = 0u; k < na[1]; ak += wa[1], bk += wb[0], ++k) { + auto bk = bj; auto ak = a; + for(auto k = 0u; k < na[1]; ak += wa[1], bk += wb[0], ++k) { - auto ci = cj; auto ai = ak; - for(auto i = 0u; i < na[0]; ai += wa[0], ci += wc[0], ++i){ - *ci += *ai * *bk; - } + auto ci = cj; auto ai = ak; + for(auto i = 0u; i < na[0]; ai += wa[0], ci += wc[0], ++i){ + *ci += *ai * *bk; + } - } + } - } + } } @@ -428,13 +428,13 @@ value_t inner(SizeType const r, SizeType const*const n, PointerIn2 b, SizeType const*const wb, value_t v) { - if(r == 0) - for(auto i0 = 0u; i0 < n[0]; a += wa[0], b += wb[0], ++i0) - v += *a * *b; - else - for(auto ir = 0u; ir < n[r]; a += wa[r], b += wb[r], ++ir) - v = inner(r-1, n, a, wa, b, wb, v); - return v; + if(r == 0) + for(auto i0 = 0u; i0 < n[0]; a += wa[0], b += wb[0], ++i0) + v += *a * *b; + else + for(auto ir = 0u; ir < n[r]; a += wa[r], b += wb[r], ++ir) + v = inner(r-1, n, a, wa, b, wb, v); + return v; } @@ -444,25 +444,25 @@ void outer_2x2(SizeType const pa, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - // assert(rc == 3); - // assert(ra == 1); - // assert(rb == 1); - - for(auto ib1 = 0u; ib1 < nb[1]; b += wb[1], c += wc[pa+1], ++ib1) { - auto c2 = c; - auto b0 = b; - for(auto ib0 = 0u; ib0 < nb[0]; b0 += wb[0], c2 += wc[pa], ++ib0) { - const auto new_b = *b0; - auto c1 = c2; - auto a1 = a; - for(auto ia1 = 0u; ia1 < na[1]; a1 += wa[1], c1 += wc[1], ++ia1) { - auto a0 = a1; - auto c0 = c1; - for(SizeType ia0 = 0u; ia0 < na[0]; a0 += wa[0], c0 += wc[0], ++ia0) - *c0 = *a0 * new_b; - } - } - } + // assert(rc == 3); + // assert(ra == 1); + // assert(rb == 1); + + for(auto ib1 = 0u; ib1 < nb[1]; b += wb[1], c += wc[pa+1], ++ib1) { + auto c2 = c; + auto b0 = b; + for(auto ib0 = 0u; ib0 < nb[0]; b0 += wb[0], c2 += wc[pa], ++ib0) { + const auto new_b = *b0; + auto c1 = c2; + auto a1 = a; + for(auto ia1 = 0u; ia1 < na[1]; a1 += wa[1], c1 += wc[1], ++ia1) { + auto a0 = a1; + auto c0 = c1; + for(SizeType ia0 = 0u; ia0 < na[0]; a0 += wa[0], c0 += wc[0], ++ia0) + *c0 = *a0 * new_b; + } + } + } } /** @brief Computes the outer product of two tensors @@ -495,14 +495,14 @@ void outer(SizeType const pa, SizeType const ra, PointerIn1 a, SizeType const*const na, SizeType const*const wa, SizeType const rb, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(rb > 1) - for(auto ib = 0u; ib < nb[rb]; b += wb[rb], c += wc[rc], ++ib) - outer(pa, rc-1, c, nc, wc, ra, a, na, wa, rb-1, b, nb, wb); - else if(ra > 1) - for(auto ia = 0u; ia < na[ra]; a += wa[ra], c += wc[ra], ++ia) - outer(pa, rc-1, c, nc, wc, ra-1, a, na, wa, rb, b, nb, wb); - else - outer_2x2(pa, c, nc, wc, a, na, wa, b, nb, wb); //assert(ra==1 && rb==1 && rc==3); + if(rb > 1) + for(auto ib = 0u; ib < nb[rb]; b += wb[rb], c += wc[rc], ++ib) + outer(pa, rc-1, c, nc, wc, ra, a, na, wa, rb-1, b, nb, wb); + else if(ra > 1) + for(auto ia = 0u; ia < na[ra]; a += wa[ra], c += wc[ra], ++ia) + outer(pa, rc-1, c, nc, wc, ra-1, a, na, wa, rb, b, nb, wb); + else + outer_2x2(pa, c, nc, wc, a, na, wa, b, nb, wb); //assert(ra==1 && rb==1 && rc==3); } @@ -541,24 +541,24 @@ void outer(SizeType const k, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(k < r) - { - assert(nc[k] == na[phia[k]-1]); - for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) - outer(k+1, r, s, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(k < r+s-1) - { - assert(nc[k] == nb[phib[k-r]-1]); - for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) - outer(k+1, r, s, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); - } - else - { - assert(nc[k] == nb[phib[k-r]-1]); - for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) - *c = *a * *b; - } + if(k < r) + { + assert(nc[k] == na[phia[k]-1]); + for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) + outer(k+1, r, s, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(k < r+s-1) + { + assert(nc[k] == nb[phib[k-r]-1]); + for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) + outer(k+1, r, s, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); + } + else + { + assert(nc[k] == nb[phib[k-r]-1]); + for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) + *c = *a * *b; + } } @@ -614,44 +614,44 @@ void ttv(SizeType const m, SizeType const p, const PointerIn1 a, SizeType const*const na, SizeType const*const wa, const PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::ttv: Argument types for pointers are not pointer types."); + static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::ttv: Argument types for pointers are not pointer types."); - if( m == 0) - throw std::length_error("Error in boost::numeric::ublas::ttv: Contraction mode must be greater than zero."); + if( m == 0) + throw std::length_error("Error in boost::numeric::ublas::ttv: Contraction mode must be greater than zero."); - if( p < m ) - throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater equal the modus."); + if( p < m ) + throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater equal the modus."); - if( p == 0) - throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater than zero."); + if( p == 0) + throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater than zero."); - if(c == nullptr || a == nullptr || b == nullptr) - throw std::length_error("Error in boost::numeric::ublas::ttv: Pointers shall not be null pointers."); + if(c == nullptr || a == nullptr || b == nullptr) + throw std::length_error("Error in boost::numeric::ublas::ttv: Pointers shall not be null pointers."); - for(auto i = 0u; i < m-1; ++i) - if(na[i] != nc[i]) - throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal."); + for(auto i = 0u; i < m-1; ++i) + if(na[i] != nc[i]) + throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal."); - for(auto i = m; i < p; ++i) - if(na[i] != nc[i-1]) - throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal."); + for(auto i = m; i < p; ++i) + if(na[i] != nc[i-1]) + throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal."); - const auto max = std::max(nb[0], nb[1]); - if( na[m-1] != max) - throw std::length_error("Error in boost::numeric::ublas::ttv: Extent of dimension mode of A and b must be equal."); + const auto max = std::max(nb[0], nb[1]); + if( na[m-1] != max) + throw std::length_error("Error in boost::numeric::ublas::ttv: Extent of dimension mode of A and b must be equal."); - if((m != 1) && (p > 2)) - detail::recursive::ttv(m-1, p-1, p-2, c, nc, wc, a, na, wa, b); - else if ((m == 1) && (p > 2)) - detail::recursive::ttv0(p-1, c, nc, wc, a, na, wa, b); - else if( p == 2 ) - detail::recursive::mtv(m-1, c, nc, wc, a, na, wa, b); - else /*if( p == 1 )*/{ - auto v = std::remove_pointer_t>{}; - *c = detail::recursive::inner(SizeType(0), na, a, wa, b, wb, v); - } + if((m != 1) && (p > 2)) + detail::recursive::ttv(m-1, p-1, p-2, c, nc, wc, a, na, wa, b); + else if ((m == 1) && (p > 2)) + detail::recursive::ttv0(p-1, c, nc, wc, a, na, wa, b); + else if( p == 2 ) + detail::recursive::mtv(m-1, c, nc, wc, a, na, wa, b); + else /*if( p == 1 )*/{ + auto v = std::remove_pointer_t>{}; + *c = detail::recursive::inner(SizeType(0), na, a, wa, b, wb, v); + } } @@ -685,39 +685,39 @@ void ttm(SizeType const m, SizeType const p, const PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); + static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); - if( m == 0 ) - throw std::length_error("Error in boost::numeric::ublas::ttm: Contraction mode must be greater than zero."); + if( m == 0 ) + throw std::length_error("Error in boost::numeric::ublas::ttm: Contraction mode must be greater than zero."); - if( p < m ) - throw std::length_error("Error in boost::numeric::ublas::ttm: Rank must be greater equal than the specified mode."); + if( p < m ) + throw std::length_error("Error in boost::numeric::ublas::ttm: Rank must be greater equal than the specified mode."); - if( p == 0) - throw std::length_error("Error in boost::numeric::ublas::ttm:Rank must be greater than zero."); + if( p == 0) + throw std::length_error("Error in boost::numeric::ublas::ttm:Rank must be greater than zero."); - if(c == nullptr || a == nullptr || b == nullptr) - throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); + if(c == nullptr || a == nullptr || b == nullptr) + throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); - for(auto i = 0u; i < m-1; ++i) - if(na[i] != nc[i]) - throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal."); + for(auto i = 0u; i < m-1; ++i) + if(na[i] != nc[i]) + throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal."); - for(auto i = m; i < p; ++i) - if(na[i] != nc[i]) - throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal."); + for(auto i = m; i < p; ++i) + if(na[i] != nc[i]) + throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal."); - if(na[m-1] != nb[1]) - throw std::length_error("Error in boost::numeric::ublas::ttm: 2nd Extent of B and M-th Extent of A must be the equal."); + if(na[m-1] != nb[1]) + throw std::length_error("Error in boost::numeric::ublas::ttm: 2nd Extent of B and M-th Extent of A must be the equal."); - if(nc[m-1] != nb[0]) - throw std::length_error("Error in boost::numeric::ublas::ttm: 1nd Extent of B and M-th Extent of C must be the equal."); + if(nc[m-1] != nb[0]) + throw std::length_error("Error in boost::numeric::ublas::ttm: 1nd Extent of B and M-th Extent of C must be the equal."); - if ( m != 1 ) - detail::recursive::ttm (m-1, p-1, c, nc, wc, a, na, wa, b, nb, wb); - else /*if (m == 1 && p > 2)*/ - detail::recursive::ttm0( p-1, c, nc, wc, a, na, wa, b, nb, wb); + if ( m != 1 ) + detail::recursive::ttm (m-1, p-1, c, nc, wc, a, na, wa, b, nb, wb); + else /*if (m == 1 && p > 2)*/ + detail::recursive::ttm0( p-1, c, nc, wc, a, na, wa, b, nb, wb); } @@ -734,9 +734,9 @@ void ttm(SizeType const m, SizeType const p, * * @param[in] pa number of dimensions (rank) of the first input tensor a with pa > 0 * @param[in] pb number of dimensions (rank) of the second input tensor b with pb > 0 - * @param[in] q number of contraction dimensions with pa >= q and pb >= q and q >= 0 - * @param[in] phia pointer to a permutation tuple for the first input tensor a - * @param[in] phib pointer to a permutation tuple for the second input tensor b + * @param[in] q number of contraction dimensions with pa >= q and pb >= q and q >= 0 + * @param[in] phia pointer to a permutation tuple for the first input tensor a + * @param[in] phib pointer to a permutation tuple for the second input tensor b * @param[out] c pointer to the output tensor with rank p-1 * @param[in] nc pointer to the extents of tensor c * @param[in] wc pointer to the strides of tensor c @@ -755,39 +755,39 @@ void ttt(SizeType const pa, SizeType const pb, SizeType const q, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); + static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); - if( pa == 0 || pb == 0) - throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero."); + if( pa == 0 || pb == 0) + throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero."); - if( q > pa && q > pb) - throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order."); + if( q > pa && q > pb) + throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order."); - SizeType const r = pa - q; - SizeType const s = pb - q; + SizeType const r = pa - q; + SizeType const s = pb - q; - if(c == nullptr || a == nullptr || b == nullptr) - throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); + if(c == nullptr || a == nullptr || b == nullptr) + throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); - for(auto i = 0ul; i < r; ++i) - if( na[phia[i]-1] != nc[i] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct."); + for(auto i = 0ul; i < r; ++i) + if( na[phia[i]-1] != nc[i] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct."); - for(auto i = 0ul; i < s; ++i) - if( nb[phib[i]-1] != nc[r+i] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct."); + for(auto i = 0ul; i < s; ++i) + if( nb[phib[i]-1] != nc[r+i] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct."); - for(auto i = 0ul; i < q; ++i) - if( nb[phib[s+i]-1] != na[phia[r+i]-1] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct."); + for(auto i = 0ul; i < q; ++i) + if( nb[phib[s+i]-1] != na[phia[r+i]-1] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct."); - if(q == 0ul) - detail::recursive::outer(SizeType{0},r,s, phia,phib, c,nc,wc, a,na,wa, b,nb,wb); - else - detail::recursive::ttt(SizeType{0},r,s,q, phia,phib, c,nc,wc, a,na,wa, b,nb,wb); + if(q == 0ul) + detail::recursive::outer(SizeType{0},r,s, phia,phib, c,nc,wc, a,na,wa, b,nb,wb); + else + detail::recursive::ttt(SizeType{0},r,s,q, phia,phib, c,nc,wc, a,na,wa, b,nb,wb); } @@ -804,7 +804,7 @@ void ttt(SizeType const pa, SizeType const pb, SizeType const q, * * @param[in] pa number of dimensions (rank) of the first input tensor a with pa > 0 * @param[in] pb number of dimensions (rank) of the second input tensor b with pb > 0 - * @param[in] q number of contraction dimensions with pa >= q and pb >= q and q >= 0 + * @param[in] q number of contraction dimensions with pa >= q and pb >= q and q >= 0 * @param[out] c pointer to the output tensor with rank p-1 * @param[in] nc pointer to the extents of tensor c * @param[in] wc pointer to the strides of tensor c @@ -822,45 +822,45 @@ void ttt(SizeType const pa, SizeType const pb, SizeType const q, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); + static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); - if( pa == 0 || pb == 0) - throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero."); + if( pa == 0 || pb == 0) + throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero."); - if( q > pa && q > pb) - throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order."); + if( q > pa && q > pb) + throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order."); - SizeType const r = pa - q; - SizeType const s = pb - q; - SizeType const pc = r+s; + SizeType const r = pa - q; + SizeType const s = pb - q; + SizeType const pc = r+s; - if(c == nullptr || a == nullptr || b == nullptr) - throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); + if(c == nullptr || a == nullptr || b == nullptr) + throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); - for(auto i = 0ul; i < r; ++i) - if( na[i] != nc[i] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct."); + for(auto i = 0ul; i < r; ++i) + if( na[i] != nc[i] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct."); - for(auto i = 0ul; i < s; ++i) - if( nb[i] != nc[r+i] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct."); + for(auto i = 0ul; i < s; ++i) + if( nb[i] != nc[r+i] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct."); - for(auto i = 0ul; i < q; ++i) - if( nb[s+i] != na[r+i] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct."); + for(auto i = 0ul; i < q; ++i) + if( nb[s+i] != na[r+i] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct."); - using value_type = std::decay_t; + using value_type = std::decay_t; - if(q == 0ul) - detail::recursive::outer(pa, pc-1, c,nc,wc, pa-1, a,na,wa, pb-1, b,nb,wb); - else if(r == 0ul && s == 0ul) - *c = detail::recursive::inner(q-1, na, a,wa, b,wb, value_type(0) ); - else - detail::recursive::ttt(SizeType{0},r,s,q, c,nc,wc, a,na,wa, b,nb,wb); + if(q == 0ul) + detail::recursive::outer(pa, pc-1, c,nc,wc, pa-1, a,na,wa, pb-1, b,nb,wb); + else if(r == 0ul && s == 0ul) + *c = detail::recursive::inner(q-1, na, a,wa, b,wb, value_type(0) ); + else + detail::recursive::ttt(SizeType{0},r,s,q, c,nc,wc, a,na,wa, b,nb,wb); } @@ -886,14 +886,14 @@ auto inner(const SizeType p, SizeType const*const n, const PointerIn2 b, SizeType const*const wb, value_t v) { - static_assert( std::is_pointer::value && std::is_pointer::value, - "Static error in boost::numeric::ublas::inner: Argument types for pointers must be pointer types."); - if(p<2) - throw std::length_error("Error in boost::numeric::ublas::inner: Rank must be greater than zero."); - if(a == nullptr || b == nullptr) - throw std::length_error("Error in boost::numeric::ublas::inner: Pointers shall not be null pointers."); + static_assert( std::is_pointer::value && std::is_pointer::value, + "Static error in boost::numeric::ublas::inner: Argument types for pointers must be pointer types."); + if(p<2) + throw std::length_error("Error in boost::numeric::ublas::inner: Rank must be greater than zero."); + if(a == nullptr || b == nullptr) + throw std::length_error("Error in boost::numeric::ublas::inner: Pointers shall not be null pointers."); - return detail::recursive::inner(p-1, n, a, wa, b, wb, v); + return detail::recursive::inner(p-1, n, a, wa, b, wb, v); } @@ -922,16 +922,16 @@ void outer(PointerOut c, SizeType const pc, SizeType const*const nc, SizeT const PointerIn1 a, SizeType const pa, SizeType const*const na, SizeType const*const wa, const PointerIn2 b, SizeType const pb, SizeType const*const nb, SizeType const*const wb) { - static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::outer: argument types for pointers must be pointer types."); - if(pa < 2u || pb < 2u) - throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs and rhs tensor must be equal or greater than two."); - if((pa + pb) != pc) - throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs plus rhs tensor must be equal to the number of extents of C."); - if(a == nullptr || b == nullptr || c == nullptr) - throw std::length_error("Error in boost::numeric::ublas::outer: pointers shall not be null pointers."); - - detail::recursive::outer(pa, pc-1, c, nc, wc, pa-1, a, na, wa, pb-1, b, nb, wb); + static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::outer: argument types for pointers must be pointer types."); + if(pa < 2u || pb < 2u) + throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs and rhs tensor must be equal or greater than two."); + if((pa + pb) != pc) + throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs plus rhs tensor must be equal to the number of extents of C."); + if(a == nullptr || b == nullptr || c == nullptr) + throw std::length_error("Error in boost::numeric::ublas::outer: pointers shall not be null pointers."); + + detail::recursive::outer(pa, pc-1, c, nc, wc, pa-1, a, na, wa, pb-1, b, nb, wb); } diff --git a/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp b/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp index 26bbbdf34..b32ed3900 100644 --- a/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp +++ b/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp @@ -16,6 +16,7 @@ #include "expression_evaluation.hpp" #include "multi_index_utility.hpp" #include "functions.hpp" +#include #include #include @@ -26,8 +27,8 @@ namespace numeric{ namespace ublas { -template -class tensor; +template +class basic_tensor; template class matrix_expression; @@ -43,8 +44,8 @@ class vector_expression; #define FIRST_ORDER_OPERATOR_RIGHT(OP, EXPR_TYPE_L, EXPR_TYPE_R) \ template \ auto operator OP ( boost::numeric::ublas:: EXPR_TYPE_L const& lhs, boost::numeric::ublas:: EXPR_TYPE_R const& rhs) { \ - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), \ - [](auto const& l, auto const& r){ return l OP r; }); \ + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), \ + [](auto const& l, auto const& r){ return l OP r; }); \ } \ FIRST_ORDER_OPERATOR_RIGHT (*, detail:: tensor_expression , vector_expression) @@ -61,8 +62,8 @@ FIRST_ORDER_OPERATOR_RIGHT (/, detail:: tensor_expression , matrix_expression) #define FIRST_ORDER_OPERATOR_LEFT(OP, EXPR_TYPE_L, EXPR_TYPE_R) \ template \ auto operator OP ( boost::numeric::ublas:: EXPR_TYPE_L const& lhs, boost::numeric::ublas:: EXPR_TYPE_R const& rhs) { \ - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), \ - [](auto const& l, auto const& r){ return l OP r; }); \ + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), \ + [](auto const& l, auto const& r){ return l OP r; }); \ } \ FIRST_ORDER_OPERATOR_LEFT (*, vector_expression, detail:: tensor_expression) @@ -78,113 +79,217 @@ FIRST_ORDER_OPERATOR_LEFT (/, matrix_expression, detail:: tensor_expression) -template -auto operator+( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l + r; }); +template +constexpr auto operator+( boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) +{ + + static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, + "operator+() : LHS tensor and RHS tensor should have same value type" + ); + + if constexpr( !std::is_same_v ){ + auto e = boost::numeric::ublas::detail::retrieve_extents(rhs); + + if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ + throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); + } + } + + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l + r; }); } -template -auto operator-( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l - r; }); +template +constexpr auto operator-( boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) +{ + + static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, + "operator-() : LHS tensor and RHS tensor should have same value type" + ); + + if constexpr( !std::is_same_v ){ + auto e = boost::numeric::ublas::detail::retrieve_extents(rhs); + + if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ + throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); + } + } + + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l - r; }); // return boost::numeric::ublas::detail::make_lambda([&lhs,&rhs](std::size_t i){ return lhs(i) - rhs(i);}); } -template -auto operator*( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l * r; }); +template +constexpr auto operator*( boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) +{ + + static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, + "operator*() : LHS tensor and RHS tensor should have same value type" + ); + + if constexpr( !std::is_same_v ){ + auto e = boost::numeric::ublas::detail::retrieve_extents(rhs); + + if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ + throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); + } + } + + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l * r; }); } -template -auto operator/( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l / r; }); +template +constexpr auto operator/( boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) +{ + + static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, + "operator/() : LHS tensor and RHS tensor should have same value type" + ); + + if constexpr( !std::is_same_v ){ + auto e = boost::numeric::ublas::detail::retrieve_extents(rhs); + + if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ + throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); + } + } + + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l / r; }); } // Overloaded Arithmetic Operators with Scalars template -auto operator+(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs + r; }); - //return boost::numeric::ublas::detail::make_lambda( [&lhs,&rhs](std::size_t i) {return lhs + rhs(i); } ); +constexpr auto operator+(typename T::const_reference lhs, + boost::numeric::ublas::detail::tensor_expression,R> const& rhs) +{ + using basic_tensor_type = boost::numeric::ublas::basic_tensor; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs + r; }); + //return boost::numeric::ublas::detail::make_lambda( [&lhs,&rhs](std::size_t i) {return lhs + rhs(i); } ); } template -auto operator-(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs - r; }); +constexpr auto operator-(typename T::const_reference lhs, + boost::numeric::ublas::detail::tensor_expression,R> const& rhs) +{ + using basic_tensor_type = boost::numeric::ublas::basic_tensor; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs - r; }); } template -auto operator*(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs * r; }); +constexpr auto operator*(typename T::const_reference lhs, + boost::numeric::ublas::detail::tensor_expression,R> const& rhs) +{ + using basic_tensor_type = boost::numeric::ublas::basic_tensor; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs * r; }); } template -auto operator/(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs / r; }); +constexpr auto operator/(typename T::const_reference lhs, + boost::numeric::ublas::detail::tensor_expression,R> const& rhs) +{ + using basic_tensor_type = boost::numeric::ublas::basic_tensor; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs / r; }); } template -auto operator+(boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l + rhs; } ); +constexpr auto operator+(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + typename T::const_reference rhs) +{ + using basic_tensor_type = boost::numeric::ublas::basic_tensor; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l + rhs; } ); } template -auto operator-(boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l - rhs; } ); +constexpr auto operator-(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + typename T::const_reference rhs) +{ + using basic_tensor_type = boost::numeric::ublas::basic_tensor; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l - rhs; } ); } template -auto operator*(boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l * rhs; } ); +constexpr auto operator*(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + typename T::const_reference rhs) +{ + using basic_tensor_type = boost::numeric::ublas::basic_tensor; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l * rhs; } ); } template -auto operator/(boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l / rhs; } ); +constexpr auto operator/(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + typename T::const_reference rhs) +{ + using basic_tensor_type = boost::numeric::ublas::basic_tensor; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l / rhs; } ); } template -auto& operator += (T& lhs, const boost::numeric::ublas::detail::tensor_expression &expr) { - boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l+=r; } ); - return lhs; +constexpr auto& operator += (boost::numeric::ublas::basic_tensor& lhs, + const boost::numeric::ublas::detail::tensor_expression,D> &expr) +{ + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l+=r; } ); + return lhs; } template -auto& operator -= (T& lhs, const boost::numeric::ublas::detail::tensor_expression &expr) { - boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l-=r; } ); - return lhs; +constexpr auto& operator -= (boost::numeric::ublas::basic_tensor& lhs, + const boost::numeric::ublas::detail::tensor_expression,D> &expr) +{ + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l-=r; } ); + return lhs; } template -auto& operator *= (T& lhs, const boost::numeric::ublas::detail::tensor_expression &expr) { - boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l*=r; } ); - return lhs; +constexpr auto& operator *= (boost::numeric::ublas::basic_tensor& lhs, + const boost::numeric::ublas::detail::tensor_expression,D> &expr) +{ + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l*=r; } ); + return lhs; } template -auto& operator /= (T& lhs, const boost::numeric::ublas::detail::tensor_expression &expr) { - boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l/=r; } ); - return lhs; +constexpr auto& operator /= (boost::numeric::ublas::basic_tensor& lhs, + const boost::numeric::ublas::detail::tensor_expression,D> &expr) +{ + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l/=r; } ); + return lhs; } -template -auto& operator += (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { - boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l+=r; } ); - return lhs; +template +constexpr auto& operator += (boost::numeric::ublas::basic_tensor& lhs, typename TensorType::const_reference r) { + static_assert( boost::numeric::ublas::is_valid_tensor_v, + "boost::numeric::ublas::operator +=() : tensor type should be valid tensor" + ); + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l+=r; } ); + return lhs; } -template -auto& operator -= (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { - boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l-=r; } ); - return lhs; +template +constexpr auto& operator -= (boost::numeric::ublas::basic_tensor& lhs, typename TensorType::const_reference r) { + static_assert( boost::numeric::ublas::is_valid_tensor_v, + "boost::numeric::ublas::operator -=() : tensor type should be valid tensor" + ); + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l-=r; } ); + return lhs; } -template -auto& operator *= (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { - boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l*=r; } ); - return lhs; +template +constexpr auto& operator *= (boost::numeric::ublas::basic_tensor& lhs, typename TensorType::const_reference r) { + static_assert( boost::numeric::ublas::is_valid_tensor_v, + "boost::numeric::ublas::operator *=() : tensor type should be valid tensor" + ); + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l*=r; } ); + return lhs; } -template -auto& operator /= (boost::numeric::ublas::tensor& lhs, typename boost::numeric::ublas::tensor::const_reference r) { - boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l/=r; } ); - return lhs; +template +constexpr auto& operator /= (boost::numeric::ublas::basic_tensor& lhs, typename TensorType::const_reference r) { + static_assert( boost::numeric::ublas::is_valid_tensor_v, + "boost::numeric::ublas::operator /=() : tensor type should be valid tensor" + ); + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l/=r; } ); + return lhs; } @@ -193,13 +298,13 @@ auto& operator /= (boost::numeric::ublas::tensor& lhs, typename boost:: template -auto const& operator +(const boost::numeric::ublas::detail::tensor_expression& lhs) { - return lhs; +constexpr auto const& operator +(const boost::numeric::ublas::detail::tensor_expression& lhs) { + return lhs; } template -auto operator -(boost::numeric::ublas::detail::tensor_expression const& lhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [] (auto const& l) { return -l; } ); +constexpr auto operator -(boost::numeric::ublas::detail::tensor_expression const& lhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [] (auto const& l) { return -l; } ); } @@ -207,37 +312,37 @@ auto operator -(boost::numeric::ublas::detail::tensor_expression const& lhs /** @brief Performs a tensor contraction, not an elementwise multiplication - * + * */ template auto operator*( - std::pair< tensor_type_left const&, tuple_type_left > lhs, - std::pair< tensor_type_right const&, tuple_type_right > rhs) + std::pair< tensor_type_left const&, tuple_type_left > lhs, + std::pair< tensor_type_right const&, tuple_type_right > rhs) { - using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas; - auto const& tensor_left = lhs.first; - auto const& tensor_right = rhs.first; + auto const& tensor_left = lhs.first; + auto const& tensor_right = rhs.first; - auto multi_index_left = lhs.second; - auto multi_index_right = rhs.second; + auto multi_index_left = lhs.second; + auto multi_index_right = rhs.second; - static constexpr auto num_equal_ind = number_equal_indexes::value; + static constexpr auto num_equal_ind = number_equal_indexes::value; - if constexpr ( num_equal_ind == 0 ){ - return tensor_left * tensor_right; - } - else if constexpr ( num_equal_ind==std::tuple_size::value && std::is_same::value ){ + if constexpr ( num_equal_ind == 0 ){ + return tensor_left * tensor_right; + } + else if constexpr ( num_equal_ind==std::tuple_size::value && std::is_same::value ){ - return boost::numeric::ublas::inner_prod( tensor_left, tensor_right ); - } - else { - auto array_index_pairs = index_position_pairs(multi_index_left,multi_index_right); - auto index_pairs = array_to_vector( array_index_pairs ); - return boost::numeric::ublas::prod( tensor_left, tensor_right, index_pairs.first, index_pairs.second ); - } + return boost::numeric::ublas::inner_prod( tensor_left, tensor_right ); + } + else { + auto array_index_pairs = index_position_pairs(multi_index_left,multi_index_right); + auto index_pairs = array_to_vector( array_index_pairs ); + return boost::numeric::ublas::prod( tensor_left, tensor_right, index_pairs.first, index_pairs.second ); + } } diff --git a/include/boost/numeric/ublas/tensor/operators_comparison.hpp b/include/boost/numeric/ublas/tensor/operators_comparison.hpp index c155a0727..13806b5f0 100644 --- a/include/boost/numeric/ublas/tensor/operators_comparison.hpp +++ b/include/boost/numeric/ublas/tensor/operators_comparison.hpp @@ -13,6 +13,7 @@ #define BOOST_UBLAS_TENSOR_OPERATORS_COMPARISON_HPP #include +#include #include #include #include @@ -20,101 +21,122 @@ #include namespace boost::numeric::ublas { -template -class tensor; +template +class basic_tensor; } namespace boost::numeric::ublas::detail { -template -bool compare(tensor const& lhs, tensor const& rhs, BinaryPred pred) +template +[[nodiscard]] inline +constexpr bool compare(basic_tensor const& lhs, basic_tensor const& rhs, BinaryPred pred) { - - if(lhs.extents() != rhs.extents()){ - if constexpr(!std::is_same>::value && !std::is_same>::value) - throw std::runtime_error("Error in boost::numeric::ublas::detail::compare: cannot compare tensors with different shapes."); - else - return false; - } - - if constexpr(std::is_same>::value || std::is_same>::value) - if(lhs.empty()) - return false; - - for(auto i = 0u; i < lhs.size(); ++i) - if(!pred(lhs(i), rhs(i))) - return false; - return true; -} - -template -bool compare(tensor const& rhs, UnaryPred pred) + static_assert( is_valid_tensor_v && is_valid_tensor_v, + "boost::numeric::ublas::detail::compare() : LHS and RHS both should the tensor" + ); + + static_assert( std::is_same_v, + "boost::numeric::ublas::detail::compare() : LHS and RHS both should have same value type" + ); + + if(lhs.extents() != rhs.extents()){ + if constexpr(!std::is_same>::value && !std::is_same>::value) + throw std::runtime_error("Error in boost::numeric::ublas::detail::compare: cannot compare tensors with different shapes."); + else + return false; + } + + if constexpr(std::is_same>::value || std::is_same>::value) + if(lhs.empty()) + return false; + + for(auto i = 0u; i < lhs.size(); ++i) + if(!pred(lhs(i), rhs(i))) + return false; + return true; +} + +template +[[nodiscard]] inline +constexpr bool compare(basic_tensor const& rhs, UnaryPred pred) { - for(auto i = 0u; i < rhs.size(); ++i) - if(!pred(rhs(i))) - return false; - return true; + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::detail::compare() : Template typename T should the tensor type" + ); + + for(auto i = 0u; i < rhs.size(); ++i) + if(!pred(rhs(i))) + return false; + return true; } -template -bool compare(tensor_expression const& lhs, tensor_expression const& rhs, BinaryPred pred) +template +[[nodiscard]] +constexpr bool compare(tensor_expression const& lhs, tensor_expression const& rhs, BinaryPred pred) { - constexpr bool lhs_is_tensor = std::is_same::value; - constexpr bool rhs_is_tensor = std::is_same::value; - - if constexpr (lhs_is_tensor && rhs_is_tensor) - return compare(static_cast( lhs ), static_cast( rhs ), pred); - else if constexpr (lhs_is_tensor && !rhs_is_tensor) - return compare(static_cast( lhs ), T( rhs ), pred); - else if constexpr (!lhs_is_tensor && rhs_is_tensor) - return compare(T( lhs ), static_cast( rhs ), pred); - else - return compare(T( lhs ), T( rhs ), pred); + constexpr bool lhs_is_tensor = std::is_same::value; + constexpr bool rhs_is_tensor = std::is_same::value; + + if constexpr (lhs_is_tensor && rhs_is_tensor) + return compare(static_cast( lhs ), static_cast( rhs ), pred); + else if constexpr (lhs_is_tensor && !rhs_is_tensor) + return compare(static_cast( lhs ), T2( rhs ), pred); + else if constexpr (!lhs_is_tensor && rhs_is_tensor) + return compare(T1( lhs ), static_cast( rhs ), pred); + else + return compare(T1( lhs ), T2( rhs ), pred); } template -bool compare(tensor_expression const& expr, UnaryPred pred) +[[nodiscard]] +constexpr bool compare(tensor_expression const& expr, UnaryPred pred) { - if constexpr (std::is_same::value) - return compare(static_cast( expr ), pred); - else - return compare(T( expr ), pred); + if constexpr (std::is_same::value) + return compare(static_cast( expr ), pred); + else + return compare(T( expr ), pred); } } -template -bool operator==( boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( lhs, rhs, std::equal_to<>{} ); +template +[[nodiscard]] inline +constexpr bool operator==( boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::equal_to<>{} ); } -template -auto operator!=(boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( lhs, rhs, std::not_equal_to<>{} ); +template +[[nodiscard]] inline +constexpr auto operator!=(boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::not_equal_to<>{} ); } -template -auto operator< ( boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( lhs, rhs, std::less<>{} ); +template +[[nodiscard]] inline +constexpr auto operator< ( boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::less<>{} ); } -template -auto operator<=( boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( lhs, rhs, std::less_equal<>{} ); +template +[[nodiscard]] inline +constexpr auto operator<=( boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::less_equal<>{} ); } -template -auto operator> ( boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( lhs, rhs, std::greater<>{} ); +template +[[nodiscard]] inline +constexpr auto operator> ( boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::greater<>{} ); } -template -auto operator>=( boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( lhs, rhs, std::greater_equal<>{} ); +template +[[nodiscard]] inline +constexpr auto operator>=( boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::greater_equal<>{} ); } @@ -122,55 +144,66 @@ auto operator>=( boost::numeric::ublas::detail::tensor_expression const& lh template -bool operator==( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs == r; } ); +[[nodiscard]] inline +constexpr bool operator==( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs == r; } ); } template -auto operator!=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs != r; } ); +[[nodiscard]] inline +constexpr auto operator!=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs != r; } ); } template -auto operator< ( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs < r; } ); +[[nodiscard]] inline +constexpr auto operator< ( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs < r; } ); } template -auto operator<=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs <= r; } ); +[[nodiscard]] inline +constexpr auto operator<=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs <= r; } ); } template -auto operator> ( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs > r; } ); +[[nodiscard]] inline +constexpr auto operator> ( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs > r; } ); } template -auto operator>=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs >= r; } ); +[[nodiscard]] inline +constexpr auto operator>=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs >= r; } ); } template bool operator==( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { - return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l == rhs; } ); + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l == rhs; } ); } template -auto operator!=( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { - return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l != rhs; } ); +[[nodiscard]] inline +constexpr auto operator!=( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l != rhs; } ); } template -auto operator< ( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { - return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l < rhs; } ); +[[nodiscard]] inline +constexpr auto operator< ( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l < rhs; } ); } template -auto operator<=( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { - return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l <= rhs; } ); +[[nodiscard]] inline +constexpr auto operator<=( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l <= rhs; } ); } template -auto operator> ( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { - return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l > rhs; } ); +[[nodiscard]] inline +constexpr auto operator> ( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l > rhs; } ); } template -auto operator>=( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { - return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l >= rhs; } ); +[[nodiscard]] inline +constexpr auto operator>=( boost::numeric::ublas::detail::tensor_expression const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l >= rhs; } ); } diff --git a/include/boost/numeric/ublas/tensor/ostream.hpp b/include/boost/numeric/ublas/tensor/ostream.hpp index 2a70d1e9b..ad61e470c 100644 --- a/include/boost/numeric/ublas/tensor/ostream.hpp +++ b/include/boost/numeric/ublas/tensor/ostream.hpp @@ -24,13 +24,13 @@ namespace detail { template void print(std::ostream& out, value_type const& p) { - out << p << " "; + out << p << " "; } template void print(std::ostream& out, const std::complex& p) { - out << std::real(p) << "+" << std::imag(p) << "i "; + out << std::real(p) << "+" << std::imag(p) << "i "; } @@ -38,33 +38,33 @@ template void print(std::ostream& out, size_type r, const value_type* p, const size_type* w, const size_type* n) { - if(r < 2) - { - out << "[ ... " << std::endl; - - for(auto row = 0u; row < n[0]; p += w[0], ++row) // iterate over one column - { - auto p1 = p; - for(auto col = 0u; col < n[1]; p1 += w[1], ++col) // iterate over first row - { - print(out,*p1); - } - if(row < n[0]-1) - out << "; " << std::endl; - } - out << "]"; - } - else - { - out << "cat("<< r+1 <<",..." << std::endl; - for(auto d = 0u; d < n[r]-1; p += w[r], ++d){ - print(out, r-1, p, w, n); - out << ",..." << std::endl; - } - print(out, r-1, p, w, n); - } - if(r>1) - out << ")"; + if(r < 2) + { + out << "[ ... " << std::endl; + + for(auto row = 0u; row < n[0]; p += w[0], ++row) // iterate over one column + { + auto p1 = p; + for(auto col = 0u; col < n[1]; p1 += w[1], ++col) // iterate over first row + { + print(out,*p1); + } + if(row < n[0]-1) + out << "; " << std::endl; + } + out << "]"; + } + else + { + out << "cat("<< r+1 <<",..." << std::endl; + for(auto d = 0u; d < n[r]-1; p += w[r], ++d){ + print(out, r-1, p, w, n); + out << ",..." << std::endl; + } + print(out, r-1, p, w, n); + } + if(r>1) + out << ")"; } //////////////////////////// @@ -94,30 +94,39 @@ class vector; } -template -std::ostream& operator << (std::ostream& out, boost::numeric::ublas::tensor const& t) +template +std::ostream& operator << (std::ostream& out, boost::numeric::ublas::basic_tensor const& t) { - if(is_scalar(t.extents())){ - out << '['; - boost::numeric::ublas::detail::print(out,t[0]); - out << ']'; - } - else if(is_vector(t.extents())) { - const auto& cat = t.extents().at(0) > t.extents().at(1) ? ';' : ','; - out << '['; - for(auto i = 0u; i < t.size()-1; ++i){ - boost::numeric::ublas::detail::print(out,t[i]); - out << cat << ' '; - } - boost::numeric::ublas::detail::print(out,t[t.size()-1]); - out << ']'; - } - else{ - boost::numeric::ublas::detail::print(out, t.rank()-1, t.data(), t.strides().data(), t.extents().data()); - } - return out; + if(is_scalar(t.extents())){ + out << '['; + boost::numeric::ublas::detail::print(out,t[0]); + out << ']'; + } + else if(is_vector(t.extents())) { + const auto& cat = t.extents().at(0) > t.extents().at(1) ? ';' : ','; + out << '['; + for(auto i = 0u; i < t.size()-1; ++i){ + boost::numeric::ublas::detail::print(out,t[i]); + out << cat << ' '; + } + boost::numeric::ublas::detail::print(out,t[t.size()-1]); + out << ']'; + } + else{ + boost::numeric::ublas::detail::print(out, t.rank()-1, t.data(), t.strides().data(), t.extents().data()); + } + return out; } +template + || boost::numeric::ublas::is_extents_v + , int> = 0 +> +std::ostream& operator<<(std::ostream& os, T const& e){ + return os< #include -#include +#include namespace boost::numeric::ublas { template struct basic_static_extents; -template class basic_extents; /** @brief Template class for storing tensor extents for compile time. * @@ -34,15 +33,15 @@ struct basic_static_extents{ static constexpr auto _size = sizeof...(E); using base_type = std::array; - using value_type = typename base_type::value_type; - using const_reference = typename base_type::const_reference; - using reference = typename base_type::reference; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - using size_type = typename base_type::size_type; + using value_type = typename base_type::value_type; + using const_reference = typename base_type::const_reference; + using reference = typename base_type::reference; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + using size_type = typename base_type::size_type; static_assert( std::numeric_limits::is_integer, "Static error in basic_static_extents: type must be of type integer."); - static_assert(!std::numeric_limits::is_signed, "Static error in basic_static_extents: type must be of type unsigned integer."); + static_assert(!std::numeric_limits::is_signed, "Static error in basic_static_extents: type must be of type unsigned integer."); //@returns the rank of basic_static_extents [[nodiscard]] inline @@ -65,14 +64,6 @@ struct basic_static_extents{ // default constructor constexpr basic_static_extents() = default; - /** @brief Returns the std::vector containing extents */ - [[nodiscard]] inline - auto to_vector() const { - std::vector temp(_size); - std::copy(begin(), end(), temp.begin()); - return temp; - } - /** @brief Returns ref to the std::array containing extents */ [[nodiscard]] inline constexpr base_type const& base() const noexcept{ @@ -85,12 +76,6 @@ struct basic_static_extents{ return m_data.data(); } - /** @brief Returns the basic_extents containing extents */ - [[nodiscard]] inline - auto to_dynamic_extents() const { - return basic_extents(this->to_vector()); - } - /** @brief Checks if extents is empty or not * * @returns true if rank is 0 else false @@ -99,26 +84,9 @@ struct basic_static_extents{ [[nodiscard]] inline constexpr bool empty() const noexcept { return m_data.empty(); } - constexpr value_type back() const noexcept{ - return m_data.back(); - } - - /** @brief Returns true if both extents are equal else false */ - template [[nodiscard]] inline - constexpr bool operator==([[maybe_unused]] basic_static_extents const &rhs) const { - if constexpr( _size != basic_static_extents::_size ){ - return false; - }else{ - return std::equal(begin(), end(), rhs.begin()); - } - } - - /** @brief Returns false if both extents are equal else true */ - template - [[nodiscard]] inline - constexpr bool operator!=(basic_static_extents const &rhs) const { - return !(*this == rhs); + constexpr const_reference back() const noexcept{ + return m_data.back(); } [[nodiscard]] inline @@ -164,4 +132,17 @@ struct static_product< basic_static_extents >{ } // namespace boost::numeric::ublas + +namespace boost::numeric::ublas{ + + template + struct tensor_traits< static_tensor > { + using container_type= std::array< T, static_product_v >; + using extents_type = E; + using layout_type = F; + using container_tag = static_tensor_tag; + }; + +} // namespace boost::numeric::ublas + #endif diff --git a/include/boost/numeric/ublas/tensor/static_strides.hpp b/include/boost/numeric/ublas/tensor/static_strides.hpp index c7b673d02..b36d8f5ed 100644 --- a/include/boost/numeric/ublas/tensor/static_strides.hpp +++ b/include/boost/numeric/ublas/tensor/static_strides.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -14,14 +14,8 @@ #ifndef BOOST_UBLAS_TENSOR_STATIC_STRIDES_HPP #define BOOST_UBLAS_TENSOR_STATIC_STRIDES_HPP -#include -#include -#include -#include -#include -#include -#include #include +#include namespace boost::numeric::ublas{ @@ -205,40 +199,43 @@ struct basic_static_strides, Layout> * @returns the element at given pos */ [[nodiscard]] inline - constexpr auto at(size_type k) const + constexpr const_reference at(size_type k) const { return m_data.at(k); } [[nodiscard]] inline - constexpr auto operator[](size_type k) const { return m_data[k]; } + constexpr const_reference operator[](size_type k) const noexcept { return m_data[k]; } //@returns the rank of basic_static_extents [[nodiscard]] inline - constexpr auto size() const noexcept { return _size; } + constexpr size_type size() const noexcept { return static_cast(_size); } - value_type back () const{ - return m_data.back(); - } + [[nodiscard]] inline + constexpr const_reference back () const noexcept{ + return m_data.back(); + } // default constructor - constexpr basic_static_strides(){ - if constexpr( _size == 0 ){ - return; - }else{ - static_assert( static_traits::is_valid_v, "Error in boost::numeric::ublas::basic_static_strides() : shape is not valid."); - - if constexpr( static_traits::is_vector_v || static_traits::is_scalar_v ){ - return; - }else{ - static_assert(_size >= 2, "Error in boost::numeric::ublas::basic_static_strides() : size of strides must be greater or equal 2."); - } - } - - + constexpr basic_static_strides() noexcept{ + static_assert( + _size == 0 || + ( static_traits::is_valid_v && + ( static_traits::is_vector_v || + static_traits::is_scalar_v || + _size >= 2 + ) + ) + , + "Error in boost::numeric::ublas::basic_static_strides() : " + "Size can be 0 or Shape should be valid and shape can be vector or shape can be scalar or size should be greater than" + " or equal to 2" + ); + + } - constexpr basic_static_strides(extents_type const&) {}; + constexpr basic_static_strides(extents_type const&) noexcept{}; // default copy constructor constexpr basic_static_strides(basic_static_strides const &other) noexcept = default; @@ -273,20 +270,6 @@ struct basic_static_strides, Layout> return m_data.empty(); } - template - constexpr bool operator==(basic_static_strides const& rhs) const noexcept{ - if constexpr( _size != basic_static_strides::_size ){ - return false; - }else{ - return std::equal(begin(), end(), rhs.begin()); - } - } - - template - constexpr bool operator!=(basic_static_strides const& rhs) const noexcept{ - return !(*this == rhs); - } - private: static constexpr base_type const m_data{ detail::strides_helper_v }; }; diff --git a/include/boost/numeric/ublas/tensor/static_tensor.hpp b/include/boost/numeric/ublas/tensor/static_tensor.hpp new file mode 100644 index 000000000..87e9cd6f8 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/static_tensor.hpp @@ -0,0 +1,212 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + + +#ifndef BOOST_UBLAS_STATIC_TENSOR_IMPL_HPP +#define BOOST_UBLAS_STATIC_TENSOR_IMPL_HPP + +#include + +namespace boost::numeric::ublas { + + template< typename T, typename E, typename F = first_order > + struct static_tensor: + public basic_tensor< static_tensor< T, E, F > > + { + + static_assert( is_static_v, + "boost::numeric::static_tensor : extents type should be of static_extents, please check"); + + using self_type = static_tensor< T, E, F >; + using super_type = basic_tensor< self_type >; + + template + using tensor_expression_type = typename super_type::template tensor_expression_type; + + template + using matrix_expression_type = typename super_type::template matrix_expression_type; + + template + using vector_expression_type = typename super_type::template vector_expression_type; + + using array_type = typename tensor_traits::container_type; + using layout_type = typename tensor_traits::layout_type; + + using size_type = typename array_type::size_type; + using difference_type = typename array_type::difference_type; + using value_type = typename array_type::value_type; + + using reference = typename array_type::reference; + using const_reference = typename array_type::const_reference; + + using pointer = typename array_type::pointer; + using const_pointer = typename array_type::const_pointer; + + using iterator = typename array_type::iterator; + using const_iterator = typename array_type::const_iterator; + + using reverse_iterator = typename array_type::reverse_iterator; + using const_reverse_iterator = typename array_type::const_reverse_iterator; + + using tensor_temporary_type = self_type; + using storage_category = dense_tag; + + using extents_type = typename tensor_traits::extents_type; + using strides_type = strides_t; + + using matrix_type = typename super_type::matrix_type; + using vector_type = typename super_type::vector_type; + + constexpr static_tensor() = default; + + constexpr static_tensor( array_type const& a ){ + std::copy(a.begin(), a.end(), super_type::begin()); + } + + constexpr static_tensor( value_type const& i ){ + std::fill(super_type::begin(), super_type::end(), i); + } + + constexpr static_tensor( matrix_type const& v ) + { + static_assert(extents_type::_size == 2 + , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : invalid extents size"); + + if( !( super_type::size(0) == v.size1() || super_type::size(1) == v.size2() ) ){ + throw std::runtime_error("Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : rank of extents are not correct, please check!"); + } + std::copy(v.data().begin(), v.data().end(),super_type::begin()); + } + + constexpr static_tensor( matrix_type && v ) + { + static_assert(extents_type::_size == 2 + , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" + " : invalid extents size"); + + if( !( super_type::size(0) == v.size1() || super_type::size(1) == v.size2() ) ){ + throw std::runtime_error("Error in boost::numeric::ublas::tensor(matrix_type &&v)" + " : rank of extents are not correct, please check!"); + } + + std::move(v.data().begin(), v.data().end(),super_type::begin()); + } + + constexpr static_tensor (const vector_type &v){ + + static_assert(extents_type::_size == 2 + , "Error in boost::numeric::ublas::tensor(const vector_type &v)" + " : invalid extents size"); + + if( !( super_type::size(0) == v.size() || super_type::size(1) == 1 ) ){ + throw std::runtime_error("Error in boost::numeric::ublas::tensor(const vector_type &v)" + " : rank of extents are not correct, please check!"); + } + + std::copy(v.data().begin(), v.data().end(),super_type::begin()); + + } + + constexpr static_tensor (vector_type &&v){ + + static_assert(extents_type::_size == 2 + , "Error in boost::numeric::ublas::tensor(const vector_type &&v)" + " : invalid extents size"); + + if( !( super_type::size(0) == v.size() || super_type::size(1) == 1 ) ){ + throw std::runtime_error("Error in boost::numeric::ublas::tensor(vector_type &&v)" + " : rank of extents are not correct, please check!"); + } + + std::move(v.data().begin(), v.data().end(),super_type::begin()); + + } + + template + constexpr static_tensor (const static_tensor &expr) + : super_type(static_cast(expr)) + {} + + template + constexpr static_tensor (const basic_tensor & other) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::static_tensor( const OtherTensor& ) : The OtherTensor should have a tensor type" + ); + + static_assert( std::is_same_v, + "boost::numeric::ublas::static_tensor( const OtherTensor& ) : The tensor should have same value type" + ); + + if ( other.extents() != super_type::extents() ){ + throw std::runtime_error("boost::numeric::ublas::static_tensor( const OtherTensor& ) : The tensor should have equal extents"); + } + + std::copy(other.begin(), other.end(), super_type::begin()); + } + + template + constexpr static_tensor (basic_tensor && other) + { + static_assert( is_valid_tensor_v, + "boost::numeric::ublas::static_tensor( OtherTensor&& ) : The OtherTensor should have a tensor type" + ); + + static_assert( std::is_same_v, + "boost::numeric::ublas::static_tensor( OtherTensor&& ) : The tensor should have same value type" + ); + + if ( other.extents() != super_type::extents() ){ + throw std::runtime_error("boost::numeric::ublas::static_tensor( OtherTensor&& ) : The tensor should have equal extents"); + } + + std::move(other.begin(), other.end(), super_type::begin()); + } + + template + constexpr static_tensor (const tensor_expression_type &expr) + : super_type(expr) + {} + + template + inline + constexpr static_tensor& operator= (const tensor_expression_type &expr) + { + static_tensor temp( expr ); + swap(*this,temp); + return *this; + } + + template + constexpr static_tensor (const matrix_expression_type &expr) + : static_tensor( matrix_type(expr) ) + {} + + template + constexpr static_tensor (const vector_expression_type &expr) + : static_tensor( vector_type(expr) ) + {} + + inline + constexpr static_tensor& operator=(const_reference v) noexcept{ + std::fill(super_type::begin(), super_type::end(), v); + return *this; + } + + void reshape (extents_type const&, value_type) = delete; + }; + +} // boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/storage.hpp b/include/boost/numeric/ublas/tensor/storage.hpp deleted file mode 100644 index 036089c6f..000000000 --- a/include/boost/numeric/ublas/tensor/storage.hpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - -#ifndef BOOST_UBLAS_TENSOR_STORAGE_HPP -#define BOOST_UBLAS_TENSOR_STORAGE_HPP - -#include -#include -#include -#include - -namespace boost::numeric::ublas::storage { - -namespace dense_tensor { - - template - struct default_storage; - - template - struct default_storage>::type> { - using type = std::vector; - }; - - template - struct default_storage>::type> { - using type = std::array>; - }; - - template - using default_storage_t = typename default_storage::type; - -} // namespace dense_tensor - -} // namespace boost::numeric::ublas::storage - -#endif diff --git a/include/boost/numeric/ublas/tensor/strides.hpp b/include/boost/numeric/ublas/tensor/strides.hpp index cf1139198..d168ec11f 100644 --- a/include/boost/numeric/ublas/tensor/strides.hpp +++ b/include/boost/numeric/ublas/tensor/strides.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -14,105 +14,41 @@ #ifndef _BOOST_UBLAS_TENSOR_STRIDES_HPP_ #define _BOOST_UBLAS_TENSOR_STRIDES_HPP_ -#include #include +#include #include -namespace boost::numeric::ublas { +namespace boost::numeric::ublas{ - template && detail::is_strides_v, int> = 0 + template && is_strides_v + , int> = 0 > - constexpr bool operator==(LStrides const &lhs, RStrides const &rhs) { - - static_assert(detail::is_strides_v && detail::is_strides_v, - "boost::numeric::ublas::operator==() : invalid type, type should be a strides"); + [[nodiscard]] inline + constexpr bool operator==(LStrides const& lhs, RStrides const& rhs) noexcept{ + static_assert( std::is_same_v, + "boost::numeric::ublas::operator==(LStrides,RStrides) : LHS value type should be same as RHS value type"); - if( lhs.size() != rhs.size() ){ - return false; - }else{ - return std::equal(lhs.begin(), lhs.end(), rhs.begin()); - } + return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); } - template && detail::is_strides_v, int> = 0 + template && is_strides_v + , int> = 0 > - constexpr bool operator!=(LStrides const &lhs, RStrides const &rhs) { - static_assert(detail::is_strides_v && detail::is_strides_v, - "boost::numeric::ublas::operator!=() : invalid type, type should be a strides"); - return !(lhs == rhs); + [[nodiscard]] inline + constexpr bool operator!=(LStrides const& lhs, RStrides const& rhs) noexcept{ + static_assert( std::is_same_v, + "boost::numeric::ublas::operator!=(LStrides,RStrides) : LHS value type should be same as RHS value type"); + return !( lhs == rhs ); } + +} // namespace boost::numeric::ublas - template , int> = 0 - > - std::ostream& operator<<(std::ostream& os, Strides const& s){ - static_assert(detail::is_strides_v, - "boost::numeric::ublas::operator<<() : invalid type, type should be a strides"); - return os< struct strides; - - /** @brief Partial Specialization of strides for basic_static_extents - * - * - * @tparam Layout either first_order or last_order - * - * @tparam R rank of extents - * - * @tparam Extents parameter pack of extents - * - */ - template - struct strides, Layout> - { - using type = basic_static_strides, Layout>; - }; - - /** @brief Partial Specialization of strides for basic_extents - * - * - * @tparam Layout either first_order or last_order - * - * @tparam T extents type - * - */ - template - struct strides, Layout> - { - using type = basic_strides; - }; - - /** @brief Partial Specialization of strides for basic_fixed_rank_strides - * - * - * @tparam Layout either first_order or last_order - * - * @tparam T extents type - * - */ - template - struct strides, Layout> - { - using type = basic_fixed_rank_strides; - }; - - /** @brief type alias of result of strides::type - * - * @tparam E extents type either basic_extents or basic_static_extents - * - * @tparam Layout either first_order or last_order - * - */ - template - using strides_t = typename strides::type; - - namespace detail{ +namespace boost::numeric::ublas::detail { /** @brief Returns relative memory index with respect to a multi-index * @@ -123,7 +59,8 @@ namespace boost::numeric::ublas { * @returns relative memory location depending on \c i and \c w */ template - auto access(std::vector const& i, Stride const& w) + [[nodiscard]] inline + constexpr auto access(std::vector const& i, Stride const& w) { static_assert( is_strides_v, "boost::numeric::ublas::detail::access() : invalid type, type should be a strides"); @@ -145,8 +82,9 @@ namespace boost::numeric::ublas { * @returns relative memory location depending on \c i and \c w */ template - auto access(std::size_t sum, Stride const& w, std::size_t i, size_types ... is) - { + [[nodiscard]] + constexpr auto access(std::size_t sum, Stride const& w, std::size_t i, size_types ... is) + { static_assert( is_strides_v, "boost::numeric::ublas::detail::access() : invalid type, type should be a strides"); sum += i*w[r]; @@ -156,9 +94,6 @@ namespace boost::numeric::ublas { return detail::access(sum,w,std::forward(is)...); } - -} // namespace detail - -} // namespace boost::numeric::ublas +} // namespace boost::numeric::ublas::detail #endif diff --git a/include/boost/numeric/ublas/tensor/tensor.hpp b/include/boost/numeric/ublas/tensor/tensor.hpp index 3f209d161..033a69ff3 100644 --- a/include/boost/numeric/ublas/tensor/tensor.hpp +++ b/include/boost/numeric/ublas/tensor/tensor.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -19,13 +19,14 @@ #include #include -#include #include #include -#include +#include +#include +#include #include #include -#include +#include namespace boost { namespace numeric { namespace ublas { @@ -38,798 +39,582 @@ namespace boost { namespace numeric { namespace ublas { // */ //template //class tensor_container: -// public detail::tensor_expression +// public detail::tensor_expression //{ //public: -// static const unsigned complexity = 0; -// typedef C container_type; -// typedef tensor_tag type_category; - -// inline -// const container_type &operator () () const { -// return *static_cast (this); -// } -// inline -// container_type &operator () () { -// return *static_cast (this); -// } +// static const unsigned complexity = 0; +// typedef C container_type; +// typedef tensor_tag type_category; + +// inline +// const container_type &operator () () const { +// return *static_cast (this); +// } +// inline +// container_type &operator () () { +// return *static_cast (this); +// } //}; - - - /** @brief A dense tensor of values of type \c T. - * - * For a \f$n\f$-dimensional tensor \f$v\f$ and \f$0\leq i < n\f$ every element \f$v_i\f$ is mapped - * to the \f$i\f$-th element of the container. A storage type \c A can be specified which defaults to \c unbounded_array. - * Elements are constructed by \c A, which need not initialise their value. - * - * @tparam T type of the objects stored in the tensor (like int, double, complex,...) - * @tparam A The type of the storage array of the tensor. Default is \c unbounded_array. \c and \c std::vector can also be used - */ -template, class F = first_order, class A = storage::dense_tensor::default_storage_t< T, E ,std::allocator> > -class tensor: - public detail::tensor_expression,tensor> +template< class T > +class basic_tensor: + public detail::tensor_expression< basic_tensor,basic_tensor > { - static_assert( std::is_same::value || - std::is_same::value, - "boost::numeric::tensor template class only supports first- or last-order storage formats."); + using self_type = basic_tensor; - using self_type = tensor; public: + template + using tensor_expression_type = detail::tensor_expression; + + template + using matrix_expression_type = matrix_expression; + + template + using vector_expression_type = vector_expression; + + using super_type = tensor_expression_type; + + using array_type = typename tensor_traits::container_type; + using layout_type = typename tensor_traits::layout_type; + + + using size_type = typename array_type::size_type; + using difference_type = typename array_type::difference_type; + using value_type = typename array_type::value_type; + + using reference = typename array_type::reference; + using const_reference = typename array_type::const_reference; + + using pointer = typename array_type::pointer; + using const_pointer = typename array_type::const_pointer; + + using iterator = typename array_type::iterator; + using const_iterator = typename array_type::const_iterator; + + using reverse_iterator = typename array_type::reverse_iterator; + using const_reverse_iterator = typename array_type::const_reverse_iterator; + + using tensor_temporary_type = self_type; + using storage_category = dense_tag; + using container_tag = typename tensor_traits::container_tag; + + using extents_type = typename tensor_traits::extents_type; + using strides_type = strides_t; + + using matrix_type = matrix >; + using vector_type = vector >; + + static_assert( std::is_same::value || + std::is_same::value, + "boost::numeric::basic_tensor template class only supports first- or last-order storage formats."); +protected: + + /** @brief Constructs a basic_tensor. + * + * @note the basic_tensor is empty. + * @note the basic_tensor needs to reshaped for further use. + * + */ + inline + constexpr basic_tensor () + : tensor_expression_type() // container_type + , extents_() + , strides_() + {} + + constexpr basic_tensor( extents_type const& e, dynamic_tensor_tag ) + : tensor_expression_type() + , extents_(e) + , strides_(extents_) + , data_( product(extents_) ) + {} + + constexpr basic_tensor( extents_type const& e, static_tensor_tag ) + : tensor_expression_type() + , extents_(e) + , strides_(extents_) + {} + + /** @brief Constructs a basic_tensor with an initializer list for dynamic_extents + * + * By default, its elements are initialized to 0. + * + * @code basic_tensor A{4,2,3}; @endcode + * + * @param l initializer list for setting the dimension extents of the basic_tensor + */ + explicit inline + basic_tensor (std::initializer_list l) + : basic_tensor( std::move(l), container_tag{} ) + {} + + /** @brief Constructs a basic_tensor with a \c shape + * + * By default, its elements are initialized to 0. + * + * @code basic_tensor A{extents{4,2,3}}; @endcode + * + * @param s initial basic_tensor dimension extents + */ + explicit inline + basic_tensor (extents_type const& s) + : basic_tensor( s, container_tag{} ) + {} + + /** @brief Constructs a basic_tensor with a \c shape + * + * By default, its elements are initialized to 0. + * + * @code basic_tensor A{extents{4,2,3}}; @endcode + * + * @param s initial basic_tensor dimension extents + * @param i initial basic_tensor with this value + */ + explicit inline + basic_tensor (extents_type const& s, value_type const& i) + : basic_tensor( s, container_tag{} ) + { + std::fill(begin(),end(),i); + } + + /** @brief Constructs a basic_tensor with a \c shape and initiates it with one-dimensional data + * + * @code basic_tensor A{extents{4,2,3}, array }; @endcode + * + * + * @param s initial basic_tensor dimension extents + * @param a container of \c array_type that is copied according to the storage layout + */ + basic_tensor (extents_type const& s, const array_type &a) + : basic_tensor( s, container_tag{} ) + { + if( product(extents_) != a.size() ){ + throw std::runtime_error("boost::numeric::ublas::basic_tensor(extents_type,array_type): array size mismatch with extents"); + } + std::copy(a.begin(),a.end(),begin()); + } + + // /** @brief Constructs a basic_tensor using a shape tuple and initiates it with a value. + // * + // * @code basic_tensor A{extents{4,2,3}, 1 }; @endcode + // * + // * @param e initial basic_tensor dimension extents + // * @param i initial value of all elements of type \c value_type + // */ + // template + // inline + // basic_tensor (shape_t const& e, const value_type &i, typename std::enable_if::value>::type* = nullptr) + // : tensor_expression_type() //tensor_container () + // , extents_ (e.begin(),e.end()) + // , strides_ (extents_) + // , data_ (product(extents_), i) + // {} - template - using tensor_expression_type = detail::tensor_expression; - - template - using matrix_expression_type = matrix_expression; - - template - using vector_expression_type = vector_expression; - - using super_type = tensor_expression_type; - -// static_assert(std::is_same_v, detail::tensor_expression,tensor>>, "tensor_expression_type"); - - using array_type = A; - using layout_type = F; - - - using size_type = typename array_type::size_type; - using difference_type = typename array_type::difference_type; - using value_type = typename array_type::value_type; - - using reference = typename array_type::reference; - using const_reference = typename array_type::const_reference; - - using pointer = typename array_type::pointer; - using const_pointer = typename array_type::const_pointer; - - using iterator = typename array_type::iterator; - using const_iterator = typename array_type::const_iterator; - - using reverse_iterator = typename array_type::reverse_iterator; - using const_reverse_iterator = typename array_type::const_reverse_iterator; - - using tensor_temporary_type = self_type; - using storage_category = dense_tag; - - using strides_type = strides_t; - using extents_type = E; - - using matrix_type = matrix>; - using vector_type = vector>; - - - /** @brief Constructs a tensor. - * - * @note the tensor is empty. - * @note the tensor needs to reshaped for further use. - * - */ - inline - constexpr tensor () - : tensor_expression_type() // container_type - , extents_() - , strides_() - { - resize(extents_); - } - - - /** @brief Constructs a tensor with an initializer list for dynamic_extents - * - * By default, its elements are initialized to 0. - * - * @code tensor A{4,2,3}; @endcode - * - * @param l initializer list for setting the dimension extents of the tensor - */ - explicit inline - tensor (std::initializer_list l) - : tensor_expression_type() - , extents_ (std::move(l)) - , strides_ (extents_) - { - resize(extents_); - } - - /** @brief Constructs a tensor with a \c shape - * - * By default, its elements are initialized to 0. - * - * @code tensor A{extents{4,2,3}}; @endcode - * - * @param s initial tensor dimension extents - */ - explicit inline - tensor (extents_type const& s) - : tensor_expression_type() //tensor_container() - , extents_ (s) - , strides_ (extents_) - { - resize(extents_); - } - - - /** @brief Constructs a tensor with a \c shape and initiates it with one-dimensional data - * - * @code tensor A{extents{4,2,3}, array }; @endcode - * - * - * @param s initial tensor dimension extents - * @param a container of \c array_type that is copied according to the storage layout - */ - inline - tensor (extents_type const& s, const array_type &a) - : tensor_expression_type() //tensor_container() - , extents_ (s) - , strides_ (extents_) - , data_ (a) - { - if(product(extents_) != this->data_.size()) - throw std::runtime_error("Error in boost::numeric::ublas::tensor: size of provided data and specified extents do not match."); - } - - - - /** @brief Constructs a tensor using a shape tuple and initiates it with a value. - * - * @code tensor A{extents{4,2,3}, 1 }; @endcode - * - * @param e initial tensor dimension extents - * @param i initial value of all elements of type \c value_type - */ - inline - tensor (extents_type const& e, const value_type &i) - : tensor_expression_type() //tensor_container () - , extents_ (e) - , strides_ (extents_) - { - resize(extents_); - std::fill(begin(),end(),i); - } - - // /** @brief Constructs a tensor using a shape tuple and initiates it with a value. - // * - // * @code tensor A{extents{4,2,3}, 1 }; @endcode - // * - // * @param e initial tensor dimension extents - // * @param i initial value of all elements of type \c value_type - // */ - // template - // inline - // tensor (shape_t const& e, const value_type &i, typename std::enable_if::value>::type* = nullptr) - // : tensor_expression_type() //tensor_container () - // , extents_ (e.begin(),e.end()) - // , strides_ (extents_) - // , data_ (product(extents_), i) - // {} - - - - /** @brief Constructs a tensor from another tensor - * - * @param v tensor to be copied. - */ - inline - tensor (const tensor &v) - : tensor_expression_type() - , extents_ (v.extents_) - , strides_ (v.strides_) - , data_ (v.data_ ) - {} - - - - /** @brief Constructs a tensor from another tensor - * - * @param v tensor to be moved. - */ - inline - tensor (tensor &&v) - : tensor_expression_type() //tensor_container () - , extents_ (std::move(v.extents_)) - , strides_ (std::move(v.strides_)) - , data_ (std::move(v.data_ )) - {} - - /** @brief Constructs a tensor with a matrix - * - * \note Initially the tensor will be two-dimensional. - * - * @param v matrix to be copied. - */ - inline - tensor (const matrix_type &v) - : tensor_expression_type() - , extents_ () - , strides_ () - { - auto const sz = v.size1() * v.size2(); - if(sz){ - if constexpr (detail::is_static::value){ - static_assert(extents_type::_size == 2 - , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : invalid extents size"); - if( !( extents_[0] == v.size1() || extents_[1] == v.size2() ) ){ - throw std::runtime_error("Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : rank of extents not correct, please check!"); - } - }else { - if constexpr( detail::is_static_rank::value ){ - static_assert(extents_type::size() == 2, "Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : rank of extents not correct, please check!"); - } - resize(sz); - extents_ = extents_type{v.size1(),v.size2()}; - strides_ = strides_type(extents_); - } - std::copy(v.data().begin(), v.data().end(),data_.begin()); - } - } - - /** @brief Constructs a tensor with a matrix - * - * \note Initially the tensor will be two-dimensional. - * - * @param v matrix to be moved. - */ - inline - tensor (matrix_type &&v) - : tensor_expression_type() - , extents_ {} - , strides_ {} - , data_ {} - { - - auto const sz = v.size1() * v.size2(); - if(sz){ - if constexpr (detail::is_static::value){ - static_assert(extents_type::_size == 2 - , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : invalid extents size"); - if( !( extents_[0] == v.size1() || extents_[1] == v.size2() ) ){ - throw std::runtime_error("Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : rank of extents not correct, please check!"); - } - }else { - if constexpr( detail::is_static_rank::value ){ - static_assert(extents_type::size() == 2, "Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : rank of extents not correct, please check!"); - } - - resize(sz); - extents_ = extents_type{v.size1(),v.size2()}; - strides_ = strides_type(extents_); - } - for(auto i = size_type{}; i < sz; ++i){ - data_[i] = std::move(v.data()[i]); - } - } - } - - /** @brief Constructs a tensor using a \c vector - * - * @note It is assumed that vector is column vector - * @note Initially the tensor will be one-dimensional. - * - * @param v vector to be copied. - */ - inline - tensor (const vector_type &v) - : tensor_expression_type() - , extents_ () - , strides_ () - { - auto const sz = v.size(); - if(sz){ - if constexpr (detail::is_static::value){ - static_assert(extents_type::_size == 2 - , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : invalid extents size"); - if( !( extents_[0] == v.size() || extents_[1] == 1 ) ){ - throw std::runtime_error("Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : rank of extents not correct, please check!"); - } - }else{ - if constexpr( detail::is_static_rank::value ){ - static_assert(extents_type::size() == 2, "Error in boost::numeric::ublas::tensor(const vector &v)" - " : rank of extents not correct, please check!"); - } - - resize(sz); - extents_ = extents_type{v.size(),1}; - strides_ = strides_type(extents_); - } - std::copy(v.data().begin(), v.data().end(),data_.begin()); - } - - } - - /** @brief Constructs a tensor using a \c vector - * - * @param v vector to be moved. - */ - inline - tensor (vector_type &&v) - : tensor_expression_type() - , extents_ {} - , strides_ {} - , data_ {} - { - auto const sz = v.size(); - if(sz){ - if constexpr (detail::is_static::value){ - static_assert(extents_type::_size == 2 - , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : invalid extents size"); - if( !( extents_[0] == v.size() || extents_[1] == 1 ) ){ - throw std::runtime_error("Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : rank of extents not correct, please check!"); - } - }else{ - if constexpr( detail::is_static_rank::value ){ - static_assert(extents_type::size() == 2, "Error in boost::numeric::ublas::tensor(const vector &v)" - " : rank of extents not correct, please check!"); - } - - resize(sz); - extents_ = extents_type{v.size(),1}; - strides_ = strides_type(extents_); - } - - for(auto i = size_type{}; i < sz; ++i){ - data_[i] = std::move(v.data()[i]); - } - } - } - - - - - /** @brief Constructs a tensor with another tensor with a different layout - * - * @param other tensor with a different layout to be copied. - */ - template - tensor (const tensor &other) - : tensor_expression_type () - , extents_ (other.extents()) - , strides_ (other.extents()) - { - resize(extents_); - copy(this->rank(), this->extents().data(), - this->data(), this->strides().data(), - other.data(), other.strides().data()); - - } - - /** @brief Constructs a tensor with an tensor expression - * - * @code tensor A = B + 3 * C; @endcode - * - * @note type must be specified of tensor must be specified. - * @note dimension extents are extracted from tensors within the expression. - * - * @param expr tensor expression - */ - template - tensor (const tensor_expression_type &expr) - : tensor_expression_type () - , extents_ ( detail::retrieve_extents(expr) ) - , strides_ ( extents_ ) - { - static_assert( detail::has_tensor_types>::value, - "Error in boost::numeric::ublas::tensor: expression does not contain a tensor. cannot retrieve shape."); - resize(extents_); - detail::eval( *this, expr ); - } - - /** @brief Constructs a tensor with a matrix expression - * - * @code tensor A = B + 3 * C; @endcode - * - * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. - * @note extents are automatically extracted from the temporary matrix - * - * @param expr matrix expression - */ - template - tensor (const matrix_expression_type &expr) - : tensor( matrix_type ( expr ) ) - { - } - - /** @brief Constructs a tensor with a vector expression - * - * @code tensor A = b + 3 * b; @endcode - * - * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. - * @note extents are automatically extracted from the temporary matrix - * - * @param expr vector expression - */ - template - tensor (const vector_expression_type &expr) - : tensor( vector_type ( expr ) ) - { - } - - /** @brief Evaluates the tensor_expression and assigns the results to the tensor - * - * @code A = B + C * 2; @endcode - * - * @note rank and dimension extents of the tensors in the expressions must conform with this tensor. - * - * @param expr expression that is evaluated. - */ - template - tensor &operator = (const tensor_expression_type &expr) - { - detail::eval(*this, expr); - return *this; - } - - tensor& operator=(tensor other) - { - swap (*this, other); - return *this; - } - - tensor& operator=(const_reference v) - { - std::fill(this->begin(), this->end(), v); - return *this; - } - - /** @brief Returns true if the tensor is empty (\c size==0) */ - inline - bool empty () const { - return this->data_.empty(); - } - - - /** @brief Returns the size of the tensor */ - inline - size_type size () const { - return this->data_.size (); - } - - /** @brief Returns the size of the tensor */ - inline - size_type size (size_type r) const { - return this->extents_.at(r); - } - - /** @brief Returns the number of dimensions/modes of the tensor */ - inline - size_type rank () const { - return this->extents_.size(); - } - - /** @brief Returns the number of dimensions/modes of the tensor */ - inline - size_type order () const { - return this->extents_.size(); - } - - /** @brief Returns the strides of the tensor */ - inline - strides_type const& strides () const { - return this->strides_; - } - - /** @brief Returns the extents of the tensor */ - inline - extents_type const& extents () const { - return this->extents_; - } - - - /** @brief Returns a \c const reference to the container. */ - inline - const_pointer data () const { - return this->data_.data(); - } - - /** @brief Returns a \c const reference to the container. */ - inline - pointer data () { - return this->data_.data(); - } - - /** @brief Element access using a single index. - * - * @code auto a = A[i]; @endcode - * - * @param i zero-based index where 0 <= i < this->size() - */ - inline - const_reference operator [] (size_type i) const { - return this->data_[i]; - } - - /** @brief Element access using a single index. - * - * @code auto a = A[i]; @endcode - * - * @param i zero-based index where 0 <= i < this->size() - */ - inline - reference operator [] (size_type i) { - return this->data_[i]; - } - - /** @brief Element access using a multi-index or single-index. - * - * - * @code auto a = A.at(i,j,k); @endcode or - * @code auto a = A.at(i); @endcode - * - * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - inline - const_reference at (size_type i, size_types ... is) const { - if constexpr (sizeof...(is) == 0) - return this->data_[i]; - else - return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward(is)...)]; - } - - /** @brief Element access using a multi-index or single-index. - * - * - * @code A.at(i,j,k) = a; @endcode or - * @code A.at(i) = a; @endcode - * - * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - inline - reference at (size_type i, size_types ... is) { - if constexpr (sizeof...(is) == 0) - return this->data_[i]; - else{ - auto temp = detail::access<0ul>(size_type(0),this->strides_,i,std::forward(is)...); - return this->data_[temp]; - } - } - - /** @brief Element access using a single index. - * - * - * @code A(i) = a; @endcode - * - * @param i zero-based index where 0 <= i < this->size() - */ - inline - const_reference operator()(size_type i) const { - return this->data_[i]; - } - - - /** @brief Element access using a single index. - * - * @code A(i) = a; @endcode - * - * @param i zero-based index where 0 <= i < this->size() - */ - inline - reference operator()(size_type i){ - return this->data_[i]; - } - - /** @brief Generates a tensor index for tensor contraction - * - * - * @code auto Ai = A(_i,_j,k); @endcode - * - * @param i placeholder - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - inline - decltype(auto) operator() (index::index_type p, index_types ... ps) const - { - constexpr auto N = sizeof...(ps)+1; - if( N != this->rank() ) - throw std::runtime_error("Error in boost::numeric::ublas::operator(): size of provided index_types does not match with the rank."); - - return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward(ps)... ) ); - } - - - - - - /** @brief Reshapes the tensor - * - * - * (1) @code A.reshape(extents{m,n,o}); @endcode or - * (2) @code A.reshape(extents{m,n,o},4); @endcode - * - * If the size of this smaller than the specified extents than - * default constructed (1) or specified (2) value is appended. - * - * @note rank of the tensor might also change. - * - * @param e extents with which the tensor is reshaped. - * @param v value which is appended if the tensor is enlarged. - */ - inline - void reshape (extents_type const& e, value_type v = value_type{}) - { - static_assert(detail::is_dynamic_v, - "Error in boost::numeric::ublas::tensor: static extents cannot be reshaped"); - this->extents_ = e; - this->strides_ = strides_type(this->extents_); - - auto p = product(extents_); - if(p != this->size()) - this->data_.resize (p, v); - } - - friend void swap(tensor& lhs, tensor& rhs) { - std::swap(lhs.data_ , rhs.data_ ); - std::swap(lhs.extents_, rhs.extents_); - std::swap(lhs.strides_, rhs.strides_); - } - - - /// \brief return an iterator on the first element of the tensor - inline - const_iterator begin () const { - return data_.begin (); - } - - /// \brief return an iterator on the first element of the tensor - inline - const_iterator cbegin () const { - return data_.cbegin (); - } - - /// \brief return an iterator after the last element of the tensor - inline - const_iterator end () const { - return data_.end(); - } - - /// \brief return an iterator after the last element of the tensor - inline - const_iterator cend () const { - return data_.cend (); - } - - /// \brief Return an iterator on the first element of the tensor - inline - iterator begin () { - return data_.begin(); - } - - /// \brief Return an iterator at the end of the tensor - inline - iterator end () { - return data_.end(); - } - - /// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor) - inline - const_reverse_iterator rbegin () const { - return data_.rbegin(); - } - - /// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor) - inline - const_reverse_iterator crbegin () const { - return data_.crbegin(); - } - - /// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor) - inline - const_reverse_iterator rend () const { - return data_.rend(); - } - - /// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor) - inline - const_reverse_iterator crend () const { - return data_.crend(); - } - - /// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor) - inline - reverse_iterator rbegin () { - return data_.rbegin(); - } - - /// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor) - inline - reverse_iterator rend () { - return data_.rend(); - } - -private: - - inline - void resize( [[maybe_unused]] extents_type const& e ){ - if constexpr( detail::is_resizable_v){ - data_.resize(product(e)); - } - } - - inline - void resize( [[maybe_unused]] size_type sz ){ - if constexpr( detail::is_resizable_v){ - data_.resize(sz); - } - } - -#if 0 - // ------------- - // Serialization - // ------------- - - /// Serialize a tensor into and archive as defined in Boost - /// \param ar Archive object. Can be a flat file, an XML file or any other stream - /// \param file_version Optional file version (not yet used) - template - void serialize(Archive & ar, const unsigned int /* file_version */){ - ar & serialization::make_nvp("data",data_); - } -#endif - - - -private: +public: - extents_type extents_; - strides_type strides_; - array_type data_; + /** @brief Constructs a basic_tensor with another basic_tensor with a different layout + * + * @param other basic_tensor with a different layout to be copied. + */ + template + basic_tensor (const basic_tensor &other) + : basic_tensor( other.extents(), container_tag{} ) + { + copy(this->rank(), this->extents().data(), + this->data(), this->strides().data(), + other.data(), other.strides().data()); + + } + + + /** @brief Constructs a basic_tensor with an basic_tensor expression + * + * @code basic_tensor A = B + 3 * C; @endcode + * + * @note type must be specified of basic_tensor must be specified. + * @note dimension extents are extracted from tensors within the expression. + * + * @param expr basic_tensor expression + * @param size basic_tensor expression + */ + template + basic_tensor (const tensor_expression_type &expr) + : basic_tensor( detail::retrieve_extents(expr), container_tag{} ) + { + static_assert( detail::has_tensor_types>::value, + "Error in boost::numeric::ublas::basic_tensor: expression does not contain a basic_tensor. cannot retrieve shape."); + detail::eval( *this, expr ); + } + + /** @brief Constructs a basic_tensor with a matrix expression + * + * @code basic_tensor A = B + 3 * C; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr matrix expression + */ + template + basic_tensor (const matrix_expression_type &expr) + : basic_tensor( matrix_type ( expr ) ) + { + } + + /** @brief Constructs a basic_tensor with a vector expression + * + * @code basic_tensor A = b + 3 * b; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr vector expression + */ + template + basic_tensor (const vector_expression_type &expr) + : basic_tensor( vector_type ( expr ) ) + { + } + + + /** @brief Constructs a basic_tensor from another basic_tensor + * + * @param v basic_tensor to be copied. + */ + inline + basic_tensor (const basic_tensor &v) + : tensor_expression_type() + , extents_ (v.extents_) + , strides_ (v.strides_) + , data_ (v.data_ ) + {} + + + + /** @brief Constructs a basic_tensor from another basic_tensor + * + * @param v basic_tensor to be moved. + */ + inline + basic_tensor (basic_tensor &&v) + : tensor_expression_type() //tensor_container () + , extents_ (std::move(v.extents_)) + , strides_ (std::move(v.strides_)) + , data_ (std::move(v.data_ )) + {} + + /** @brief Evaluates the tensor_expression and assigns the results to the basic_tensor + * + * @code A = B + C * 2; @endcode + * + * @note rank and dimension extents of the tensors in the expressions must conform with this basic_tensor. + * + * @param expr expression that is evaluated. + */ + template + basic_tensor &operator = (const tensor_expression_type &expr) + { + detail::eval(*this, expr); + return *this; + } + + basic_tensor& operator=(basic_tensor other) + { + swap (*this, other); + return *this; + } + + basic_tensor& operator=(const_reference v) + { + std::fill(this->begin(), this->end(), v); + return *this; + } + + /** @brief Returns true if the basic_tensor is empty (\c size==0) */ + inline + bool empty () const { + return this->data_.empty(); + } + + + /** @brief Returns the size of the basic_tensor */ + inline + size_type size () const { + return this->data_.size (); + } + + /** @brief Returns the size of the basic_tensor */ + inline + size_type size (size_type r) const { + return this->extents_.at(r); + } + + /** @brief Returns the number of dimensions/modes of the basic_tensor */ + inline + size_type rank () const { + return this->extents_.size(); + } + + /** @brief Returns the number of dimensions/modes of the basic_tensor */ + inline + size_type order () const { + return this->extents_.size(); + } + + /** @brief Returns the strides of the basic_tensor */ + inline + strides_type const& strides () const { + return this->strides_; + } + + /** @brief Returns the extents of the basic_tensor */ + inline + extents_type const& extents () const { + return this->extents_; + } + + + /** @brief Returns a \c const reference to the container. */ + inline + const_pointer data () const { + return this->data_.data(); + } + + /** @brief Returns a \c const reference to the container. */ + inline + pointer data () { + return this->data_.data(); + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + inline + const_reference operator [] (size_type i) const { + return this->data_[i]; + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + inline + reference operator [] (size_type i) { + return this->data_[i]; + } + + /** @brief Element access using a multi-index or single-index. + * + * + * @code auto a = A.at(i,j,k); @endcode or + * @code auto a = A.at(i); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + inline + const_reference at (size_type i, size_types ... is) const { + if constexpr (sizeof...(is) == 0) + return this->data_[i]; + else + return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward(is)...)]; + } + + /** @brief Element access using a multi-index or single-index. + * + * + * @code A.at(i,j,k) = a; @endcode or + * @code A.at(i) = a; @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + inline + reference at (size_type i, size_types ... is) { + if constexpr (sizeof...(is) == 0) + return this->data_[i]; + else{ + auto temp = detail::access<0ul>(size_type(0),this->strides_,i,std::forward(is)...); + return this->data_[temp]; + } + } + + /** @brief Element access using a single index. + * + * + * @code A(i) = a; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + inline + const_reference operator()(size_type i) const { + return this->data_[i]; + } + + + /** @brief Element access using a single index. + * + * @code A(i) = a; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + inline + reference operator()(size_type i){ + return this->data_[i]; + } + + /** @brief Generates a basic_tensor index for basic_tensor contraction + * + * + * @code auto Ai = A(_i,_j,k); @endcode + * + * @param i placeholder + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + inline + decltype(auto) operator() (index::index_type p, index_types ... ps) const + { + constexpr auto N = sizeof...(ps)+1; + if( N != this->rank() ) + throw std::runtime_error("Error in boost::numeric::ublas::operator(): size of provided index_types does not match with the rank."); + + return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward(ps)... ) ); + } + + /** @brief Reshapes the basic_tensor + * + * + * (1) @code A.reshape(extents{m,n,o}); @endcode or + * (2) @code A.reshape(extents{m,n,o},4); @endcode + * + * If the size of this smaller than the specified extents than + * default constructed (1) or specified (2) value is appended. + * + * @note rank of the basic_tensor might also change. + * + * @param e extents with which the basic_tensor is reshaped. + * @param v value which is appended if the basic_tensor is enlarged. + */ + inline + void reshape (extents_type const& e, value_type v = value_type{}) + { + static_assert(is_dynamic_v, + "Error in boost::numeric::ublas::basic_tensor: static extents cannot be reshaped"); + this->extents_ = e; + this->strides_ = strides_type(this->extents_); + + auto p = product(extents_); + if(p != this->size()) + this->data_.resize (p, v); + } + + friend void swap(basic_tensor& lhs, basic_tensor& rhs) { + std::swap(lhs.data_ , rhs.data_ ); + std::swap(lhs.extents_, rhs.extents_); + std::swap(lhs.strides_, rhs.strides_); + } + + + /// \brief return an iterator on the first element of the basic_tensor + inline + const_iterator begin () const { + return data_.begin (); + } + + /// \brief return an iterator on the first element of the basic_tensor + inline + const_iterator cbegin () const { + return data_.cbegin (); + } + + /// \brief return an iterator after the last element of the basic_tensor + inline + const_iterator end () const { + return data_.end(); + } + + /// \brief return an iterator after the last element of the basic_tensor + inline + const_iterator cend () const { + return data_.cend (); + } + + /// \brief Return an iterator on the first element of the basic_tensor + inline + iterator begin () { + return data_.begin(); + } + + /// \brief Return an iterator at the end of the basic_tensor + inline + iterator end () { + return data_.end(); + } + + /// \brief Return a const reverse iterator before the first element of the reversed basic_tensor (i.e. end() of normal basic_tensor) + inline + const_reverse_iterator rbegin () const { + return data_.rbegin(); + } + + /// \brief Return a const reverse iterator before the first element of the reversed basic_tensor (i.e. end() of normal basic_tensor) + inline + const_reverse_iterator crbegin () const { + return data_.crbegin(); + } + + /// \brief Return a const reverse iterator on the end of the reverse basic_tensor (i.e. first element of the normal basic_tensor) + inline + const_reverse_iterator rend () const { + return data_.rend(); + } + + /// \brief Return a const reverse iterator on the end of the reverse basic_tensor (i.e. first element of the normal basic_tensor) + inline + const_reverse_iterator crend () const { + return data_.crend(); + } + + /// \brief Return a const reverse iterator before the first element of the reversed basic_tensor (i.e. end() of normal basic_tensor) + inline + reverse_iterator rbegin () { + return data_.rbegin(); + } + + /// \brief Return a const reverse iterator on the end of the reverse basic_tensor (i.e. first element of the normal basic_tensor) + inline + reverse_iterator rend () { + return data_.rend(); + } + +protected: + + extents_type extents_; + strides_type strides_; + array_type data_; }; -#if __cpp_deduction_guides - -tensor() -> tensor>; - -template::value >::type* = nullptr> -tensor(E const&, T const& ) ->tensor; - -template::value >::type* = nullptr> -tensor(E const&) ->tensor; -#endif - - }}} // namespaces +namespace boost::numeric::ublas{ + template + struct tensor_rebind,Ts...>{ + using type = tensor_rebind_t; + }; + +} // namespace boost::numeric::ublas::detail diff --git a/include/boost/numeric/ublas/tensor/type_traits.hpp b/include/boost/numeric/ublas/tensor/type_traits.hpp new file mode 100644 index 000000000..3a24b3845 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/type_traits.hpp @@ -0,0 +1,22 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_HPP + +#include +#include + +#include +#include + +#endif diff --git a/test/tensor/Jamfile b/test/tensor/Jamfile index 84a1716c5..3ce59e748 100644 --- a/test/tensor/Jamfile +++ b/test/tensor/Jamfile @@ -43,6 +43,7 @@ test-suite boost-ublas-tensor-test test_einstein_notation.cpp test_algorithms.cpp test_tensor_matrix_vector.cpp + test_functions.cpp unit_test_framework ] [ run test_static_tensor.cpp @@ -52,16 +53,17 @@ test-suite boost-ublas-tensor-test test_static_operators_comparison.cpp test_static_expression_evaluation.cpp test_static_tensor_matrix_vector.cpp + test_static_functions.cpp unit_test_framework ] [ run test_fixed_rank_tensor.cpp + test_fixed_rank_extents.cpp + test_fixed_rank_strides.cpp test_fixed_rank_operators_arithmetic.cpp test_fixed_rank_operators_comparison.cpp test_fixed_rank_expression_evaluation.cpp test_fixed_rank_tensor_matrix_vector.cpp + test_fixed_rank_functions.cpp unit_test_framework ] - [ run test_functions.cpp - unit_test_framework - ] ; diff --git a/test/tensor/test_algorithms.cpp b/test/tensor/test_algorithms.cpp index 784bbe022..b6dcbd105 100644 --- a/test/tensor/test_algorithms.cpp +++ b/test/tensor/test_algorithms.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -15,7 +15,9 @@ #include #include #include -#include +#include +#include +#include #include #include "utility.hpp" @@ -34,21 +36,21 @@ using test_types2 = std::tuple>; struct fixture { - using extents_type = boost::numeric::ublas::dynamic_extents<>; - 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; + using extents_type = boost::numeric::ublas::dynamic_extents<>; + 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; }; @@ -56,63 +58,63 @@ struct fixture 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; + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector; - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto b = vector_type(product(n)); - auto c = vector_type(product(n)); + auto a = vector_type(product(n)); + auto b = vector_type(product(n)); + auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wb = ublas::strides_t,ublas::last_order> (n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wb = ublas::strides_t,ublas::last_order> (n); + auto wc = ublas::strides_t,ublas::first_order>(n); - auto v = value_type{}; - for(auto i = 0ul; i < a.size(); ++i, v+=1){ - a[i]=v; - } + 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() ); + 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] ); + for(auto i = 1ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i], a[i] ); - using size_type = typename ublas::strides_t,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::runtime_error ); - BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), p0, b.data(), wb.data() ), std::runtime_error ); - BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), p0 ), std::runtime_error ); + using size_type = typename ublas::strides_t,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::runtime_error ); + BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), p0, b.data(), wb.data() ), std::runtime_error ); + BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), p0 ), std::runtime_error ); - value_type* c0 = nullptr; - BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c0, wc.data(), b.data(), wb.data() ), std::runtime_error ); - } + value_type* c0 = nullptr; + BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c0, wc.data(), b.data(), wb.data() ), std::runtime_error ); + } - // special case rank == 0 - { - auto n = ublas::dynamic_extents<>{}; + // special case rank == 0 + { + auto n = ublas::dynamic_extents<>{}; - auto a = vector_type(product(n)); - auto b = vector_type(product(n)); - auto c = vector_type(product(n)); + auto a = vector_type(product(n)); + auto b = vector_type(product(n)); + auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wb = ublas::strides_t,ublas::last_order> (n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wb = ublas::strides_t,ublas::last_order> (n); + auto wc = ublas::strides_t,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() ); + 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_CHECK_NO_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() ) ); - } + } @@ -123,117 +125,117 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_type BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, test_types2, fixture ) { - using namespace boost::numeric; - using value_type = value; - using vector_type = std::vector; + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector; - for(auto const& n : extents) { + for(auto const& n : extents) { - value_type* a = nullptr; - auto c = vector_type(product(n)); + value_type* a = nullptr; + auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - value_type* a = nullptr; - value_type* c = nullptr; + value_type* a = nullptr; + value_type* c = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); - } + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - value_type* c = nullptr; + auto a = vector_type(product(n)); + value_type* c = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c, wc.data(), a.data(), wa.data() ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c, wc.data(), a.data(), wa.data() ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); - size_t* wa = nullptr; - auto wc = ublas::strides_t,ublas::first_order>(n); + size_t* wa = nullptr; + auto wc = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); - size_t* wc = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); + size_t* wc = nullptr; + auto wa = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); - - size_t* m = nullptr; - auto wc = ublas::strides_t,ublas::first_order>(n); - auto wa = ublas::strides_t,ublas::first_order>(n); + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); + + size_t* m = nullptr; + auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::copy( n.size(), m, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::copy( n.size(), m, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + + } } 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; + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector; - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto b = vector_type(product(n)); - auto c = vector_type(product(n)); + auto a = vector_type(product(n)); + auto b = vector_type(product(n)); + auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wb = ublas::strides_t,ublas::last_order> (n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wb = ublas::strides_t,ublas::last_order> (n); + auto wc = ublas::strides_t,ublas::first_order>(n); - auto v = value_type{}; - for(auto i = 0ul; i < a.size(); ++i, v+=1){ - a[i]=v; - } + 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);} ); + 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);} ); using size_type = typename ublas::strides_t,ublas::first_order>::value_type; size_type zero = 0; - ublas::transform(zero, n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a + value_type(1);} ); + ublas::transform(zero, n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a + value_type(1);} ); - value_type* c0 = nullptr; + value_type* c0 = nullptr; const size_type* s0 = nullptr; size_type const*const p0 = nullptr; @@ -243,119 +245,119 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform, value, test for(auto i = 1ul; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i], a[i] ); + BOOST_CHECK_EQUAL( c[i], a[i] ); - } + } } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform_exceptions, value, test_types2, fixture ) { - using namespace boost::numeric; - using value_type = value; - using vector_type = std::vector; + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector; - for(auto const& n : extents) { + for(auto const& n : extents) { - value_type* a = nullptr; - auto c = vector_type(product(n)); + value_type* a = nullptr; + auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - value_type* a = nullptr; - value_type* c = nullptr; + value_type* a = nullptr; + value_type* c = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c, wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c, wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - } + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - value_type* c = nullptr; + auto a = vector_type(product(n)); + value_type* c = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c, wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c, wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); - size_t* wa = nullptr; - auto wc = ublas::strides_t,ublas::first_order>(n); + size_t* wa = nullptr; + auto wc = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc.data(), a.data(), wa, [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc.data(), a.data(), wa, [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); - size_t* wc = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); + size_t* wc = nullptr; + auto wa = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); - - size_t* m = nullptr; - auto wc = ublas::strides_t,ublas::first_order>(n); - auto wa = ublas::strides_t,ublas::first_order>(n); + auto a = vector_type(product(n)); + auto c = vector_type(product(n)); + + size_t* m = nullptr; + auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::transform( n.size(), m, c.data(), wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::transform( n.size(), m, c.data(), wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + + } } 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; + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector; - for(auto const& n : extents) { + for(auto const& n : extents) { - auto const s = product(n); + auto const s = product(n); - auto a = vector_type(product(n)); - // auto b = vector_type(product(n)); - // auto c = vector_type(product(n)); + auto a = vector_type(product(n)); + // auto b = vector_type(product(n)); + // auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - // auto wb = ublas::strides_t,ublas::last_order> (n); - // auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); + // auto wb = ublas::strides_t,ublas::last_order> (n); + // auto wc = ublas::strides_t,ublas::first_order>(n); - auto v = value_type{}; - for(auto i = 0ul; i < a.size(); ++i, v+=value_type(1)){ - a[i]=v; - } + 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); + auto acc = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v); - BOOST_CHECK_EQUAL( acc, value_type( static_cast< inner_type_t >( s*(s+1) / 2 ) ) ); + BOOST_CHECK_EQUAL( acc, value_type( static_cast< inner_type_t >( s*(s+1) / 2 ) ) ); using size_type = typename ublas::strides_t,ublas::first_order>::value_type; size_type zero = 0; @@ -370,7 +372,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, tes auto acc2 = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v, - [](auto const& l, auto const& r){return l + r; }); + [](auto const& l, auto const& r){return l + r; }); BOOST_CHECK_EQUAL( acc2, value_type( static_cast< inner_type_t >( s*(s+1) / 2 ) ) ); @@ -380,77 +382,77 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, tes BOOST_CHECK_THROW(ublas::accumulate( n.size(), n.data(), a.data(), p0, v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); BOOST_CHECK_THROW(ublas::accumulate( n.size(), p0, a.data(), wa.data(),v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); - } + } } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, value, test_types2, fixture ) { - using namespace boost::numeric; - using value_type = value; - using vector_type = std::vector; + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector; - for(auto const& n : extents) { + for(auto const& n : extents) { - value_type* a = nullptr; + value_type* a = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0} ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0} ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - value_type* a = nullptr; + value_type* a = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); - BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0},[](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0},[](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); + auto a = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - size_t p = 0u; - BOOST_CHECK_EQUAL ( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0} ), value_type{0} ); - - } + auto wa = ublas::strides_t,ublas::first_order>(n); + size_t p = 0u; + BOOST_CHECK_EQUAL ( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0} ), value_type{0} ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); + auto a = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - size_t p = 0u; - BOOST_CHECK_EQUAL( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), value_type{0} ); - - } + auto wa = ublas::strides_t,ublas::first_order>(n); + size_t p = 0u; + BOOST_CHECK_EQUAL( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), value_type{0} ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); + auto a = vector_type(product(n)); - size_t* wa = nullptr; + size_t* wa = nullptr; - BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a.data(), wa, value_type{0} ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a.data(), wa, value_type{0} ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); + auto a = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::first_order>(n); - size_t* m = nullptr; + size_t* m = nullptr; - BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), m, a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), m, a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); + + } } @@ -458,93 +460,93 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, template void init(std::vector& a) { - auto v = V(1); - for(auto i = 0u; i < a.size(); ++i, ++v){ - a[i] = v; - } + auto v = V(1); + for(auto i = 0u; i < a.size(); ++i, ++v){ + a[i] = v; + } } template void init(std::vector>& a) { - auto v = std::complex(1,1); - for(auto i = 0u; i < a.size(); ++i){ - a[i] = v; - v.real(v.real()+1); - v.imag(v.imag()+1); - } + auto v = std::complex(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; - using extents_type = ublas::dynamic_extents<>; - using strides_type = ublas::strides_t; - using size_type = typename extents_type::value_type; - using permutation_type = std::vector; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using vector_type = std::vector; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; + using size_type = typename extents_type::value_type; + using permutation_type = std::vector; - for(auto const& n : extents) { + for(auto const& n : extents) { - auto p = n.size(); - auto s = product(n); + auto p = n.size(); + auto s = product(n); - 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 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); + auto wa = strides_type(n); - init(a); + init(a); - // so wie last-order. - for(auto i = size_type(0), j = p; i < n.size(); ++i, --j) - pi[i] = j; + // 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 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]; + 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() ); + 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) - for(auto i = 0ul; i < s; ++i) - BOOST_CHECK_EQUAL( c1[i], c2[i] ); + if(!std::is_compound_v) + 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 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]; + 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() ); + 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) - for(auto i = 0ul; i < s; ++i) - BOOST_CHECK_EQUAL( b1[i], b2[i] ); + if(!std::is_compound_v) + 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] ); + for(auto i = 0ul; i < s; ++i) + BOOST_CHECK_EQUAL( a[i], b2[i] ); - size_type zero = 0; + size_type zero = 0; ublas::trans( zero, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() ); ublas::trans( zero, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() ); @@ -562,178 +564,178 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans, value, test_typ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans_exceptions, 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; - using extents_type = ublas::dynamic_extents<>; - using strides_type = ublas::strides_t; - using size_type = typename extents_type::value_type; - using permutation_type = std::vector; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using vector_type = std::vector; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; + using size_type = typename extents_type::value_type; + using permutation_type = std::vector; - for(auto const& n : extents) { + for(auto const& n : extents) { - auto p = n.size(); - auto s = product(n); + auto p = n.size(); + auto s = product(n); - auto pi = permutation_type(p); - value_type* a = nullptr; - auto c = vector_type(s); + auto pi = permutation_type(p); + value_type* a = nullptr; + auto c = vector_type(s); - auto wa = strides_type(n); + auto wa = strides_type(n); - auto nc = typename extents_type::base_type (p); - auto wc = strides_type(n); - auto wc_pi = typename strides_type::base_type (p); + auto nc = typename extents_type::base_type (p); + auto wc = strides_type(n); + auto wc_pi = typename strides_type::base_type (p); - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), a, wa.data(), c.data(), wc.data() ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), a, wa.data(), c.data(), wc.data() ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto p = n.size(); - auto s = product(n); + auto p = n.size(); + auto s = product(n); - auto pi = permutation_type(p); - value_type* a = nullptr; - auto c = vector_type(s); + auto pi = permutation_type(p); + value_type* a = nullptr; + auto c = vector_type(s); - auto wa = strides_type(n); - auto nc = typename extents_type::base_type (p); - - auto wc = strides_type(n); + auto wa = strides_type(n); + auto nc = typename extents_type::base_type (p); + + auto wc = strides_type(n); - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto p = n.size(); + auto p = n.size(); - auto pi = permutation_type(p); - value_type* a = nullptr; - value_type* c = nullptr; + auto pi = permutation_type(p); + value_type* a = nullptr; + value_type* c = nullptr; - auto wa = strides_type(n); - auto nc = typename extents_type::base_type (p); - - auto wc = strides_type(n); + auto wa = strides_type(n); + auto nc = typename extents_type::base_type (p); + + auto wc = strides_type(n); - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto p = n.size(); - auto s = product(n); + auto p = n.size(); + auto s = product(n); - auto pi = permutation_type(p); - auto a = vector_type(s); - auto c = vector_type(s); + auto pi = permutation_type(p); + auto a = vector_type(s); + auto c = vector_type(s); - auto wa = strides_type(n); + auto wa = strides_type(n); - auto nc = typename extents_type::base_type (p); - - size_t* wc = nullptr; + auto nc = typename extents_type::base_type (p); + + size_t* wc = nullptr; - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto p = n.size(); - auto s = product(n); + auto p = n.size(); + auto s = product(n); - auto pi = permutation_type(p); - auto a = vector_type(s); - auto c = vector_type(s); + auto pi = permutation_type(p); + auto a = vector_type(s); + auto c = vector_type(s); - auto wc = strides_type(n); - auto nc = typename extents_type::base_type (p); - - size_t* wa = nullptr; + auto wc = strides_type(n); + auto nc = typename extents_type::base_type (p); + + size_t* wa = nullptr; - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto p = n.size(); - auto s = product(n); + auto p = n.size(); + auto s = product(n); - auto pi = permutation_type(p); - auto a = vector_type(s); - auto c = vector_type(s); + auto pi = permutation_type(p); + auto a = vector_type(s); + auto c = vector_type(s); - size_t* wc = nullptr; + size_t* wc = nullptr; - auto nc = typename extents_type::base_type (p); - - size_t* wa = nullptr; + auto nc = typename extents_type::base_type (p); + + size_t* wa = nullptr; - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc, a.data(), wa ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc, a.data(), wa ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto p = n.size(); - auto s = product(n); + auto p = n.size(); + auto s = product(n); - size_type* pi = nullptr; - auto a = vector_type(s); - auto c = vector_type(s); + size_type* pi = nullptr; + auto a = vector_type(s); + auto c = vector_type(s); - auto wa = strides_type(n); + auto wa = strides_type(n); - auto nc = typename extents_type::base_type (p); - auto wc = strides_type(n); + auto nc = typename extents_type::base_type (p); + auto wc = strides_type(n); - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto p = n.size(); - auto s = product(n); + auto p = n.size(); + auto s = product(n); - auto pi = permutation_type(p); - auto a = vector_type(s); - auto c = vector_type(s); + auto pi = permutation_type(p); + auto a = vector_type(s); + auto c = vector_type(s); - auto wa = strides_type(n); - size_t* nc = nullptr; - - auto wc = strides_type(n); + auto wa = strides_type(n); + size_t* nc = nullptr; + + auto wc = strides_type(n); - BOOST_REQUIRE_THROW( ublas::trans( p, nc, pi.data(), c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); - - } + BOOST_REQUIRE_THROW( ublas::trans( p, nc, pi.data(), c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + + } - for(auto const& n : extents) { + for(auto const& n : extents) { - size_type p = 1; - auto s = product(n); + size_type p = 1; + auto s = product(n); - auto pi = permutation_type(p); - auto a = vector_type(s); - auto c = vector_type(s); + auto pi = permutation_type(p); + auto a = vector_type(s); + auto c = vector_type(s); - auto wa = strides_type(n); - auto nc = typename extents_type::base_type (p); - - auto wc = strides_type(n); + auto wa = strides_type(n); + auto nc = typename extents_type::base_type (p); + + auto wc = strides_type(n); - ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a.data(), wa.data() ); - - } + ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a.data(), wa.data() ); + + } } diff --git a/test/tensor/test_einstein_notation.cpp b/test/tensor/test_einstein_notation.cpp index 782d7b86d..f8508f08c 100644 --- a/test/tensor/test_einstein_notation.cpp +++ b/test/tensor/test_einstein_notation.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -29,96 +29,94 @@ using test_types = zip>::with_t; - using tensor_type = tensor; - 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}; + using namespace boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = dynamic_tensor; + 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( static_cast< inner_type_t >(i+1) ); + 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( static_cast< inner_type_t >(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( static_cast< inner_type_t >(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( static_cast< inner_type_t >(i+1) ); - auto AB = A(_,_e) * B(_e,_); + auto AB = A(_,_e) * B(_e,_); - // std::cout << "A = " << A << std::endl; - // std::cout << "B = " << B << std::endl; - // std::cout << "AB = " << AB << std::endl; + // 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 )) ); + 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}; + { + 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( static_cast< inner_type_t >(i+1) ); + 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( static_cast< inner_type_t >(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( static_cast< inner_type_t >(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( static_cast< inner_type_t >(i+1) ); - auto AB = A(_d,_,_f) * B(_f,_d,_); + 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 ); + // 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( static_cast< inner_type_t >(nf * nd) ) ); + 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( static_cast< inner_type_t >(nf * nd) ) ); - } + } - { - auto A = tensor_type{4,3}; - auto B = tensor_type{3,4,2}; + { + 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( static_cast< inner_type_t >(i+1) ); + 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( static_cast< inner_type_t >(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( static_cast< inner_type_t >(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( static_cast< inner_type_t >(i+1) ); - auto AB = A(_d,_f) * B(_f,_d,_); + 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 ); + // 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( static_cast< inner_type_t >(nf * nd) ) ); + for(auto i = 0u; i < AB.extents().at(0); ++i) + BOOST_CHECK_EQUAL ( AB.at( i ) , value_type( static_cast< inner_type_t >(nf * nd) ) ); - } + } } BOOST_AUTO_TEST_SUITE_END() - diff --git a/test/tensor/test_expression.cpp b/test/tensor/test_expression.cpp index 5cbe7ae65..39cb84c46 100644 --- a/test/tensor/test_expression.cpp +++ b/test/tensor/test_expression.cpp @@ -13,7 +13,7 @@ #include -#include +#include #include #include "utility.hpp" @@ -27,144 +27,147 @@ using test_types = zip>::with_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{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; + using extents_type = boost::numeric::ublas::dynamic_extents<>; + 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; }; 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, layout_type>; - using tensor_expression_type = typename tensor_type::super_type; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using basic_tensor_type = typename tensor_type::super_type; + using tensor_expression_type = typename basic_tensor_type::super_type; - for(auto const& e : extents) { + for(auto const& e : extents) { - auto v = value_type{}; - auto t = tensor_type(e); + 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( t ); + for(auto& tt: t){ tt = v; v+=value_type{1}; } + const auto& tensor_expression_const = static_cast( t ); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( tensor_expression_const()(i), t(i) ); + 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, layout_type>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using basic_tensor_type = typename tensor_type::super_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - for(auto const& e : extents) { + 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 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( t, uplus1 ); + const auto uexpr = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( uexpr(i), uplus1(t(i)) ); + 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( uexpr, uplus1 ); + auto uexpr_uexpr = ublas::detail::make_unary_tensor_expression( uexpr, uplus1 ); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( uexpr_uexpr(i), uplus1(uplus1(t(i))) ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( uexpr_uexpr(i), uplus1(uplus1(t(i))) ); - const auto & uexpr_e = uexpr.e; + const auto & uexpr_e = uexpr.e; - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_e) >, tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_e) >, basic_tensor_type > ) ); - const auto & uexpr_uexpr_e_e = uexpr_uexpr.e.e; + 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_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_uexpr_e_e) >, basic_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, layout_type>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using basic_tensor_type = typename tensor_type::super_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, std::placeholders::_1, value_type(2) ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, std::placeholders::_1, value_type(2) ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; - for(auto const& e : extents) { + 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 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( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, basic_tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, basic_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( uexpr1(i), uplus1(t(i)) ); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( uexpr2(i), uplus2(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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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 > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, basic_tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, basic_tensor_type > ) ); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( bexpr_uexpr(i), bplus(uexpr1(i),uexpr2(i)) ); + 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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 > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, basic_tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, basic_tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, basic_tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, basic_tensor_type > ) ); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) ); - } + } } diff --git a/test/tensor/test_expression_evaluation.cpp b/test/tensor/test_expression_evaluation.cpp index ef43fdc59..c4188ea29 100644 --- a/test/tensor/test_expression_evaluation.cpp +++ b/test/tensor/test_expression_evaluation.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -14,7 +14,7 @@ #include #include -#include +#include #include "utility.hpp" #include @@ -27,116 +27,116 @@ using test_types = zip>::with_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{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; + using extents_type = boost::numeric::ublas::dynamic_extents<>; + 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; }; 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 extents_type = ublas::dynamic_extents<>; - using tensor_type = ublas::tensor; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using basic_tensor_type = typename tensor_type::super_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; - for(auto const& e : extents) { + 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 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 ); + BOOST_CHECK( ublas::detail::retrieve_extents( t ) == e ); - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - BOOST_CHECK( ublas::detail::retrieve_extents( uexpr1 ) == e ); - BOOST_CHECK( ublas::detail::retrieve_extents( uexpr2 ) == e ); + 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( uexpr1, uexpr2, bplus ); + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_uexpr ) == e ); + 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( bexpr_uexpr, t, bminus ); + // bexpr_bexpr_uexpr = ((t+1) + (2+t)) - t + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); - } + } - for(auto i = 0u; i < extents.size()-1; ++i) - { + for(auto i = 0u; i < extents.size()-1; ++i) + { - auto v = value_type{}; + auto v = value_type{}; - auto t1 = tensor_type(extents[i]); - for(auto& tt: t1){ tt = v; v+=value_type{1}; } + 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}; } + 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 ) ); + 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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + // uexpr1 = t1+1 + // uexpr2 = 2+t2 + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 ) ); + 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( uexpr1, uexpr2, bplus ); + // bexpr_uexpr = (t1+1) + (2+t2) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_uexpr ) == ublas::detail::retrieve_extents(t1) ); + 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( bexpr_uexpr, t2, bminus ); + // bexpr_bexpr_uexpr = ((t1+1) + (2+t2)) - t2 + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t2, bminus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr1 ) == ublas::detail::retrieve_extents(t2) ); + 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( t2, bexpr_uexpr, bminus ); + // bexpr_bexpr_uexpr = t2 - ((t1+1) + (2+t2)) + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( t2, bexpr_uexpr, bminus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); - } + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); + } } @@ -147,100 +147,101 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_retrieve_extents, value 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, layout_type>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using basic_tensor_type = typename tensor_type::super_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; - for(auto const& e : extents) { + 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 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 ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - BOOST_CHECK( ublas::detail::all_extents_equal( uexpr1, e ) ); - BOOST_CHECK( ublas::detail::all_extents_equal( uexpr2, e ) ); + 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( uexpr1, uexpr2, bplus ); + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_uexpr, e ) ); + 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( bexpr_uexpr, t, bminus ); + // bexpr_bexpr_uexpr = ((t+1) + (2+t)) - t + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); - BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); - } + } - for(auto i = 0u; i < extents.size()-1; ++i) - { + for(auto i = 0u; i < extents.size()-1; ++i) + { - auto v = value_type{}; + auto v = value_type{}; - auto t1 = tensor_type(extents[i]); - for(auto& tt: t1){ tt = v; v+=value_type{1}; } + 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}; } + 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) ) ); + 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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + // uexpr1 = t1+1 + // uexpr2 = 2+t2 + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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) ) ); + 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( uexpr1, uexpr2, bplus ); + // bexpr_uexpr = (t1+1) + (2+t2) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_uexpr, ublas::detail::retrieve_extents( bexpr_uexpr ) ) ); + 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( bexpr_uexpr, t2, bminus ); + // bexpr_bexpr_uexpr = ((t1+1) + (2+t2)) - t2 + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t2, bminus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr1, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr1 ) ) ); + 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( t2, bexpr_uexpr, bminus ); + // bexpr_bexpr_uexpr = t2 - ((t1+1) + (2+t2)) + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( t2, bexpr_uexpr, bminus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr2, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) ) ); + 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( uexpr1, t2, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_uexpr2, ublas::detail::retrieve_extents( bexpr_uexpr2 ) ) ); + // bexpr_uexpr2 = (t1+1) + t2 + auto bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr2, t1, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr3, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr3 ) ) ); + // bexpr_uexpr2 = ((t1+1) + t2) + t1 + auto bexpr_bexpr_uexpr3 = ublas::detail::make_binary_tensor_expression( 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( t1, bexpr_bexpr_uexpr3, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); + // bexpr_uexpr2 = t1 + (((t1+1) + t2) + t1) + auto bexpr_bexpr_uexpr4 = ublas::detail::make_binary_tensor_expression( t1, bexpr_bexpr_uexpr3, bplus ); + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); - } + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_extents.cpp b/test/tensor/test_extents.cpp index a02ec3386..d69a2ffb4 100644 --- a/test/tensor/test_extents.cpp +++ b/test/tensor/test_extents.cpp @@ -11,7 +11,9 @@ // #include -#include +#include +#include +#include #include BOOST_AUTO_TEST_SUITE ( test_extents ) @@ -22,1145 +24,662 @@ BOOST_AUTO_TEST_SUITE ( test_extents ) BOOST_AUTO_TEST_CASE(test_extents_ctor) { - using namespace boost::numeric; - using extents = ublas::basic_extents; + using namespace boost::numeric; + using extents = ublas::basic_extents; - auto e0 = extents{}; - BOOST_CHECK( e0.empty()); - BOOST_CHECK ( e0.size() == 0 ); + auto e0 = extents{}; + BOOST_CHECK( e0.empty()); + BOOST_CHECK ( e0.size() == 0 ); - auto e1 = extents{1,1}; - BOOST_CHECK(!e1.empty()); - BOOST_CHECK ( e1.size() == 2 ); + auto e1 = extents{1,1}; + BOOST_CHECK(!e1.empty()); + BOOST_CHECK ( e1.size() == 2 ); - auto e2 = extents{1,2}; - BOOST_CHECK(!e2.empty()); - BOOST_CHECK ( e2.size() == 2 ); + auto e2 = extents{1,2}; + BOOST_CHECK(!e2.empty()); + BOOST_CHECK ( e2.size() == 2 ); - auto e3 = extents{2,1}; - BOOST_CHECK (!e3.empty()); - BOOST_CHECK ( e3.size() == 2 ); + auto e3 = extents{2,1}; + BOOST_CHECK (!e3.empty()); + BOOST_CHECK ( e3.size() == 2 ); - auto e4 = extents{2,3}; - BOOST_CHECK(!e4.empty()); - BOOST_CHECK ( e4.size() == 2 ); + auto e4 = extents{2,3}; + BOOST_CHECK(!e4.empty()); + BOOST_CHECK ( e4.size() == 2 ); - auto e5 = extents{2,3,1}; - BOOST_CHECK (!e5.empty()); - BOOST_CHECK ( e5.size() == 3 ); + auto e5 = extents{2,3,1}; + BOOST_CHECK (!e5.empty()); + BOOST_CHECK ( e5.size() == 3 ); - auto e6 = extents{1,2,3}; // 6 - BOOST_CHECK(!e6.empty()); - BOOST_CHECK ( e6.size() == 3 ); + auto e6 = extents{1,2,3}; // 6 + BOOST_CHECK(!e6.empty()); + BOOST_CHECK ( e6.size() == 3 ); - auto e7 = extents{4,2,3}; // 7 - BOOST_CHECK(!e7.empty()); - BOOST_CHECK ( e7.size() == 3 ); + auto e7 = extents{4,2,3}; // 7 + BOOST_CHECK(!e7.empty()); + BOOST_CHECK ( 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); + 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); } BOOST_AUTO_TEST_CASE(test_static_rank_extents_ctor) { - namespace ub = boost::numeric::ublas; + namespace ub = boost::numeric::ublas; - auto e0 = ub::dynamic_extents<0>{}; - BOOST_CHECK( e0.empty()); - BOOST_CHECK ( e0.size() == 0); + auto e0 = ub::dynamic_extents<0>{}; + BOOST_CHECK( e0.empty()); + BOOST_CHECK ( e0.size() == 0); - auto e1 = ub::dynamic_extents<2>{1,1}; - BOOST_CHECK(!e1.empty()); - BOOST_CHECK ( e1.size() == 2); + auto e1 = ub::dynamic_extents<2>{1,1}; + BOOST_CHECK(!e1.empty()); + BOOST_CHECK ( e1.size() == 2); - auto e2 = ub::dynamic_extents<2>{1,2}; - BOOST_CHECK(!e2.empty()); - BOOST_CHECK ( e2.size() == 2); + auto e2 = ub::dynamic_extents<2>{1,2}; + BOOST_CHECK(!e2.empty()); + BOOST_CHECK ( e2.size() == 2); - auto e3 = ub::dynamic_extents<2>{2,1}; - BOOST_CHECK (!e3.empty()); - BOOST_CHECK ( e3.size() == 2); + auto e3 = ub::dynamic_extents<2>{2,1}; + BOOST_CHECK (!e3.empty()); + BOOST_CHECK ( e3.size() == 2); - auto e4 = ub::dynamic_extents<2>{2,3}; - BOOST_CHECK(!e4.empty()); - BOOST_CHECK ( e4.size() == 2); + auto e4 = ub::dynamic_extents<2>{2,3}; + BOOST_CHECK(!e4.empty()); + BOOST_CHECK ( e4.size() == 2); - auto e5 = ub::dynamic_extents<3>{2,3,1}; - BOOST_CHECK (!e5.empty()); - BOOST_CHECK ( e5.size() == 3); + auto e5 = ub::dynamic_extents<3>{2,3,1}; + BOOST_CHECK (!e5.empty()); + BOOST_CHECK ( e5.size() == 3); - auto e6 = ub::dynamic_extents<3>{1,2,3}; // 6 - BOOST_CHECK(!e6.empty()); - BOOST_CHECK ( e6.size() == 3); + auto e6 = ub::dynamic_extents<3>{1,2,3}; // 6 + BOOST_CHECK(!e6.empty()); + BOOST_CHECK ( e6.size() == 3); - auto e7 = ub::dynamic_extents<3>{4,2,3}; // 7 - BOOST_CHECK(!e7.empty()); - BOOST_CHECK ( e7.size() == 3); + auto e7 = ub::dynamic_extents<3>{4,2,3}; // 7 + BOOST_CHECK(!e7.empty()); + BOOST_CHECK ( e7.size() == 3); - BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,0}), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<1>({0} ), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<1>({3} ), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<2>({0,1}), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,1,2}), std::out_of_range); + BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,0}), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<1>({0} ), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<1>({3} ), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<2>({0,1}), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,1,2}), std::out_of_range); } struct fixture { - using extents_type = boost::numeric::ublas::dynamic_extents<>; - template - using static_rank_extents_type = boost::numeric::ublas::dynamic_extents; - - 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 - - extents_type{1,4,1}, // 13 - extents_type{1,1,1,1}, // 14 - extents_type{1,4,1,1,1}, // 15 - extents_type{1,1,2,1,1,1}, // 16 - extents_type{1,1,2,3,1,1}, // 17 - } - {} - std::vector extents; - - static_rank_extents_type<0> de0{}; // 0 - - static_rank_extents_type<2> de1{1,1}; // 1 - static_rank_extents_type<2> de2{1,2}; // 2 - static_rank_extents_type<2> de3{2,1}; // 3 - - static_rank_extents_type<2> de4{2,3}; // 4 - static_rank_extents_type<3> de5{2,3,1}; // 5 - static_rank_extents_type<3> de6{1,2,3}; // 6 - static_rank_extents_type<4> de7{1,1,2,3}; // 7 - static_rank_extents_type<5> de8{1,2,3,1,1}; // 8 - - static_rank_extents_type<3> de9{4,2,3}; // 9 - static_rank_extents_type<4> de10{4,2,1,3}; // 10 - static_rank_extents_type<5> de11{4,2,1,3,1}; // 11 - static_rank_extents_type<6> de12{1,4,2,1,3,1};// 12 - - static_rank_extents_type<3> de13{1,4,1}; // 13 - static_rank_extents_type<4> de14{1,1,1,1}; // 14 - static_rank_extents_type<5> de15{1,4,1,1,1}; // 15 - static_rank_extents_type<6> de16{1,1,2,1,1,1};// 16 - static_rank_extents_type<6> de17{1,1,2,3,1,1};// 17 + using extents_type = boost::numeric::ublas::dynamic_extents<>; + template + using static_rank_extents_type = boost::numeric::ublas::dynamic_extents; + + 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 + + extents_type{1,4,1}, // 13 + extents_type{1,1,1,1}, // 14 + extents_type{1,4,1,1,1}, // 15 + extents_type{1,1,2,1,1,1}, // 16 + extents_type{1,1,2,3,1,1}, // 17 + } + {} + std::vector 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(),18); - - 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_REQUIRE_EQUAL(extents[13].size(), 3); - BOOST_REQUIRE_EQUAL(extents[14].size(), 4); - BOOST_REQUIRE_EQUAL(extents[15].size(), 5); - BOOST_REQUIRE_EQUAL(extents[16].size(), 6); - BOOST_REQUIRE_EQUAL(extents[17].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_CHECK_EQUAL(extents[13][0],1); - BOOST_CHECK_EQUAL(extents[13][1],4); - BOOST_CHECK_EQUAL(extents[13][2],1); - - BOOST_CHECK_EQUAL(extents[14][0],1); - BOOST_CHECK_EQUAL(extents[14][1],1); - BOOST_CHECK_EQUAL(extents[14][2],1); - BOOST_CHECK_EQUAL(extents[14][3],1); - - BOOST_CHECK_EQUAL(extents[15][0],1); - BOOST_CHECK_EQUAL(extents[15][1],4); - BOOST_CHECK_EQUAL(extents[15][2],1); - BOOST_CHECK_EQUAL(extents[15][3],1); - BOOST_CHECK_EQUAL(extents[15][4],1); - - BOOST_CHECK_EQUAL(extents[16][0],1); - BOOST_CHECK_EQUAL(extents[16][1],1); - BOOST_CHECK_EQUAL(extents[16][2],2); - BOOST_CHECK_EQUAL(extents[16][3],1); - BOOST_CHECK_EQUAL(extents[16][4],1); - BOOST_CHECK_EQUAL(extents[16][5],1); - - BOOST_CHECK_EQUAL(extents[17][0],1); - BOOST_CHECK_EQUAL(extents[17][1],1); - BOOST_CHECK_EQUAL(extents[17][2],2); - BOOST_CHECK_EQUAL(extents[17][3],3); - BOOST_CHECK_EQUAL(extents[17][4],1); - BOOST_CHECK_EQUAL(extents[17][5],1); -} - -BOOST_FIXTURE_TEST_CASE(test_static_rank_extents_access, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("access")) -{ - using namespace boost::numeric; - - BOOST_CHECK_EQUAL(de0.size(), 0); - BOOST_CHECK (de0.empty() ); - - BOOST_REQUIRE_EQUAL(de1.size(), 2); - BOOST_REQUIRE_EQUAL(de2.size(), 2); - BOOST_REQUIRE_EQUAL(de3.size(), 2); - BOOST_REQUIRE_EQUAL(de4.size(), 2); - BOOST_REQUIRE_EQUAL(de5.size(), 3); - BOOST_REQUIRE_EQUAL(de6.size(), 3); - BOOST_REQUIRE_EQUAL(de7.size(), 4); - BOOST_REQUIRE_EQUAL(de8.size(), 5); - BOOST_REQUIRE_EQUAL(de9.size(), 3); - BOOST_REQUIRE_EQUAL(de10.size(), 4); - BOOST_REQUIRE_EQUAL(de11.size(), 5); - BOOST_REQUIRE_EQUAL(de12.size(), 6); - BOOST_REQUIRE_EQUAL(de13.size(), 3); - BOOST_REQUIRE_EQUAL(de14.size(), 4); - BOOST_REQUIRE_EQUAL(de15.size(), 5); - BOOST_REQUIRE_EQUAL(de16.size(), 6); - BOOST_REQUIRE_EQUAL(de17.size(), 6); - - - BOOST_CHECK_EQUAL(de1[0],1); - BOOST_CHECK_EQUAL(de1[1],1); - - BOOST_CHECK_EQUAL(de2[0],1); - BOOST_CHECK_EQUAL(de2[1],2); - - BOOST_CHECK_EQUAL(de3[0],2); - BOOST_CHECK_EQUAL(de3[1],1); - - BOOST_CHECK_EQUAL(de4[0],2); - BOOST_CHECK_EQUAL(de4[1],3); - - BOOST_CHECK_EQUAL(de5[0],2); - BOOST_CHECK_EQUAL(de5[1],3); - BOOST_CHECK_EQUAL(de5[2],1); - - BOOST_CHECK_EQUAL(de6[0],1); - BOOST_CHECK_EQUAL(de6[1],2); - BOOST_CHECK_EQUAL(de6[2],3); - - BOOST_CHECK_EQUAL(de7[0],1); - BOOST_CHECK_EQUAL(de7[1],1); - BOOST_CHECK_EQUAL(de7[2],2); - BOOST_CHECK_EQUAL(de7[3],3); - - BOOST_CHECK_EQUAL(de8[0],1); - BOOST_CHECK_EQUAL(de8[1],2); - BOOST_CHECK_EQUAL(de8[2],3); - BOOST_CHECK_EQUAL(de8[3],1); - BOOST_CHECK_EQUAL(de8[4],1); - - BOOST_CHECK_EQUAL(de9[0],4); - BOOST_CHECK_EQUAL(de9[1],2); - BOOST_CHECK_EQUAL(de9[2],3); - - BOOST_CHECK_EQUAL(de10[0],4); - BOOST_CHECK_EQUAL(de10[1],2); - BOOST_CHECK_EQUAL(de10[2],1); - BOOST_CHECK_EQUAL(de10[3],3); - - BOOST_CHECK_EQUAL(de11[0],4); - BOOST_CHECK_EQUAL(de11[1],2); - BOOST_CHECK_EQUAL(de11[2],1); - BOOST_CHECK_EQUAL(de11[3],3); - BOOST_CHECK_EQUAL(de11[4],1); - - BOOST_CHECK_EQUAL(de12[0],1); - BOOST_CHECK_EQUAL(de12[1],4); - BOOST_CHECK_EQUAL(de12[2],2); - BOOST_CHECK_EQUAL(de12[3],1); - BOOST_CHECK_EQUAL(de12[4],3); - BOOST_CHECK_EQUAL(de12[5],1); - - BOOST_CHECK_EQUAL(de13[0],1); - BOOST_CHECK_EQUAL(de13[1],4); - BOOST_CHECK_EQUAL(de13[2],1); - - BOOST_CHECK_EQUAL(de14[0],1); - BOOST_CHECK_EQUAL(de14[1],1); - BOOST_CHECK_EQUAL(de14[2],1); - BOOST_CHECK_EQUAL(de14[3],1); - - BOOST_CHECK_EQUAL(de15[0],1); - BOOST_CHECK_EQUAL(de15[1],4); - BOOST_CHECK_EQUAL(de15[2],1); - BOOST_CHECK_EQUAL(de15[3],1); - BOOST_CHECK_EQUAL(de15[4],1); - - BOOST_CHECK_EQUAL(de16[0],1); - BOOST_CHECK_EQUAL(de16[1],1); - BOOST_CHECK_EQUAL(de16[2],2); - BOOST_CHECK_EQUAL(de16[3],1); - BOOST_CHECK_EQUAL(de16[4],1); - BOOST_CHECK_EQUAL(de16[5],1); - - BOOST_CHECK_EQUAL(de17[0],1); - BOOST_CHECK_EQUAL(de17[1],1); - BOOST_CHECK_EQUAL(de17[2],2); - BOOST_CHECK_EQUAL(de17[3],3); - BOOST_CHECK_EQUAL(de17[4],1); - BOOST_CHECK_EQUAL(de17[5],1); + using namespace boost::numeric; + + BOOST_REQUIRE_EQUAL(extents.size(),18); + + 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_REQUIRE_EQUAL(extents[13].size(), 3); + BOOST_REQUIRE_EQUAL(extents[14].size(), 4); + BOOST_REQUIRE_EQUAL(extents[15].size(), 5); + BOOST_REQUIRE_EQUAL(extents[16].size(), 6); + BOOST_REQUIRE_EQUAL(extents[17].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_CHECK_EQUAL(extents[13][0],1); + BOOST_CHECK_EQUAL(extents[13][1],4); + BOOST_CHECK_EQUAL(extents[13][2],1); + + BOOST_CHECK_EQUAL(extents[14][0],1); + BOOST_CHECK_EQUAL(extents[14][1],1); + BOOST_CHECK_EQUAL(extents[14][2],1); + BOOST_CHECK_EQUAL(extents[14][3],1); + + BOOST_CHECK_EQUAL(extents[15][0],1); + BOOST_CHECK_EQUAL(extents[15][1],4); + BOOST_CHECK_EQUAL(extents[15][2],1); + BOOST_CHECK_EQUAL(extents[15][3],1); + BOOST_CHECK_EQUAL(extents[15][4],1); + + BOOST_CHECK_EQUAL(extents[16][0],1); + BOOST_CHECK_EQUAL(extents[16][1],1); + BOOST_CHECK_EQUAL(extents[16][2],2); + BOOST_CHECK_EQUAL(extents[16][3],1); + BOOST_CHECK_EQUAL(extents[16][4],1); + BOOST_CHECK_EQUAL(extents[16][5],1); + + BOOST_CHECK_EQUAL(extents[17][0],1); + BOOST_CHECK_EQUAL(extents[17][1],1); + BOOST_CHECK_EQUAL(extents[17][2],2); + BOOST_CHECK_EQUAL(extents[17][3],3); + BOOST_CHECK_EQUAL(extents[17][4],1); + BOOST_CHECK_EQUAL(extents[17][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(),18); - - 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} - auto e13 = extents[13]; // {1,4,1} - auto e14 = extents[14]; // {1,1,1,1} - auto e15 = extents[15]; // {1,4,1,1,1} - auto e16 = extents[16]; // {1,1,2,1,1,1} - auto e17 = extents[17]; // {1,1,2,3,1,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_REQUIRE_EQUAL(e13.size(), 3); - BOOST_REQUIRE_EQUAL(e14.size(), 4); - BOOST_REQUIRE_EQUAL(e15.size(), 5); - BOOST_REQUIRE_EQUAL(e16.size(), 6); - BOOST_REQUIRE_EQUAL(e17.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_CHECK_EQUAL(e13[0],1); - BOOST_CHECK_EQUAL(e13[1],4); - BOOST_CHECK_EQUAL(e13[2],1); - - BOOST_CHECK_EQUAL(e14[0],1); - BOOST_CHECK_EQUAL(e14[1],1); - BOOST_CHECK_EQUAL(e14[2],1); - BOOST_CHECK_EQUAL(e14[3],1); - - BOOST_CHECK_EQUAL(e15[0],1); - BOOST_CHECK_EQUAL(e15[1],4); - BOOST_CHECK_EQUAL(e15[2],1); - BOOST_CHECK_EQUAL(e15[3],1); - BOOST_CHECK_EQUAL(e15[4],1); - - BOOST_CHECK_EQUAL(e16[0],1); - BOOST_CHECK_EQUAL(e16[1],1); - BOOST_CHECK_EQUAL(e16[2],2); - BOOST_CHECK_EQUAL(e16[3],1); - BOOST_CHECK_EQUAL(e16[4],1); - BOOST_CHECK_EQUAL(e16[5],1); - - BOOST_CHECK_EQUAL(e17[0],1); - BOOST_CHECK_EQUAL(e17[1],1); - BOOST_CHECK_EQUAL(e17[2],2); - BOOST_CHECK_EQUAL(e17[3],3); - BOOST_CHECK_EQUAL(e17[4],1); - BOOST_CHECK_EQUAL(e17[5],1); - -} - -BOOST_FIXTURE_TEST_CASE(test_static_rank_extents_copy_ctor, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("copy_ctor")) -{ - - auto e0 = de0; // {} - auto e1 = de1; // {1,1} - auto e2 = de2; // {1,2} - auto e3 = de3; // {2,1} - auto e4 = de4; // {2,3} - auto e5 = de5; // {2,3,1} - auto e6 = de6; // {1,2,3} - auto e7 = de7; // {1,1,2,3} - auto e8 = de8; // {1,2,3,1,1} - auto e9 = de9; // {4,2,3} - auto e10 = de10; // {4,2,1,3} - auto e11 = de11; // {4,2,1,3,1} - auto e12 = de12; // {1,4,2,1,3,1} - auto e13 = de13; // {1,4,1} - auto e14 = de14; // {1,1,1,1} - auto e15 = de15; // {1,4,1,1,1} - auto e16 = de16; // {1,1,2,1,1,1} - auto e17 = de17; // {1,1,2,3,1,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_REQUIRE_EQUAL(e13.size(), 3); - BOOST_REQUIRE_EQUAL(e14.size(), 4); - BOOST_REQUIRE_EQUAL(e15.size(), 5); - BOOST_REQUIRE_EQUAL(e16.size(), 6); - BOOST_REQUIRE_EQUAL(e17.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_CHECK_EQUAL(e13[0],1); - BOOST_CHECK_EQUAL(e13[1],4); - BOOST_CHECK_EQUAL(e13[2],1); - - BOOST_CHECK_EQUAL(e14[0],1); - BOOST_CHECK_EQUAL(e14[1],1); - BOOST_CHECK_EQUAL(e14[2],1); - BOOST_CHECK_EQUAL(e14[3],1); - - BOOST_CHECK_EQUAL(e15[0],1); - BOOST_CHECK_EQUAL(e15[1],4); - BOOST_CHECK_EQUAL(e15[2],1); - BOOST_CHECK_EQUAL(e15[3],1); - BOOST_CHECK_EQUAL(e15[4],1); - - BOOST_CHECK_EQUAL(e16[0],1); - BOOST_CHECK_EQUAL(e16[1],1); - BOOST_CHECK_EQUAL(e16[2],2); - BOOST_CHECK_EQUAL(e16[3],1); - BOOST_CHECK_EQUAL(e16[4],1); - BOOST_CHECK_EQUAL(e16[5],1); - - BOOST_CHECK_EQUAL(e17[0],1); - BOOST_CHECK_EQUAL(e17[1],1); - BOOST_CHECK_EQUAL(e17[2],2); - BOOST_CHECK_EQUAL(e17[3],3); - BOOST_CHECK_EQUAL(e17[4],1); - BOOST_CHECK_EQUAL(e17[5],1); + BOOST_REQUIRE_EQUAL(extents.size(),18); + + 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} + auto e13 = extents[13]; // {1,4,1} + auto e14 = extents[14]; // {1,1,1,1} + auto e15 = extents[15]; // {1,4,1,1,1} + auto e16 = extents[16]; // {1,1,2,1,1,1} + auto e17 = extents[17]; // {1,1,2,3,1,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_REQUIRE_EQUAL(e13.size(), 3); + BOOST_REQUIRE_EQUAL(e14.size(), 4); + BOOST_REQUIRE_EQUAL(e15.size(), 5); + BOOST_REQUIRE_EQUAL(e16.size(), 6); + BOOST_REQUIRE_EQUAL(e17.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_CHECK_EQUAL(e13[0],1); + BOOST_CHECK_EQUAL(e13[1],4); + BOOST_CHECK_EQUAL(e13[2],1); + + BOOST_CHECK_EQUAL(e14[0],1); + BOOST_CHECK_EQUAL(e14[1],1); + BOOST_CHECK_EQUAL(e14[2],1); + BOOST_CHECK_EQUAL(e14[3],1); + + BOOST_CHECK_EQUAL(e15[0],1); + BOOST_CHECK_EQUAL(e15[1],4); + BOOST_CHECK_EQUAL(e15[2],1); + BOOST_CHECK_EQUAL(e15[3],1); + BOOST_CHECK_EQUAL(e15[4],1); + + BOOST_CHECK_EQUAL(e16[0],1); + BOOST_CHECK_EQUAL(e16[1],1); + BOOST_CHECK_EQUAL(e16[2],2); + BOOST_CHECK_EQUAL(e16[3],1); + BOOST_CHECK_EQUAL(e16[4],1); + BOOST_CHECK_EQUAL(e16[5],1); + + BOOST_CHECK_EQUAL(e17[0],1); + BOOST_CHECK_EQUAL(e17[1],1); + BOOST_CHECK_EQUAL(e17[2],2); + BOOST_CHECK_EQUAL(e17[3],3); + BOOST_CHECK_EQUAL(e17[4],1); + BOOST_CHECK_EQUAL(e17[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(),18); - - 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} - auto e13 = extents[13]; // {1,4,1} - auto e14 = extents[14]; // {1,1,1,1} - auto e15 = extents[15]; // {1,4,1,1,1} - auto e16 = extents[16]; // {1,1,2,1,1,1} - auto e17 = extents[17]; // {1,1,2,3,1,1} - - BOOST_CHECK( e0.empty ( )); - BOOST_CHECK( ! is_scalar(e0)); - BOOST_CHECK( ! is_vector(e0)); - BOOST_CHECK( ! is_matrix(e0)); - BOOST_CHECK( ! is_tensor(e0)); - - BOOST_CHECK( ! e1.empty ( ) ); - BOOST_CHECK( is_scalar(e1) ); - BOOST_CHECK( ! is_vector(e1) ); - BOOST_CHECK( ! is_matrix(e1) ); - BOOST_CHECK( ! is_tensor(e1) ); - - BOOST_CHECK( ! e2.empty ( ) ); - BOOST_CHECK( ! is_scalar(e2) ); - BOOST_CHECK( is_vector(e2) ); - BOOST_CHECK( ! is_matrix(e2) ); - BOOST_CHECK( ! is_tensor(e2) ); - - BOOST_CHECK( ! e3.empty ( ) ); - BOOST_CHECK( ! is_scalar(e3) ); - BOOST_CHECK( is_vector(e3) ); - BOOST_CHECK( ! is_matrix(e3) ); - BOOST_CHECK( ! is_tensor(e3) ); - - BOOST_CHECK( ! e4.empty ( ) ); - BOOST_CHECK( ! is_scalar(e4) ); - BOOST_CHECK( ! is_vector(e4) ); - BOOST_CHECK( is_matrix(e4) ); - BOOST_CHECK( ! is_tensor(e4) ); - - BOOST_CHECK( ! e5.empty ( ) ); - BOOST_CHECK( ! is_scalar(e5) ); - BOOST_CHECK( ! is_vector(e5) ); - BOOST_CHECK( is_matrix(e5) ); - BOOST_CHECK( ! is_tensor(e5) ); - - BOOST_CHECK( ! e6.empty ( ) ); - BOOST_CHECK( ! is_scalar(e6) ); - BOOST_CHECK( ! is_vector(e6) ); - BOOST_CHECK( ! is_matrix(e6) ); - BOOST_CHECK( is_tensor(e6) ); - - BOOST_CHECK( ! e7.empty ( ) ); - BOOST_CHECK( ! is_scalar(e7) ); - BOOST_CHECK( ! is_vector(e7) ); - BOOST_CHECK( ! is_matrix(e7) ); - BOOST_CHECK( is_tensor(e7) ); - - BOOST_CHECK( ! e8.empty ( ) ); - BOOST_CHECK( ! is_scalar(e8) ); - BOOST_CHECK( ! is_vector(e8) ); - BOOST_CHECK( ! is_matrix(e8) ); - BOOST_CHECK( is_tensor(e8) ); - - BOOST_CHECK( ! e9.empty ( ) ); - BOOST_CHECK( ! is_scalar(e9) ); - BOOST_CHECK( ! is_vector(e9) ); - BOOST_CHECK( ! is_matrix(e9) ); - BOOST_CHECK( is_tensor(e9) ); - - BOOST_CHECK( ! e10.empty( ) ); - BOOST_CHECK( ! is_scalar(e10) ); - BOOST_CHECK( ! is_vector(e10) ); - BOOST_CHECK( ! is_matrix(e10) ); - BOOST_CHECK( is_tensor(e10) ); - - BOOST_CHECK( ! e11.empty( ) ); - BOOST_CHECK( ! is_scalar(e11) ); - BOOST_CHECK( ! is_vector(e11) ); - BOOST_CHECK( ! is_matrix(e11) ); - BOOST_CHECK( is_tensor(e11) ); - - BOOST_CHECK( ! e12.empty( ) ); - BOOST_CHECK( ! is_scalar(e12) ); - BOOST_CHECK( ! is_vector(e12) ); - BOOST_CHECK( ! is_matrix(e12) ); - BOOST_CHECK( is_tensor(e12) ); - - BOOST_CHECK( ! e13.empty( ) ); - BOOST_CHECK( ! is_scalar(e13) ); - BOOST_CHECK( is_vector(e13) ); - BOOST_CHECK( ! is_matrix(e13) ); - BOOST_CHECK( ! is_tensor(e13) ); - - BOOST_CHECK( ! e14.empty( ) ); - BOOST_CHECK( is_scalar(e14) ); - BOOST_CHECK( ! is_vector(e14) ); - BOOST_CHECK( ! is_matrix(e14) ); - BOOST_CHECK( ! is_tensor(e14) ); - - BOOST_CHECK( ! e15.empty( ) ); - BOOST_CHECK( ! is_scalar(e15) ); - BOOST_CHECK( is_vector(e15) ); - BOOST_CHECK( ! is_matrix(e15) ); - BOOST_CHECK( ! is_tensor(e15) ); - - BOOST_CHECK( ! e16.empty( ) ); - BOOST_CHECK( ! is_scalar(e16) ); - BOOST_CHECK( ! is_vector(e16) ); - BOOST_CHECK( ! is_matrix(e16) ); - BOOST_CHECK( is_tensor(e16) ); - - BOOST_CHECK( ! e17.empty( ) ); - BOOST_CHECK( ! is_scalar(e17) ); - BOOST_CHECK( ! is_vector(e17) ); - BOOST_CHECK( ! is_matrix(e17) ); - BOOST_CHECK( is_tensor(e17) ); + BOOST_REQUIRE_EQUAL(extents.size(),18); + + 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} + auto e13 = extents[13]; // {1,4,1} + auto e14 = extents[14]; // {1,1,1,1} + auto e15 = extents[15]; // {1,4,1,1,1} + auto e16 = extents[16]; // {1,1,2,1,1,1} + auto e17 = extents[17]; // {1,1,2,3,1,1} + + BOOST_CHECK( e0.empty ( )); + BOOST_CHECK( ! is_scalar(e0)); + BOOST_CHECK( ! is_vector(e0)); + BOOST_CHECK( ! is_matrix(e0)); + BOOST_CHECK( ! is_tensor(e0)); + + BOOST_CHECK( ! e1.empty ( ) ); + BOOST_CHECK( is_scalar(e1) ); + BOOST_CHECK( ! is_vector(e1) ); + BOOST_CHECK( ! is_matrix(e1) ); + BOOST_CHECK( ! is_tensor(e1) ); + + BOOST_CHECK( ! e2.empty ( ) ); + BOOST_CHECK( ! is_scalar(e2) ); + BOOST_CHECK( is_vector(e2) ); + BOOST_CHECK( ! is_matrix(e2) ); + BOOST_CHECK( ! is_tensor(e2) ); + + BOOST_CHECK( ! e3.empty ( ) ); + BOOST_CHECK( ! is_scalar(e3) ); + BOOST_CHECK( is_vector(e3) ); + BOOST_CHECK( ! is_matrix(e3) ); + BOOST_CHECK( ! is_tensor(e3) ); + + BOOST_CHECK( ! e4.empty ( ) ); + BOOST_CHECK( ! is_scalar(e4) ); + BOOST_CHECK( ! is_vector(e4) ); + BOOST_CHECK( is_matrix(e4) ); + BOOST_CHECK( ! is_tensor(e4) ); + + BOOST_CHECK( ! e5.empty ( ) ); + BOOST_CHECK( ! is_scalar(e5) ); + BOOST_CHECK( ! is_vector(e5) ); + BOOST_CHECK( is_matrix(e5) ); + BOOST_CHECK( ! is_tensor(e5) ); + + BOOST_CHECK( ! e6.empty ( ) ); + BOOST_CHECK( ! is_scalar(e6) ); + BOOST_CHECK( ! is_vector(e6) ); + BOOST_CHECK( ! is_matrix(e6) ); + BOOST_CHECK( is_tensor(e6) ); + + BOOST_CHECK( ! e7.empty ( ) ); + BOOST_CHECK( ! is_scalar(e7) ); + BOOST_CHECK( ! is_vector(e7) ); + BOOST_CHECK( ! is_matrix(e7) ); + BOOST_CHECK( is_tensor(e7) ); + + BOOST_CHECK( ! e8.empty ( ) ); + BOOST_CHECK( ! is_scalar(e8) ); + BOOST_CHECK( ! is_vector(e8) ); + BOOST_CHECK( ! is_matrix(e8) ); + BOOST_CHECK( is_tensor(e8) ); + + BOOST_CHECK( ! e9.empty ( ) ); + BOOST_CHECK( ! is_scalar(e9) ); + BOOST_CHECK( ! is_vector(e9) ); + BOOST_CHECK( ! is_matrix(e9) ); + BOOST_CHECK( is_tensor(e9) ); + + BOOST_CHECK( ! e10.empty( ) ); + BOOST_CHECK( ! is_scalar(e10) ); + BOOST_CHECK( ! is_vector(e10) ); + BOOST_CHECK( ! is_matrix(e10) ); + BOOST_CHECK( is_tensor(e10) ); + + BOOST_CHECK( ! e11.empty( ) ); + BOOST_CHECK( ! is_scalar(e11) ); + BOOST_CHECK( ! is_vector(e11) ); + BOOST_CHECK( ! is_matrix(e11) ); + BOOST_CHECK( is_tensor(e11) ); + + BOOST_CHECK( ! e12.empty( ) ); + BOOST_CHECK( ! is_scalar(e12) ); + BOOST_CHECK( ! is_vector(e12) ); + BOOST_CHECK( ! is_matrix(e12) ); + BOOST_CHECK( is_tensor(e12) ); + + BOOST_CHECK( ! e13.empty( ) ); + BOOST_CHECK( ! is_scalar(e13) ); + BOOST_CHECK( is_vector(e13) ); + BOOST_CHECK( ! is_matrix(e13) ); + BOOST_CHECK( ! is_tensor(e13) ); + + BOOST_CHECK( ! e14.empty( ) ); + BOOST_CHECK( is_scalar(e14) ); + BOOST_CHECK( ! is_vector(e14) ); + BOOST_CHECK( ! is_matrix(e14) ); + BOOST_CHECK( ! is_tensor(e14) ); + + BOOST_CHECK( ! e15.empty( ) ); + BOOST_CHECK( ! is_scalar(e15) ); + BOOST_CHECK( is_vector(e15) ); + BOOST_CHECK( ! is_matrix(e15) ); + BOOST_CHECK( ! is_tensor(e15) ); + + BOOST_CHECK( ! e16.empty( ) ); + BOOST_CHECK( ! is_scalar(e16) ); + BOOST_CHECK( ! is_vector(e16) ); + BOOST_CHECK( ! is_matrix(e16) ); + BOOST_CHECK( is_tensor(e16) ); + + BOOST_CHECK( ! e17.empty( ) ); + BOOST_CHECK( ! is_scalar(e17) ); + BOOST_CHECK( ! is_vector(e17) ); + BOOST_CHECK( ! is_matrix(e17) ); + BOOST_CHECK( is_tensor(e17) ); } -BOOST_FIXTURE_TEST_CASE(test_static_rank_extents_is, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("query")) -{ - - auto e0 = de0; // {} - auto e1 = de1; // {1,1} - auto e2 = de2; // {1,2} - auto e3 = de3; // {2,1} - auto e4 = de4; // {2,3} - auto e5 = de5; // {2,3,1} - auto e6 = de6; // {1,2,3} - auto e7 = de7; // {1,1,2,3} - auto e8 = de8; // {1,2,3,1,1} - auto e9 = de9; // {4,2,3} - auto e10 = de10; // {4,2,1,3} - auto e11 = de11; // {4,2,1,3,1} - auto e12 = de12; // {1,4,2,1,3,1} - auto e13 = de13; // {1,4,1} - auto e14 = de14; // {1,1,1,1} - auto e15 = de15; // {1,4,1,1,1} - auto e16 = de16; // {1,1,2,1,1,1} - auto e17 = de17; // {1,1,2,3,1,1} - - BOOST_CHECK( e0.empty ( )); - BOOST_CHECK( ! is_scalar(e0)); - BOOST_CHECK( ! is_vector(e0)); - BOOST_CHECK( ! is_matrix(e0)); - BOOST_CHECK( ! is_tensor(e0)); - - BOOST_CHECK( ! e1.empty ( ) ); - BOOST_CHECK( is_scalar(e1) ); - BOOST_CHECK( ! is_vector(e1) ); - BOOST_CHECK( ! is_matrix(e1) ); - BOOST_CHECK( ! is_tensor(e1) ); - - BOOST_CHECK( ! e2.empty ( ) ); - BOOST_CHECK( ! is_scalar(e2) ); - BOOST_CHECK( is_vector(e2) ); - BOOST_CHECK( ! is_matrix(e2) ); - BOOST_CHECK( ! is_tensor(e2) ); - - BOOST_CHECK( ! e3.empty ( ) ); - BOOST_CHECK( ! is_scalar(e3) ); - BOOST_CHECK( is_vector(e3) ); - BOOST_CHECK( ! is_matrix(e3) ); - BOOST_CHECK( ! is_tensor(e3) ); - - BOOST_CHECK( ! e4.empty ( ) ); - BOOST_CHECK( ! is_scalar(e4) ); - BOOST_CHECK( ! is_vector(e4) ); - BOOST_CHECK( is_matrix(e4) ); - BOOST_CHECK( ! is_tensor(e4) ); - - BOOST_CHECK( ! e5.empty ( ) ); - BOOST_CHECK( ! is_scalar(e5) ); - BOOST_CHECK( ! is_vector(e5) ); - BOOST_CHECK( is_matrix(e5) ); - BOOST_CHECK( ! is_tensor(e5) ); - - BOOST_CHECK( ! e6.empty ( ) ); - BOOST_CHECK( ! is_scalar(e6) ); - BOOST_CHECK( ! is_vector(e6) ); - BOOST_CHECK( ! is_matrix(e6) ); - BOOST_CHECK( is_tensor(e6) ); - - BOOST_CHECK( ! e7.empty ( ) ); - BOOST_CHECK( ! is_scalar(e7) ); - BOOST_CHECK( ! is_vector(e7) ); - BOOST_CHECK( ! is_matrix(e7) ); - BOOST_CHECK( is_tensor(e7) ); - - BOOST_CHECK( ! e8.empty ( ) ); - BOOST_CHECK( ! is_scalar(e8) ); - BOOST_CHECK( ! is_vector(e8) ); - BOOST_CHECK( ! is_matrix(e8) ); - BOOST_CHECK( is_tensor(e8) ); - - BOOST_CHECK( ! e9.empty ( ) ); - BOOST_CHECK( ! is_scalar(e9) ); - BOOST_CHECK( ! is_vector(e9) ); - BOOST_CHECK( ! is_matrix(e9) ); - BOOST_CHECK( is_tensor(e9) ); - - BOOST_CHECK( ! e10.empty( ) ); - BOOST_CHECK( ! is_scalar(e10) ); - BOOST_CHECK( ! is_vector(e10) ); - BOOST_CHECK( ! is_matrix(e10) ); - BOOST_CHECK( is_tensor(e10) ); - - BOOST_CHECK( ! e11.empty( ) ); - BOOST_CHECK( ! is_scalar(e11) ); - BOOST_CHECK( ! is_vector(e11) ); - BOOST_CHECK( ! is_matrix(e11) ); - BOOST_CHECK( is_tensor(e11) ); - - BOOST_CHECK( ! e12.empty( ) ); - BOOST_CHECK( ! is_scalar(e12) ); - BOOST_CHECK( ! is_vector(e12) ); - BOOST_CHECK( ! is_matrix(e12) ); - BOOST_CHECK( is_tensor(e12) ); - - BOOST_CHECK( ! e13.empty( ) ); - BOOST_CHECK( ! is_scalar(e13) ); - BOOST_CHECK( is_vector(e13) ); - BOOST_CHECK( ! is_matrix(e13) ); - BOOST_CHECK( ! is_tensor(e13) ); - - BOOST_CHECK( ! e14.empty( ) ); - BOOST_CHECK( is_scalar(e14) ); - BOOST_CHECK( ! is_vector(e14) ); - BOOST_CHECK( ! is_matrix(e14) ); - BOOST_CHECK( ! is_tensor(e14) ); - - BOOST_CHECK( ! e15.empty( ) ); - BOOST_CHECK( ! is_scalar(e15) ); - BOOST_CHECK( is_vector(e15) ); - BOOST_CHECK( ! is_matrix(e15) ); - BOOST_CHECK( ! is_tensor(e15) ); - - BOOST_CHECK( ! e16.empty( ) ); - BOOST_CHECK( ! is_scalar(e16) ); - BOOST_CHECK( ! is_vector(e16) ); - BOOST_CHECK( ! is_matrix(e16) ); - BOOST_CHECK( is_tensor(e16) ); - - BOOST_CHECK( ! e17.empty( ) ); - BOOST_CHECK( ! is_scalar(e17) ); - BOOST_CHECK( ! is_vector(e17) ); - BOOST_CHECK( ! is_matrix(e17) ); - BOOST_CHECK( is_tensor(e17) ); -} - - BOOST_FIXTURE_TEST_CASE(test_extents_squeeze, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("squeeze")) { - BOOST_REQUIRE_EQUAL(extents.size(),18); - - auto e0 = squeeze(extents[ 0]); // {} - auto e1 = squeeze(extents[ 1]); // {1,1} - auto e2 = squeeze(extents[ 2]); // {1,2} - auto e3 = squeeze(extents[ 3]); // {2,1} - - auto e4 = squeeze(extents[ 4]); // {2,3} - auto e5 = squeeze(extents[ 5]); // {2,3} - auto e6 = squeeze(extents[ 6]); // {2,3} - auto e7 = squeeze(extents[ 7]); // {2,3} - auto e8 = squeeze(extents[ 8]); // {2,3} - - auto e9 = squeeze(extents[ 9]); // {4,2,3} - auto e10 = squeeze(extents[10]); // {4,2,3} - auto e11 = squeeze(extents[11]); // {4,2,3} - auto e12 = squeeze(extents[12]); // {4,2,3} - - auto e13 = squeeze(extents[13]); // {1,4} - auto e14 = squeeze(extents[14]); // {1,1} - auto e15 = squeeze(extents[15]); // {1,4} - auto e16 = squeeze(extents[16]); // {2,1} - auto e17 = squeeze(extents[17]); // {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_CHECK( (e13 == extents_type{1,4}) ); - BOOST_CHECK( (e14 == extents_type{1,1}) ); - BOOST_CHECK( (e15 == extents_type{1,4}) ); - BOOST_CHECK( (e16 == extents_type{2,1}) ); - BOOST_CHECK( (e17 == extents_type{2,3}) ); - -} - -BOOST_FIXTURE_TEST_CASE(test_static_rank_extents_squeeze, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("squeeze")) -{ - BOOST_REQUIRE_EQUAL(extents.size(),18); - - auto e0 = squeeze(de0); // {} - auto e1 = squeeze(de1); // {1,1} - auto e2 = squeeze(de2); // {1,2} - auto e3 = squeeze(de3); // {2,1} - - auto e4 = squeeze(de4); // {2,3} - auto e5 = squeeze(de5); // {2,3} - auto e6 = squeeze(de6); // {2,3} - auto e7 = squeeze(de7); // {2,3} - auto e8 = squeeze(de8); // {2,3} - - auto e9 = squeeze(de9); // {4,2,3} - auto e10 = squeeze(de10); // {4,2,3} - auto e11 = squeeze(de11); // {4,2,3} - auto e12 = squeeze(de12); // {4,2,3} - - auto e13 = squeeze(de13); // {1,4} - auto e14 = squeeze(de14); // {1,1} - auto e15 = squeeze(de15); // {1,4} - auto e16 = squeeze(de16); // {2,1} - auto e17 = squeeze(de17); // {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_CHECK( (e13 == extents_type{1,4}) ); - BOOST_CHECK( (e14 == extents_type{1,1}) ); - BOOST_CHECK( (e15 == extents_type{1,4}) ); - BOOST_CHECK( (e16 == extents_type{2,1}) ); - BOOST_CHECK( (e17 == extents_type{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(),18); - - for(auto const& e : extents){ - if(e.empty()) - BOOST_CHECK_EQUAL(valid(e),false); - else - BOOST_CHECK_EQUAL(valid(e), true ); - } - - BOOST_CHECK_EQUAL( valid(extents_type{}) , false ); - - BOOST_CHECK_THROW( ublas::basic_extents({0,1}), std::length_error ); - BOOST_CHECK_THROW( ublas::basic_extents({1,0,1}), std::length_error ); - - BOOST_CHECK(!valid(de0)); - BOOST_CHECK(valid(de1)); - BOOST_CHECK(valid(de2)); - BOOST_CHECK(valid(de3)); - BOOST_CHECK(valid(de4)); - BOOST_CHECK(valid(de5)); - BOOST_CHECK(valid(de6)); - BOOST_CHECK(valid(de7)); - BOOST_CHECK(valid(de8)); - BOOST_CHECK(valid(de9)); - BOOST_CHECK(valid(de10)); - BOOST_CHECK(valid(de11)); - BOOST_CHECK(valid(de12)); - BOOST_CHECK(valid(de13)); - BOOST_CHECK(valid(de14)); - BOOST_CHECK(valid(de15)); - BOOST_CHECK(valid(de16)); - BOOST_CHECK(valid(de17)); + BOOST_REQUIRE_EQUAL(extents.size(),18); + + auto e0 = squeeze(extents[ 0]); // {} + auto e1 = squeeze(extents[ 1]); // {1,1} + auto e2 = squeeze(extents[ 2]); // {1,2} + auto e3 = squeeze(extents[ 3]); // {2,1} + + auto e4 = squeeze(extents[ 4]); // {2,3} + auto e5 = squeeze(extents[ 5]); // {2,3} + auto e6 = squeeze(extents[ 6]); // {2,3} + auto e7 = squeeze(extents[ 7]); // {2,3} + auto e8 = squeeze(extents[ 8]); // {2,3} + + auto e9 = squeeze(extents[ 9]); // {4,2,3} + auto e10 = squeeze(extents[10]); // {4,2,3} + auto e11 = squeeze(extents[11]); // {4,2,3} + auto e12 = squeeze(extents[12]); // {4,2,3} + + auto e13 = squeeze(extents[13]); // {1,4} + auto e14 = squeeze(extents[14]); // {1,1} + auto e15 = squeeze(extents[15]); // {1,4} + auto e16 = squeeze(extents[16]); // {2,1} + auto e17 = squeeze(extents[17]); // {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_CHECK( (e13 == extents_type{1,4}) ); + BOOST_CHECK( (e14 == extents_type{1,1}) ); + BOOST_CHECK( (e15 == extents_type{1,4}) ); + BOOST_CHECK( (e16 == extents_type{2,1}) ); + BOOST_CHECK( (e17 == extents_type{2,3}) ); } BOOST_FIXTURE_TEST_CASE(test_extents_comparison, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("compare")) { - using namespace boost::numeric; - - auto s0 = ublas::static_extents<>{}; - auto s1 = ublas::static_extents<1,1>{}; - auto s2 = ublas::static_extents<1,4,2,1,3,1>{}; - auto s3 = ublas::static_extents<1,4,2,1,1,1>{}; - - auto d0 = ublas::dynamic_extents<0>{}; - auto d1 = ublas::dynamic_extents<2>{1,1}; - auto d2 = ublas::dynamic_extents<6>{1,4,2,1,3,1}; - auto d3 = ublas::dynamic_extents<6>{1,4,2,1,1,1}; - - auto e0 = extents[ 0]; // {} - auto e1 = extents[ 1]; // {1,1} - auto e2 = extents[12]; // {1,4,2,1,3,1} - - // static_extents<...> == dynamic_extents<> - BOOST_TEST( s0 == e0 ); - BOOST_TEST( s1 == e1 ); - BOOST_TEST( s2 == e2 ); - - BOOST_TEST( e0 == s0 ); - BOOST_TEST( e1 == s1 ); - BOOST_TEST( e2 == s2 ); - - BOOST_TEST( s0 != e1 ); - BOOST_TEST( s0 != e2 ); - BOOST_TEST( s1 != e0 ); - BOOST_TEST( s1 != e2 ); - BOOST_TEST( s2 != e0 ); - BOOST_TEST( s2 != e1 ); - BOOST_TEST( s3 != e0 ); - BOOST_TEST( s3 != e1 ); - BOOST_TEST( s3 != e2 ); - - BOOST_TEST( e1 != s0 ); - BOOST_TEST( e2 != s0 ); - BOOST_TEST( e0 != s1 ); - BOOST_TEST( e2 != s1 ); - BOOST_TEST( e0 != s2 ); - BOOST_TEST( e1 != s2 ); - BOOST_TEST( e0 != s3 ); - BOOST_TEST( e1 != s3 ); - BOOST_TEST( e2 != s3 ); - - // dynamic_extents == dynamic_extents<> - BOOST_TEST( d0 == e0 ); - BOOST_TEST( d1 == e1 ); - BOOST_TEST( d2 == e2 ); - - BOOST_TEST( e0 == d0 ); - BOOST_TEST( e1 == d1 ); - BOOST_TEST( e2 == d2 ); - - BOOST_TEST( d0 != e1 ); - BOOST_TEST( d0 != e2 ); - BOOST_TEST( d1 != e0 ); - BOOST_TEST( d1 != e2 ); - BOOST_TEST( d2 != e0 ); - BOOST_TEST( d2 != e1 ); - BOOST_TEST( d3 != e0 ); - BOOST_TEST( d3 != e1 ); - BOOST_TEST( d3 != e2 ); - - BOOST_TEST( e1 != d0 ); - BOOST_TEST( e2 != d0 ); - BOOST_TEST( e0 != d1 ); - BOOST_TEST( e2 != d1 ); - BOOST_TEST( e0 != d2 ); - BOOST_TEST( e1 != d2 ); - BOOST_TEST( e0 != d3 ); - BOOST_TEST( e1 != d3 ); - BOOST_TEST( e2 != d3 ); - - // static_extents<...> == dynamic_extents - - BOOST_TEST( s0 == d0 ); - BOOST_TEST( s1 == d1 ); - BOOST_TEST( s2 == d2 ); - BOOST_TEST( s3 == d3 ); - - BOOST_TEST( d0 == s0 ); - BOOST_TEST( d1 == s1 ); - BOOST_TEST( d2 == s2 ); - BOOST_TEST( d3 == s3 ); - - BOOST_TEST( s0 != d1 ); - BOOST_TEST( s0 != d2 ); - BOOST_TEST( s0 != d3 ); - BOOST_TEST( s1 != d0 ); - BOOST_TEST( s1 != d2 ); - BOOST_TEST( s1 != d3 ); - BOOST_TEST( s2 != d0 ); - BOOST_TEST( s2 != d1 ); - BOOST_TEST( s2 != d3 ); - BOOST_TEST( s3 != d0 ); - BOOST_TEST( s3 != d1 ); - BOOST_TEST( s3 != d2 ); - - BOOST_TEST( d1 != s0 ); - BOOST_TEST( d2 != s0 ); - BOOST_TEST( d3 != s0 ); - BOOST_TEST( d0 != s1 ); - BOOST_TEST( d2 != s1 ); - BOOST_TEST( d3 != s1 ); - BOOST_TEST( d0 != s2 ); - BOOST_TEST( d1 != s2 ); - BOOST_TEST( d3 != s2 ); - BOOST_TEST( d0 != s3 ); - BOOST_TEST( d1 != s3 ); - BOOST_TEST( d2 != s3 ); + using namespace boost::numeric; + + auto s0 = ublas::static_extents<>{}; + auto s1 = ublas::static_extents<1,1>{}; + auto s2 = ublas::static_extents<1,4,2,1,3,1>{}; + auto s3 = ublas::static_extents<1,4,2,1,1,1>{}; + + auto d0 = ublas::dynamic_extents<0>{}; + auto d1 = ublas::dynamic_extents<2>{1,1}; + auto d2 = ublas::dynamic_extents<6>{1,4,2,1,3,1}; + auto d3 = ublas::dynamic_extents<6>{1,4,2,1,1,1}; + + auto e0 = extents[ 0]; // {} + auto e1 = extents[ 1]; // {1,1} + auto e2 = extents[12]; // {1,4,2,1,3,1} + + // static_extents<...> == dynamic_extents<> + BOOST_TEST( s0 == e0 ); + BOOST_TEST( s1 == e1 ); + BOOST_TEST( s2 == e2 ); + + BOOST_TEST( e0 == s0 ); + BOOST_TEST( e1 == s1 ); + BOOST_TEST( e2 == s2 ); + + BOOST_TEST( s0 != e1 ); + BOOST_TEST( s0 != e2 ); + BOOST_TEST( s1 != e0 ); + BOOST_TEST( s1 != e2 ); + BOOST_TEST( s2 != e0 ); + BOOST_TEST( s2 != e1 ); + BOOST_TEST( s3 != e0 ); + BOOST_TEST( s3 != e1 ); + BOOST_TEST( s3 != e2 ); + + BOOST_TEST( e1 != s0 ); + BOOST_TEST( e2 != s0 ); + BOOST_TEST( e0 != s1 ); + BOOST_TEST( e2 != s1 ); + BOOST_TEST( e0 != s2 ); + BOOST_TEST( e1 != s2 ); + BOOST_TEST( e0 != s3 ); + BOOST_TEST( e1 != s3 ); + BOOST_TEST( e2 != s3 ); + + // dynamic_extents == dynamic_extents<> + BOOST_TEST( d0 == e0 ); + BOOST_TEST( d1 == e1 ); + BOOST_TEST( d2 == e2 ); + + BOOST_TEST( e0 == d0 ); + BOOST_TEST( e1 == d1 ); + BOOST_TEST( e2 == d2 ); + + BOOST_TEST( d0 != e1 ); + BOOST_TEST( d0 != e2 ); + BOOST_TEST( d1 != e0 ); + BOOST_TEST( d1 != e2 ); + BOOST_TEST( d2 != e0 ); + BOOST_TEST( d2 != e1 ); + BOOST_TEST( d3 != e0 ); + BOOST_TEST( d3 != e1 ); + BOOST_TEST( d3 != e2 ); + + BOOST_TEST( e1 != d0 ); + BOOST_TEST( e2 != d0 ); + BOOST_TEST( e0 != d1 ); + BOOST_TEST( e2 != d1 ); + BOOST_TEST( e0 != d2 ); + BOOST_TEST( e1 != d2 ); + BOOST_TEST( e0 != d3 ); + BOOST_TEST( e1 != d3 ); + BOOST_TEST( e2 != d3 ); + + // static_extents<...> == dynamic_extents + + BOOST_TEST( s0 == d0 ); + BOOST_TEST( s1 == d1 ); + BOOST_TEST( s2 == d2 ); + BOOST_TEST( s3 == d3 ); + + BOOST_TEST( d0 == s0 ); + BOOST_TEST( d1 == s1 ); + BOOST_TEST( d2 == s2 ); + BOOST_TEST( d3 == s3 ); + + BOOST_TEST( s0 != d1 ); + BOOST_TEST( s0 != d2 ); + BOOST_TEST( s0 != d3 ); + BOOST_TEST( s1 != d0 ); + BOOST_TEST( s1 != d2 ); + BOOST_TEST( s1 != d3 ); + BOOST_TEST( s2 != d0 ); + BOOST_TEST( s2 != d1 ); + BOOST_TEST( s2 != d3 ); + BOOST_TEST( s3 != d0 ); + BOOST_TEST( s3 != d1 ); + BOOST_TEST( s3 != d2 ); + + BOOST_TEST( d1 != s0 ); + BOOST_TEST( d2 != s0 ); + BOOST_TEST( d3 != s0 ); + BOOST_TEST( d0 != s1 ); + BOOST_TEST( d2 != s1 ); + BOOST_TEST( d3 != s1 ); + BOOST_TEST( d0 != s2 ); + BOOST_TEST( d1 != s2 ); + BOOST_TEST( d3 != s2 ); + BOOST_TEST( d0 != s3 ); + BOOST_TEST( d1 != s3 ); + BOOST_TEST( d2 != s3 ); } @@ -1168,88 +687,43 @@ BOOST_FIXTURE_TEST_CASE(test_extents_comparison, fixture, *boost::unit_test::lab BOOST_FIXTURE_TEST_CASE(test_extents_product, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("product")) { - auto e0 = product(extents[ 0]); // {} - auto e1 = product(extents[ 1]); // {1,1} - auto e2 = product(extents[ 2]); // {1,2} - auto e3 = product(extents[ 3]); // {2,1} - auto e4 = product(extents[ 4]); // {2,3} - auto e5 = product(extents[ 5]); // {2,3,1} - auto e6 = product(extents[ 6]); // {1,2,3} - auto e7 = product(extents[ 7]); // {1,1,2,3} - auto e8 = product(extents[ 8]); // {1,2,3,1,1} - auto e9 = product(extents[ 9]); // {4,2,3} - auto e10 = product(extents[10]); // {4,2,1,3} - auto e11 = product(extents[11]); // {4,2,1,3,1} - auto e12 = product(extents[12]); // {1,4,2,1,3,1} - auto e13 = product(extents[13]); // {1,4,1} - auto e14 = product(extents[14]); // {1,1,1,1} - auto e15 = product(extents[15]); // {1,4,1,1,1} - auto e16 = product(extents[16]); // {1,1,2,1,1,1} - auto e17 = product(extents[17]); // {1,1,2,3,1,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_CHECK_EQUAL( e13, 4 ); - BOOST_CHECK_EQUAL( e14, 1 ); - BOOST_CHECK_EQUAL( e15, 4 ); - BOOST_CHECK_EQUAL( e16, 2 ); - BOOST_CHECK_EQUAL( e17, 6 ); - - -} - - -BOOST_FIXTURE_TEST_CASE(test_static_rank_extents_product, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("product")) -{ - - auto e0 = product( de0 ); // {} - auto e1 = product( de1 ); // {1,1} - auto e2 = product( de2 ); // {1,2} - auto e3 = product( de3 ); // {2,1} - auto e4 = product( de4 ); // {2,3} - auto e5 = product( de5 ); // {2,3,1} - auto e6 = product( de6 ); // {1,2,3} - auto e7 = product( de7 ); // {1,1,2,3} - auto e8 = product( de8 ); // {1,2,3,1,1} - auto e9 = product( de9 ); // {4,2,3} - auto e10 = product( de10 ); // {4,2,1,3} - auto e11 = product( de11 ); // {4,2,1,3,1} - auto e12 = product( de12 ); // {1,4,2,1,3,1} - auto e13 = product( de13 ); // {1,4,1} - auto e14 = product( de14 ); // {1,1,1,1} - auto e15 = product( de15 ); // {1,4,1,1,1} - auto e16 = product( de16 ); // {1,1,2,1,1,1} - auto e17 = product( de17 ); // {1,1,2,3,1,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_CHECK_EQUAL( e13, 4 ); - BOOST_CHECK_EQUAL( e14, 1 ); - BOOST_CHECK_EQUAL( e15, 4 ); - BOOST_CHECK_EQUAL( e16, 2 ); - BOOST_CHECK_EQUAL( e17, 6 ); + auto e0 = product(extents[ 0]); // {} + auto e1 = product(extents[ 1]); // {1,1} + auto e2 = product(extents[ 2]); // {1,2} + auto e3 = product(extents[ 3]); // {2,1} + auto e4 = product(extents[ 4]); // {2,3} + auto e5 = product(extents[ 5]); // {2,3,1} + auto e6 = product(extents[ 6]); // {1,2,3} + auto e7 = product(extents[ 7]); // {1,1,2,3} + auto e8 = product(extents[ 8]); // {1,2,3,1,1} + auto e9 = product(extents[ 9]); // {4,2,3} + auto e10 = product(extents[10]); // {4,2,1,3} + auto e11 = product(extents[11]); // {4,2,1,3,1} + auto e12 = product(extents[12]); // {1,4,2,1,3,1} + auto e13 = product(extents[13]); // {1,4,1} + auto e14 = product(extents[14]); // {1,1,1,1} + auto e15 = product(extents[15]); // {1,4,1,1,1} + auto e16 = product(extents[16]); // {1,1,2,1,1,1} + auto e17 = product(extents[17]); // {1,1,2,3,1,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_CHECK_EQUAL( e13, 4 ); + BOOST_CHECK_EQUAL( e14, 1 ); + BOOST_CHECK_EQUAL( e15, 4 ); + BOOST_CHECK_EQUAL( e16, 2 ); + BOOST_CHECK_EQUAL( e17, 6 ); } diff --git a/test/tensor/test_fixed_rank_expression_evaluation.cpp b/test/tensor/test_fixed_rank_expression_evaluation.cpp index 7c50b087c..37498d2e9 100644 --- a/test/tensor/test_fixed_rank_expression_evaluation.cpp +++ b/test/tensor/test_fixed_rank_expression_evaluation.cpp @@ -12,9 +12,7 @@ -#include -#include -#include +#include #include "utility.hpp" #include @@ -27,135 +25,138 @@ using test_types = zip>::with_t - using extents_type = boost::numeric::ublas::dynamic_extents; - - std::tuple< - extents_type<0>, // 0 - extents_type<2>, // 1 - extents_type<2>, // 2 - extents_type<2>, // 3 - extents_type<2>, // 4 - extents_type<3>, // 5 - extents_type<3>, // 6 - extents_type<3>, // 7 - extents_type<3>, // 8 - extents_type<4> // 9 - > extents = { - extents_type<0>{}, - extents_type<2>{1,1}, - extents_type<2>{1,2}, - extents_type<2>{2,1}, - extents_type<2>{2,3}, - extents_type<3>{2,3,1}, - extents_type<3>{4,1,3}, - extents_type<3>{1,2,3}, - extents_type<3>{4,2,3}, - extents_type<4>{4,2,3,5} - }; + template + using extents_type = boost::numeric::ublas::dynamic_extents; + + std::tuple< + extents_type<0>, // 0 + extents_type<2>, // 1 + extents_type<2>, // 2 + extents_type<2>, // 3 + extents_type<2>, // 4 + extents_type<3>, // 5 + extents_type<3>, // 6 + extents_type<3>, // 7 + extents_type<3>, // 8 + extents_type<4> // 9 + > extents = { + extents_type<0>{}, + extents_type<2>{1,1}, + extents_type<2>{1,2}, + extents_type<2>{2,1}, + extents_type<2>{2,3}, + extents_type<3>{2,3,1}, + extents_type<3>{4,1,3}, + extents_type<3>{1,2,3}, + extents_type<3>{4,2,3}, + extents_type<4>{4,2,3,5} + }; }; BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; - for_each_tuple(extents, [&](auto const&, auto & e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; + for_each_tuple(extents, [&](auto const&, auto & e){ + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + using basic_tensor_type = typename tensor_type::super_type; - auto t = tensor_type(e); - auto v = value_type{}; - for(auto& tt: t){ tt = v; v+=value_type{1}; } + 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 ); + BOOST_CHECK( ublas::detail::retrieve_extents( t ) == e ); - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - BOOST_CHECK( ublas::detail::retrieve_extents( uexpr1 ) == e ); - BOOST_CHECK( ublas::detail::retrieve_extents( uexpr2 ) == e ); + 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( uexpr1, uexpr2, bplus ); + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_uexpr ) == e ); + 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( bexpr_uexpr, t, bminus ); + // bexpr_bexpr_uexpr = ((t+1) + (2+t)) - t + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); - }); + }); - for_each_tuple(extents, [&](auto const& I, auto& e1){ + for_each_tuple(extents, [&](auto const& I, auto& e1){ - if ( I >= std::tuple_size_v - 1 ){ - return; - } - - using extents_type1 = std::decay_t; - using tensor_type1 = ublas::tensor; + if ( I >= std::tuple_size_v - 1 ){ + return; + } + + using extents_type1 = std::decay_t; + using tensor_type1 = ublas::fixed_rank_tensor; + using basic_tensor_type1 = typename tensor_type1::super_type; - for_each_tuple(extents, [&](auto const& J, auto& e2){ - if( J != I + 1 ){ - return; - } + for_each_tuple(extents, [&](auto const& J, auto& e2){ + if( J != I + 1 ){ + return; + } - using extents_type2 = std::decay_t; - using tensor_type2 = ublas::tensor; + using extents_type2 = std::decay_t; + using tensor_type2 = ublas::fixed_rank_tensor; + using basic_tensor_type2 = typename tensor_type2::super_type; - auto v = value_type{}; + auto v = value_type{}; - tensor_type1 t1(e1); - for(auto& tt: t1){ tt = v; v+=value_type{1}; } + tensor_type1 t1(e1); + for(auto& tt: t1){ tt = v; v+=value_type{1}; } - tensor_type2 t2(e2); - for(auto& tt: t2){ tt = v; v+=value_type{2}; } + tensor_type2 t2(e2); + for(auto& tt: t2){ tt = v; v+=value_type{2}; } - BOOST_CHECK( ublas::detail::retrieve_extents( t1 ) != ublas::detail::retrieve_extents( t2 ) ); + 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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + // uexpr1 = t1+1 + // uexpr2 = 2+t2 + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 ) ); + 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 ) ); - if constexpr( extents_type1::_size == extents_type2::_size ){ - // bexpr_uexpr = (t1+1) + (2+t2) - auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + if constexpr( extents_type1::_size == extents_type2::_size ){ + // bexpr_uexpr = (t1+1) + (2+t2) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_uexpr ) == ublas::detail::retrieve_extents(t1) ); + 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( bexpr_uexpr, t2, bminus ); + // bexpr_bexpr_uexpr = ((t1+1) + (2+t2)) - t2 + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t2, bminus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr1 ) == ublas::detail::retrieve_extents(t2) ); + 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( t2, bexpr_uexpr, bminus ); + // bexpr_bexpr_uexpr = t2 - ((t1+1) + (2+t2)) + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( t2, bexpr_uexpr, bminus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); - } + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); + } - }); - }); + }); + }); } @@ -166,118 +167,121 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_retrieve_ext BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; - for_each_tuple(extents, [&](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; + for_each_tuple(extents, [&](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + using basic_tensor_type = typename tensor_type::super_type; - auto t = tensor_type(e); - auto v = value_type{}; - for(auto& tt: t){ tt = v; v+=value_type{1}; } + 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 ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - BOOST_CHECK( ublas::detail::all_extents_equal( uexpr1, e ) ); - BOOST_CHECK( ublas::detail::all_extents_equal( uexpr2, e ) ); + 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( uexpr1, uexpr2, bplus ); + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_uexpr, e ) ); + 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( bexpr_uexpr, t, bminus ); + // bexpr_bexpr_uexpr = ((t+1) + (2+t)) - t + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); - BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); - }); + }); - for_each_tuple(extents, [&](auto const& I, auto& e1){ + for_each_tuple(extents, [&](auto const& I, auto& e1){ - if ( I >= std::tuple_size_v - 1){ - return; - } - - using extents_type1 = std::decay_t; - using tensor_type1 = ublas::tensor; + if ( I >= std::tuple_size_v - 1){ + return; + } + + using extents_type1 = std::decay_t; + using tensor_type1 = ublas::fixed_rank_tensor; + using basic_tensor_type1 = typename tensor_type1::super_type; - for_each_tuple(extents, [&](auto const& J, auto& e2){ - if( J != I + 1 ){ - return; - } + for_each_tuple(extents, [&](auto const& J, auto& e2){ + if( J != I + 1 ){ + return; + } - using extents_type2 = std::decay_t; - using tensor_type2 = ublas::tensor; + using extents_type2 = std::decay_t; + using tensor_type2 = ublas::fixed_rank_tensor; + using basic_tensor_type2 = typename tensor_type2::super_type; - auto v = value_type{}; + auto v = value_type{}; - tensor_type1 t1(e1); - for(auto& tt: t1){ tt = v; v+=value_type{1}; } + tensor_type1 t1(e1); + for(auto& tt: t1){ tt = v; v+=value_type{1}; } - tensor_type2 t2(e2); - for(auto& tt: t2){ tt = v; v+=value_type{2}; } + tensor_type2 t2(e2); + 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) ) ); + 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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + // uexpr1 = t1+1 + // uexpr2 = 2+t2 + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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) ) ); + 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) ) ); - if constexpr( extents_type1::_size == extents_type2::_size ){ - // bexpr_uexpr = (t1+1) + (2+t2) - auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + if constexpr( extents_type1::_size == extents_type2::_size ){ + // bexpr_uexpr = (t1+1) + (2+t2) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_uexpr, ublas::detail::retrieve_extents( bexpr_uexpr ) ) ); + 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( bexpr_uexpr, t2, bminus ); + // bexpr_bexpr_uexpr = ((t1+1) + (2+t2)) - t2 + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t2, bminus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr1, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr1 ) ) ); + 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( t2, bexpr_uexpr, bminus ); + // bexpr_bexpr_uexpr = t2 - ((t1+1) + (2+t2)) + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( t2, bexpr_uexpr, bminus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr2, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) ) ); + 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( uexpr1, t2, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_uexpr2, ublas::detail::retrieve_extents( bexpr_uexpr2 ) ) ); + // bexpr_uexpr2 = (t1+1) + t2 + auto bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr2, t1, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr3, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr3 ) ) ); + // bexpr_uexpr2 = ((t1+1) + t2) + t1 + auto bexpr_bexpr_uexpr3 = ublas::detail::make_binary_tensor_expression( 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( t1, bexpr_bexpr_uexpr3, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); - } + // bexpr_uexpr2 = t1 + (((t1+1) + t2) + t1) + auto bexpr_bexpr_uexpr4 = ublas::detail::make_binary_tensor_expression( t1, bexpr_bexpr_uexpr3, bplus ); + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); + } - }); - }); + }); + }); } diff --git a/test/tensor/test_fixed_rank_extents.cpp b/test/tensor/test_fixed_rank_extents.cpp new file mode 100644 index 000000000..2f026966f --- /dev/null +++ b/test/tensor/test_fixed_rank_extents.cpp @@ -0,0 +1,556 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include // Needed for squeeze +#include +#include + +BOOST_AUTO_TEST_SUITE ( test_fixed_rank_extents ) + + +//*boost::unit_test::label("extents") +//*boost::unit_test::label("constructor") + +BOOST_AUTO_TEST_CASE(test_fixed_rank_extents_ctor) +{ + namespace ub = boost::numeric::ublas; + + + auto e0 = ub::dynamic_extents<0>{}; + BOOST_CHECK( e0.empty()); + BOOST_CHECK ( e0.size() == 0); + + auto e1 = ub::dynamic_extents<2>{1,1}; + BOOST_CHECK(!e1.empty()); + BOOST_CHECK ( e1.size() == 2); + + auto e2 = ub::dynamic_extents<2>{1,2}; + BOOST_CHECK(!e2.empty()); + BOOST_CHECK ( e2.size() == 2); + + auto e3 = ub::dynamic_extents<2>{2,1}; + BOOST_CHECK (!e3.empty()); + BOOST_CHECK ( e3.size() == 2); + + auto e4 = ub::dynamic_extents<2>{2,3}; + BOOST_CHECK(!e4.empty()); + BOOST_CHECK ( e4.size() == 2); + + auto e5 = ub::dynamic_extents<3>{2,3,1}; + BOOST_CHECK (!e5.empty()); + BOOST_CHECK ( e5.size() == 3); + + auto e6 = ub::dynamic_extents<3>{1,2,3}; // 6 + BOOST_CHECK(!e6.empty()); + BOOST_CHECK ( e6.size() == 3); + + auto e7 = ub::dynamic_extents<3>{4,2,3}; // 7 + BOOST_CHECK(!e7.empty()); + BOOST_CHECK ( e7.size() == 3); + + BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,0}), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<1>({0} ), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<1>({3} ), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<2>({0,1}), std::length_error); + BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,1,2}), std::out_of_range); +} + + +struct fixture { + template + using dynamic_extents = boost::numeric::ublas::dynamic_extents; + + dynamic_extents<0> de0{}; // 0 + + dynamic_extents<2> de1{1,1}; // 1 + dynamic_extents<2> de2{1,2}; // 2 + dynamic_extents<2> de3{2,1}; // 3 + + dynamic_extents<2> de4{2,3}; // 4 + dynamic_extents<3> de5{2,3,1}; // 5 + dynamic_extents<3> de6{1,2,3}; // 6 + dynamic_extents<4> de7{1,1,2,3}; // 7 + dynamic_extents<5> de8{1,2,3,1,1}; // 8 + + dynamic_extents<3> de9{4,2,3}; // 9 + dynamic_extents<4> de10{4,2,1,3}; // 10 + dynamic_extents<5> de11{4,2,1,3,1}; // 11 + dynamic_extents<6> de12{1,4,2,1,3,1};// 12 + + dynamic_extents<3> de13{1,4,1}; // 13 + dynamic_extents<4> de14{1,1,1,1}; // 14 + dynamic_extents<5> de15{1,4,1,1,1}; // 15 + dynamic_extents<6> de16{1,1,2,1,1,1};// 16 + dynamic_extents<6> de17{1,1,2,3,1,1};// 17 +}; + +BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_access, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("access")) +{ + using namespace boost::numeric; + + BOOST_CHECK_EQUAL(de0.size(), 0); + BOOST_CHECK (de0.empty() ); + + BOOST_REQUIRE_EQUAL(de1.size(), 2); + BOOST_REQUIRE_EQUAL(de2.size(), 2); + BOOST_REQUIRE_EQUAL(de3.size(), 2); + BOOST_REQUIRE_EQUAL(de4.size(), 2); + BOOST_REQUIRE_EQUAL(de5.size(), 3); + BOOST_REQUIRE_EQUAL(de6.size(), 3); + BOOST_REQUIRE_EQUAL(de7.size(), 4); + BOOST_REQUIRE_EQUAL(de8.size(), 5); + BOOST_REQUIRE_EQUAL(de9.size(), 3); + BOOST_REQUIRE_EQUAL(de10.size(), 4); + BOOST_REQUIRE_EQUAL(de11.size(), 5); + BOOST_REQUIRE_EQUAL(de12.size(), 6); + BOOST_REQUIRE_EQUAL(de13.size(), 3); + BOOST_REQUIRE_EQUAL(de14.size(), 4); + BOOST_REQUIRE_EQUAL(de15.size(), 5); + BOOST_REQUIRE_EQUAL(de16.size(), 6); + BOOST_REQUIRE_EQUAL(de17.size(), 6); + + + BOOST_CHECK_EQUAL(de1[0],1); + BOOST_CHECK_EQUAL(de1[1],1); + + BOOST_CHECK_EQUAL(de2[0],1); + BOOST_CHECK_EQUAL(de2[1],2); + + BOOST_CHECK_EQUAL(de3[0],2); + BOOST_CHECK_EQUAL(de3[1],1); + + BOOST_CHECK_EQUAL(de4[0],2); + BOOST_CHECK_EQUAL(de4[1],3); + + BOOST_CHECK_EQUAL(de5[0],2); + BOOST_CHECK_EQUAL(de5[1],3); + BOOST_CHECK_EQUAL(de5[2],1); + + BOOST_CHECK_EQUAL(de6[0],1); + BOOST_CHECK_EQUAL(de6[1],2); + BOOST_CHECK_EQUAL(de6[2],3); + + BOOST_CHECK_EQUAL(de7[0],1); + BOOST_CHECK_EQUAL(de7[1],1); + BOOST_CHECK_EQUAL(de7[2],2); + BOOST_CHECK_EQUAL(de7[3],3); + + BOOST_CHECK_EQUAL(de8[0],1); + BOOST_CHECK_EQUAL(de8[1],2); + BOOST_CHECK_EQUAL(de8[2],3); + BOOST_CHECK_EQUAL(de8[3],1); + BOOST_CHECK_EQUAL(de8[4],1); + + BOOST_CHECK_EQUAL(de9[0],4); + BOOST_CHECK_EQUAL(de9[1],2); + BOOST_CHECK_EQUAL(de9[2],3); + + BOOST_CHECK_EQUAL(de10[0],4); + BOOST_CHECK_EQUAL(de10[1],2); + BOOST_CHECK_EQUAL(de10[2],1); + BOOST_CHECK_EQUAL(de10[3],3); + + BOOST_CHECK_EQUAL(de11[0],4); + BOOST_CHECK_EQUAL(de11[1],2); + BOOST_CHECK_EQUAL(de11[2],1); + BOOST_CHECK_EQUAL(de11[3],3); + BOOST_CHECK_EQUAL(de11[4],1); + + BOOST_CHECK_EQUAL(de12[0],1); + BOOST_CHECK_EQUAL(de12[1],4); + BOOST_CHECK_EQUAL(de12[2],2); + BOOST_CHECK_EQUAL(de12[3],1); + BOOST_CHECK_EQUAL(de12[4],3); + BOOST_CHECK_EQUAL(de12[5],1); + + BOOST_CHECK_EQUAL(de13[0],1); + BOOST_CHECK_EQUAL(de13[1],4); + BOOST_CHECK_EQUAL(de13[2],1); + + BOOST_CHECK_EQUAL(de14[0],1); + BOOST_CHECK_EQUAL(de14[1],1); + BOOST_CHECK_EQUAL(de14[2],1); + BOOST_CHECK_EQUAL(de14[3],1); + + BOOST_CHECK_EQUAL(de15[0],1); + BOOST_CHECK_EQUAL(de15[1],4); + BOOST_CHECK_EQUAL(de15[2],1); + BOOST_CHECK_EQUAL(de15[3],1); + BOOST_CHECK_EQUAL(de15[4],1); + + BOOST_CHECK_EQUAL(de16[0],1); + BOOST_CHECK_EQUAL(de16[1],1); + BOOST_CHECK_EQUAL(de16[2],2); + BOOST_CHECK_EQUAL(de16[3],1); + BOOST_CHECK_EQUAL(de16[4],1); + BOOST_CHECK_EQUAL(de16[5],1); + + BOOST_CHECK_EQUAL(de17[0],1); + BOOST_CHECK_EQUAL(de17[1],1); + BOOST_CHECK_EQUAL(de17[2],2); + BOOST_CHECK_EQUAL(de17[3],3); + BOOST_CHECK_EQUAL(de17[4],1); + BOOST_CHECK_EQUAL(de17[5],1); +} + +BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_copy_ctor, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("copy_ctor")) +{ + + auto e0 = de0; // {} + auto e1 = de1; // {1,1} + auto e2 = de2; // {1,2} + auto e3 = de3; // {2,1} + auto e4 = de4; // {2,3} + auto e5 = de5; // {2,3,1} + auto e6 = de6; // {1,2,3} + auto e7 = de7; // {1,1,2,3} + auto e8 = de8; // {1,2,3,1,1} + auto e9 = de9; // {4,2,3} + auto e10 = de10; // {4,2,1,3} + auto e11 = de11; // {4,2,1,3,1} + auto e12 = de12; // {1,4,2,1,3,1} + auto e13 = de13; // {1,4,1} + auto e14 = de14; // {1,1,1,1} + auto e15 = de15; // {1,4,1,1,1} + auto e16 = de16; // {1,1,2,1,1,1} + auto e17 = de17; // {1,1,2,3,1,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_REQUIRE_EQUAL(e13.size(), 3); + BOOST_REQUIRE_EQUAL(e14.size(), 4); + BOOST_REQUIRE_EQUAL(e15.size(), 5); + BOOST_REQUIRE_EQUAL(e16.size(), 6); + BOOST_REQUIRE_EQUAL(e17.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_CHECK_EQUAL(e13[0],1); + BOOST_CHECK_EQUAL(e13[1],4); + BOOST_CHECK_EQUAL(e13[2],1); + + BOOST_CHECK_EQUAL(e14[0],1); + BOOST_CHECK_EQUAL(e14[1],1); + BOOST_CHECK_EQUAL(e14[2],1); + BOOST_CHECK_EQUAL(e14[3],1); + + BOOST_CHECK_EQUAL(e15[0],1); + BOOST_CHECK_EQUAL(e15[1],4); + BOOST_CHECK_EQUAL(e15[2],1); + BOOST_CHECK_EQUAL(e15[3],1); + BOOST_CHECK_EQUAL(e15[4],1); + + BOOST_CHECK_EQUAL(e16[0],1); + BOOST_CHECK_EQUAL(e16[1],1); + BOOST_CHECK_EQUAL(e16[2],2); + BOOST_CHECK_EQUAL(e16[3],1); + BOOST_CHECK_EQUAL(e16[4],1); + BOOST_CHECK_EQUAL(e16[5],1); + + BOOST_CHECK_EQUAL(e17[0],1); + BOOST_CHECK_EQUAL(e17[1],1); + BOOST_CHECK_EQUAL(e17[2],2); + BOOST_CHECK_EQUAL(e17[3],3); + BOOST_CHECK_EQUAL(e17[4],1); + BOOST_CHECK_EQUAL(e17[5],1); + +} + +BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_is, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("query")) +{ + + auto e0 = de0; // {} + auto e1 = de1; // {1,1} + auto e2 = de2; // {1,2} + auto e3 = de3; // {2,1} + auto e4 = de4; // {2,3} + auto e5 = de5; // {2,3,1} + auto e6 = de6; // {1,2,3} + auto e7 = de7; // {1,1,2,3} + auto e8 = de8; // {1,2,3,1,1} + auto e9 = de9; // {4,2,3} + auto e10 = de10; // {4,2,1,3} + auto e11 = de11; // {4,2,1,3,1} + auto e12 = de12; // {1,4,2,1,3,1} + auto e13 = de13; // {1,4,1} + auto e14 = de14; // {1,1,1,1} + auto e15 = de15; // {1,4,1,1,1} + auto e16 = de16; // {1,1,2,1,1,1} + auto e17 = de17; // {1,1,2,3,1,1} + + BOOST_CHECK( e0.empty ( )); + BOOST_CHECK( ! is_scalar(e0)); + BOOST_CHECK( ! is_vector(e0)); + BOOST_CHECK( ! is_matrix(e0)); + BOOST_CHECK( ! is_tensor(e0)); + + BOOST_CHECK( ! e1.empty ( ) ); + BOOST_CHECK( is_scalar(e1) ); + BOOST_CHECK( ! is_vector(e1) ); + BOOST_CHECK( ! is_matrix(e1) ); + BOOST_CHECK( ! is_tensor(e1) ); + + BOOST_CHECK( ! e2.empty ( ) ); + BOOST_CHECK( ! is_scalar(e2) ); + BOOST_CHECK( is_vector(e2) ); + BOOST_CHECK( ! is_matrix(e2) ); + BOOST_CHECK( ! is_tensor(e2) ); + + BOOST_CHECK( ! e3.empty ( ) ); + BOOST_CHECK( ! is_scalar(e3) ); + BOOST_CHECK( is_vector(e3) ); + BOOST_CHECK( ! is_matrix(e3) ); + BOOST_CHECK( ! is_tensor(e3) ); + + BOOST_CHECK( ! e4.empty ( ) ); + BOOST_CHECK( ! is_scalar(e4) ); + BOOST_CHECK( ! is_vector(e4) ); + BOOST_CHECK( is_matrix(e4) ); + BOOST_CHECK( ! is_tensor(e4) ); + + BOOST_CHECK( ! e5.empty ( ) ); + BOOST_CHECK( ! is_scalar(e5) ); + BOOST_CHECK( ! is_vector(e5) ); + BOOST_CHECK( is_matrix(e5) ); + BOOST_CHECK( ! is_tensor(e5) ); + + BOOST_CHECK( ! e6.empty ( ) ); + BOOST_CHECK( ! is_scalar(e6) ); + BOOST_CHECK( ! is_vector(e6) ); + BOOST_CHECK( ! is_matrix(e6) ); + BOOST_CHECK( is_tensor(e6) ); + + BOOST_CHECK( ! e7.empty ( ) ); + BOOST_CHECK( ! is_scalar(e7) ); + BOOST_CHECK( ! is_vector(e7) ); + BOOST_CHECK( ! is_matrix(e7) ); + BOOST_CHECK( is_tensor(e7) ); + + BOOST_CHECK( ! e8.empty ( ) ); + BOOST_CHECK( ! is_scalar(e8) ); + BOOST_CHECK( ! is_vector(e8) ); + BOOST_CHECK( ! is_matrix(e8) ); + BOOST_CHECK( is_tensor(e8) ); + + BOOST_CHECK( ! e9.empty ( ) ); + BOOST_CHECK( ! is_scalar(e9) ); + BOOST_CHECK( ! is_vector(e9) ); + BOOST_CHECK( ! is_matrix(e9) ); + BOOST_CHECK( is_tensor(e9) ); + + BOOST_CHECK( ! e10.empty( ) ); + BOOST_CHECK( ! is_scalar(e10) ); + BOOST_CHECK( ! is_vector(e10) ); + BOOST_CHECK( ! is_matrix(e10) ); + BOOST_CHECK( is_tensor(e10) ); + + BOOST_CHECK( ! e11.empty( ) ); + BOOST_CHECK( ! is_scalar(e11) ); + BOOST_CHECK( ! is_vector(e11) ); + BOOST_CHECK( ! is_matrix(e11) ); + BOOST_CHECK( is_tensor(e11) ); + + BOOST_CHECK( ! e12.empty( ) ); + BOOST_CHECK( ! is_scalar(e12) ); + BOOST_CHECK( ! is_vector(e12) ); + BOOST_CHECK( ! is_matrix(e12) ); + BOOST_CHECK( is_tensor(e12) ); + + BOOST_CHECK( ! e13.empty( ) ); + BOOST_CHECK( ! is_scalar(e13) ); + BOOST_CHECK( is_vector(e13) ); + BOOST_CHECK( ! is_matrix(e13) ); + BOOST_CHECK( ! is_tensor(e13) ); + + BOOST_CHECK( ! e14.empty( ) ); + BOOST_CHECK( is_scalar(e14) ); + BOOST_CHECK( ! is_vector(e14) ); + BOOST_CHECK( ! is_matrix(e14) ); + BOOST_CHECK( ! is_tensor(e14) ); + + BOOST_CHECK( ! e15.empty( ) ); + BOOST_CHECK( ! is_scalar(e15) ); + BOOST_CHECK( is_vector(e15) ); + BOOST_CHECK( ! is_matrix(e15) ); + BOOST_CHECK( ! is_tensor(e15) ); + + BOOST_CHECK( ! e16.empty( ) ); + BOOST_CHECK( ! is_scalar(e16) ); + BOOST_CHECK( ! is_vector(e16) ); + BOOST_CHECK( ! is_matrix(e16) ); + BOOST_CHECK( is_tensor(e16) ); + + BOOST_CHECK( ! e17.empty( ) ); + BOOST_CHECK( ! is_scalar(e17) ); + BOOST_CHECK( ! is_vector(e17) ); + BOOST_CHECK( ! is_matrix(e17) ); + BOOST_CHECK( is_tensor(e17) ); +} + +BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_squeeze, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("squeeze")) +{ + auto e1 = squeeze(de1); // {1,1} + auto e2 = squeeze(de2); // {1,2} + auto e3 = squeeze(de3); // {2,1} + + auto e4 = squeeze(de4); // {2,3} + auto e5 = squeeze(de5); // {2,3} + auto e6 = squeeze(de6); // {2,3} + auto e7 = squeeze(de7); // {2,3} + auto e8 = squeeze(de8); // {2,3} + + auto e9 = squeeze(de9); // {4,2,3} + auto e10 = squeeze(de10); // {4,2,3} + auto e11 = squeeze(de11); // {4,2,3} + auto e12 = squeeze(de12); // {4,2,3} + + auto e13 = squeeze(de13); // {1,4} + auto e14 = squeeze(de14); // {1,1} + auto e15 = squeeze(de15); // {1,4} + auto e16 = squeeze(de16); // {2,1} + auto e17 = squeeze(de17); // {2,3} + + BOOST_CHECK( (e1 == dynamic_extents<2>{1,1}) ); + BOOST_CHECK( (e2 == dynamic_extents<2>{1,2}) ); + BOOST_CHECK( (e3 == dynamic_extents<2>{2,1}) ); + + BOOST_CHECK( (e4 == dynamic_extents<2>{2,3}) ); + BOOST_CHECK( (e5 == dynamic_extents<2>{2,3}) ); + BOOST_CHECK( (e6 == dynamic_extents<2>{2,3}) ); + BOOST_CHECK( (e7 == dynamic_extents<2>{2,3}) ); + BOOST_CHECK( (e8 == dynamic_extents<2>{2,3}) ); + + BOOST_CHECK( (e9 == dynamic_extents<3>{4,2,3}) ); + BOOST_CHECK( (e10 == dynamic_extents<3>{4,2,3}) ); + BOOST_CHECK( (e11 == dynamic_extents<3>{4,2,3}) ); + BOOST_CHECK( (e12 == dynamic_extents<3>{4,2,3}) ); + + BOOST_CHECK( (e13 == dynamic_extents<2>{1,4}) ); + BOOST_CHECK( (e14 == dynamic_extents<2>{1,1}) ); + BOOST_CHECK( (e15 == dynamic_extents<2>{1,4}) ); + BOOST_CHECK( (e16 == dynamic_extents<2>{2,1}) ); + BOOST_CHECK( (e17 == dynamic_extents<2>{2,3}) ); + +} + + +BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_product, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("product")) +{ + + auto e0 = product( de0 ); // {} + auto e1 = product( de1 ); // {1,1} + auto e2 = product( de2 ); // {1,2} + auto e3 = product( de3 ); // {2,1} + auto e4 = product( de4 ); // {2,3} + auto e5 = product( de5 ); // {2,3,1} + auto e6 = product( de6 ); // {1,2,3} + auto e7 = product( de7 ); // {1,1,2,3} + auto e8 = product( de8 ); // {1,2,3,1,1} + auto e9 = product( de9 ); // {4,2,3} + auto e10 = product( de10 ); // {4,2,1,3} + auto e11 = product( de11 ); // {4,2,1,3,1} + auto e12 = product( de12 ); // {1,4,2,1,3,1} + auto e13 = product( de13 ); // {1,4,1} + auto e14 = product( de14 ); // {1,1,1,1} + auto e15 = product( de15 ); // {1,4,1,1,1} + auto e16 = product( de16 ); // {1,1,2,1,1,1} + auto e17 = product( de17 ); // {1,1,2,3,1,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_CHECK_EQUAL( e13, 4 ); + BOOST_CHECK_EQUAL( e14, 1 ); + BOOST_CHECK_EQUAL( e15, 4 ); + BOOST_CHECK_EQUAL( e16, 2 ); + BOOST_CHECK_EQUAL( e17, 6 ); + + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_functions.cpp b/test/tensor/test_fixed_rank_functions.cpp new file mode 100644 index 000000000..3855a67fc --- /dev/null +++ b/test/tensor/test_fixed_rank_functions.cpp @@ -0,0 +1,405 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// +// And we acknowledge the support from all contributors. + + +#include +#include +#include +#include +#include + +#include + +#include "utility.hpp" + +// BOOST_AUTO_TEST_SUITE ( test_tensor_functions, * boost::unit_test::depends_on("test_tensor_contraction") ) +BOOST_AUTO_TEST_SUITE ( test_fixed_rank_tensor_functions) + + +using test_types = zip>::with_t; + +//using test_types = zip::with_t; + + +struct fixture +{ + template + using fixed_rank_extents_type = boost::numeric::ublas::dynamic_extents; + + using dynamic_extents_type = boost::numeric::ublas::dynamic_extents<>; + fixture() + : extents { + dynamic_extents_type{1,1}, // 1 + dynamic_extents_type{2,3}, // 2 + dynamic_extents_type{2,3,1}, // 3 + dynamic_extents_type{4,2,3}, // 4 + dynamic_extents_type{4,2,3,5}} // 5 + { + } + + std::tuple< + fixed_rank_extents_type<2>, + fixed_rank_extents_type<2>, + fixed_rank_extents_type<3>, + fixed_rank_extents_type<3>, + fixed_rank_extents_type<4> + > fixed_rank_extents{ + {1,1}, // 1 + {2,3}, // 2 + {2,3,1}, // 3 + {4,2,3}, // 4 + {4,2,3,5} // 5 + }; + + + std::vector extents; + +}; + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_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; + + for_each_tuple(fixed_rank_extents,[](auto const&, auto & n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::fixed_rank_tensor; + using vector_type = typename tensor_type::vector_type; + 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( static_cast< inner_type_t >(n[m]) ) * a[i]); + } + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_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; + + for_each_tuple(fixed_rank_extents,[](auto const&, auto & n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::fixed_rank_tensor; + using matrix_type = typename tensor_type::matrix_type; + 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( static_cast< inner_type_t >(n[m]) ) * a[i]); + } + }); + +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_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; + + auto const body = [](auto const& a, auto const& b){ + auto const pa = a.rank(); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phi = std::vector(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 *= value_type( static_cast< inner_type_t >( 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]); + } + }; + + + + for_each_tuple(fixed_rank_extents,[&](auto const&, auto & n){ + auto n1 = n; + auto n2 = n; + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = + ublas::fixed_rank_tensor; + using tensor_type_2 = + ublas::fixed_rank_tensor; + auto a = tensor_type_1(n1, value_type{2}); + auto b = tensor_type_2(n2, value_type{3}); + body(a,b); + }); + + for_each_tuple(fixed_rank_extents,[&](auto const& I, auto & n){ + auto n1 = n; + auto n2 = extents[I]; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = + ublas::fixed_rank_tensor; + using tensor_type_2 = + ublas::dynamic_tensor; + auto a = tensor_type_1(n1, value_type{2}); + auto b = tensor_type_2(n2, value_type{3}); + body(a,b); + }); + + for_each_tuple(fixed_rank_extents,[&](auto const& I, auto & n){ + auto n1 = extents[I]; + auto n2 = n; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = + ublas::dynamic_tensor; + using tensor_type_2 = + ublas::fixed_rank_tensor; + auto a = tensor_type_1(n1, value_type{2}); + auto b = tensor_type_2(n2, value_type{3}); + body(a,b); + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_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; + + + + auto compute_factorial = [](auto const& p){ + auto f = 1ul; + for(auto i = 1u; i <= p; ++i) + f *= i; + return f; + }; + + auto permute_extents_s_1 = [](auto const& pi, auto const& na){ + + auto nb = ublas::dynamic_extents<>(na); + assert(pi.size() == na.size()); + for(auto j = 0u; j < pi.size(); ++j) + nb[pi[j]-1] = na[j]; + return nb; + }; + auto permute_extents_s_2 = [](auto const& pi, auto const& na){ + auto tempn = na.base(); + assert(pi.size() == na.size()); + for(auto j = 0u; j < pi.size(); ++j) + tempn[pi[j]-1] = na[j]; + return ublas::dynamic_extents::type::_size>(tempn.begin(),tempn.end()); + }; + + for_each_tuple(fixed_rank_extents,[&](auto const&, auto & n){ + auto na = n; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::fixed_rank_tensor; + auto a = tensor_type_1(na, value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_s_1(pi, na); + using tensor_type_2 = ublas::dynamic_tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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 *= value_type( static_cast< inner_type_t >( 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()); + } + }); + + for_each_tuple(fixed_rank_extents,[&](auto const&, auto & n){ + auto na = n; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::fixed_rank_tensor; + auto a = tensor_type_1(na, value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_s_2(pi, na); + + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::fixed_rank_tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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 *= value_type( static_cast< inner_type_t >( 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_fixed_rank_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; + + auto const body = [&](auto const& a, auto const& b){ + 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 ); + }; + + for_each_tuple(fixed_rank_extents,[&](auto const&, auto & n){ + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::fixed_rank_tensor; + using tensor_type_2 = ublas::fixed_rank_tensor; + auto a = tensor_type_1(n, value_type(2)); + auto b = tensor_type_2(n, value_type(1)); + body(a,b); + + }); + + for_each_tuple(fixed_rank_extents,[&](auto const& I, auto & n){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::fixed_rank_tensor; + using tensor_type_2 = ublas::dynamic_tensor; + auto a = tensor_type_1(n, value_type(2)); + auto b = tensor_type_2(extents[I], value_type(1)); + body(a,b); + + }); + + for_each_tuple(fixed_rank_extents,[&](auto const& I, auto & n){ + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::dynamic_tensor; + using tensor_type_2 = ublas::fixed_rank_tensor; + auto a = tensor_type_1(extents[I], value_type(2)); + auto b = tensor_type_2(n, value_type(1)); + body(a,b); + + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_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; + + for_each_tuple(fixed_rank_extents,[&](auto const&, auto const& n1){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::fixed_rank_tensor; + auto a = tensor_type_1(n1, value_type(2)); + for_each_tuple(fixed_rank_extents,[&](auto const& J, auto const& n2){ + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::fixed_rank_tensor; + auto b = tensor_type_2(n2, value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + + }); + + }); + + for_each_tuple(fixed_rank_extents,[&](auto const& I, auto const& n1){ + using tensor_type_1 = ublas::dynamic_tensor; + auto a = tensor_type_1(extents[I], value_type(2)); + for_each_tuple(fixed_rank_extents,[&](auto const& J, auto const& n2){ + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::fixed_rank_tensor; + auto b = tensor_type_2(n2, value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + }); + + }); + + for_each_tuple(fixed_rank_extents,[&](auto const&, auto const& n1){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::fixed_rank_tensor; + auto a = tensor_type_1(n1, value_type(2)); + for(auto n2 : extents){ + using tensor_type_2 = ublas::dynamic_tensor; + auto b = tensor_type_2(n2, value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + } + + }); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_operators_arithmetic.cpp b/test/tensor/test_fixed_rank_operators_arithmetic.cpp index 715288be2..5a3980a8c 100644 --- a/test/tensor/test_fixed_rank_operators_arithmetic.cpp +++ b/test/tensor/test_fixed_rank_operators_arithmetic.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -26,136 +26,136 @@ using test_types = zip::with_t - using extents_type = boost::numeric::ublas::dynamic_extents; - - std::tuple< - extents_type<2>, // 1 - extents_type<2>, // 2 - extents_type<3>, // 3 - extents_type<3>, // 4 - extents_type<4> // 5 - > extents = { - extents_type<2>{1,1}, - extents_type<2>{2,3}, - extents_type<3>{4,1,3}, - extents_type<3>{4,2,3}, - extents_type<4>{4,2,3,5} - }; + template + using extents_type = boost::numeric::ublas::dynamic_extents; + + std::tuple< + extents_type<2>, // 1 + extents_type<2>, // 2 + extents_type<3>, // 3 + extents_type<3>, // 4 + extents_type<4> // 5 + > extents = { + extents_type<2>{1,1}, + extents_type<2>{2,3}, + extents_type<3>{4,1,3}, + extents_type<3>{4,2,3}, + extents_type<4>{4,2,3,5} + }; }; 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto r = tensor_type (e); - auto v = value_type {}; + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + 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; + 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) ); + 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 + 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) ); + 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 + 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) ); + 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; + r = t2 - t + t2 - t; - for(auto i = 0ul; i < r.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 4 ); + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 4 ); - r = tensor_type (e,1) + tensor_type (e,1); + r = tensor_type (e,1) + tensor_type (e,1); - for(auto i = 0ul; i < r.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 2 ); + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2 ); - r = t * t * t * t2; + 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) ); + 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); + r = (t2/t2) * (t2/t2); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 1 ); - }; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 1 ); + }; - for_each_tuple(extents,check); + for_each_tuple(extents,check); } 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto v = value_type {}; + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + 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); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - tensor_type r1 = t + 2 + t + 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 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r1(i), 2*t(i) + 4 ); - tensor_type r2 = 2 + t + 2 + t; + tensor_type r2 = 2 + t + 2 + t; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r2(i), 2*t(i) + 4 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r2(i), 2*t(i) + 4 ); - tensor_type r3 = (t-2) + (t-2); + tensor_type r3 = (t-2) + (t-2); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r3(i), 2*t(i) - 4 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r3(i), 2*t(i) - 4 ); - tensor_type r4 = (t*2) * (3*t); + 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) ); + 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; + 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) ); + 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; + 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 i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r6(i), (t2(i)/2+1) / (2/t2(i)+1) / t2(i) ); - }; + }; - for_each_tuple(extents,check); + for_each_tuple(extents,check); } @@ -164,79 +164,79 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto r = tensor_type (e); - auto v = value_type {}; + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + 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); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - r = t + 2; - r += t; - r += 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 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2*t(i) + 4 ); - r = 2 + t; - r += t; - r += 2; + 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 ); - 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; + r = (t-2); + 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 *= 3; - r *= t; + 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) ); + 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; + 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) ); + 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; + 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) ); + 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 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) ); - }; + tensor_type p = +r; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( p(i), r(i) ); + }; - for_each_tuple(extents,check); + for_each_tuple(extents,check); } diff --git a/test/tensor/test_fixed_rank_operators_comparison.cpp b/test/tensor/test_fixed_rank_operators_comparison.cpp index 33aea14c2..e8b901b4d 100644 --- a/test/tensor/test_fixed_rank_operators_comparison.cpp +++ b/test/tensor/test_fixed_rank_operators_comparison.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,9 +12,7 @@ -#include -#include -#include +#include #include #include #include "utility.hpp" @@ -26,107 +24,107 @@ using double_extended = boost::multiprecision::cpp_bin_float_double_extended; using test_types = zip::with_t; struct fixture { - template - using extents_type = boost::numeric::ublas::dynamic_extents; - - std::tuple< - extents_type<2>, // 1 - extents_type<2>, // 2 - extents_type<3>, // 3 - extents_type<3>, // 4 - extents_type<4> // 5 - > extents = { - extents_type<2>{1,1}, - extents_type<2>{2,3}, - extents_type<3>{4,1,3}, - extents_type<3>{4,2,3}, - extents_type<4>{4,2,3,5} - }; + template + using extents_type = boost::numeric::ublas::dynamic_extents; + + std::tuple< + extents_type<2>, // 1 + extents_type<2>, // 2 + extents_type<3>, // 3 + extents_type<3>, // 4 + extents_type<4> // 5 + > extents = { + extents_type<2>{1,1}, + extents_type<2>{2,3}, + extents_type<3>{4,1,3}, + extents_type<3>{4,2,3}, + extents_type<4>{4,2,3,5} + }; }; 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; - - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + 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_each_tuple(extents,check); } 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto v = value_type {}; + 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); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - BOOST_CHECK( t == t ); - BOOST_CHECK( t != t2 ); + BOOST_CHECK( t == t ); + BOOST_CHECK( t != t2 ); - if(t.empty()) - return; + 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 ); + 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_each_tuple(extents,check); + for_each_tuple(extents,check); } @@ -134,68 +132,68 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions 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; - - - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - - 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)) ); - - }; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + + 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_each_tuple(extents,check); diff --git a/test/tensor/test_fixed_rank_strides.cpp b/test/tensor/test_fixed_rank_strides.cpp new file mode 100644 index 000000000..d5c24f2b0 --- /dev/null +++ b/test/tensor/test_fixed_rank_strides.cpp @@ -0,0 +1,161 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + + +#include +#include +#include + +//BOOST_AUTO_TEST_SUITE(test_strides, * boost::unit_test::depends_on("test_extents")); + +BOOST_AUTO_TEST_SUITE(test_fixed_rank_strides) + +using test_types = std::tuple; + +BOOST_AUTO_TEST_CASE_TEMPLATE( test_fixed_rank_strides_ctor, value, test_types) +{ + namespace ub = boost::numeric::ublas; + + ub::basic_fixed_rank_strides s0{ub::dynamic_extents<0>{}}; + BOOST_CHECK ( s0.empty()); + BOOST_CHECK_EQUAL ( s0.size(), 0); + + ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; + BOOST_CHECK (!s1.empty()); + BOOST_CHECK_EQUAL ( s1.size(), 2); + + ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; + BOOST_CHECK (!s2.empty()); + BOOST_CHECK_EQUAL ( s2.size(), 2); + + ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; + BOOST_CHECK (!s3.empty()); + BOOST_CHECK_EQUAL ( s3.size(), 2); + + ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; + BOOST_CHECK (!s4.empty()); + BOOST_CHECK_EQUAL ( s4.size(), 2); + + ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{2,3,1}}; + BOOST_CHECK (!s5.empty()); + BOOST_CHECK_EQUAL ( s5.size(), 3); + + ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{1,2,3}}; + BOOST_CHECK (!s6.empty()); + BOOST_CHECK_EQUAL ( s6.size(), 3); + + ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{4,2,3}}; + BOOST_CHECK (!s7.empty()); + BOOST_CHECK_EQUAL ( s7.size(), 3); +} + + +BOOST_AUTO_TEST_CASE( test_fixed_rank_strides_ctor_access_first_order) +{ + namespace ub = boost::numeric::ublas; + + ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; + BOOST_REQUIRE_EQUAL( s1.size(),2); + BOOST_CHECK_EQUAL ( s1[0], 1); + BOOST_CHECK_EQUAL ( s1[1], 1); + + ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; + BOOST_REQUIRE_EQUAL ( s2.size(),2); + BOOST_CHECK_EQUAL ( s2[0], 1); + BOOST_CHECK_EQUAL ( s2[1], 1); + + ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; + BOOST_REQUIRE_EQUAL ( s3.size(),2); + BOOST_CHECK_EQUAL ( s3[0], 1); + BOOST_CHECK_EQUAL ( s3[1], 1); + + ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; + BOOST_REQUIRE_EQUAL ( s4.size(),2); + BOOST_CHECK_EQUAL ( s4[0], 1); + BOOST_CHECK_EQUAL ( s4[1], 2); + + ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s8{ub::dynamic_extents<3>{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_fixed_rank_strides_ctor_access_last_order) +{ + namespace ub = boost::numeric::ublas; + + ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; + BOOST_REQUIRE_EQUAL( s1.size(),2); + BOOST_CHECK_EQUAL ( s1[0], 1); + BOOST_CHECK_EQUAL ( s1[1], 1); + + ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; + BOOST_REQUIRE_EQUAL ( s2.size(),2); + BOOST_CHECK_EQUAL ( s2[0], 1); + BOOST_CHECK_EQUAL ( s2[1], 1); + + ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; + BOOST_REQUIRE_EQUAL ( s3.size(),2); + BOOST_CHECK_EQUAL ( s3[0], 1); + BOOST_CHECK_EQUAL ( s3[1], 1); + + ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; + BOOST_REQUIRE_EQUAL ( s4.size(),2); + BOOST_CHECK_EQUAL ( s4[0], 3); + BOOST_CHECK_EQUAL ( s4[1], 1); + + ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{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); + + ub::basic_fixed_rank_strides s8{ub::dynamic_extents<3>{4,2,3}}; + BOOST_REQUIRE_EQUAL ( s8.size(),3); + BOOST_CHECK_EQUAL ( s8[0], 6); + BOOST_CHECK_EQUAL ( s8[1], 3); + BOOST_CHECK_EQUAL ( s8[2], 1); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_tensor.cpp b/test/tensor/test_fixed_rank_tensor.cpp index 794a594b6..5f63a5fab 100644 --- a/test/tensor/test_fixed_rank_tensor.cpp +++ b/test/tensor/test_fixed_rank_tensor.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,7 +13,7 @@ #include -#include +#include #ifndef BOOST_TEST_DYN_LINK #define BOOST_TEST_DYN_LINK @@ -31,351 +31,351 @@ using test_types = zip>::with_t,layout_type>{}; - BOOST_CHECK_EQUAL( a1.size() , 0ul ); - BOOST_CHECK( a1.empty() ); - BOOST_CHECK_EQUAL( a1.data() , nullptr); - - auto a2 = ublas::tensor,layout_type>{1,1}; - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - BOOST_CHECK_NE( a2.data() , nullptr); - - auto a3 = ublas::tensor,layout_type>{2,1}; - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - BOOST_CHECK_NE( a3.data() , nullptr); - - auto a4 = ublas::tensor,layout_type>{1,2}; - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - BOOST_CHECK_NE( a4.data() , nullptr); - - auto a5 = ublas::tensor,layout_type>{2,1}; - BOOST_CHECK_EQUAL( a5.size() , 2 ); - BOOST_CHECK( !a5.empty() ); - BOOST_CHECK_NE( a5.data() , nullptr); - - auto a6 = ublas::tensor,layout_type>{4,3,2}; - BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); - BOOST_CHECK( !a6.empty() ); - BOOST_CHECK_NE( a6.data() , nullptr); - - auto a7 = ublas::tensor,layout_type>{4,1,2}; - BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); - BOOST_CHECK( !a7.empty() ); - BOOST_CHECK_NE( a7.data() , nullptr); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + auto a1 = ublas::fixed_rank_tensor{}; + BOOST_CHECK_EQUAL( a1.size() , 0ul ); + BOOST_CHECK( a1.empty() ); + BOOST_CHECK_EQUAL( a1.data() , nullptr); + + auto a2 = ublas::fixed_rank_tensor{1,1}; + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + BOOST_CHECK_NE( a2.data() , nullptr); + + auto a3 = ublas::fixed_rank_tensor{2,1}; + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + BOOST_CHECK_NE( a3.data() , nullptr); + + auto a4 = ublas::fixed_rank_tensor{1,2}; + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + BOOST_CHECK_NE( a4.data() , nullptr); + + auto a5 = ublas::fixed_rank_tensor{2,1}; + BOOST_CHECK_EQUAL( a5.size() , 2 ); + BOOST_CHECK( !a5.empty() ); + BOOST_CHECK_NE( a5.data() , nullptr); + + auto a6 = ublas::fixed_rank_tensor{4,3,2}; + BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); + BOOST_CHECK( !a6.empty() ); + BOOST_CHECK_NE( a6.data() , nullptr); + + auto a7 = ublas::fixed_rank_tensor{4,1,2}; + BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); + BOOST_CHECK( !a7.empty() ); + BOOST_CHECK_NE( a7.data() , nullptr); } struct fixture { - template - using extents_type = boost::numeric::ublas::dynamic_extents; - - std::tuple< - extents_type<2>, // 1 - extents_type<2>, // 2 - extents_type<3>, // 3 - extents_type<3>, // 4 - extents_type<4> // 5 - > extents = { - extents_type<2>{1,1}, - extents_type<2>{2,3}, - extents_type<3>{4,1,3}, - extents_type<3>{4,2,3}, - extents_type<4>{4,2,3,5} - }; + template + using extents_type = boost::numeric::ublas::dynamic_extents; + + std::tuple< + extents_type<2>, // 1 + extents_type<2>, // 2 + extents_type<3>, // 3 + extents_type<3>, // 4 + extents_type<4> // 5 + > extents = { + extents_type<2>{1,1}, + extents_type<2>{2,3}, + extents_type<3>{4,1,3}, + extents_type<3>{4,2,3}, + extents_type<4>{4,2,3,5} + }; }; 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; - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - auto t = ublas::tensor{e}; - - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - 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); - } - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + auto t = ublas::fixed_rank_tensor{e}; + + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + 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); + } + }); } 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; - - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - auto r = ublas::tensor{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] ); - - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + auto r = ublas::fixed_rank_tensor{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] ); + + }); } 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 other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - auto r = tensor_type{e}; - ublas::tensor t = r; - tensor_type q = t; + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + auto r = tensor_type{e}; + ublas::fixed_rank_tensor 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 ( 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() ); + 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] ); + 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; - - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - auto r = tensor_type{e}; - auto t = std::move(r); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + auto r = tensor_type{e}; + auto t = std::move(r); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + 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_each_tuple(extents,check); } 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; - - std::random_device device{}; - std::minstd_rand0 generator(device()); - - using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; - auto distribution = distribution_type(1,6); - - for_each_tuple(extents, [&](auto const&, auto const& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - - auto r = value_type( static_cast< inner_type_t >(distribution(generator)) ); - auto t = tensor_type{e,r}; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( t[i], r ); - - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + std::random_device device{}; + std::minstd_rand0 generator(device()); + + using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; + auto distribution = distribution_type(1,6); + + for_each_tuple(extents, [&](auto const&, auto const& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + + auto r = value_type( static_cast< inner_type_t >(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; - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - using array_type = typename tensor_type::array_type; - - auto a = array_type(product(e)); - 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); - - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + using array_type = typename tensor_type::array_type; + + auto a = array_type(product(e)); + 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; - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - - 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 ); - } - - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + + 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; - - auto check1 = [](const auto& 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 auto& t) - { - std::array k; - auto r = std::is_same::value ? 1 : 0; - auto q = std::is_same::value ? 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 auto& t) - { - std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 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 auto& t) - { - std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 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&, auto const& e) { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + auto check1 = [](const auto& 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 auto& t) + { + std::array k; + auto r = std::is_same::value ? 1 : 0; + auto q = std::is_same::value ? 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 auto& t) + { + std::array k; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 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 auto& t) + { + std::array k; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 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&, auto const& e) { + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + 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_each_tuple(extents,check); } @@ -383,40 +383,40 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, 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; - - for_each_tuple(extents,[&](auto const&, auto& efrom){ - - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - - for_each_tuple(extents,[&](auto const&, auto& eto){ - - if ( efrom.size() == eto.size() ){ - - 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(product(efrom),product(eto)); ++i) - BOOST_CHECK_EQUAL( t[i], v ); - - BOOST_CHECK_EQUAL ( t.size() , product(eto) ); - BOOST_CHECK_EQUAL ( t.rank() , eto.size() ); - BOOST_CHECK ( t.extents() == eto ); - - if(efrom != eto){ - for(auto i = product(efrom); i < t.size(); ++i) - BOOST_CHECK_EQUAL( t[i], value_type{} ); - } - } - }); - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + for_each_tuple(extents,[&](auto const&, auto& efrom){ + + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + + for_each_tuple(extents,[&](auto const&, auto& eto){ + + if ( efrom.size() == eto.size() ){ + + 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(product(efrom),product(eto)); ++i) + BOOST_CHECK_EQUAL( t[i], v ); + + BOOST_CHECK_EQUAL ( t.size() , product(eto) ); + BOOST_CHECK_EQUAL ( t.rank() , eto.size() ); + BOOST_CHECK ( t.extents() == eto ); + + if(efrom != eto){ + for(auto i = product(efrom); i < t.size(); ++i) + BOOST_CHECK_EQUAL( t[i], value_type{} ); + } + } + }); + }); } @@ -424,71 +424,71 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixtu 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; - - for_each_tuple(extents,[&](auto const&, auto& e_t){ - - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - - for_each_tuple(extents,[&](auto const&, auto& e_r){ - - if ( e_t.size() == e_r.size() ){ - - 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() , product(e_r) ); - 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() , product(e_t) ); - BOOST_CHECK_EQUAL ( r.rank() , e_t.size() ); - BOOST_CHECK ( r.extents() == e_t ); - - } - }); - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + for_each_tuple(extents,[&](auto const&, auto& e_t){ + + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; + + for_each_tuple(extents,[&](auto const&, auto& e_r){ + + if ( e_t.size() == e_r.size() ){ + + 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() , product(e_r) ); + 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() , product(e_t) ); + 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + for_each_tuple(extents,[](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::fixed_rank_tensor; - for_each_tuple(extents,[](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - - auto v = value_type {} + value_type{1}; - auto t = tensor_type{e, v}; + 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.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() ); + 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() ) ) ; - } - }); + if(t.size() > 0) { + BOOST_CHECK( t.data() == std::addressof( *t.begin () ) ) ; + BOOST_CHECK( t.data() == std::addressof( *t.cbegin() ) ) ; + } + }); } @@ -497,7 +497,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, 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, layout_type>; + using tensor_type = ublas::fixed_rank_tensor; std::vector vec(30); BOOST_CHECK_THROW(tensor_type({5,5},vec), std::runtime_error); diff --git a/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp b/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp index ade7f891e..30f0c3b82 100644 --- a/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp +++ b/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -26,90 +26,80 @@ using test_types = zip::with_t,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - - ublas::tensor,layout_type> a1 = matrix_type(); - BOOST_CHECK_EQUAL( a1.size() , 0ul ); - BOOST_CHECK( a1.empty() ); - BOOST_CHECK_EQUAL( a1.data() , nullptr); - - ublas::tensor,layout_type> a2 = matrix_type(1,1); - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - BOOST_CHECK_NE( a2.data() , nullptr); - - ublas::tensor,layout_type> a3 = matrix_type(2,1); - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - BOOST_CHECK_NE( a3.data() , nullptr); - - ublas::tensor,layout_type> a4 = matrix_type(1,2); - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - BOOST_CHECK_NE( a4.data() , nullptr); - - ublas::tensor,layout_type> a5 = matrix_type(2,3); - BOOST_CHECK_EQUAL( a5.size() , 6 ); - BOOST_CHECK( !a5.empty() ); - BOOST_CHECK_NE( a5.data() , nullptr); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + ublas::fixed_rank_tensor a2 = matrix_type(1,1); + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + BOOST_CHECK_NE( a2.data() , nullptr); + + ublas::fixed_rank_tensor a3 = matrix_type(2,1); + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + BOOST_CHECK_NE( a3.data() , nullptr); + + ublas::fixed_rank_tensor a4 = matrix_type(1,2); + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + BOOST_CHECK_NE( a4.data() , nullptr); + + ublas::fixed_rank_tensor 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,layout_type>; - using vector_type = typename tensor_type::vector_type; - - ublas::tensor,layout_type> a1 = vector_type(); - BOOST_CHECK_EQUAL( a1.size() , 0ul ); - BOOST_CHECK( a1.empty() ); - BOOST_CHECK_EQUAL( a1.data() , nullptr); - - ublas::tensor,layout_type> a2 = vector_type(1); - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - BOOST_CHECK_NE( a2.data() , nullptr); - - ublas::tensor,layout_type> a3 = vector_type(2); - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - BOOST_CHECK_NE( a3.data() , nullptr); - - ublas::tensor,layout_type> a4 = vector_type(2); - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - BOOST_CHECK_NE( a4.data() , nullptr); - - ublas::tensor,layout_type> a5 = vector_type(3); - BOOST_CHECK_EQUAL( a5.size() , 3 ); - BOOST_CHECK( !a5.empty() ); - BOOST_CHECK_NE( a5.data() , nullptr); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + ublas::fixed_rank_tensor a2 = vector_type(1); + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + BOOST_CHECK_NE( a2.data() , nullptr); + + ublas::fixed_rank_tensor a3 = vector_type(2); + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + BOOST_CHECK_NE( a3.data() , nullptr); + + ublas::fixed_rank_tensor a4 = vector_type(2); + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + BOOST_CHECK_NE( a4.data() , nullptr); + + ublas::fixed_rank_tensor a5 = vector_type(3); + BOOST_CHECK_EQUAL( a5.size() , 3 ); + BOOST_CHECK( !a5.empty() ); + BOOST_CHECK_NE( a5.data() , nullptr); } struct fixture { - template - using extents_type = boost::numeric::ublas::dynamic_extents; - - std::tuple< - extents_type<2>, // 0 - extents_type<2>, // 1 - extents_type<2>, // 2 - extents_type<2> // 3 - > extents = { - {1,2}, - {2,1}, - {9,7}, - {12,12}, - }; + template + using extents_type = boost::numeric::ublas::dynamic_extents; + + std::tuple< + extents_type<2>, // 0 + extents_type<2>, // 1 + extents_type<2>, // 2 + extents_type<2> // 3 + > extents = { + {1,2}, + {2,1}, + {9,7}, + {12,12}, + }; }; @@ -117,159 +107,159 @@ struct fixture 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size()==2); - etensor_type t = matrix_type{e[0],e[1]}; - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - BOOST_CHECK_NE ( t.data() , nullptr); - }; - - for_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::fixed_rank_tensor; + + assert(e.size()==2); + etensor_type t = matrix_type{e[0],e[1]}; + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + }; + + for_each_tuple(extents,check); } 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,layout_type>; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size()==2); - if(e.empty()) - return; - - etensor_type t = vector_type(product(e)); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - BOOST_CHECK_NE ( t.data() , nullptr); - }; - - for_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::fixed_rank_tensor; + + assert(e.size()==2); + if(e.empty()) + return; + + etensor_type t = vector_type(product(e)); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + }; + + for_each_tuple(extents,check); } 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - auto t = etensor_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() , product(e) ); - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::fixed_rank_tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + 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_each_tuple(extents,check); } 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,layout_type>; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - auto t = etensor_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() , product(e) ); - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::fixed_rank_tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + 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_each_tuple(extents,check); } 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - auto t = etensor_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() , product(e) ); - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::fixed_rank_tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + 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_each_tuple(extents,check); } @@ -277,36 +267,36 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, te 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,layout_type>; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - auto t = etensor_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() , product(e) ); - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::fixed_rank_tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + 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_each_tuple(extents,check); } @@ -315,57 +305,57 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, te 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - auto t = etensor_type{}; - auto r = matrix_type(e[0],e[1]); - std::iota(r.data().begin(),r.data().end(), 1); - t = r + 3*r; - etensor_type s = r + 3*r; - etensor_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() , product(e) ); - 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() , product(e) ); - 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() , product(e) ); - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::fixed_rank_tensor; + + assert(e.size() == 2); + auto t = etensor_type{}; + auto r = matrix_type(e[0],e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r + 3*r; + etensor_type s = r + 3*r; + etensor_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() , product(e) ); + 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() , product(e) ); + 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() , product(e) ); + 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_each_tuple(extents,check); } @@ -375,108 +365,107 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_t 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,layout_type>; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - auto t = etensor_type{}; - auto r = vector_type(e[0]*e[1]); - std::iota(r.data().begin(),r.data().end(), 1); - t = r + 3*r; - etensor_type s = r + 3*r; - etensor_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() , product(e) ); - 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() , product(e) ); - 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() , product(e) ); - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::fixed_rank_tensor; + + assert(e.size() == 2); + auto t = etensor_type{}; + auto r = vector_type(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r + 3*r; + etensor_type s = r + 3*r; + etensor_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() , product(e) ); + 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() , product(e) ); + 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() , product(e) ); + 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_each_tuple(extents,check); } 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - if(product(e) <= 2) - return; - assert(e.size() == 2); - auto Q = etensor_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); - - etensor_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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::fixed_rank_tensor; + + if(product(e) <= 2) + return; + assert(e.size() == 2); + auto Q = etensor_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); + + etensor_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_each_tuple(extents,check); } BOOST_AUTO_TEST_SUITE_END() - diff --git a/test/tensor/test_functions.cpp b/test/tensor/test_functions.cpp index a328e94fa..1f1fab3f0 100644 --- a/test/tensor/test_functions.cpp +++ b/test/tensor/test_functions.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,12 +18,6 @@ #include #include -#ifndef BOOST_TEST_DYN_LINK -#define BOOST_TEST_DYN_LINK -#endif - -#define BOOST_TEST_MODULE TestTensorFunctions - #include #include "utility.hpp" @@ -39,45 +33,18 @@ using test_types = zip>::with_t; - template - using static_extents_type = boost::numeric::ublas::static_extents; - - template - using dynamic_rank_extents_type = boost::numeric::ublas::dynamic_extents; - fixture() - : extents { - dynamic_extents_type{1,1}, // 1 - dynamic_extents_type{2,3}, // 2 - dynamic_extents_type{2,3,1}, // 3 - dynamic_extents_type{4,2,3}, // 4 - dynamic_extents_type{4,2,3,5}} // 5 - { - } - - std::tuple< - static_extents_type<1,1>, // 1 - static_extents_type<2,3>, // 2 - static_extents_type<2,3,1>, // 3 - static_extents_type<4,2,3>, // 4 - static_extents_type<4,2,3,5> // 5 - > static_extents{}; - - std::tuple< - dynamic_rank_extents_type<2>, - dynamic_rank_extents_type<2>, - dynamic_rank_extents_type<3>, - dynamic_rank_extents_type<3>, - dynamic_rank_extents_type<4> - > dynamic_rank_extents{ - {1,1}, // 1 - {2,3}, // 2 - {2,3,1}, // 3 - {4,2,3}, // 4 - {4,2,3,5} // 5 - }; - - std::vector extents; + using dynamic_extents_type = boost::numeric::ublas::dynamic_extents<>; + fixture() + : extents { + dynamic_extents_type{1,1}, // 1 + dynamic_extents_type{2,3}, // 2 + dynamic_extents_type{2,3,1}, // 3 + dynamic_extents_type{4,2,3}, // 4 + dynamic_extents_type{4,2,3,5}} // 5 + { + } + + std::vector extents; }; @@ -85,28 +52,28 @@ struct fixture 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,layout_type>; - using vector_type = typename tensor_type::vector_type; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; - for(auto const& n : extents){ + for(auto const& n : extents){ - auto a = tensor_type(n, value_type{2}); + auto a = tensor_type(n, value_type{2}); - for(auto m = 0u; m < n.size(); ++m){ + for(auto m = 0u; m < n.size(); ++m){ - auto b = vector_type (n[m], value_type{1} ); + auto b = vector_type (n[m], value_type{1} ); - auto c = ublas::prod(a, b, m+1); + auto c = ublas::prod(a, b, m+1); - for(auto i = 0u; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(n[m]) ) * a[i] ); + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(n[m]) ) * a[i] ); - } - } + } + } auto n = extents[4]; auto a = tensor_type(n, value_type{2}); auto b = vector_type(n[0], value_type{1}); @@ -121,81 +88,29 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_vector, value, test_types, f } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - for_each_tuple(static_extents,[](auto const&, auto& n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::tensor; - using vector_type = typename tensor_type::vector_type; - auto a = tensor_type(extents_type{}, 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( static_cast< inner_type_t >(n[m]) ) * a[i]); - } - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_dynamic_rank_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; - - for_each_tuple(dynamic_rank_extents,[](auto const&, auto & n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::tensor; - using vector_type = typename tensor_type::vector_type; - 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( static_cast< inner_type_t >(n[m]) ) * a[i]); - } - }); - -} - - - BOOST_AUTO_TEST_CASE( test_tensor_prod_vector_exception ) { - using namespace boost::numeric; - using value_type = float; - using layout_type = ublas::first_order; - using d_extents_type = ublas::dynamic_extents<>; - using s_extents_type = ublas::static_extents<1,2,3>; - using d_tensor_type = ublas::tensor; - using s_tensor_type = ublas::tensor; - using vector_type = typename d_tensor_type::vector_type; - - auto t1 = d_tensor_type{d_extents_type{},1.f}; - auto v1 = vector_type{3,value_type{1}}; - - BOOST_REQUIRE_THROW(prod(t1,v1,0),std::length_error); - BOOST_REQUIRE_THROW(prod(t1,v1,1),std::length_error); - BOOST_REQUIRE_THROW(prod(t1,v1,3),std::length_error); - - auto t2 = s_tensor_type{}; - BOOST_REQUIRE_THROW(prod(t2,v1,2),std::length_error); - - auto t3 = s_tensor_type{s_extents_type{},value_type{1}}; - auto v2 = vector_type{0,value_type{1}}; - BOOST_REQUIRE_THROW(prod(t3,v2,2),std::length_error); + using namespace boost::numeric; + using value_type = float; + using layout_type = ublas::first_order; + using s_extents_type = ublas::static_extents<1,2,3>; + using d_tensor_type = ublas::dynamic_tensor; + using s_tensor_type = ublas::static_tensor; + using vector_type = typename d_tensor_type::vector_type; + + auto t1 = d_tensor_type{ublas::dynamic_extents<>{},1.f}; + auto v1 = vector_type{3,value_type{1}}; + + BOOST_REQUIRE_THROW(prod(t1,v1,0),std::length_error); + BOOST_REQUIRE_THROW(prod(t1,v1,1),std::length_error); + BOOST_REQUIRE_THROW(prod(t1,v1,3),std::length_error); + + auto t2 = s_tensor_type{}; + BOOST_REQUIRE_THROW(prod(t2,v1,2),std::length_error); + + auto t3 = s_tensor_type{value_type{1}}; + auto v2 = vector_type{0,value_type{1}}; + BOOST_REQUIRE_THROW(prod(t3,v2,2),std::length_error); } @@ -203,28 +118,28 @@ BOOST_AUTO_TEST_CASE( test_tensor_prod_vector_exception ) 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = tensor_type(n, value_type{2}); + auto a = tensor_type(n, value_type{2}); - for(auto m = 0u; m < n.size(); ++m){ + for(auto m = 0u; m < n.size(); ++m){ - auto b = matrix_type ( n[m], n[m], value_type{1} ); + auto b = matrix_type ( n[m], n[m], value_type{1} ); - auto c = ublas::prod(a, b, m+1); + auto c = ublas::prod(a, b, m+1); - for(auto i = 0u; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(n[m]) ) * a[i] ); + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(n[m]) ) * a[i] ); - } - } + } + } auto n = extents[4]; auto a = tensor_type(n, value_type{2}); @@ -239,379 +154,182 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_matrix, value, test_types, f BOOST_CHECK_THROW(prod(a, empty, 2), std::length_error); } - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - for_each_tuple(static_extents,[](auto const&, auto & n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::tensor; - using matrix_type = typename tensor_type::matrix_type; - auto a = tensor_type(extents_type{}, 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( static_cast< inner_type_t >(n[m]) ) * a[i]); - } - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_dynamic_rank_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; - - for_each_tuple(dynamic_rank_extents,[](auto const&, auto & n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::tensor; - using matrix_type = typename tensor_type::matrix_type; - 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( static_cast< inner_type_t >(n[m]) ) * a[i]); - } - }); - -} - - BOOST_AUTO_TEST_CASE( test_tensor_prod_matrix_exception ) { - using namespace boost::numeric; - using value_type = float; - using layout_type = ublas::first_order; - using d_extents_type = ublas::dynamic_extents<>; - using s_extents_type = ublas::static_extents<1,2,3>; - using d_tensor_type = ublas::tensor; - using s_tensor_type = ublas::tensor; - using matrix_type = typename d_tensor_type::matrix_type; + using namespace boost::numeric; + using value_type = float; + using layout_type = ublas::first_order; + using d_extents_type = ublas::dynamic_extents<>; + using s_extents_type = ublas::static_extents<1,2,3>; + using d_tensor_type = ublas::dynamic_tensor; + using s_tensor_type = ublas::static_tensor; + using matrix_type = typename d_tensor_type::matrix_type; - auto t1 = d_tensor_type{d_extents_type{},1.f}; - auto m1 = matrix_type{3,3,value_type{1}}; + auto t1 = d_tensor_type{d_extents_type{},1.f}; + auto m1 = matrix_type{3,3,value_type{1}}; - BOOST_REQUIRE_THROW(prod(t1,m1,0),std::length_error); - BOOST_REQUIRE_THROW(prod(t1,m1,1),std::length_error); - BOOST_REQUIRE_THROW(prod(t1,m1,3),std::length_error); + BOOST_REQUIRE_THROW(prod(t1,m1,0),std::length_error); + BOOST_REQUIRE_THROW(prod(t1,m1,1),std::length_error); + BOOST_REQUIRE_THROW(prod(t1,m1,3),std::length_error); - auto t2 = s_tensor_type{}; + auto t2 = s_tensor_type{}; - BOOST_REQUIRE_THROW(prod(t2,m1,2),std::length_error); + BOOST_REQUIRE_THROW(prod(t2,m1,2),std::length_error); - auto t3 = s_tensor_type{s_extents_type{},value_type{1}}; - auto m2 = matrix_type{0,0,value_type{1}}; - BOOST_REQUIRE_THROW(prod(t3,m2,2),std::length_error); + auto t3 = s_tensor_type{value_type{1}}; + auto m2 = matrix_type{0,0,value_type{1}}; + BOOST_REQUIRE_THROW(prod(t3,m2,2),std::length_error); } 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,layout_type>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; - // left-hand and right-hand side have the - // the same number of elements + // left-hand and right-hand side have the + // the same number of elements - for(auto const& na : extents) { + for(auto const& na : extents) { - auto a = tensor_type( na, value_type{2} ); - auto b = tensor_type( na, value_type{3} ); + auto a = tensor_type( na, value_type{2} ); + auto b = tensor_type( na, value_type{3} ); - auto const pa = a.rank(); + auto const pa = a.rank(); - // the number of contractions is changed. - for( auto q = 0ul; q <= pa; ++q) { // pa + // the number of contractions is changed. + for( auto q = 0ul; q <= pa; ++q) { // pa - auto phi = std::vector ( q ); + auto phi = std::vector ( q ); - std::iota(phi.begin(), phi.end(), 1ul); + std::iota(phi.begin(), phi.end(), 1ul); - auto c = ublas::prod(a, b, phi); + auto c = ublas::prod(a, b, phi); - auto acc = value_type(1); - for(auto i = 0ul; i < q; ++i) - acc *= value_type( static_cast< inner_type_t >( a.extents().at(phi.at(i)-1) ) ); + auto acc = value_type(1); + for(auto i = 0ul; i < q; ++i) + acc *= value_type( static_cast< inner_type_t >( 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] ); + for(auto i = 0ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); - } - } + } + } } - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - auto const body = [](auto const& a, auto const& b){ - auto const pa = a.rank(); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phi = std::vector(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 *= value_type( static_cast< inner_type_t >( 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]); - } - }; - - - //static extents and static_extents - for_each_tuple(static_extents,[&](auto const&, auto & n){ - auto n1 = n; - auto n2 = n; - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = - ublas::tensor; - using tensor_type_2 = - ublas::tensor; - auto a = tensor_type_1(n1, value_type{2}); - auto b = tensor_type_2(n2, value_type{3}); - body(a,b); - }); - - for_each_tuple(static_extents,[&](auto const& I, auto & n){ - auto n1 = n; - auto n2 = extents[I]; - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = - ublas::tensor; - using tensor_type_2 = - ublas::tensor; - auto a = tensor_type_1(n1, value_type{2}); - auto b = tensor_type_2(n2, value_type{3}); - body(a,b); - }); - - for_each_tuple(static_extents,[&](auto const& I, auto & n){ - auto n1 = extents[I]; - auto n2 = n; - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = - ublas::tensor; - using tensor_type_2 = - ublas::tensor; - auto a = tensor_type_1(n1, value_type{2}); - auto b = tensor_type_2(n2, value_type{3}); - body(a,b); - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_dynamic_rank_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; - - auto const body = [](auto const& a, auto const& b){ - auto const pa = a.rank(); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phi = std::vector(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 *= value_type( static_cast< inner_type_t >( 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]); - } - }; - - - - for_each_tuple(dynamic_rank_extents,[&](auto const&, auto & n){ - auto n1 = n; - auto n2 = n; - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = - ublas::tensor; - using tensor_type_2 = - ublas::tensor; - auto a = tensor_type_1(n1, value_type{2}); - auto b = tensor_type_2(n2, value_type{3}); - body(a,b); - }); - - for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto & n){ - auto n1 = n; - auto n2 = extents[I]; - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = - ublas::tensor; - using tensor_type_2 = - ublas::tensor; - auto a = tensor_type_1(n1, value_type{2}); - auto b = tensor_type_2(n2, value_type{3}); - body(a,b); - }); - - for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto & n){ - auto n1 = extents[I]; - auto n2 = n; - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = - ublas::tensor; - using tensor_type_2 = - ublas::tensor; - auto a = tensor_type_1(n1, value_type{2}); - auto b = tensor_type_2(n2, value_type{3}); - body(a,b); - }); - -} - - - BOOST_AUTO_TEST_CASE( test_tensor_prod_tensor_1_exception ) { - using namespace boost::numeric; - using value_type = float; - using layout_type = ublas::first_order; - using d_extents_type = ublas::dynamic_extents<>; - using s_extents_type = ublas::static_extents<1,2,3>; - using d_tensor_type = ublas::tensor; - using s_tensor_type = ublas::tensor; + using namespace boost::numeric; + using value_type = float; + using layout_type = ublas::first_order; + using d_extents_type = ublas::dynamic_extents<>; + using s_extents_type = ublas::static_extents<1,2,3>; + using d_tensor_type = ublas::dynamic_tensor; + using s_tensor_type = ublas::static_tensor; - auto t1 = d_tensor_type{}; - auto t2 = s_tensor_type{s_extents_type{},1.f}; - std::vector phia = {1,2,3}; - std::vector phib = {1,2,3,4,5}; + auto t1 = d_tensor_type{}; + auto t2 = s_tensor_type{1.f}; + std::vector phia = {1,2,3}; + std::vector phib = {1,2,3,4,5}; - BOOST_REQUIRE_THROW(prod(t1,t2,phia,phib),std::runtime_error); - BOOST_REQUIRE_THROW(prod(t2,t1,phia,phib),std::runtime_error); + BOOST_REQUIRE_THROW(prod(t1,t2,phia,phib),std::runtime_error); + BOOST_REQUIRE_THROW(prod(t2,t1,phia,phib),std::runtime_error); - auto t3 = d_tensor_type{d_extents_type{1,2},1.f}; - auto t4 = d_tensor_type{d_extents_type{1,2},1.f}; - BOOST_REQUIRE_THROW(prod(t3,t4,phia,phib),std::runtime_error); + auto t3 = d_tensor_type{d_extents_type{1,2},1.f}; + auto t4 = d_tensor_type{d_extents_type{1,2},1.f}; + BOOST_REQUIRE_THROW(prod(t3,t4,phia,phib),std::runtime_error); - auto t5 = d_tensor_type{d_extents_type{1,2,3,4},1.f}; - auto t6 = d_tensor_type{d_extents_type{1,2},1.f}; - BOOST_REQUIRE_THROW(prod(t5,t6,phia,phib),std::runtime_error); + auto t5 = d_tensor_type{d_extents_type{1,2,3,4},1.f}; + auto t6 = d_tensor_type{d_extents_type{1,2},1.f}; + BOOST_REQUIRE_THROW(prod(t5,t6,phia,phib),std::runtime_error); - auto t7 = d_tensor_type{d_extents_type{1,2,3,4,5},1.f}; - auto t8 = d_tensor_type{d_extents_type{1,2,3,4,5},1.f}; - BOOST_REQUIRE_THROW(prod(t7,t8,phia,phib),std::runtime_error); + auto t7 = d_tensor_type{d_extents_type{1,2,3,4,5},1.f}; + auto t8 = d_tensor_type{d_extents_type{1,2,3,4,5},1.f}; + BOOST_REQUIRE_THROW(prod(t7,t8,phia,phib),std::runtime_error); - std::vector phia_2 = {1,2,3,5,4}; - std::vector phib_2 = {1,2,3,4,5}; - auto t9 = d_tensor_type{d_extents_type{1,2,3,4,5,6},1.f}; - auto t10 = d_tensor_type{d_extents_type{1,2,3,4,5,6},1.f}; - BOOST_REQUIRE_THROW(prod(t9,t10,phia_2,phib_2),std::runtime_error); + std::vector phia_2 = {1,2,3,5,4}; + std::vector phib_2 = {1,2,3,4,5}; + auto t9 = d_tensor_type{d_extents_type{1,2,3,4,5,6},1.f}; + auto t10 = d_tensor_type{d_extents_type{1,2,3,4,5,6},1.f}; + BOOST_REQUIRE_THROW(prod(t9,t10,phia_2,phib_2),std::runtime_error); } 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,layout_type>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; - auto compute_factorial = [](auto const& p){ - auto f = 1ul; - for(auto i = 1u; i <= p; ++i) - f *= i; - return f; - }; + 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; - }; + 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 + // left-hand and right-hand side have the + // the same number of elements - for(auto const& na : extents) { + for(auto const& na : extents) { - auto a = tensor_type( na, value_type{2} ); - auto const pa = a.rank(); + auto a = tensor_type( na, value_type{2} ); + auto const pa = a.rank(); - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota( pi.begin(), pi.end(), 1 ); + auto pi = std::vector(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} ); + 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 + // the number of contractions is changed. + for( auto q = 0ul; q <= pa; ++q) { // pa - auto phia = std::vector ( q ); // concatenation for a - auto phib = std::vector ( q ); // concatenation for b + auto phia = std::vector ( q ); // concatenation for a + auto phib = std::vector ( 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); } ); + 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 c = ublas::prod(a, b, phia, phib); - auto acc = value_type(1); - for(auto i = 0ul; i < q; ++i) - acc *= value_type( static_cast< inner_type_t >( a.extents().at(phia.at(i)-1) ) ); + auto acc = value_type(1); + for(auto i = 0ul; i < q; ++i) + acc *= value_type( static_cast< inner_type_t >( 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] ); + 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()); - } - } + std::next_permutation(pi.begin(), pi.end()); + } + } - auto phia = std::vector(3); - auto sphia = std::vector(2); + auto phia = std::vector(3); + auto sphia = std::vector(2); - BOOST_CHECK_THROW(ublas::prod(tensor_type{}, tensor_type({2,1,2}), phia, phia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type{}, tensor_type({2,1,2}), phia, phia), std::runtime_error); BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2,3}), tensor_type(), phia, phia), std::runtime_error); BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2,4}), tensor_type({2,1}), phia, phia), std::runtime_error); BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2}), tensor_type({2,1,2}), phia, phia), std::runtime_error); @@ -621,351 +339,25 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_2, value, test_types, } - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - - - auto compute_factorial = [](auto const& p){ - auto f = 1ul; - for(auto i = 1u; i <= p; ++i) - f *= i; - return f; - }; - - auto permute_extents_d = [](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; - }; - - auto permute_extents_s_1 = [](auto const& pi, auto const& na){ - auto nb = na.to_dynamic_extents(); - assert(pi.size() == na.size()); - for(auto j = 0u; j < pi.size(); ++j) - nb[pi[j]-1] = na[j]; - return nb; - }; - auto permute_extents_s_2 = [](auto const& pi, auto const& na){ - auto tempn = na.base(); - assert(pi.size() == na.size()); - for(auto j = 0u; j < pi.size(); ++j) - tempn[pi[j]-1] = na[j]; - return ublas::dynamic_extents::type::_size>(tempn.begin(),tempn.end()); - }; - -// static and dynamic - for_each_tuple(static_extents,[&](auto const&, auto & n){ - auto na = n; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(na, value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_s_1(pi, na); - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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 *= value_type( static_cast< inner_type_t >( 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()); - } - }); - - //dynamic and static - for_each_tuple(static_extents,[&](auto const& I, auto & n){ - auto na = extents[I]; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(na, value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_d(pi, na); - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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 *= value_type( static_cast< inner_type_t >( 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()); - } - }); - //static and static - for_each_tuple(static_extents,[&](auto const&, auto & n){ - auto na = n; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(na, value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_s_2(pi, na); - - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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_dynamic_rank_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; - - - - auto compute_factorial = [](auto const& p){ - auto f = 1ul; - for(auto i = 1u; i <= p; ++i) - f *= i; - return f; - }; - - auto permute_extents_d = [](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; - }; - - auto permute_extents_s_1 = [](auto const& pi, auto const& na){ - auto nb = na.to_dynamic_extents(); - assert(pi.size() == na.size()); - for(auto j = 0u; j < pi.size(); ++j) - nb[pi[j]-1] = na[j]; - return nb; - }; - auto permute_extents_s_2 = [](auto const& pi, auto const& na){ - auto tempn = na.base(); - assert(pi.size() == na.size()); - for(auto j = 0u; j < pi.size(); ++j) - tempn[pi[j]-1] = na[j]; - return ublas::dynamic_extents::type::_size>(tempn.begin(),tempn.end()); - }; - - for_each_tuple(dynamic_rank_extents,[&](auto const&, auto & n){ - auto na = n; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(na, value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_s_1(pi, na); - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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 *= value_type( static_cast< inner_type_t >( 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()); - } - }); - - for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto & n){ - auto na = extents[I]; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(na, value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_d(pi, na); - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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 *= value_type( static_cast< inner_type_t >( 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()); - } - }); - - for_each_tuple(dynamic_rank_extents,[&](auto const&, auto & n){ - auto na = n; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(na, value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_s_2(pi, na); - - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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 *= value_type( static_cast< inner_type_t >( 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,layout_type>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = tensor_type(n, value_type(2)); - auto b = tensor_type(n, value_type(1)); + 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)); + 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_CHECK_EQUAL( c , r ); - } + } BOOST_CHECK_THROW(ublas::inner_prod(tensor_type({1,2,3}), tensor_type({1,2,3,4})), std::length_error); // rank different BOOST_CHECK_THROW(ublas::inner_prod(tensor_type(), tensor_type()), std::length_error); //empty tensor BOOST_CHECK_THROW(ublas::inner_prod(tensor_type({1,2,3}), tensor_type({3,2,1})), std::length_error); // different extent @@ -974,222 +366,123 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_inner_prod, value, test_types, fi BOOST_AUTO_TEST_CASE( test_tensor_inner_prod_exception ) { - using namespace boost::numeric; - using value_type = float; - using layout_type = ublas::first_order; - using d_extents_type = ublas::dynamic_extents<>; - using s_extents_type = ublas::static_extents<1,2,3>; - using d_tensor_type = ublas::tensor; - using s_tensor_type = ublas::tensor; - - auto t1 = d_tensor_type{d_extents_type{1,2},1.f}; - auto t2 = d_tensor_type{d_extents_type{1,2,3},1.f}; - BOOST_REQUIRE_THROW( ublas::inner_prod(t1, t2), std::length_error); - - auto t3 = s_tensor_type{s_extents_type{},1.f}; - auto t4 = d_tensor_type{d_extents_type{1,2,4,5},1.f}; - BOOST_REQUIRE_THROW( ublas::inner_prod(t3, t4), std::length_error); -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - auto const body = [&](auto const& a, auto const& b){ - 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 ); - }; - - for_each_tuple(static_extents,[&](auto const&, auto & n){ - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - using tensor_type_2 = ublas::tensor; - auto a = tensor_type_1(n, value_type(2)); - auto b = tensor_type_2(n, value_type(1)); - body(a,b); - - }); - - for_each_tuple(static_extents,[&](auto const& I, auto & n){ - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - using tensor_type_2 = ublas::tensor; - auto a = tensor_type_1(n, value_type(2)); - auto b = tensor_type_2(extents[I], value_type(1)); - body(a,b); - - }); - - for_each_tuple(static_extents,[&](auto const& I, auto & n){ - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - using tensor_type_2 = ublas::tensor; - auto a = tensor_type_1(extents[I], value_type(2)); - auto b = tensor_type_2(n, value_type(1)); - body(a,b); - - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_dynamic_rank_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; - - auto const body = [&](auto const& a, auto const& b){ - 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 ); - }; - - for_each_tuple(dynamic_rank_extents,[&](auto const&, auto & n){ - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - using tensor_type_2 = ublas::tensor; - auto a = tensor_type_1(n, value_type(2)); - auto b = tensor_type_2(n, value_type(1)); - body(a,b); - - }); - - for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto & n){ - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - using tensor_type_2 = ublas::tensor; - auto a = tensor_type_1(n, value_type(2)); - auto b = tensor_type_2(extents[I], value_type(1)); - body(a,b); - - }); - - for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto & n){ - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - using tensor_type_2 = ublas::tensor; - auto a = tensor_type_1(extents[I], value_type(2)); - auto b = tensor_type_2(n, value_type(1)); - body(a,b); - - }); - + using namespace boost::numeric; + using value_type = float; + using layout_type = ublas::first_order; + using d_extents_type = ublas::dynamic_extents<>; + using s_extents_type = ublas::static_extents<1,2,3>; + using d_tensor_type = ublas::dynamic_tensor; + using s_tensor_type = ublas::static_tensor; + + auto t1 = d_tensor_type{d_extents_type{1,2},1.f}; + auto t2 = d_tensor_type{d_extents_type{1,2,3},1.f}; + BOOST_REQUIRE_THROW( ublas::inner_prod(t1, t2), std::length_error); + + auto t3 = s_tensor_type{1.f}; + auto t4 = d_tensor_type{d_extents_type{1,2,4,5},1.f}; + BOOST_REQUIRE_THROW( ublas::inner_prod(t3, t4), std::length_error); } - 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,layout_type>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = tensor_type(n); + auto a = tensor_type(n); - auto one = value_type(1); - auto v = one; - for(auto& aa: a) - aa = v, v += one; + 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 c = ublas::inner_prod(a, a); + auto r = std::inner_product(a.begin(),a.end(), a.begin(),value_type(0)); - tensor_type var = (a+a)/2.0f; // std::complex/int not allowed as expression is captured - auto r2 = ublas::norm( var ); + tensor_type var = (a+a)/2.0f; // std::complex/int not allowed as expression is captured + auto r2 = ublas::norm( var ); - BOOST_CHECK_THROW(ublas::norm(tensor_type{}), std::runtime_error); + BOOST_CHECK_THROW(ublas::norm(tensor_type{}), std::runtime_error); - BOOST_CHECK_EQUAL( c , r ); - BOOST_CHECK_EQUAL( std::sqrt( c ) , r2 ); + 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; - using layout_type = ublas::first_order; + using namespace boost::numeric; + using value_type = float; + using complex_type = std::complex; + using layout_type = ublas::first_order; - using tensor_complex_type = ublas::tensor,layout_type>; - using tensor_type = ublas::tensor,layout_type>; + using tensor_complex_type = ublas::dynamic_tensor; + using tensor_type = ublas::dynamic_tensor; - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = tensor_type(n); - auto r0 = tensor_type(n); - auto r00 = tensor_complex_type(n); + 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; + 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( (bool) (r0 == r1) ); + 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( (bool) (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( (bool) (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( (bool) (r00 == r3) ); + 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( (bool) (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( (bool) (r00 == r3) ); - } + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = tensor_complex_type(n); + auto a = tensor_complex_type(n); - auto r00 = tensor_complex_type(n); - auto r0 = tensor_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; + 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_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( (bool) (r0 == r1) ); + 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( (bool) (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( (bool) (r0 == r2) ); + 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( (bool) (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( (bool) (r00 == r3) ); + 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( (bool) (r00 == r3) ); - } + } @@ -1198,275 +491,99 @@ BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) 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,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] ); - } - } -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - for_each_tuple(static_extents,[&](auto const&, auto const& n1){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(n1, value_type(2)); - for_each_tuple(static_extents,[&](auto const& J, auto const& n2){ - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(n2, value_type(1)); - auto c = ublas::outer_prod(a, b); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - - }); - - }); - - for_each_tuple(static_extents,[&](auto const& I, auto const& n1){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(extents[I], value_type(2)); - for_each_tuple(static_extents,[&](auto const& J, auto const& n2){ - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(n2, value_type(1)); - auto c = ublas::outer_prod(a, b); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - }); - - }); - - for_each_tuple(static_extents,[&](auto const&, auto const& n1){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(n1, value_type(2)); - for(auto n2 : extents){ - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(n2, value_type(1)); - auto c = ublas::outer_prod(a, b); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - } - - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_dynamic_rank_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; - - for_each_tuple(static_extents,[&](auto const&, auto const& n1){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(n1, value_type(2)); - for_each_tuple(static_extents,[&](auto const& J, auto const& n2){ - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(n2, value_type(1)); - auto c = ublas::outer_prod(a, b); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - - }); - - }); - - for_each_tuple(dynamic_rank_extents,[&](auto const& I, auto const& n1){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(extents[I], value_type(2)); - for_each_tuple(dynamic_rank_extents,[&](auto const& J, auto const& n2){ - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(n2, value_type(1)); - auto c = ublas::outer_prod(a, b); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - }); - - }); - - for_each_tuple(dynamic_rank_extents,[&](auto const&, auto const& n1){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::tensor; - auto a = tensor_type_1(n1, value_type(2)); - for(auto n2 : extents){ - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::tensor; - auto b = tensor_type_2(n2, value_type(1)); - auto c = ublas::outer_prod(a, b); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - } - - }); - + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + 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 void init(std::vector& a) { - auto v = V(1); - for(auto i = 0u; i < a.size(); ++i, ++v){ - a[i] = v; - } + auto v = V(1); + for(auto i = 0u; i < a.size(); ++i, ++v){ + a[i] = v; + } } template void init(std::vector>& a) { - auto v = std::complex(1,1); - for(auto i = 0u; i < a.size(); ++i){ - a[i] = v; - v.real(v.real()+1); - v.imag(v.imag()+1); - } + auto v = std::complex(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,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 = product(n); - 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(p); - std::iota(pi.begin(), pi.end(), 1); - a = ublas::trans( a, pi ); - bool res1 = a == aref; - BOOST_CHECK( res1 ); - - - 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 ); - } + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + 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 = product(n); + 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(p); + std::iota(pi.begin(), pi.end(), 1); + a = ublas::trans( a, pi ); + bool res1 = a == aref; + BOOST_CHECK( res1 ); + + + 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 ); + } bool res2 = a == aref; // it was an expression. so evaluate into bool - BOOST_CHECK( res2 ); - - } -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_trans, value, test_types, fixture ) -{ - using namespace boost::numeric; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto fac = [](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_each_tuple(static_extents,[&](auto const&, auto & n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::tensor; - auto const p = n.size(); - auto const s = product(n); - auto aref = tensor_type(n); - auto v = value_type{}; - for(auto i = 0u; i < s; ++i, v+=1) - aref[i] = v; - - auto pi = std::vector(p); - std::iota(pi.begin(), pi.end(), 1); - - auto a = ublas::trans( aref, pi ); - - for(auto i = 0ul; i < a.size(); i++){ - BOOST_CHECK( a[i] == aref[i] ); - } - - - auto const pfac = fac(p); - auto i = 0u; - for(; i < pfac-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 ); - } - - for(auto j = 0ul; j < a.size(); j++){ - BOOST_CHECK( a[j] == aref[j] ); - } - }); + BOOST_CHECK( res2 ); + } } BOOST_AUTO_TEST_SUITE_END() - diff --git a/test/tensor/test_multi_index.cpp b/test/tensor/test_multi_index.cpp index 59f82dc10..6665e980d 100644 --- a/test/tensor/test_multi_index.cpp +++ b/test/tensor/test_multi_index.cpp @@ -29,118 +29,117 @@ using test_types = zip>::with_t ind(_a, _b); + { + multi_index<2> ind(_a, _b); - BOOST_CHECK_EQUAL ( get<0>( ind ), 1 ) ; - BOOST_CHECK_EQUAL ( get<1>( ind ), 2 ) ; - } + BOOST_CHECK_EQUAL ( get<0>( ind ), 1 ) ; + BOOST_CHECK_EQUAL ( get<1>( ind ), 2 ) ; + } - { - multi_index<2> ind(_d,_c); + { + multi_index<2> ind(_d,_c); - BOOST_CHECK_EQUAL ( ind[0] , 4 ) ; - BOOST_CHECK_EQUAL ( ind[1] , 3 ) ; - } + 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,layout_type>; + using namespace boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = dynamic_tensor; - auto t = std::make_tuple ( - index::_a, // 0 - index::_b, // 1 - index::_c, // 2 - index::_d, // 3 - index::_e // 4 - ); + auto t = std::make_tuple ( + index::_a, // 0 + index::_b, // 1 + index::_c, // 2 + index::_d, // 3 + index::_e // 4 + ); - { - auto a = tensor_type(dynamic_extents<>{2,3}, value_type{2}); - auto a_ind = a( std::get<0>(t), std::get<2>(t) ); + { + auto a = tensor_type(dynamic_extents<>{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::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() ) ; - } + 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(dynamic_extents<>{2,3}, value_type{2}); - auto a_ind = a( std::get<2>(t), std::get<0>(t) ); + { + auto a = tensor_type(dynamic_extents<>{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::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() ) ; - } + 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(dynamic_extents<>{2,3}, value_type{2}); - auto a_ind = a( std::get<2>(t), std::get<3>(t) ); + { + auto a = tensor_type(dynamic_extents<>{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::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<0>(a_ind.second)(), index::_c() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), index::_d() ) ; + } - { - auto a = tensor_type(dynamic_extents<>{2,3,4}, value_type{2}); - auto a_ind = a( std::get<2>(t), std::get<3>(t), std::get<0>(t) ); + { + auto a = tensor_type(dynamic_extents<>{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::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_CHECK_EQUAL (std::get<0>(a_ind.second)(), index::_c() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), index::_d() ) ; + BOOST_CHECK_EQUAL (std::get<2>(a_ind.second)(), index::_a() ) ; + } } BOOST_AUTO_TEST_SUITE_END() - diff --git a/test/tensor/test_multi_index_utility.cpp b/test/tensor/test_multi_index_utility.cpp index 2f31a58f2..a4ed17e1c 100644 --- a/test/tensor/test_multi_index_utility.cpp +++ b/test/tensor/test_multi_index_utility.cpp @@ -19,98 +19,98 @@ 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::value; - constexpr auto has_b = has_index::value; - BOOST_CHECK( !has_a ); - BOOST_CHECK( !has_b ); - } - - - { - constexpr auto tuple = std::make_tuple(_a); - constexpr auto has_a = has_index::value; - constexpr auto has_b = has_index::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::value; - constexpr auto has_b = has_index::value; - constexpr auto has_c = has_index::value; - constexpr auto has_d = has_index::value; - constexpr auto has_e = has_index::value; - constexpr auto has__ = has_index::value; - BOOST_CHECK( has_a ); - BOOST_CHECK( has_b ); - BOOST_CHECK( has_c ); - BOOST_CHECK( has_d ); - BOOST_CHECK( !has_e ); - BOOST_CHECK( has__ ); - } + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + { + constexpr auto tuple = std::tuple<>{}; + constexpr auto has_a = has_index::value; + constexpr auto has_b = has_index::value; + BOOST_CHECK( !has_a ); + BOOST_CHECK( !has_b ); + } + + + { + constexpr auto tuple = std::make_tuple(_a); + constexpr auto has_a = has_index::value; + constexpr auto has_b = has_index::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::value; + constexpr auto has_b = has_index::value; + constexpr auto has_c = has_index::value; + constexpr auto has_d = has_index::value; + constexpr auto has_e = has_index::value; + constexpr auto has__ = has_index::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::value; - BOOST_CHECK( valid ); - } - - - { - constexpr auto tuple = std::make_tuple(_a); - constexpr auto valid = valid_multi_index::value; - BOOST_CHECK( valid ); - } - - { - constexpr auto tuple = std::make_tuple(_a,_,_b); - constexpr auto valid = valid_multi_index::value; - BOOST_CHECK( valid ); - } - - { - constexpr auto tuple = std::make_tuple(_a,_,_b,_b); - constexpr auto valid = valid_multi_index::value; - BOOST_CHECK( !valid ); - } - - { - constexpr auto tuple = std::make_tuple(_c,_a,_,_b,_b); - constexpr auto valid = valid_multi_index::value; - BOOST_CHECK( !valid ); - } - - { - constexpr auto tuple = std::make_tuple(_c,_a,_,_b); - constexpr auto valid = valid_multi_index::value; - BOOST_CHECK( valid ); - } - - { - constexpr auto tuple = std::make_tuple(_,_c,_a,_,_b); - constexpr auto valid = valid_multi_index::value; - BOOST_CHECK( valid ); - } - - { - constexpr auto tuple = std::make_tuple(_,_c,_a,_,_b,_); - constexpr auto valid = valid_multi_index::value; - BOOST_CHECK( valid ); - } + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + { + constexpr auto tuple = std::tuple<>{}; + constexpr auto valid = valid_multi_index::value; + BOOST_CHECK( valid ); + } + + + { + constexpr auto tuple = std::make_tuple(_a); + constexpr auto valid = valid_multi_index::value; + BOOST_CHECK( valid ); + } + + { + constexpr auto tuple = std::make_tuple(_a,_,_b); + constexpr auto valid = valid_multi_index::value; + BOOST_CHECK( valid ); + } + + { + constexpr auto tuple = std::make_tuple(_a,_,_b,_b); + constexpr auto valid = valid_multi_index::value; + BOOST_CHECK( !valid ); + } + + { + constexpr auto tuple = std::make_tuple(_c,_a,_,_b,_b); + constexpr auto valid = valid_multi_index::value; + BOOST_CHECK( !valid ); + } + + { + constexpr auto tuple = std::make_tuple(_c,_a,_,_b); + constexpr auto valid = valid_multi_index::value; + BOOST_CHECK( valid ); + } + + { + constexpr auto tuple = std::make_tuple(_,_c,_a,_,_b); + constexpr auto valid = valid_multi_index::value; + BOOST_CHECK( valid ); + } + + { + constexpr auto tuple = std::make_tuple(_,_c,_a,_,_b,_); + constexpr auto valid = valid_multi_index::value; + BOOST_CHECK( valid ); + } } @@ -119,138 +119,138 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_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::value; - BOOST_CHECK_EQUAL( num, 0 ); - } - - { - constexpr auto lhs = std::make_tuple(_a); - constexpr auto rhs = std::tuple<>{}; - constexpr auto num = number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 0 ); - } - - { - constexpr auto lhs = std::tuple<>{}; - constexpr auto rhs = std::make_tuple(_a); - constexpr auto num = number_equal_indexes::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::value; - BOOST_CHECK_EQUAL( num, 1 ); - } + 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::value; + BOOST_CHECK_EQUAL( num, 0 ); + } + + { + constexpr auto lhs = std::make_tuple(_a); + constexpr auto rhs = std::tuple<>{}; + constexpr auto num = number_equal_indexes::value; + BOOST_CHECK_EQUAL( num, 0 ); + } + + { + constexpr auto lhs = std::tuple<>{}; + constexpr auto rhs = std::make_tuple(_a); + constexpr auto num = number_equal_indexes::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::value; + BOOST_CHECK_EQUAL( num, 1 ); + } } @@ -261,71 +261,71 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_number_equal_indices ) 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::value; - BOOST_CHECK_EQUAL(ind,0); - } - - { - constexpr auto tuple = std::make_tuple(_); - constexpr auto ind = index_position::value; - BOOST_CHECK_EQUAL(ind,0); - } - - { - constexpr auto tuple = std::make_tuple(_); - constexpr auto ind = index_position::value; - BOOST_CHECK_EQUAL(ind,1); - } - - { - constexpr auto tuple = std::make_tuple(_,_a); - constexpr auto ind = index_position::value; - BOOST_CHECK_EQUAL(ind,0); - } - - { - constexpr auto tuple = std::make_tuple(_,_a); - constexpr auto ind = index_position::value; - BOOST_CHECK_EQUAL(ind,1); - } - - { - constexpr auto tuple = std::make_tuple(_,_a); - constexpr auto ind = index_position::value; - BOOST_CHECK_EQUAL(ind,2); - } - - - - - { - constexpr auto tuple = std::make_tuple(_c,_,_a); - constexpr auto ind = index_position::value; - BOOST_CHECK_EQUAL(ind,0); - } - - { - constexpr auto tuple = std::make_tuple(_c,_,_a,_); - constexpr auto ind = index_position::value; - BOOST_CHECK_EQUAL(ind,1); - } - - { - constexpr auto tuple = std::make_tuple(_c,_,_a); - constexpr auto ind = index_position::value; - BOOST_CHECK_EQUAL(ind,2); - } - - { - constexpr auto tuple = std::make_tuple(_c,_,_a); - constexpr auto ind = index_position::value; - BOOST_CHECK_EQUAL(ind,3); - } + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + { + constexpr auto tuple = std::tuple<>{}; + constexpr auto ind = index_position::value; + BOOST_CHECK_EQUAL(ind,0); + } + + { + constexpr auto tuple = std::make_tuple(_); + constexpr auto ind = index_position::value; + BOOST_CHECK_EQUAL(ind,0); + } + + { + constexpr auto tuple = std::make_tuple(_); + constexpr auto ind = index_position::value; + BOOST_CHECK_EQUAL(ind,1); + } + + { + constexpr auto tuple = std::make_tuple(_,_a); + constexpr auto ind = index_position::value; + BOOST_CHECK_EQUAL(ind,0); + } + + { + constexpr auto tuple = std::make_tuple(_,_a); + constexpr auto ind = index_position::value; + BOOST_CHECK_EQUAL(ind,1); + } + + { + constexpr auto tuple = std::make_tuple(_,_a); + constexpr auto ind = index_position::value; + BOOST_CHECK_EQUAL(ind,2); + } + + + + + { + constexpr auto tuple = std::make_tuple(_c,_,_a); + constexpr auto ind = index_position::value; + BOOST_CHECK_EQUAL(ind,0); + } + + { + constexpr auto tuple = std::make_tuple(_c,_,_a,_); + constexpr auto ind = index_position::value; + BOOST_CHECK_EQUAL(ind,1); + } + + { + constexpr auto tuple = std::make_tuple(_c,_,_a); + constexpr auto ind = index_position::value; + BOOST_CHECK_EQUAL(ind,2); + } + + { + constexpr auto tuple = std::make_tuple(_c,_,_a); + constexpr auto ind = index_position::value; + BOOST_CHECK_EQUAL(ind,3); + } } @@ -338,227 +338,226 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position ) 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 ); - } + 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)); + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + auto check = [](auto const& lhs, auto const& rhs) + { + auto array = index_position_pairs(lhs, rhs); + + auto vector_pair = array_to_vector( array ); + + BOOST_CHECK_EQUAL(vector_pair.first .size(), array.size() ); + BOOST_CHECK_EQUAL(vector_pair.second.size(), array.size() ); + + for(auto i = 0ul; i < array.size(); ++i) + { + BOOST_CHECK_EQUAL(vector_pair.first [i], array[i].first +1 ); + BOOST_CHECK_EQUAL(vector_pair.second[i], array[i].second+1 ); + } + + }; + + check(std::tuple<>{} , std::tuple<>{}); + check(std::make_tuple(_a) , std::tuple<>{}); + check(std::tuple<>{} , std::make_tuple(_a)); + check(std::make_tuple(_a) , std::make_tuple(_b)); + check(std::make_tuple(_a) , std::make_tuple(_a)); + check(std::make_tuple(_a,_b), std::make_tuple(_a)); + check(std::make_tuple(_a) , std::make_tuple(_a,_b)); + check(std::make_tuple(_a,_b), std::make_tuple(_a,_b)); + check(std::make_tuple(_b,_a), std::make_tuple(_a,_b)); + check(std::make_tuple(_b,_a,_c), std::make_tuple(_a,_b,_d)); } BOOST_AUTO_TEST_SUITE_END() - diff --git a/test/tensor/test_multiplication.cpp b/test/tensor/test_multiplication.cpp index b2249f136..13093b1af 100644 --- a/test/tensor/test_multiplication.cpp +++ b/test/tensor/test_multiplication.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -16,7 +16,9 @@ #include #include -#include +#include +#include +#include #include #include "utility.hpp" @@ -33,99 +35,99 @@ using test_types = zip>::with_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{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; + using extents_type = boost::numeric::ublas::dynamic_extents<>; + 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; }; 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 vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; - using strides_type = ublas::strides_t; - using extents_type_base = typename extents_type::base_type; - using size_type = typename extents_type_base::value_type; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using vector_type = std::vector; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; + using extents_type_base = typename extents_type::base_type; + using size_type = typename extents_type_base::value_type; - for(auto const& na : extents) { + for(auto const& na : extents) { - if(na.size() > 2) - continue; + if(na.size() > 2) + continue; - auto a = vector_type(product(na), 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 (product(nb), value_type{1} ); + auto a = vector_type(product(na), 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 (product(nb), value_type{1} ); - auto nc_base = extents_type_base(std::max(na.size()-1, size_type{2}), 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]; + 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 (product(nc), value_type{0}); + auto nc = extents_type (nc_base); + auto wc = strides_type (nc); + auto c = vector_type (product(nc), value_type{0}); - ublas::detail::recursive::mtv( - size_type(m), - c.data(), nc.data(), wc.data(), - a.data(), na.data(), wa.data(), - b.data()); + 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( static_cast< inner_type_t >(na[m]) ) * a[i] ); + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(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 vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; - using strides_type = ublas::strides_t; - // using extents_type_base = typename extents_type::base_type; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using vector_type = std::vector; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; + // using extents_type_base = typename extents_type::base_type; - for(auto const& na : extents) { + for(auto const& na : extents) { - if(na.size() != 2) - continue; + if(na.size() != 2) + continue; - auto a = vector_type (product(na), value_type{2}); - auto wa = strides_type (na); + auto a = vector_type (product(na), 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 (product(nb), value_type{1} ); + auto nb = extents_type {na[1],na[0]}; + auto wb = strides_type (nb); + auto b = vector_type (product(nb), value_type{1} ); - auto nc = extents_type {na[0],nb[1]}; + auto nc = extents_type {na[0],nb[1]}; auto wc = strides_type (nc); auto c = vector_type (product(nc)); @@ -146,273 +148,273 @@ BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(na 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 vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; - using strides_type = ublas::strides_t; - using extents_type_base = typename extents_type::base_type; - using size_type = typename extents_type_base::value_type; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using vector_type = std::vector; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; + using extents_type_base = typename extents_type::base_type; + using size_type = typename extents_type_base::value_type; - for(auto const& na : extents) { + for(auto const& na : extents) { - auto a = vector_type(product(na), 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 a = vector_type(product(na), 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); + 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]; + 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 (product(nc), value_type{0}); + auto nc = extents_type (nc_base); + auto wc = strides_type (nc); + auto c = vector_type (product(nc), 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()); + 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] ); + 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 vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; - using strides_type = ublas::strides_t; - using size_type = typename extents_type::value_type; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using vector_type = std::vector; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; + using size_type = typename extents_type::value_type; - for(auto const& na : extents) { + for(auto const& na : extents) { - auto a = vector_type(product(na), 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 (product(nb), value_type{1} ); - auto wb = strides_type (nb); + auto a = vector_type(product(na), 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 (product(nb), value_type{1} ); + auto wb = strides_type (nb); - auto nc = na; - auto wc = strides_type (nc); - auto c = vector_type (product(nc), value_type{0}); + auto nc = na; + auto wc = strides_type (nc); + auto c = vector_type (product(nc), 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()); + 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( static_cast< inner_type_t >(na[m]) ) * a[i] ); + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(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 vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; - using strides_type = ublas::strides_t; - using size_type = typename strides_type::value_type; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using vector_type = std::vector; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; + 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_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 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; - }; + 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 + // 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 + // computing the inner product with + // different permutation tuples for + // right-hand side - for(auto const& na : extents) { + for(auto const& na : extents) { - auto wa = strides_type(na); - auto a = vector_type(product(na), value_type{2}); - auto pa = na.size(); - auto pia = std::vector(pa); - std::iota( pia.begin(), pia.end(), 1 ); + auto wa = strides_type(na); + auto a = vector_type(product(na), value_type{2}); + auto pa = na.size(); + auto pia = std::vector(pa); + std::iota( pia.begin(), pia.end(), 1 ); - auto pib = pia; - auto pib_inv = compute_inverse_permutation(pib); + auto pib = pia; + auto pib_inv = compute_inverse_permutation(pib); - auto f = compute_factorial(pa); + auto f = compute_factorial(pa); - // for the number of possible permutations - // only permutation tuple pib is changed. - for(auto i = 0u; i < f; ++i) { + // 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(product(nb), value_type{3}); - auto pb = nb.size(); + auto nb = permute_extents( pib, na ); + auto wb = strides_type(nb); + auto b = vector_type(product(nb), value_type{3}); + auto pb = nb.size(); - // the number of contractions is changed. - for( auto q = size_type(0); q <= pa; ++q) { + // the number of contractions is changed. + for( auto q = size_type(0); q <= pa; ++q) { - auto r = pa - q; - auto s = pb - 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 pc = r+s > 0 ? std::max(r+s,size_type(2)) : size_type(2); - auto nc_base = std::vector( pc , 1 ); + auto nc_base = std::vector( pc , 1 ); - for(auto j = 0u; j < r; ++j) - nc_base[ j ] = na[ pia[j]-1 ]; + for(auto j = 0u; j < r; ++j) + nc_base[ j ] = na[ pia[j]-1 ]; - for(auto j = 0u; j < s; ++j) - nc_base[ r + j ] = nb[ pib_inv[j]-1 ]; + for(auto j = 0u; j < s; ++j) + nc_base[ r + j ] = nb[ pib_inv[j]-1 ]; - auto nc = extents_type ( nc_base ); - auto wc = strides_type ( nc ); - auto c = vector_type ( product(nc), value_type(0) ); + auto nc = extents_type ( nc_base ); + auto wc = strides_type ( nc ); + auto c = vector_type ( product(nc), 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()); + 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 j = r; j < pa; ++j) - acc *= value_type( static_cast< inner_type_t >(na[pia[j]-1]) ); + auto acc = value_type(1); + for(auto j = r; j < pa; ++j) + acc *= value_type( static_cast< inner_type_t >(na[pia[j]-1]) ); - for(auto j = 0ul; j < c.size(); ++j) - BOOST_CHECK_EQUAL( c[j] , acc * a[0] * b[0] ); + for(auto j = 0ul; j < c.size(); ++j) + BOOST_CHECK_EQUAL( c[j] , acc * a[0] * b[0] ); - } + } - std::next_permutation(pib.begin(), pib.end()); - pib_inv = compute_inverse_permutation(pib); - } - } + 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 vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; - using strides_type = ublas::strides_t; - using size_type = typename strides_type::value_type; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using vector_type = std::vector; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; + using size_type = typename strides_type::value_type; - // left-hand and right-hand side have the - // the same number of elements + // 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 + // computing the inner product with + // different permutation tuples for + // right-hand side - for(auto const& na : extents) { + for(auto const& na : extents) { - auto wa = strides_type(na); - auto a = vector_type(product(na), value_type{2}); - auto pa = na.size(); + auto wa = strides_type(na); + auto a = vector_type(product(na), value_type{2}); + auto pa = na.size(); - auto nb = na; - auto wb = strides_type(nb); - auto b = vector_type(product(nb), value_type{3}); - auto pb = nb.size(); + auto nb = na; + auto wb = strides_type(nb); + auto b = vector_type(product(nb), value_type{3}); + auto pb = nb.size(); - // std::cout << "na = "; - // std::copy(na.begin(), na.end(), std::ostream_iterator(std::cout, " ")); - // std::cout << std::endl; + // std::cout << "na = "; + // std::copy(na.begin(), na.end(), std::ostream_iterator(std::cout, " ")); + // std::cout << std::endl; - // std::cout << "nb = "; - // std::copy(nb.begin(), nb.end(), std::ostream_iterator(std::cout, " ")); - // std::cout << std::endl; + // std::cout << "nb = "; + // std::copy(nb.begin(), nb.end(), std::ostream_iterator(std::cout, " ")); + // std::cout << std::endl; - // the number of contractions is changed. - for( auto q = size_type(0); q <= pa; ++q) { // pa + // 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 r = pa - q; + auto s = pb - q; - auto pc = r+s > 0 ? std::max(r+s, size_type(2)) : size_type(2); + auto pc = r+s > 0 ? std::max(r+s, size_type(2)) : size_type(2); - auto nc_base = std::vector( pc , 1 ); + auto nc_base = std::vector( pc , 1 ); - for(auto i = 0u; i < r; ++i) - nc_base[ i ] = na[ i ]; + 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 ]; + 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 ( product(nc), value_type{0} ); + auto nc = extents_type ( nc_base ); + auto wc = strides_type ( nc ); + auto c = vector_type ( product(nc), value_type{0} ); - // std::cout << "nc = "; - // std::copy(nc.begin(), nc.end(), std::ostream_iterator(std::cout, " ")); - // std::cout << std::endl; + // std::cout << "nc = "; + // std::copy(nc.begin(), nc.end(), std::ostream_iterator(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()); + 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( static_cast< inner_type_t >(na[i]) ); + auto acc = value_type(1); + for(auto i = r; i < pa; ++i) + acc *= value_type( static_cast< inner_type_t >(na[i]) ); - for(auto i = 0u; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); - } + } - } + } } @@ -421,72 +423,71 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt, value, test_types, fixture ) 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_t,layout_type>; - using vector_type = std::vector; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using strides_type = ublas::strides_t,layout_type>; + using vector_type = std::vector; - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n), value_type{2}); - auto b = vector_type(product(n), value_type{3}); - auto w = strides_type(n); + auto a = vector_type(product(n), value_type{2}); + auto b = vector_type(product(n), 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)); + 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_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::dynamic_extents<>; - using strides_type = ublas::strides_t; - using vector_type = std::vector; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using extents_type = ublas::dynamic_extents<>; + using strides_type = ublas::strides_t; + using vector_type = std::vector; - for(auto const& na : extents) { + for(auto const& na : extents) { - auto a = vector_type(product(na), value_type{2}); - auto wa = strides_type(na); + auto a = vector_type(product(na), value_type{2}); + auto wa = strides_type(na); - for(auto const& nb : extents) { + for(auto const& nb : extents) { - auto b = vector_type(product(nb), value_type{3}); - auto wb = strides_type(nb); + auto b = vector_type(product(nb), value_type{3}); + auto wb = strides_type(nb); - auto c = vector_type(product(nb)*product(na)); - auto nc = typename extents_type::base_type(na.size()+nb.size()); + auto c = vector_type(product(nb)*product(na)); + 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]; + 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)); + 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()); + 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] ); - } + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + } - } + } } BOOST_AUTO_TEST_SUITE_END() - diff --git a/test/tensor/test_operators_arithmetic.cpp b/test/tensor/test_operators_arithmetic.cpp index 797920469..1ff83402d 100644 --- a/test/tensor/test_operators_arithmetic.cpp +++ b/test/tensor/test_operators_arithmetic.cpp @@ -25,22 +25,22 @@ using test_types = zip::with_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; + using extents_type = boost::numeric::ublas::basic_extents; + 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; }; @@ -48,67 +48,67 @@ struct fixture 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,layout_type>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; - auto check = [](auto const& e) - { - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto r = tensor_type (e); - auto v = value_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); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - r = t + t + t + t2; + r = t + t + t + t2; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 3*t(i) + t2(i) ); + 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 + 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) ); + 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 + 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) ); + 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; + r = t2 - t + t2 - t; - for(auto i = 0ul; i < r.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 4 ); + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 4 ); - r = tensor_type (e,1) + tensor_type (e,1); + r = tensor_type (e,1) + tensor_type (e,1); - for(auto i = 0ul; i < r.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 2 ); + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2 ); - r = t * t * t * t2; + 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) ); + 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); + r = (t2/t2) * (t2/t2); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 1 ); - }; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 1 ); + }; - for(auto const& e : extents) - check(e); + 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_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 ); } @@ -117,61 +117,61 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, valu 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,layout_type>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; - auto check = [](auto const& e) - { - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto v = value_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); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - tensor_type r1 = t + 2 + t + 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 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r1(i), 2*t(i) + 4 ); - tensor_type r2 = 2 + t + 2 + t; + tensor_type r2 = 2 + t + 2 + t; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r2(i), 2*t(i) + 4 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r2(i), 2*t(i) + 4 ); - tensor_type r3 = (t-2) + (t-2); + tensor_type r3 = (t-2) + (t-2); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r3(i), 2*t(i) - 4 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r3(i), 2*t(i) - 4 ); - tensor_type r4 = (t*2) * (3*t); + 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) ); + 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; + 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) ); + 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; + 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 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); + 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_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 ); } @@ -180,87 +180,88 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value 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,layout_type>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; - auto check = [](auto const& e) - { - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto r = tensor_type (e); - auto v = value_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); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - r = t + 2; - r += t; - r += 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 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2*t(i) + 4 ); - r = 2 + t; - r += t; - r += 2; + r = 2 + t; + r += t; + r += 2; + (void)r; + 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 ); + 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; - r = (t-2); - 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 *= 3; + r *= t; - 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) ); - 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; - 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) ); - 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; - 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) ); - 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 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) ); + + }; - 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); - for(auto const& e : extents) - check(e); + auto r = tensor_type (extents.at(0)); - 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_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 ); } diff --git a/test/tensor/test_operators_comparison.cpp b/test/tensor/test_operators_comparison.cpp index 337a20078..f8f5b80cf 100644 --- a/test/tensor/test_operators_comparison.cpp +++ b/test/tensor/test_operators_comparison.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include "utility.hpp" @@ -26,148 +26,148 @@ using double_extended = boost::multiprecision::cpp_bin_float_double_extended; using test_types = zip::with_t; struct fixture { - using extents_type = boost::numeric::ublas::basic_extents; - 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; + using extents_type = boost::numeric::ublas::dynamic_extents<>; + 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; }; 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,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 ); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + + 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,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 ); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + + 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 ); } @@ -175,70 +175,70 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions 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,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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + + 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); } diff --git a/test/tensor/test_static_expression_evaluation.cpp b/test/tensor/test_static_expression_evaluation.cpp index 98e652265..281f39d34 100644 --- a/test/tensor/test_static_expression_evaluation.cpp +++ b/test/tensor/test_static_expression_evaluation.cpp @@ -12,9 +12,7 @@ -#include -#include -#include +#include #include "utility.hpp" #include @@ -27,102 +25,103 @@ using test_types = zip>::with_t - using extents_type = boost::numeric::ublas::static_extents; - - fixture() {} - - std::tuple< - extents_type<1,1>, // 1 - extents_type<2,3>, // 2 - extents_type<4,1,3>, // 3 - extents_type<4,2,3>, // 4 - extents_type<4,2,3,5> // 5 - > extents; + template + using extents_type = boost::numeric::ublas::static_extents; + + std::tuple< + extents_type<1,1>, // 1 + extents_type<2,3>, // 2 + extents_type<4,1,3>, // 3 + extents_type<4,2,3>, // 4 + extents_type<4,2,3,5> // 5 + > extents; }; BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; - for_each_tuple(extents, [&](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; + for_each_tuple(extents, [&](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + using basic_tensor_type = typename tensor_type::super_type; - auto t = tensor_type(e); - auto v = value_type{}; - for(auto& tt: t){ tt = v; v+=value_type{1}; } + auto t = tensor_type{}; + auto v = value_type{}; + for(auto& tt: t){ tt = v; v+=value_type{1}; } - BOOST_CHECK( ublas::detail::retrieve_extents( t ) == e ); + BOOST_CHECK( ublas::detail::retrieve_extents( t ) == e ); - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - BOOST_CHECK( ublas::detail::retrieve_extents( uexpr1 ) == e ); - BOOST_CHECK( ublas::detail::retrieve_extents( uexpr2 ) == e ); + 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( uexpr1, uexpr2, bplus ); + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_uexpr ) == e ); + 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( bexpr_uexpr, t, bminus ); + // bexpr_bexpr_uexpr = ((t+1) + (2+t)) - t + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); - }); + }); - for_each_tuple(extents, [&](auto const& I, auto& e1){ + for_each_tuple(extents, [&](auto const& I, auto& e1){ - if ( I >= std::tuple_size_v - 1){ - return; - } - - using extents_type1 = std::decay_t; - using tensor_type1 = ublas::tensor; + if ( I >= std::tuple_size_v - 1){ + return; + } + + using extents_type1 = std::decay_t; + using tensor_type1 = ublas::static_tensor; + using basic_tensor_type1 = typename tensor_type1::super_type; - for_each_tuple(extents, [&](auto const& J, auto& e2){ - if( J != I + 1 ){ - return; - } - - using extents_type2 = std::decay_t; - using tensor_type2 = ublas::tensor; + for_each_tuple(extents, [&](auto const& J, auto& e2){ + if( J != I + 1 ){ + return; + } + + using extents_type2 = std::decay_t; + using tensor_type2 = ublas::static_tensor; + using basic_tensor_type2 = typename tensor_type2::super_type; - auto v = value_type{}; + auto v = value_type{}; - tensor_type1 t1(e1); - for(auto& tt: t1){ tt = v; v+=value_type{1}; } + tensor_type1 t1; + for(auto& tt: t1){ tt = v; v+=value_type{1}; } - tensor_type2 t2(e2); - for(auto& tt: t2){ tt = v; v+=value_type{2}; } + tensor_type2 t2; + for(auto& tt: t2){ tt = v; v+=value_type{2}; } - BOOST_CHECK( ublas::detail::retrieve_extents( t1 ) != ublas::detail::retrieve_extents( t2 ) ); + 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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + // uexpr1 = t1+1 + // uexpr2 = 2+t2 + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 ) ); + 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 ) ); - }); - }); + }); + }); } @@ -133,88 +132,91 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_retrieve_extents BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; - for_each_tuple(extents, [&](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; + for_each_tuple(extents, [&](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + using basic_tensor_type = typename tensor_type::super_type; - auto t = tensor_type(e); - auto v = value_type{}; - for(auto& tt: t){ tt = v; v+=value_type{1}; } + auto t = tensor_type{}; + auto v = value_type{}; + for(auto& tt: t){ tt = v; v+=value_type{1}; } - BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - BOOST_CHECK( ublas::detail::all_extents_equal( uexpr1, e ) ); - BOOST_CHECK( ublas::detail::all_extents_equal( uexpr2, e ) ); + 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( uexpr1, uexpr2, bplus ); + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_uexpr, e ) ); + 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( bexpr_uexpr, t, bminus ); + // bexpr_bexpr_uexpr = ((t+1) + (2+t)) - t + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); - BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); - }); + }); - for_each_tuple(extents, [&](auto const& I, auto& e1){ + for_each_tuple(extents, [&](auto const& I, auto& e1){ - if ( I >= std::tuple_size_v - 1){ - return; - } - - using extents_type1 = std::decay_t; - using tensor_type1 = ublas::tensor; + if ( I >= std::tuple_size_v - 1){ + return; + } + + using extents_type1 = std::decay_t; + using tensor_type1 = ublas::static_tensor; + using basic_tensor_type1 = typename tensor_type1::super_type; - for_each_tuple(extents, [&](auto const& J, auto& e2){ - if( J != I + 1 ){ - return; - } + for_each_tuple(extents, [&](auto const& J, auto& e2){ + if( J != I + 1 ){ + return; + } - using extents_type2 = std::decay_t; - using tensor_type2 = ublas::tensor; + using extents_type2 = std::decay_t; + using tensor_type2 = ublas::static_tensor; + using basic_tensor_type2 = typename tensor_type2::super_type; - auto v = value_type{}; + auto v = value_type{}; - tensor_type1 t1(e1); - for(auto& tt: t1){ tt = v; v+=value_type{1}; } + tensor_type1 t1; + for(auto& tt: t1){ tt = v; v+=value_type{1}; } - tensor_type2 t2(e2); - for(auto& tt: t2){ tt = v; v+=value_type{2}; } + tensor_type2 t2; + 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) ) ); + 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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + // uexpr1 = t1+1 + // uexpr2 = 2+t2 + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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) ) ); + 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) ) ); - }); - }); + }); + }); } -BOOST_AUTO_TEST_SUITE_END(); \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END(); diff --git a/test/tensor/test_static_extents.cpp b/test/tensor/test_static_extents.cpp index 4d9d2a1e1..c8bbecb64 100644 --- a/test/tensor/test_static_extents.cpp +++ b/test/tensor/test_static_extents.cpp @@ -11,7 +11,6 @@ // #include -#include #include #include #include "utility.hpp" @@ -357,34 +356,6 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, } -BOOST_FIXTURE_TEST_CASE(test_static_extents_to_functions, fixture, *boost::unit_test::label("static_extents") *boost::unit_test::label("to_functions")) -{ - - for_each_tuple(scalars,[](auto const&, auto& e){ - if (e.size() > 1){ - auto d = e.to_dynamic_extents(); - BOOST_CHECK(d == e); - } - }); - - for_each_tuple(vectors,[](auto const&, auto& e){ - auto d = e.to_dynamic_extents(); - BOOST_CHECK(d == e); - }); - - - for_each_tuple(matrices,[](auto const&, auto& e){ - auto d = e.to_dynamic_extents(); - BOOST_CHECK(d == e); - }); - - for_each_tuple(tensors,[](auto const&, auto& e){ - auto d = e.to_dynamic_extents(); - BOOST_CHECK(d == e); - }); - -} - BOOST_FIXTURE_TEST_CASE(test_static_extents_valid, fixture, *boost::unit_test::label("static_extents") *boost::unit_test::label("valid")) { using namespace boost::numeric::ublas; @@ -488,18 +459,16 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents_comparsion_operator, fixture, *boost BOOST_FIXTURE_TEST_CASE(test_static_extents_squeeze, fixture, *boost::unit_test::label("static_extents") *boost::unit_test::label("squeeze")) { - using extents_type = boost::numeric::ublas::basic_extents; - auto e_sq2 = squeeze(e2 ) ;//==> {2,3} auto e_sq3 = squeeze(e3 ) ;//==> {4,2,3} auto e_sq4 = squeeze(e4 ) ;//==> {4,2,3} auto e_sq5 = squeeze(e5 ) ;//==> {4,2,3} - BOOST_CHECK( (e_sq2 == extents_type{2,3}) ); - BOOST_CHECK( (e_sq3 == extents_type{4,2,3}) ); + BOOST_CHECK( (e_sq2 == extents<2,3>{}) ); + BOOST_CHECK( (e_sq3 == extents<4,2,3>{}) ); - BOOST_CHECK( (e_sq4 == extents_type{4,2,3}) ); - BOOST_CHECK( (e_sq5 == extents_type{4,2,3}) ); + BOOST_CHECK( (e_sq4 == extents<4,2,3>{}) ); + BOOST_CHECK( (e_sq5 == extents<4,2,3>{}) ); } diff --git a/test/tensor/test_static_functions.cpp b/test/tensor/test_static_functions.cpp new file mode 100644 index 000000000..1d53ca389 --- /dev/null +++ b/test/tensor/test_static_functions.cpp @@ -0,0 +1,459 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// +// And we acknowledge the support from all contributors. + + +#include +#include +#include +#include +#include + +#include + +#include "utility.hpp" + +// BOOST_AUTO_TEST_SUITE ( test_tensor_functions, * boost::unit_test::depends_on("test_tensor_contraction") ) +BOOST_AUTO_TEST_SUITE ( test_tensor_functions) + + +using test_types = zip>::with_t; + +//using test_types = zip::with_t; + + +struct fixture +{ + template + using static_extents_type = boost::numeric::ublas::static_extents; + + using dynamic_extents_type = boost::numeric::ublas::dynamic_extents<>; + + fixture() + : extents { + dynamic_extents_type{1,1}, // 1 + dynamic_extents_type{2,3}, // 2 + dynamic_extents_type{2,3,1}, // 3 + dynamic_extents_type{4,2,3}, // 4 + dynamic_extents_type{4,2,3,5}} // 5 + { + } + + std::tuple< + static_extents_type<1,1>, // 1 + static_extents_type<2,3>, // 2 + static_extents_type<2,3,1>, // 3 + static_extents_type<4,2,3>, // 4 + static_extents_type<4,2,3,5> // 5 + > static_extents{}; + + + std::vector extents; +}; + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + for_each_tuple(static_extents,[](auto const&, auto& n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::static_tensor; + using vector_type = typename tensor_type::vector_type; + auto a = tensor_type(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( static_cast< inner_type_t >(n[m]) ) * a[i]); + } + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + for_each_tuple(static_extents,[](auto const&, auto & n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::static_tensor; + using matrix_type = typename tensor_type::matrix_type; + auto a = tensor_type(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( static_cast< inner_type_t >(n[m]) ) * a[i]); + } + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + auto const body = [](auto const& a, auto const& b){ + auto const pa = a.rank(); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phi = std::vector(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 *= value_type( static_cast< inner_type_t >( 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]); + } + }; + + + //static extents and static_extents + for_each_tuple(static_extents,[&](auto const&, auto & n){ + auto n1 = n; + auto n2 = n; + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = + ublas::static_tensor; + using tensor_type_2 = + ublas::static_tensor; + auto a = tensor_type_1(value_type{2}); + auto b = tensor_type_2(value_type{3}); + body(a,b); + }); + + for_each_tuple(static_extents,[&](auto const& I, auto & n){ + auto n1 = n; + auto n2 = extents[I]; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = + ublas::static_tensor; + using tensor_type_2 = + ublas::dynamic_tensor; + auto a = tensor_type_1(value_type{2}); + auto b = tensor_type_2(n1,value_type{3}); + body(a,b); + }); + + for_each_tuple(static_extents,[&](auto const& I, auto & n){ + auto n1 = extents[I]; + auto n2 = n; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = + ublas::dynamic_tensor; + using tensor_type_2 = + ublas::static_tensor; + auto a = tensor_type_1(n1,value_type{2}); + auto b = tensor_type_2(value_type{3}); + body(a,b); + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + + + auto compute_factorial = [](auto const& p){ + auto f = 1ul; + for(auto i = 1u; i <= p; ++i) + f *= i; + return f; + }; + + auto permute_extents_s_1 = [](auto const& pi, auto const& na){ + auto nb = ublas::dynamic_extents<>(na); + assert(pi.size() == na.size()); + for(auto j = 0u; j < pi.size(); ++j) + nb[pi[j]-1] = na[j]; + return nb; + }; + auto permute_extents_s_2 = [](auto const& pi, auto const& na){ + auto tempn = na.base(); + assert(pi.size() == na.size()); + for(auto j = 0u; j < pi.size(); ++j) + tempn[pi[j]-1] = na[j]; + return ublas::dynamic_extents::type::_size>(tempn.begin(),tempn.end()); + }; + +// static and dynamic + for_each_tuple(static_extents,[&](auto const&, auto & n){ + auto na = n; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::static_tensor; + auto a = tensor_type_1(value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_s_1(pi, na); + using tensor_type_2 = ublas::dynamic_tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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 *= value_type( static_cast< inner_type_t >( 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()); + } + }); + + //static and static + for_each_tuple(static_extents,[&](auto const&, auto & n){ + auto na = n; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::static_tensor; + auto a = tensor_type_1(value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_s_2(pi, na); + + using tensor_type_2 = ublas::dynamic_tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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_static_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; + + auto const body = [&](auto const& a, auto const& b){ + 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 ); + }; + + for_each_tuple(static_extents,[&](auto const&, auto & n){ + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::static_tensor; + using tensor_type_2 = ublas::static_tensor; + auto a = tensor_type_1(value_type(2)); + auto b = tensor_type_2(value_type(1)); + body(a,b); + + }); + + for_each_tuple(static_extents,[&](auto const& I, auto & n){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::static_tensor; + using tensor_type_2 = ublas::dynamic_tensor; + auto a = tensor_type_1(value_type(2)); + auto b = tensor_type_2(extents[I], value_type(1)); + body(a,b); + + }); + + for_each_tuple(static_extents,[&](auto const& I, auto & n){ + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::dynamic_tensor; + using tensor_type_2 = ublas::static_tensor; + auto a = tensor_type_1(extents[I], value_type(2)); + auto b = tensor_type_2(value_type(1)); + body(a,b); + + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; + + for_each_tuple(static_extents,[&](auto const&, auto const& n1){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::static_tensor; + auto a = tensor_type_1(value_type(2)); + for_each_tuple(static_extents,[&](auto const& J, auto const& n2){ + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::static_tensor; + auto b = tensor_type_2(value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + + }); + + }); + + for_each_tuple(static_extents,[&](auto const& I, auto const& n1){ + using tensor_type_1 = ublas::dynamic_tensor; + auto a = tensor_type_1(extents[I], value_type(2)); + for_each_tuple(static_extents,[&](auto const& J, auto const& n2){ + using extents_type_2 = typename std::decay::type; + using tensor_type_2 = ublas::static_tensor; + auto b = tensor_type_2(value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + }); + + }); + + for_each_tuple(static_extents,[&](auto const&, auto const& n1){ + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::static_tensor; + auto a = tensor_type_1(value_type(2)); + for(auto n2 : extents){ + using tensor_type_2 = ublas::dynamic_tensor; + auto b = tensor_type_2(n2, value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + } + + }); + +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_trans, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + auto fac = [](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_each_tuple(static_extents,[&](auto const&, auto & n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::static_tensor; + auto const p = n.size(); + auto const s = product(n); + auto aref = tensor_type(); + auto v = value_type{}; + for(auto i = 0u; i < s; ++i, v+=1) + aref[i] = v; + + auto pi = std::vector(p); + std::iota(pi.begin(), pi.end(), 1); + + auto a = ublas::trans( aref, pi ); + + for(auto i = 0ul; i < a.size(); i++){ + BOOST_CHECK( a[i] == aref[i] ); + } + + + auto const pfac = fac(p); + auto i = 0u; + for(; i < pfac-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 ); + } + + for(auto j = 0ul; j < a.size(); j++){ + BOOST_CHECK( a[j] == aref[j] ); + } + }); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_operators_arithmetic.cpp b/test/tensor/test_static_operators_arithmetic.cpp index 6646a6aff..78e5a167e 100644 --- a/test/tensor/test_static_operators_arithmetic.cpp +++ b/test/tensor/test_static_operators_arithmetic.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -26,135 +26,135 @@ using test_types = zip::with_t - using extents_type = boost::numeric::ublas::static_extents; + template + using extents_type = boost::numeric::ublas::static_extents; - fixture() {} + fixture() {} - std::tuple< - extents_type<1,1>, // 1 - extents_type<2,3>, // 2 - extents_type<4,1,3>, // 3 - extents_type<4,2,3>, // 4 - extents_type<4,2,3,5> // 5 - > extents; + std::tuple< + extents_type<1,1>, // 1 + extents_type<2,3>, // 2 + extents_type<4,1,3>, // 3 + extents_type<4,2,3>, // 4 + extents_type<4,2,3,5> // 5 + > extents; }; 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto r = tensor_type (e); - auto v = value_type {}; + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + auto t = tensor_type (); + auto t2 = tensor_type (); + auto r = tensor_type (); + auto v = value_type {}; - std::iota(t.begin(), t.end(), v); - std::iota(t2.begin(), t2.end(), v+2); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - r = t + t + t + t2; + r = t + t + t + t2; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 3*t(i) + t2(i) ); + 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 + 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) ); + 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 + 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) ); + 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; + r = t2 - t + t2 - t; - for(auto i = 0ul; i < r.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 4 ); + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 4 ); - r = tensor_type (e,1) + tensor_type (e,1); + r = tensor_type (1) + tensor_type (1); - for(auto i = 0ul; i < r.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 2 ); + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2 ); - r = t * t * t * t2; + 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) ); + 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); + r = (t2/t2) * (t2/t2); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 1 ); - }; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 1 ); + }; - for_each_tuple(extents,check); + for_each_tuple(extents,check); } 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto v = value_type {}; + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + auto t = tensor_type (); + auto t2 = tensor_type (); + auto v = value_type {}; - std::iota(t.begin(), t.end(), v); - std::iota(t2.begin(), t2.end(), v+2); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - tensor_type r1 = t + 2 + t + 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 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r1(i), 2*t(i) + 4 ); - tensor_type r2 = 2 + t + 2 + t; + tensor_type r2 = 2 + t + 2 + t; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r2(i), 2*t(i) + 4 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r2(i), 2*t(i) + 4 ); - tensor_type r3 = (t-2) + (t-2); + tensor_type r3 = (t-2) + (t-2); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r3(i), 2*t(i) - 4 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r3(i), 2*t(i) - 4 ); - tensor_type r4 = (t*2) * (3*t); + 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) ); + 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; + 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) ); + 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; + 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 i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r6(i), (t2(i)/2+1) / (2/t2(i)+1) / t2(i) ); - }; + }; - for_each_tuple(extents,check); + for_each_tuple(extents,check); } @@ -163,79 +163,79 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto r = tensor_type (e); - auto v = value_type {}; + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + auto t = tensor_type (); + auto t2 = tensor_type (); + auto r = tensor_type (); + auto v = value_type {}; - std::iota(t.begin(), t.end(), v); - std::iota(t2.begin(), t2.end(), v+2); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - r = t + 2; - r += t; - r += 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 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2*t(i) + 4 ); - r = 2 + t; - r += t; - r += 2; + 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 ); - 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; + r = (t-2); + 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 *= 3; - r *= t; + 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) ); + 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; + 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) ); + 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; + 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) ); + 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 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) ); - }; + tensor_type p = +r; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( p(i), r(i) ); + }; - for_each_tuple(extents,check); + for_each_tuple(extents,check); } diff --git a/test/tensor/test_static_operators_comparison.cpp b/test/tensor/test_static_operators_comparison.cpp index e64ce1e25..b45817494 100644 --- a/test/tensor/test_static_operators_comparison.cpp +++ b/test/tensor/test_static_operators_comparison.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,9 +12,7 @@ -#include -#include -#include +#include #include #include #include "utility.hpp" @@ -26,103 +24,103 @@ using double_extended = boost::multiprecision::cpp_bin_float_double_extended; using test_types = zip::with_t; struct fixture { - template - using extents_type = boost::numeric::ublas::static_extents; - - fixture() {} - - std::tuple< - extents_type<1,1>, // 1 - extents_type<2,3>, // 2 - extents_type<4,1,3>, // 3 - extents_type<4,2,3>, // 4 - extents_type<4,2,3,5> // 5 - > extents; + template + using extents_type = boost::numeric::ublas::static_extents; + + fixture() {} + + std::tuple< + extents_type<1,1>, // 1 + extents_type<2,3>, // 2 + extents_type<4,1,3>, // 3 + extents_type<4,2,3>, // 4 + extents_type<4,2,3,5> // 5 + > extents; }; 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; - - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + auto t = tensor_type (); + auto t2 = tensor_type (); + 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_each_tuple(extents,check); } 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto v = value_type {}; + auto t = tensor_type (); + auto t2 = tensor_type (); + auto v = value_type {}; - std::iota(t.begin(), t.end(), v); - std::iota(t2.begin(), t2.end(), v+2); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - BOOST_CHECK( t == t ); - BOOST_CHECK( t != t2 ); + BOOST_CHECK( t == t ); + BOOST_CHECK( t != t2 ); - if(t.empty()) - return; + 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 ); + 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_each_tuple(extents,check); + for_each_tuple(extents,check); } @@ -130,68 +128,68 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions 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; - - - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - - 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)) ); - - }; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + + BOOST_CHECK( tensor_type(value_type{2}) == tensor_type(value_type{2}) ); + BOOST_CHECK( tensor_type(value_type{2}) != tensor_type(value_type{1}) ); + + if(e.empty()) + return; + + BOOST_CHECK( !(tensor_type(2) < 2) ); + BOOST_CHECK( !(tensor_type(2) > 2) ); + BOOST_CHECK( (tensor_type(2) >= 2) ); + BOOST_CHECK( (tensor_type(2) <= 2) ); + BOOST_CHECK( (tensor_type(2) == 2) ); + BOOST_CHECK( (tensor_type(2) != 3) ); + + BOOST_CHECK( !(2 > tensor_type(2)) ); + BOOST_CHECK( !(2 < tensor_type(2)) ); + BOOST_CHECK( (2 <= tensor_type(2)) ); + BOOST_CHECK( (2 >= tensor_type(2)) ); + BOOST_CHECK( (2 == tensor_type(2)) ); + BOOST_CHECK( (3 != tensor_type(2)) ); + + BOOST_CHECK( !( tensor_type(2)+3 < 5) ); + BOOST_CHECK( !( tensor_type(2)+3 > 5) ); + BOOST_CHECK( ( tensor_type(2)+3 >= 5) ); + BOOST_CHECK( ( tensor_type(2)+3 <= 5) ); + BOOST_CHECK( ( tensor_type(2)+3 == 5) ); + BOOST_CHECK( ( tensor_type(2)+3 != 6) ); + + + BOOST_CHECK( !( 5 > tensor_type(2)+3) ); + BOOST_CHECK( !( 5 < tensor_type(2)+3) ); + BOOST_CHECK( ( 5 >= tensor_type(2)+3) ); + BOOST_CHECK( ( 5 <= tensor_type(2)+3) ); + BOOST_CHECK( ( 5 == tensor_type(2)+3) ); + BOOST_CHECK( ( 6 != tensor_type(2)+3) ); + + + BOOST_CHECK( !( tensor_type(2)+tensor_type(3) < 5) ); + BOOST_CHECK( !( tensor_type(2)+tensor_type(3) > 5) ); + BOOST_CHECK( ( tensor_type(2)+tensor_type(3) >= 5) ); + BOOST_CHECK( ( tensor_type(2)+tensor_type(3) <= 5) ); + BOOST_CHECK( ( tensor_type(2)+tensor_type(3) == 5) ); + BOOST_CHECK( ( tensor_type(2)+tensor_type(3) != 6) ); + + + BOOST_CHECK( !( 5 > tensor_type(2)+tensor_type(3)) ); + BOOST_CHECK( !( 5 < tensor_type(2)+tensor_type(3)) ); + BOOST_CHECK( ( 5 >= tensor_type(2)+tensor_type(3)) ); + BOOST_CHECK( ( 5 <= tensor_type(2)+tensor_type(3)) ); + BOOST_CHECK( ( 5 == tensor_type(2)+tensor_type(3)) ); + BOOST_CHECK( ( 6 != tensor_type(2)+tensor_type(3)) ); + + }; for_each_tuple(extents,check); diff --git a/test/tensor/test_static_strides.cpp b/test/tensor/test_static_strides.cpp index 946dd60c9..fbe4a37d0 100644 --- a/test/tensor/test_static_strides.cpp +++ b/test/tensor/test_static_strides.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -10,7 +10,9 @@ // Google // -#include +#include +#include +#include #include #include diff --git a/test/tensor/test_static_tensor.cpp b/test/tensor/test_static_tensor.cpp index 8a93508a5..ebed2fab9 100644 --- a/test/tensor/test_static_tensor.cpp +++ b/test/tensor/test_static_tensor.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,7 +13,7 @@ #include -#include +#include #ifndef BOOST_TEST_DYN_LINK #define BOOST_TEST_DYN_LINK @@ -31,360 +31,360 @@ using test_types = zip>::with_t,layout_type>{}; - BOOST_CHECK_EQUAL( a1.size() , 0ul ); - BOOST_CHECK( a1.empty() ); + auto a1 = ublas::static_tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a1.size() , 0ul ); + BOOST_CHECK( a1.empty() ); - auto a2 = ublas::tensor,layout_type>{}; - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); + auto a2 = ublas::static_tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); - auto a3 = ublas::tensor,layout_type>{}; - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); + auto a3 = ublas::static_tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); - auto a4 = ublas::tensor,layout_type>{}; - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); + auto a4 = ublas::static_tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); - auto a5 = ublas::tensor,layout_type>{}; - BOOST_CHECK_EQUAL( a5.size() , 2 ); - BOOST_CHECK( !a5.empty() ); + auto a5 = ublas::static_tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a5.size() , 2 ); + BOOST_CHECK( !a5.empty() ); - auto a6 = ublas::tensor,layout_type>{}; - BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); - BOOST_CHECK( !a6.empty() ); + auto a6 = ublas::static_tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); + BOOST_CHECK( !a6.empty() ); - auto a7 = ublas::tensor,layout_type>{}; - BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); - BOOST_CHECK( !a7.empty() ); + auto a7 = ublas::static_tensor,layout_type>{}; + BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); + BOOST_CHECK( !a7.empty() ); } struct fixture { - template - using extents_type = boost::numeric::ublas::static_extents; - - fixture() {} - - std::tuple< - extents_type<1,1>, // 1 - extents_type<2,3>, // 2 - extents_type<4,1,3>, // 3 - extents_type<4,2,3>, // 4 - extents_type<4,2,3,5> // 5 - > extents; + template + using extents_type = boost::numeric::ublas::static_extents; + + fixture() {} + + std::tuple< + extents_type<1,1>, // 1 + extents_type<2,3>, // 2 + extents_type<4,1,3>, // 3 + extents_type<4,2,3>, // 4 + extents_type<4,2,3,5> // 5 + > 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; - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - auto t = ublas::tensor{e}; - - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - if(e.empty()) { - BOOST_CHECK ( t.empty() ); - } - else{ - BOOST_CHECK ( !t.empty() ); - } - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + auto t = ublas::static_tensor{}; + + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + if(e.empty()) { + BOOST_CHECK ( t.empty() ); + } + else{ + BOOST_CHECK ( !t.empty() ); + } + }); } 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - auto r = ublas::tensor{e,0}; + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + auto r = ublas::static_tensor{0}; - 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() ); + 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() ); - } - else{ - BOOST_CHECK ( !t.empty() ); - } + if(e.empty()) { + BOOST_CHECK ( t.empty() ); + } + else{ + BOOST_CHECK ( !t.empty() ); + } - for(auto i = 0ul; i < t.size(); ++i) - BOOST_TEST( t[i] == r[i]); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_TEST( t[i] == r[i]); - }); + }); } 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 other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - auto r = tensor_type{e,0}; - ublas::tensor t = r; - tensor_type q = t; + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + auto r = tensor_type{0}; + ublas::static_tensor 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 ( 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() ); + 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_TEST( q[i] == r[i]); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_TEST( 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; - - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - auto r = tensor_type{e}; - auto t = std::move(r); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - - if(e.empty()) { - BOOST_CHECK ( t.empty() ); - } - else{ - BOOST_CHECK ( !t.empty() ); - } - - }; - - for_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + auto check = [](auto const&, auto& e) + { + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + auto r = tensor_type{}; + auto t = std::move(r); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + + if(e.empty()) { + BOOST_CHECK ( t.empty() ); + } + else{ + BOOST_CHECK ( !t.empty() ); + } + + }; + + for_each_tuple(extents,check); } 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; - - std::random_device device{}; - std::minstd_rand0 generator(device()); - - using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; - auto distribution = distribution_type(1,6); - - for_each_tuple(extents, [&](auto const&, auto const& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - - auto r = value_type( static_cast< inner_type_t >(distribution(generator)) ); - auto t = tensor_type{e,r}; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( t[i], r ); - - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + std::random_device device{}; + std::minstd_rand0 generator(device()); + + using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; + auto distribution = distribution_type(1,6); + + for_each_tuple(extents, [&](auto const&, auto const& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + + auto r = value_type( static_cast< inner_type_t >(distribution(generator)) ); + auto t = tensor_type{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; - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - using array_type = typename tensor_type::array_type; - - auto a = array_type(); - 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); - - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + using array_type = typename tensor_type::array_type; + + auto a = array_type(); + auto v = value_type {}; + + for(auto& aa : a){ + aa = v; + v += value_type{1}; + } + auto t = tensor_type{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; - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - - 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 ); - } - - }); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + for_each_tuple(extents, [](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + + auto t = tensor_type{}; + 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; - - auto check1 = [](const auto& 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 auto& t) - { - std::array k; - auto r = std::is_same::value ? 1 : 0; - auto q = std::is_same::value ? 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 auto& t) - { - std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 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 auto& t) - { - std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 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&, auto const& e) { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - 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 constexpr ( extents_type::_size == 1) check1(t); - else if constexpr ( extents_type::_size == 2) check2(t); - else if constexpr ( extents_type::_size == 3) check3(t); - else if constexpr ( extents_type::_size == 4) check4(t); - - }; - - for_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + auto check1 = [](const auto& 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 auto& t) + { + std::array k; + auto r = std::is_same::value ? 1 : 0; + auto q = std::is_same::value ? 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 auto& t) + { + std::array k; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 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 auto& t) + { + std::array k; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 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&, auto const& e) { + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + auto t = tensor_type{}; + auto v = value_type {}; + for(auto i = 0ul; i < t.size(); ++i){ + t[i] = v; + v+=value_type{1}; + } + + if constexpr ( extents_type::_size == 1) check1(t); + else if constexpr ( extents_type::_size == 2) check2(t); + else if constexpr ( extents_type::_size == 3) check3(t); + else if constexpr ( extents_type::_size == 4) check4(t); + + }; + + for_each_tuple(extents,check); } 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 namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - for_each_tuple(extents,[](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor; - - auto v = value_type {} + value_type{1}; - auto t = tensor_type{e, v}; + for_each_tuple(extents,[](auto const&, auto& e){ + using extents_type = std::decay_t; + using tensor_type = ublas::static_tensor; + + auto v = value_type {} + value_type{1}; + auto t = tensor_type{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.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() ); + 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() ) ) ; - } - }); + if(t.size() > 0) { + BOOST_CHECK( t.data() == std::addressof( *t.begin () ) ) ; + BOOST_CHECK( t.data() == std::addressof( *t.cbegin() ) ) ; + } + }); } @@ -393,12 +393,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, 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, layout_type>; + using tensor_type = ublas::static_tensor, layout_type>; - std::vector vec(30); - BOOST_CHECK_THROW(tensor_type({5,5},vec), std::runtime_error); - - auto t = tensor_type{{5,5}}; + auto t = tensor_type{}; auto i = ublas::index::index_type<4>{}; BOOST_CHECK_THROW(t.operator()(i,i,i), std::runtime_error); diff --git a/test/tensor/test_static_tensor_matrix_vector.cpp b/test/tensor/test_static_tensor_matrix_vector.cpp index dc15e1695..3578886d7 100644 --- a/test/tensor/test_static_tensor_matrix_vector.cpp +++ b/test/tensor/test_static_tensor_matrix_vector.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -28,69 +28,69 @@ using test_types = zip::with_t,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - - ublas::tensor,layout_type> a2 = matrix_type(1,1); - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - - ublas::tensor,layout_type> a3 = matrix_type(2,1); - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - - ublas::tensor,layout_type> a4 = matrix_type(1,2); - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - - ublas::tensor,layout_type> a5 = matrix_type(2,3); - BOOST_CHECK_EQUAL( a5.size() , 6 ); - BOOST_CHECK( !a5.empty() ); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + ublas::static_tensor,layout_type> a2 = matrix_type(1,1); + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + + ublas::static_tensor,layout_type> a3 = matrix_type(2,1); + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + + ublas::static_tensor,layout_type> a4 = matrix_type(1,2); + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + + ublas::static_tensor,layout_type> a5 = matrix_type(2,3); + BOOST_CHECK_EQUAL( a5.size() , 6 ); + BOOST_CHECK( !a5.empty() ); } 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,layout_type>; - using vector_type = typename tensor_type::vector_type; - - ublas::tensor,layout_type> a2 = vector_type(1); - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - - ublas::tensor,layout_type> a3 = vector_type(2); - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - - ublas::tensor,layout_type> a4 = vector_type(2); - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - - ublas::tensor,layout_type> a5 = vector_type(3); - BOOST_CHECK_EQUAL( a5.size() , 3 ); - BOOST_CHECK( !a5.empty() ); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + ublas::static_tensor,layout_type> a2 = vector_type(1); + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + + ublas::static_tensor,layout_type> a3 = vector_type(2); + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + + ublas::static_tensor,layout_type> a4 = vector_type(2); + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + + ublas::static_tensor,layout_type> a5 = vector_type(3); + BOOST_CHECK_EQUAL( a5.size() , 3 ); + BOOST_CHECK( !a5.empty() ); } struct fixture { - template - using extents_type = boost::numeric::ublas::static_extents; + template + using extents_type = boost::numeric::ublas::static_extents; - fixture() {} + fixture() {} - std::tuple< - extents_type<1,1>, // 0 - extents_type<2,3>, // 1 - extents_type<9,7>, // 2 - extents_type<15,17> // 3 - > extents;; + std::tuple< + extents_type<1,1>, // 0 + extents_type<2,3>, // 1 + extents_type<9,7>, // 2 + extents_type<15,17> // 3 + > extents;; }; @@ -98,160 +98,160 @@ struct fixture 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size()==2); - etensor_type t = matrix_type{e[0],e[1]}; - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - }; - - for_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::static_tensor; + + assert(e.size()==2); + etensor_type t = matrix_type{e[0],e[1]}; + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + }; + + for_each_tuple(extents,check); } 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,layout_type>; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - if constexpr( extents_type::at(1) == 1 ){ - assert(e.size()==2); - if(e.empty()) - return; - - etensor_type t = vector_type(product(e)); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - } - - }; - - for_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::static_tensor; + + if constexpr( extents_type::at(1) == 1 ){ + assert(e.size()==2); + if(e.empty()) + return; + + etensor_type t = vector_type(product(e)); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + } + + }; + + for_each_tuple(extents,check); } 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - auto t = etensor_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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::static_tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + 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_each_tuple(extents,check); } 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,layout_type>; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - - if constexpr( extents_type::at(1) == 1 ){ - auto t = etensor_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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - - for(auto i = 0ul; i < t.size(); ++i){ - BOOST_CHECK_EQUAL( t[i], r(i) ); - } - } - }; - - for_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::static_tensor; + + assert(e.size() == 2); + + if constexpr( extents_type::at(1) == 1 ){ + auto t = etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_CHECK_EQUAL( t[i], r(i) ); + } + } + }; + + for_each_tuple(extents,check); } 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - auto t = etensor_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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::static_tensor; + + assert(e.size() == 2); + auto t = etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + 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_each_tuple(extents,check); } @@ -259,37 +259,37 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, te 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,layout_type>; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - if constexpr( extents_type::at(1) == 1 ){ - auto t = etensor_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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - - for(auto i = 0ul; i < t.size(); ++i){ - BOOST_CHECK_EQUAL( t[i], q(i) ); - } - } - }; - - for_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::static_tensor; + + assert(e.size() == 2); + if constexpr( extents_type::at(1) == 1 ){ + auto t = etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_CHECK_EQUAL( t[i], q(i) ); + } + } + }; + + for_each_tuple(extents,check); } @@ -298,54 +298,54 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, te 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - auto t = etensor_type{}; - auto r = matrix_type(e[0],e[1]); - std::iota(r.data().begin(),r.data().end(), 1); - t = r + 3*r; - etensor_type s = r + 3*r; - etensor_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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - - 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() , product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , e.size() ); - BOOST_CHECK ( !s.empty() ); - - 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() , product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , e.size() ); - BOOST_CHECK ( !q.empty() ); - - - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::static_tensor; + + assert(e.size() == 2); + auto t = etensor_type{}; + auto r = matrix_type(e[0],e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r + 3*r; + etensor_type s = r + 3*r; + etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + 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() , product(e) ); + BOOST_CHECK_EQUAL ( s.rank() , e.size() ); + BOOST_CHECK ( !s.empty() ); + + 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() , product(e) ); + BOOST_CHECK_EQUAL ( q.rank() , e.size() ); + BOOST_CHECK ( !q.empty() ); + + + 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_each_tuple(extents,check); } @@ -355,106 +355,105 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_t 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,layout_type>; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::tensor; - - assert(e.size() == 2); - if constexpr( extents_type::at(1) == 1 ){ - auto t = etensor_type{}; - auto r = vector_type(e[0]*e[1]); - std::iota(r.data().begin(),r.data().end(), 1); - t = r + 3*r; - etensor_type s = r + 3*r; - etensor_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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - - 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() , product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , e.size() ); - BOOST_CHECK ( !s.empty() ); - - 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() , product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , e.size() ); - BOOST_CHECK ( !q.empty() ); - - - - 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_each_tuple(extents,check); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; + using etensor_type = ublas::static_tensor; + + assert(e.size() == 2); + if constexpr( extents_type::at(1) == 1 ){ + auto t = etensor_type{}; + auto r = vector_type(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r + 3*r; + etensor_type s = r + 3*r; + etensor_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() , product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + + 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() , product(e) ); + BOOST_CHECK_EQUAL ( s.rank() , e.size() ); + BOOST_CHECK ( !s.empty() ); + + 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() , product(e) ); + BOOST_CHECK_EQUAL ( q.rank() , e.size() ); + BOOST_CHECK ( !q.empty() ); + + + + 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_each_tuple(extents,check); } 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - using vector_type = typename tensor_type::vector_type; + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + using vector_type = typename tensor_type::vector_type; - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; + auto check = [](auto const&, auto& e) { + using extents_type = std::decay_t; - if(product(e) <= 2) - return; + if(product(e) <= 2) + return; - assert(e.size() == 2); - auto Q = ublas::tensor,layout_type>{} ; - 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); + assert(e.size() == 2); + auto Q = ublas::static_tensor,layout_type>{} ; + 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); - decltype(Q) T = Q + (ublas::prod(A , b) + 2*c) + 3*Q; + decltype(Q) 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_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() ); - 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 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_each_tuple(extents,check); + for_each_tuple(extents,check); } BOOST_AUTO_TEST_SUITE_END() - diff --git a/test/tensor/test_strides.cpp b/test/tensor/test_strides.cpp index 0623125f7..e7a63585c 100644 --- a/test/tensor/test_strides.cpp +++ b/test/tensor/test_strides.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -14,7 +14,7 @@ #include #include -#include +#include //BOOST_AUTO_TEST_SUITE(test_strides, * boost::unit_test::depends_on("test_extents")); @@ -24,283 +24,146 @@ using test_types = std::tuple; - using strides_type = ublas::strides_t; + using extents_type = ublas::basic_extents; + using strides_type = ublas::strides_t; - strides_type s0{}; - BOOST_CHECK ( s0.empty()); - BOOST_CHECK_EQUAL ( s0.size(), 0); + 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 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 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 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 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 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 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); + strides_type s7{extents_type{4,2,3}}; + BOOST_CHECK (!s7.empty()); + BOOST_CHECK_EQUAL ( s7.size(), 3); } -BOOST_AUTO_TEST_CASE_TEMPLATE( test_static_rank_strides_ctor, value, test_types) -{ - namespace ub = boost::numeric::ublas; - - ub::basic_fixed_rank_strides s0{ub::dynamic_extents<0>{}}; - BOOST_CHECK ( s0.empty()); - BOOST_CHECK_EQUAL ( s0.size(), 0); - - ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; - BOOST_CHECK (!s1.empty()); - BOOST_CHECK_EQUAL ( s1.size(), 2); - - ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; - BOOST_CHECK (!s2.empty()); - BOOST_CHECK_EQUAL ( s2.size(), 2); - - ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; - BOOST_CHECK (!s3.empty()); - BOOST_CHECK_EQUAL ( s3.size(), 2); - - ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; - BOOST_CHECK (!s4.empty()); - BOOST_CHECK_EQUAL ( s4.size(), 2); - - ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{2,3,1}}; - BOOST_CHECK (!s5.empty()); - BOOST_CHECK_EQUAL ( s5.size(), 3); - - ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{1,2,3}}; - BOOST_CHECK (!s6.empty()); - BOOST_CHECK_EQUAL ( s6.size(), 3); - - ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{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; - using strides_type = ublas::strides_t; - - 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_static_rank_strides_ctor_access_first_order) -{ - namespace ub = boost::numeric::ublas; - - ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; - BOOST_REQUIRE_EQUAL( s1.size(),2); - BOOST_CHECK_EQUAL ( s1[0], 1); - BOOST_CHECK_EQUAL ( s1[1], 1); - - ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; - BOOST_REQUIRE_EQUAL ( s2.size(),2); - BOOST_CHECK_EQUAL ( s2[0], 1); - BOOST_CHECK_EQUAL ( s2[1], 1); - - ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; - BOOST_REQUIRE_EQUAL ( s3.size(),2); - BOOST_CHECK_EQUAL ( s3[0], 1); - BOOST_CHECK_EQUAL ( s3[1], 1); - - ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; - BOOST_REQUIRE_EQUAL ( s4.size(),2); - BOOST_CHECK_EQUAL ( s4[0], 1); - BOOST_CHECK_EQUAL ( s4[1], 2); - - ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{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); - - ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{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); - - ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{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); - - ub::basic_fixed_rank_strides s8{ub::dynamic_extents<3>{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); + using namespace boost::numeric; + + using extents_type = ublas::basic_extents; + using strides_type = ublas::strides_t; + + 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; - using strides_type = ublas::strides_t; - - 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_CASE( test_static_rank_strides_ctor_access_last_order) -{ - namespace ub = boost::numeric::ublas; - - ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; - BOOST_REQUIRE_EQUAL( s1.size(),2); - BOOST_CHECK_EQUAL ( s1[0], 1); - BOOST_CHECK_EQUAL ( s1[1], 1); - - ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; - BOOST_REQUIRE_EQUAL ( s2.size(),2); - BOOST_CHECK_EQUAL ( s2[0], 1); - BOOST_CHECK_EQUAL ( s2[1], 1); - - ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; - BOOST_REQUIRE_EQUAL ( s3.size(),2); - BOOST_CHECK_EQUAL ( s3[0], 1); - BOOST_CHECK_EQUAL ( s3[1], 1); - - ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; - BOOST_REQUIRE_EQUAL ( s4.size(),2); - BOOST_CHECK_EQUAL ( s4[0], 3); - BOOST_CHECK_EQUAL ( s4[1], 1); - - ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{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); - - ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{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); - - ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{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); - - ub::basic_fixed_rank_strides s8{ub::dynamic_extents<3>{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); + using namespace boost::numeric; + + using extents_type = ublas::basic_extents; + using strides_type = ublas::strides_t; + + strides_type s1{extents_type{1,1}}; + BOOST_REQUIRE_EQUAL( s1.size(),2); + BOOST_CHECK_EQUAL ( s1[0], 1); + BOOST_CHECK_EQUAL ( s1[1], 1); + + strides_type s2{extents_type{1,2}}; + BOOST_REQUIRE_EQUAL ( s2.size(),2); + BOOST_CHECK_EQUAL ( s2[0], 1); + BOOST_CHECK_EQUAL ( s2[1], 1); + + strides_type s3{extents_type{2,1}}; + BOOST_REQUIRE_EQUAL ( s3.size(),2); + BOOST_CHECK_EQUAL ( s3[0], 1); + BOOST_CHECK_EQUAL ( s3[1], 1); + + strides_type s4{extents_type{2,3}}; + BOOST_REQUIRE_EQUAL ( s4.size(),2); + BOOST_CHECK_EQUAL ( s4[0], 3); + BOOST_CHECK_EQUAL ( s4[1], 1); + + strides_type s5{extents_type{2,3,1}}; + BOOST_REQUIRE_EQUAL ( s5.size(),3); + BOOST_CHECK_EQUAL ( s5[0], 3); + BOOST_CHECK_EQUAL ( s5[1], 1); + BOOST_CHECK_EQUAL ( s5[2], 1); + + strides_type s6{extents_type{1,2,3}}; + BOOST_REQUIRE_EQUAL ( s6.size(),3); + BOOST_CHECK_EQUAL ( s6[0], 6); + BOOST_CHECK_EQUAL ( s6[1], 3); + BOOST_CHECK_EQUAL ( s6[2], 1); + + strides_type s7{extents_type{2,1,3}}; + BOOST_REQUIRE_EQUAL ( s7.size(),3); + BOOST_CHECK_EQUAL ( s7[0], 3); + BOOST_CHECK_EQUAL ( s7[1], 3); + BOOST_CHECK_EQUAL ( s7[2], 1); + + strides_type s8{extents_type{4,2,3}}; + BOOST_REQUIRE_EQUAL ( s8.size(),3); + BOOST_CHECK_EQUAL ( s8[0], 6); + BOOST_CHECK_EQUAL ( s8[1], 3); + BOOST_CHECK_EQUAL ( s8[2], 1); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_tensor.cpp b/test/tensor/test_tensor.cpp index 0c7bd4cb9..5e09c57a0 100644 --- a/test/tensor/test_tensor.cpp +++ b/test/tensor/test_tensor.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,7 +13,7 @@ #include -#include +#include #ifndef BOOST_TEST_DYN_LINK #define BOOST_TEST_DYN_LINK @@ -33,45 +33,45 @@ using test_types = zip>::with_t,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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + 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); } @@ -79,299 +79,299 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) struct fixture { - using extents_type = boost::numeric::ublas::basic_extents; - 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; + using extents_type = boost::numeric::ublas::dynamic_extents<>; + 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; }; 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,layout_type>; - - auto check = [](auto const& e) { - auto t = tensor_type{e}; - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - 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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + auto check = [](auto const& e) { + auto t = tensor_type{e}; + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + 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,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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + 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,layout_type>; - using other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; - using other_tensor_type = ublas::tensor, 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] ); - } + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; + using other_tensor_type = ublas::dynamic_tensor; + + + 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,layout_type>; - - auto check = [](auto const& e) - { - auto r = tensor_type{e}; - auto t = std::move(r); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - 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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + auto check = [](auto const& e) + { + auto r = tensor_type{e}; + auto t = std::move(r); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + 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,layout_type>; - - std::random_device device{}; - std::minstd_rand0 generator(device()); - - using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; - auto distribution = distribution_type(1,6); - - for(auto const& e : extents){ - auto r = value_type( static_cast< inner_type_t >(distribution(generator)) ); - auto t = tensor_type{e,r}; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( t[i], r ); - } + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + std::random_device device{}; + std::minstd_rand0 generator(device()); + + using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; + auto distribution = distribution_type(1,6); + + for(auto const& e : extents){ + auto r = value_type( static_cast< inner_type_t >(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,layout_type>; - using array_type = typename tensor_type::array_type; - - for(auto const& e : extents) { - auto a = array_type(product(e)); - 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); - } + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using array_type = typename tensor_type::array_type; + + for(auto const& e : extents) { + auto a = array_type(product(e)); + 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,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 ); - } - } + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + 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,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 k; - auto r = std::is_same::value ? 1 : 0; - auto q = std::is_same::value ? 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 k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 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 k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + 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 k; + auto r = std::is_same::value ? 1 : 0; + auto q = std::is_same::value ? 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 k; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 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 k; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 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); } @@ -379,34 +379,34 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, 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,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(product(efrom),product(eto)); ++i) - BOOST_CHECK_EQUAL( t[i], v ); - - BOOST_CHECK_EQUAL ( t.size() , product(eto) ); - BOOST_CHECK_EQUAL ( t.rank() , eto.size() ); - BOOST_CHECK ( t.extents() == eto ); - - if(efrom != eto){ - for(auto i = product(efrom); i < t.size(); ++i) - BOOST_CHECK_EQUAL( t[i], value_type{} ); - } - } - } + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + 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(product(efrom),product(eto)); ++i) + BOOST_CHECK_EQUAL( t[i], v ); + + BOOST_CHECK_EQUAL ( t.size() , product(eto) ); + BOOST_CHECK_EQUAL ( t.rank() , eto.size() ); + BOOST_CHECK ( t.extents() == eto ); + + if(efrom != eto){ + for(auto i = product(efrom); i < t.size(); ++i) + BOOST_CHECK_EQUAL( t[i], value_type{} ); + } + } + } } @@ -414,64 +414,64 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixtu 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,layout_type>; - for(auto const& e_t : extents){ - for(auto const& e_r : extents) { + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + 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}; + 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 ); + std::swap( r, t ); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( t[i], w ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( t[i], w ); - BOOST_CHECK_EQUAL ( t.size() , product(e_r) ); - BOOST_CHECK_EQUAL ( t.rank() , e_r.size() ); - BOOST_CHECK ( t.extents() == e_r ); + BOOST_CHECK_EQUAL ( t.size() , product(e_r) ); + 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 ); + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL( r[i], v ); - BOOST_CHECK_EQUAL ( r.size() , product(e_t) ); - BOOST_CHECK_EQUAL ( r.rank() , e_t.size() ); - BOOST_CHECK ( r.extents() == e_t ); + BOOST_CHECK_EQUAL ( r.size() , product(e_t) ); + 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,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() ) ) ; - } - } + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + + 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_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, value, test_types, fixture) @@ -479,7 +479,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, 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, layout_type>; + using tensor_type = ublas::dynamic_tensor; std::vector vec(30); BOOST_CHECK_THROW(tensor_type({5,5},vec), std::runtime_error); diff --git a/test/tensor/test_tensor_matrix_vector.cpp b/test/tensor/test_tensor_matrix_vector.cpp index d6f71f871..313e5f7f8 100644 --- a/test/tensor/test_tensor_matrix_vector.cpp +++ b/test/tensor/test_tensor_matrix_vector.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -28,86 +28,76 @@ using test_types = zip::with_t,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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + + 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,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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using vector_type = typename tensor_type::vector_type; + + 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::dynamic_extents<>; - fixture() - : extents{ - extents_type{1,1}, // 1 - extents_type{2,3}, // 2 - extents_type{9,11}, // 2 - extents_type{15,17}} // 3 - { - } - std::vector extents; + using extents_type = boost::numeric::ublas::dynamic_extents<>; + fixture() + : extents{ + extents_type{1,1}, // 1 + extents_type{2,3}, // 2 + extents_type{9,11}, // 2 + extents_type{15,17}} // 3 + { + } + std::vector extents; }; @@ -115,152 +105,152 @@ struct fixture 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,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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - BOOST_CHECK_NE ( t.data() , nullptr); - }; - - for(auto const& e : extents) - check(e); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + 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() , product(e) ); + 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,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(product(e)); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - BOOST_CHECK_NE ( t.data() , nullptr); - }; - - for(auto const& e : extents) - check(e); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + 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(product(e)); + BOOST_CHECK_EQUAL ( t.size() , product(e) ); + 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,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() , product(e) ); - 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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + 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() , product(e) ); + 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,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() , product(e) ); - 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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + 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() , product(e) ); + 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,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() , product(e) ); - 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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + 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() , product(e) ); + 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); } @@ -268,35 +258,35 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, te 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,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() , product(e) ); - 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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + 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() , product(e) ); + 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); } @@ -305,56 +295,56 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, te 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,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() , product(e) ); - 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() , product(e) ); - 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() , product(e) ); - 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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + 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() , product(e) ); + 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() , product(e) ); + 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() , product(e) ); + 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); } @@ -364,106 +354,105 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_t 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,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() , product(e) ); - 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() , product(e) ); - 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() , product(e) ); - 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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + 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() , product(e) ); + 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() , product(e) ); + 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() , product(e) ); + 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,layout_type>; - using matrix_type = typename tensor_type::matrix_type; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const& e) - { - if(product(e) <= 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); + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::dynamic_tensor; + using matrix_type = typename tensor_type::matrix_type; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const& e) + { + if(product(e) <= 2) + return; + assert(e.size() == 2); + auto Q = tensor_type{e[0],1}; + auto A = matrix_type(e[0],e[1]); + auto b = vector_type(e[1]); + auto c = vector_type(e[0]); + std::iota(b.data().begin(),b.data().end(), 1); + std::fill(A.data().begin(),A.data().end(), 1); + std::fill(c.data().begin(),c.data().end(), 2); + std::fill(Q.begin(),Q.end(), 2); + + tensor_type T = Q + (ublas::prod(A , b) + 2*c) + 3*Q; + + BOOST_CHECK_EQUAL ( T.extents().at(0) , Q.extents().at(0) ); + BOOST_CHECK_EQUAL ( T.extents().at(1) , Q.extents().at(1)); + BOOST_CHECK_EQUAL ( T.size() , Q.size() ); + BOOST_CHECK_EQUAL ( T.size() , c.size() ); + BOOST_CHECK_EQUAL ( T.rank() , Q.rank() ); + BOOST_CHECK ( !T.empty() ); + BOOST_CHECK_NE ( T.data() , nullptr); + + for(auto i = 0ul; i < T.size(); ++i){ + auto n = e[1]; + auto ab = n * (n+1) / 2; + BOOST_CHECK_EQUAL( T(i), ab+4*Q(0)+2*c(0) ); + } + + }; + + + + for(auto const& e : extents) + check(e); } BOOST_AUTO_TEST_SUITE_END() - diff --git a/test/tensor/utility.hpp b/test/tensor/utility.hpp index 2f029f349..45c2b48b9 100644 --- a/test/tensor/utility.hpp +++ b/test/tensor/utility.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -21,28 +21,28 @@ struct zip_helper; template struct zip_helper, type1> { - template - struct with - { - using type = std::tuple...>; - }; - template - using with_t = typename with::type; + template + struct with + { + using type = std::tuple...>; + }; + template + using with_t = typename with::type; }; template struct zip_helper, type1, types1...> { - template - struct with - { - using next_tuple = std::tuple...>; - using type = typename zip_helper::template with::type; - }; - - template - using with_t = typename with::type; + template + struct with + { + using next_tuple = std::tuple...>; + using type = typename zip_helper::template with::type; + }; + + template + using with_t = typename with::type; }; template From 47a314dd01d1adacaaf7265c7c644f8f70afd402 Mon Sep 17 00:00:00 2001 From: Conrad Poelman Date: Mon, 11 May 2020 13:53:03 -0400 Subject: [PATCH 13/36] C++20/gcc10 removed allocator construct/destroy (#83) std::allocator::construct/destroy were deprecated in C++17 and removed in C++20, in favor of std::allocator_traits::construct/destroy. (https://en.cppreference.com/w/cpp/memory/allocator_traits/construct). They are gone in gcc10. This fix switches to the the latter for C++17 and greater. --- include/boost/numeric/ublas/storage.hpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/boost/numeric/ublas/storage.hpp b/include/boost/numeric/ublas/storage.hpp index e28ac7c1b..fd0c58d24 100644 --- a/include/boost/numeric/ublas/storage.hpp +++ b/include/boost/numeric/ublas/storage.hpp @@ -76,7 +76,11 @@ namespace boost { namespace numeric { namespace ublas { #pragma warning(pop) #endif for (pointer d = data_; d != data_ + size_; ++d) +#if __cplusplus >= 201703L + std::allocator_traits::construct (alloc_, d, value_type()); +#else alloc_.construct(d, value_type()); +#endif } } else @@ -149,17 +153,29 @@ namespace boost { namespace numeric { namespace ublas { pointer di = data_; if (size < size_) { for (; di != data_ + size; ++di) { +#if __cplusplus >= 201703L + std::allocator_traits::construct (alloc_, di, *si); +#else alloc_.construct (di, *si); +#endif ++si; } } else { for (; si != p_data + size_; ++si) { +#if __cplusplus >= 201703L + std::allocator_traits::construct (alloc_, di, *si); +#else alloc_.construct (di, *si); +#endif ++di; } for (; di != data_ + size; ++di) { +#if __cplusplus >= 201703L + std::allocator_traits::construct (alloc_, di, init); +#else alloc_.construct (di, init); +#endif } } } @@ -174,7 +190,11 @@ namespace boost { namespace numeric { namespace ublas { #pragma warning(pop) #endif for (pointer di = data_; di != data_ + size; ++di) +#if __cplusplus >= 201703L + std::allocator_traits::construct(alloc_, di, value_type()); +#else alloc_.construct (di, value_type()); +#endif } } } @@ -190,7 +210,11 @@ namespace boost { namespace numeric { namespace ublas { #pragma warning(pop) #endif for (pointer si = p_data; si != p_data + size_; ++si) +#if __cplusplus >= 201703L + std::allocator_traits::destroy (alloc_, si); +#else alloc_.destroy (si); +#endif } alloc_.deallocate (p_data, size_); } From 6f823d183b375dbc52adc30860c2c30458fae901 Mon Sep 17 00:00:00 2001 From: Cem Bassoy Date: Tue, 23 Jun 2020 14:59:51 +0200 Subject: [PATCH 14/36] bug in test/tensor/test_static_functions.cpp with memory leak fixed. (#85) --- .../ublas/tensor/fixed_rank_extents.hpp | 2 +- .../numeric/ublas/tensor/static_extents.hpp | 3 +- test/tensor/test_fixed_rank_functions.cpp | 6 +- test/tensor/test_static_functions.cpp | 405 ++++++++++-------- test/tensor/utility.hpp | 24 +- 5 files changed, 241 insertions(+), 199 deletions(-) diff --git a/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp b/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp index 7d8ce075d..66ccef2f9 100644 --- a/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp +++ b/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp @@ -90,7 +90,7 @@ struct basic_fixed_rank_extents } constexpr basic_fixed_rank_extents(const_iterator begin, const_iterator end){ - if( std::distance(begin,end) > _size ){ + if( std::distance(begin,end) < 0 || static_cast(std::distance(begin,end)) > _size){ throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than _size"); } diff --git a/include/boost/numeric/ublas/tensor/static_extents.hpp b/include/boost/numeric/ublas/tensor/static_extents.hpp index c2719be8a..675765e0e 100644 --- a/include/boost/numeric/ublas/tensor/static_extents.hpp +++ b/include/boost/numeric/ublas/tensor/static_extents.hpp @@ -6,8 +6,7 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // -// The authors gratefully acknowledge the support of -// Google +// The authors gratefully acknowledge the support of Google // #ifndef _BOOST_NUMERIC_UBLAS_TENSOR_STATIC_EXTENTS_HPP_ diff --git a/test/tensor/test_fixed_rank_functions.cpp b/test/tensor/test_fixed_rank_functions.cpp index 3855a67fc..cf6e4332c 100644 --- a/test/tensor/test_fixed_rank_functions.cpp +++ b/test/tensor/test_fixed_rank_functions.cpp @@ -357,7 +357,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_outer_prod, value, tes using extents_type_1 = typename std::decay::type; using tensor_type_1 = ublas::fixed_rank_tensor; auto a = tensor_type_1(n1, value_type(2)); - for_each_tuple(fixed_rank_extents,[&](auto const& J, auto const& n2){ + for_each_tuple(fixed_rank_extents,[&](auto const& /*J*/, auto const& n2){ using extents_type_2 = typename std::decay::type; using tensor_type_2 = ublas::fixed_rank_tensor; auto b = tensor_type_2(n2, value_type(1)); @@ -370,10 +370,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_outer_prod, value, tes }); - for_each_tuple(fixed_rank_extents,[&](auto const& I, auto const& n1){ + for_each_tuple(fixed_rank_extents,[&](auto const& I, auto const& /*n1*/){ using tensor_type_1 = ublas::dynamic_tensor; auto a = tensor_type_1(extents[I], value_type(2)); - for_each_tuple(fixed_rank_extents,[&](auto const& J, auto const& n2){ + for_each_tuple(fixed_rank_extents,[&](auto const& /*J*/, auto const& n2){ using extents_type_2 = typename std::decay::type; using tensor_type_2 = ublas::fixed_rank_tensor; auto b = tensor_type_2(n2, value_type(1)); diff --git a/test/tensor/test_static_functions.cpp b/test/tensor/test_static_functions.cpp index 1d53ca389..c93e258c4 100644 --- a/test/tensor/test_static_functions.cpp +++ b/test/tensor/test_static_functions.cpp @@ -35,7 +35,7 @@ struct fixture { template using static_extents_type = boost::numeric::ublas::static_extents; - + using dynamic_extents_type = boost::numeric::ublas::dynamic_extents<>; fixture() @@ -68,21 +68,21 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_prod_vector, value, test_t using value_type = typename value::first_type; using layout_type = typename value::second_type; - for_each_tuple(static_extents,[](auto const&, auto& n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::static_tensor; - using vector_type = typename tensor_type::vector_type; + for_each_tuple(static_extents,[](auto const&, auto& n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::static_tensor; + using vector_type = typename tensor_type::vector_type; auto a = tensor_type(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( static_cast< inner_type_t >(n[m]) ) * a[i]); - } + + 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( static_cast< inner_type_t >(n[m]) ) * a[i]); + } }); } @@ -93,20 +93,20 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_prod_matrix, value, test_t using value_type = typename value::first_type; using layout_type = typename value::second_type; - for_each_tuple(static_extents,[](auto const&, auto & n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::static_tensor; - using matrix_type = typename tensor_type::matrix_type; - auto a = tensor_type(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( static_cast< inner_type_t >(n[m]) ) * a[i]); - } + for_each_tuple(static_extents,[](auto const&, auto & n){ + using extents_type = typename std::decay::type; + using tensor_type = ublas::static_tensor; + using matrix_type = typename tensor_type::matrix_type; + auto a = tensor_type(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( static_cast< inner_type_t >(n[m]) ) * a[i]); + } }); } @@ -117,67 +117,63 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_prod_tensor_1, value, test using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto const body = [](auto const& a, auto const& b){ - auto const pa = a.rank(); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phi = std::vector(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 *= value_type( static_cast< inner_type_t >( 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]); - } - }; + auto const body = [](auto const& a, auto const& b){ + auto const pa = a.rank(); + for (auto q = 0ul; q <= pa; ++q) { - //static extents and static_extents - for_each_tuple(static_extents,[&](auto const&, auto & n){ - auto n1 = n; - auto n2 = n; - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = - ublas::static_tensor; - using tensor_type_2 = - ublas::static_tensor; - auto a = tensor_type_1(value_type{2}); - auto b = tensor_type_2(value_type{3}); - body(a,b); - }); + auto phi = std::vector(q); - for_each_tuple(static_extents,[&](auto const& I, auto & n){ - auto n1 = n; - auto n2 = extents[I]; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = - ublas::static_tensor; - using tensor_type_2 = - ublas::dynamic_tensor; - auto a = tensor_type_1(value_type{2}); - auto b = tensor_type_2(n1,value_type{3}); - body(a,b); - }); + std::iota(phi.begin(), phi.end(), 1ul); - for_each_tuple(static_extents,[&](auto const& I, auto & n){ - auto n1 = extents[I]; - auto n2 = n; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = - ublas::dynamic_tensor; - using tensor_type_2 = - ublas::static_tensor; - auto a = tensor_type_1(n1,value_type{2}); - auto b = tensor_type_2(value_type{3}); - body(a,b); - }); + auto c = ublas::prod(a, b, phi); + + auto acc = value_type(1); + for (auto i = 0ul; i < q; ++i) + acc *= value_type( static_cast< inner_type_t >( 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]); + } + }; + + std::apply ( + [&body](auto&& ... sextents) + { + ( + body( + ublas::static_tensor, layout_type>(value_type{2}) , + ublas::static_tensor, layout_type>(value_type{3}) ), ... + ); + }, + static_extents + ); + + + std::apply ( + [&body](auto&& ... sextents ) + { + ( + body( + ublas::static_tensor , layout_type>( value_type{2}) , + ublas::dynamic_tensor((sextents),value_type{3})), ... + ); + }, + static_extents + ); + + + std::apply ( + [&body](auto&& ... sextents ) + { + ( + body( + ublas::dynamic_tensor((sextents),value_type{2}), + ublas::static_tensor , layout_type>( value_type{3})), ... + ); + }, + static_extents + ); } @@ -213,83 +209,83 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_prod_tensor_2, value, test // static and dynamic for_each_tuple(static_extents,[&](auto const&, auto & n){ - auto na = n; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::static_tensor; - auto a = tensor_type_1(value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_s_1(pi, na); - using tensor_type_2 = ublas::dynamic_tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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) + auto na = n; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::static_tensor; + auto a = tensor_type_1(value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_s_1(pi, na); + using tensor_type_2 = ublas::dynamic_tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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 *= value_type( static_cast< inner_type_t >( 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()); - } + + 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()); + } }); //static and static for_each_tuple(static_extents,[&](auto const&, auto & n){ - auto na = n; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::static_tensor; - auto a = tensor_type_1(value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_s_2(pi, na); - - using tensor_type_2 = ublas::dynamic_tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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) + auto na = n; + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::static_tensor; + auto a = tensor_type_1(value_type{2}); + auto const pa = a.rank(); + + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota(pi.begin(), pi.end(), 1); + + for (auto f = 0ul; f < fac; ++f) { + auto nb = permute_extents_s_2(pi, na); + + using tensor_type_2 = ublas::dynamic_tensor; + auto b = tensor_type_2(nb, value_type{3}); + + for (auto q = 0ul; q <= pa; ++q) { + + auto phia = std::vector(q); + auto phib = std::vector(q); + + 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()); - } + + 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()); + } }); } @@ -302,17 +298,24 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_inner_prod, value, test_ty using layout_type = typename value::second_type; auto const body = [&](auto const& a, auto const& b){ - auto c = ublas::inner_prod(a, b); - auto r = std::inner_product(a.begin(),a.end(), b.begin(),value_type(0)); + if(a.size() == 0u || b.size() == 0u ) + return; + + 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_CHECK_EQUAL( c , r ); }; for_each_tuple(static_extents,[&](auto const&, auto & n){ - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; + using extents_type_1 = typename std::decay::type; + using extents_type_2 = typename std::decay::type; using tensor_type_1 = ublas::static_tensor; using tensor_type_2 = ublas::static_tensor; + + if constexpr(extents_type_1::_size == 0u || extents_type_2::_size == 0u) + return; + auto a = tensor_type_1(value_type(2)); auto b = tensor_type_2(value_type(1)); body(a,b); @@ -320,22 +323,42 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_inner_prod, value, test_ty }); for_each_tuple(static_extents,[&](auto const& I, auto & n){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::static_tensor; - using tensor_type_2 = ublas::dynamic_tensor; - auto a = tensor_type_1(value_type(2)); - auto b = tensor_type_2(extents[I], value_type(1)); - body(a,b); + if(extents.empty() || std::tuple_size_v == 0u) + return; + + assert(extents.size() > I); + + using extents_type_1 = typename std::decay::type; + using tensor_type_1 = ublas::static_tensor; + using tensor_type_2 = ublas::dynamic_tensor; + + if constexpr(extents_type_1::_size == 0u) + return; + + auto a = tensor_type_1(value_type(2)); + auto b = tensor_type_2(extents[I], value_type(1)); + body(a,b); + }); for_each_tuple(static_extents,[&](auto const& I, auto & n){ - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::dynamic_tensor; - using tensor_type_2 = ublas::static_tensor; - auto a = tensor_type_1(extents[I], value_type(2)); - auto b = tensor_type_2(value_type(1)); - body(a,b); + + if(extents.empty()) + return; + + using extents_type_2 = typename std::decay::type; + using tensor_type_1 = ublas::dynamic_tensor; + using tensor_type_2 = ublas::static_tensor; + + if constexpr(extents_type_2::_size == 0u) + return; + + assert(extents.size() > I); + + auto a = tensor_type_1(extents[I], value_type(2)); + auto b = tensor_type_2(value_type(1)); + body(a,b); }); @@ -348,27 +371,41 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_outer_prod, value, test_ty using layout_type = typename value::second_type; for_each_tuple(static_extents,[&](auto const&, auto const& n1){ - using extents_type_1 = typename std::decay::type; + using extents_type_1 = typename std::decay::type; + + if constexpr(extents_type_1::_size == 0u) + return; + using tensor_type_1 = ublas::static_tensor; auto a = tensor_type_1(value_type(2)); - for_each_tuple(static_extents,[&](auto const& J, auto const& n2){ - using extents_type_2 = typename std::decay::type; + for_each_tuple(static_extents,[&](auto const& /*J*/, auto const& n2){ + using extents_type_2 = typename std::decay::type; using tensor_type_2 = ublas::static_tensor; + + if constexpr(extents_type_2::_size == 0u) + return; + auto b = tensor_type_2(value_type(1)); auto c = ublas::outer_prod(a, b); for(auto const& cc : c) BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - + }); }); - for_each_tuple(static_extents,[&](auto const& I, auto const& n1){ + for_each_tuple(static_extents,[&](auto const& I, auto const& /*n1*/){ using tensor_type_1 = ublas::dynamic_tensor; + + if(extents.empty() || std::tuple_size_v) + return; + + assert(extents.size() > I); + auto a = tensor_type_1(extents[I], value_type(2)); - for_each_tuple(static_extents,[&](auto const& J, auto const& n2){ - using extents_type_2 = typename std::decay::type; + for_each_tuple(static_extents,[&](auto const& /*J*/, auto const& n2){ + using extents_type_2 = typename std::decay::type; using tensor_type_2 = ublas::static_tensor; auto b = tensor_type_2(value_type(1)); auto c = ublas::outer_prod(a, b); @@ -380,7 +417,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_outer_prod, value, test_ty }); for_each_tuple(static_extents,[&](auto const&, auto const& n1){ - using extents_type_1 = typename std::decay::type; + using extents_type_1 = typename std::decay::type; using tensor_type_1 = ublas::static_tensor; auto a = tensor_type_1(value_type(2)); for(auto n2 : extents){ @@ -428,9 +465,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_trans, value, test_types, auto pi = std::vector(p); std::iota(pi.begin(), pi.end(), 1); - + auto a = ublas::trans( aref, pi ); - + for(auto i = 0ul; i < a.size(); i++){ BOOST_CHECK( a[i] == aref[i] ); } diff --git a/test/tensor/utility.hpp b/test/tensor/utility.hpp index 45c2b48b9..859101ed1 100644 --- a/test/tensor/utility.hpp +++ b/test/tensor/utility.hpp @@ -50,19 +50,25 @@ using zip = zip_helper,types...>; template struct for_each_tuple_impl{ - auto operator()(std::tuple& t, CallBack call_back){ - call_back(I,std::get(t)); - if constexpr(sizeof...(Ts) - 1 > I){ - for_each_tuple_impl it; - it(t,call_back); - } - } + static_assert(sizeof...(Ts) > I, "Static Assert in boost::numeric::ublas::detail::for_each_tuple"); + auto operator()(std::tuple& t, CallBack call_back) + { + call_back(I,std::get(t)); + if constexpr(sizeof...(Ts) - 1 > I){ + for_each_tuple_impl it; + it(t,call_back); + } + } }; template auto for_each_tuple(std::tuple& t, CallBack call_back){ - for_each_tuple_impl<0,CallBack,Ts...> f; - f(t,call_back); + if constexpr (std::tuple_size_v> == 0u ) + return; + + for_each_tuple_impl<0,CallBack,Ts...> f; + f(t,call_back); + } From 0584e2abaa587b24ddd7227a306f281c08228603 Mon Sep 17 00:00:00 2001 From: Ashar Date: Sat, 11 Jul 2020 11:57:28 +0000 Subject: [PATCH 15/36] GSoC20 Phase 1: Enhance CI workflows and switch to Github Actions (#89) * GSoC Phase 1: Enhance CI workflows and switch to Github Actions More details of the work of this phase could be checked at my wiki https://github.com/BoostGSoC20/ublas/wiki * Tensor tests use Github Actions Old uBLAS will only use Travis and Appveyor from old legacy CI while Tensor is now build using modern Github Action on wide array of compiler and standards and codes. * Add Copyright notice and refactor windows matrix --- .appveyor.yml | 10 +- .ci/install-clblas.sh | 3 + .ci/post_review.py | 221 ++++++++++++++ .ci/report_coverage.sh | 23 +- .clang-format | 394 +++++++++++++++++++++++++ .clang-tidy | 11 + .github/workflows/address_san.yml | 67 +++++ .github/workflows/apple_clang.yml | 65 ++++ .github/workflows/clangtidy_check.yml | 37 +++ .github/workflows/clangtidy_review.yml | 44 +++ .github/workflows/code_format.yml | 24 ++ .github/workflows/linux_clang.yml | 82 +++++ .github/workflows/linux_gcc.yml | 91 ++++++ .github/workflows/thread_san.yml | 68 +++++ .github/workflows/ub_san.yml | 68 +++++ .github/workflows/windows_msvc.yml | 85 ++++++ .travis.yml | 22 +- README.md | 64 +++- benchmarks/opencl/Jamfile | 1 + examples/tensor/.clang-tidy | 11 + examples/tensor/Jamfile | 4 +- test/Jamfile | 2 - test/opencl/Jamfile | 1 + test/tensor/Jamfile | 3 +- 24 files changed, 1336 insertions(+), 65 deletions(-) create mode 100644 .ci/post_review.py create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .github/workflows/address_san.yml create mode 100644 .github/workflows/apple_clang.yml create mode 100644 .github/workflows/clangtidy_check.yml create mode 100644 .github/workflows/clangtidy_review.yml create mode 100644 .github/workflows/code_format.yml create mode 100644 .github/workflows/linux_clang.yml create mode 100644 .github/workflows/linux_gcc.yml create mode 100644 .github/workflows/thread_san.yml create mode 100644 .github/workflows/ub_san.yml create mode 100644 .github/workflows/windows_msvc.yml create mode 100644 examples/tensor/.clang-tidy diff --git a/.appveyor.yml b/.appveyor.yml index 12bec8fce..2b2d8fd53 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -11,8 +11,6 @@ branches: - master - develop - /feature\/.*/ - - expr_template - - framework environment: matrix: @@ -26,9 +24,6 @@ environment: TOOLSET: msvc-14.0 CXXSTD: 11 -# cache: - # - c:\tools\vcpkg\installed\ - install: - cd "C:\Tools\vcpkg" - git pull @@ -74,9 +69,6 @@ install: build: off test_script: - #- PATH=%ADDPATH%%PATH% - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% - set ADDRMD=address-model=64 - - b2 -j3 libs/numeric/ublas/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% - - b2 -j3 libs/numeric/ublas/benchmarks toolset=%TOOLSET% %CXXSTD% %ADDRMD% - - b2 -j3 libs/numeric/ublas/examples/tensor toolset=%TOOLSET% %CXXSTD% %ADDRMD% + - b2 -j3 libs/numeric/ublas/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% \ No newline at end of file diff --git a/.ci/install-clblas.sh b/.ci/install-clblas.sh index f8d9a6cc7..27994e87c 100755 --- a/.ci/install-clblas.sh +++ b/.ci/install-clblas.sh @@ -3,8 +3,11 @@ wget https://github.com/clMathLibraries/clBLAS/releases/download/v2.12/clBLAS-2.12.0-Linux-x64.tar.gz tar xvf clBLAS-2.12.0-Linux-x64.tar.gz if [ ${CLBLAS_PREFIX} ]; then + echo "Installing clBLAS-2.12.0" mkdir -p ${CLBLAS_PREFIX}/lib/ cp -r clBLAS-2.12.0-Linux-x64/include ${CLBLAS_PREFIX}/include cp -r clBLAS-2.12.0-Linux-x64/lib64/* ${CLBLAS_PREFIX}/lib/ cp -r clBLAS-2.12.0-Linux-x64/bin ${CLBLAS_PREFIX}/bin +else + echo "CLBLAS_PREFIX is not set. Skipping CLBLAS Installation" fi diff --git a/.ci/post_review.py b/.ci/post_review.py new file mode 100644 index 000000000..7f6f473d3 --- /dev/null +++ b/.ci/post_review.py @@ -0,0 +1,221 @@ +#! usr/bin/env python3 + +# Automatically create review from clang-tidy report +# Copyright (c) 2020 Ashar Khan +# Licensed under Boost Software License 1.0 + +import argparse +from github import Github +import unidiff +import os +import requests + + +def fetch_diff(repository, pr, token): + """ + Fetch the diff of PR from repository using Github Authentication token + """ + headers = { + "Accept": "application/vnd.github.v3.diff", + "Authorization": f"token {token}", + } + url = f"https://api.github.com/repos/{repository}/pulls/{pr}" + response = requests.get(url, headers=headers) + response.raise_for_status() + + return unidiff.PatchSet(response.text) + + +def parse_report_file(content): + """ + Parses clang-tidy stdout content to a list of tuple(relpath, line, comment), this tuple is called reports throughout the docs. + relpath: The relative path of source that generated clang-tidy warning or error + line: Line number in the above soure to which the error or warning belongs + comment: The actual clang-tidy error or warning for above line and source + """ + root_path = os.getcwd() + parsed_report = [] + n = len(content) + i = 0 + while (i < n): + if "error" in content[i] or "warning" in content[i]: + abs_file_path, line_number, _, severity, message = content[i].split( + ":", maxsplit=4) + relative_path = os.path.relpath(abs_file_path, root_path) + + k = 1 + body = "" + while i+k < n and not ("error" in content[i+k] or "warning" in content[i+k]): + body += "\n" + content[i + k].replace(abs_file_path, relative_path) + k += 1 + i += k + + message = message.strip().replace("'", "`") + body = body.strip() + + comment_text = f"""{message} +```cpp +{body} +``` +Reported as{severity} by clang-tidy. +""" + parsed_report.append((relative_path, line_number, comment_text)) + return parsed_report + + +def file_filter_report(reports, diff): + """ + Filter the reports so that it only contains the reports for files in diff that have changed or been added in the PR + """ + changed_files = [] + for file in diff: + changed_files.append(file.target_file[2:]) + + filtered_report = [] + for report in reports: + rel_path, line_number, comment_text = report + if rel_path in changed_files: + filtered_report.append(report) + + return filtered_report + + +def line_filter_report(reports, diff): + """ + Filter the reports so that it only contains the reports for lines in the diff that have been added. + """ + files_in_report = [i[0] for i in reports] + filtered_report = [] + + lookup = {} + for file in diff: + if file.target_file[2:] in files_in_report: + for hunk in file: + for line in hunk.target_lines(): + if line.is_added: + if file.target_file[2:] not in lookup: + lookup[file.target_file[2:]] = list() + lookup[file.target_file[2:]].append( + int(line.target_line_no)) + + for report in reports: + fileName, number, _ = report + number = int(number) + if number in lookup[fileName]: + filtered_report.append(report) + + return filtered_report + + +def line_to_position(reports, diff): + """ + The actual source file line number in report is different from what we need to send to github as review payload. + This function converts the clang-tidy generated error or warning line numbers to position in diff, + so that review can be made for position relevant to the PR. + """ + lookup = {} + for file in diff: + filename = file.target_file[2:] + lookup[filename] = {} + pos = 1 + for hunk in file: + for line in hunk: + if not line.is_removed: + lookup[filename][line.target_line_no] = pos + pos += 1 + pos += 1 + new_reports = [] + for report in reports: + x, y, z = report + new_reports.append((x, lookup[x][int(y)], z)) + + return new_reports + + +def comment_lgtm(pr_handle): + """ + Posts a LGTM (Looks good to me!) comment in the PR, if PR did not produced new clang-tidy warnings or errors. + """ + lgtm = 'This Pull request Passed all of clang-tidy tests. :+1:' + comments = pr_handle.get_issue_comments() + + for comment in comments: + if comment.body == lgtm: + print("Already posted LGTM!!") + return + + pr_handle.create_issue_comment(lgtm) + + +def post_review(reports, pr_handle): + """ + Posts the reports as review to the PR + """ + comments = pr_handle.get_review_comments() + for comment in comments: + target = (comment.path, comment.position, comment.body) + if target in reports: + reports.remove((comment.path, comment.position, comment.body)) + + if len(reports) == 0: + comment_lgtm(pr_handle) + else: + comments = [] + for report in reports: + comments.append( + {"path": report[0], "position": report[1], "body": report[2]}) + + review = { + "body": "Reports by clang tidy", + "event": "COMMENT", + "comments": comments, + } + + pr_handle.create_review(**review) + print("Review comments are on its way!") + + +def main(pathToClangReport, repository, pr, token): + """ + Psudo-Main function, that calls all above functions in order. + """ + f = open(pathToClangReport) + lines = f.read().splitlines() + f.close() + + reports = parse_report_file(lines) + diff = fetch_diff(repository, pr, token) + # Filter the report, So that only changed files are commented + reports = file_filter_report(reports, diff) + # Fileter the reports, So that only changed lines are commented + reports = line_filter_report(reports, diff) + + github = Github(token) + repo = github.get_repo(f"{repository}") + pr_handle = repo.get_pull(pr) + + if len(reports) == 0: + comment_lgtm(pr_handle) + else: + post_review(line_to_position(reports, diff), pr_handle) + + +if __name__ == "__main__": + """ + Parses command line arguments for the script and calls main function with the script. + """ + parser = argparse.ArgumentParser( + description="Create review from clang tidy file") + parser.add_argument( + "--path", help="Path to clang-tidy report file. This file can be" + "generated by redirecting stdout of clang-tidy to a file while running the check", required=True) + parser.add_argument( + "--repository", help="Pass repositor on Github with owner/repo format", required=True) + parser.add_argument( + "--pr", help="The repository's PR number to perform review", type=int, required=True) + parser.add_argument( + "--token", help="Github authentication token", required=True) + + args = parser.parse_args() + + main(args.path, args.repository, args.pr, args.token) diff --git a/.ci/report_coverage.sh b/.ci/report_coverage.sh index 0106329de..19ec243e6 100755 --- a/.ci/report_coverage.sh +++ b/.ci/report_coverage.sh @@ -1,19 +1,10 @@ #! /bin/bash -e -# Only collect and upload coverage reports from C++17 Builds -# This is required because Tensor Extension only runs with C++17 +sudo apt-get install lcov +lcov --rc lcov_branch_coverage=1 --directory $BOOST_ROOT --capture --output-file coverage.info -if [ $CXXSTD == '17' ] - then - # Capture all the coverge reports - lcov --rc lcov_branch_coverage=1 --directory $BOOST_ROOT --capture --output-file coverage.info - - # Remove all unwanted coverages libs. - # Boost.uBLAS depends uses many internal boost libs, we don't want them to be in coverage. - - lcov --rc lcov_branch_coverage=1 --extract coverage.info "*/boost/numeric/ublas/*" "*/libs/numeric/ublas/*" --output-file coverage.info - - lcov --rc lcov_branch_coverage=1 --list coverage.info -else - echo "Skipping Coverage Reporting as CXXSTD is 11" -fi +# Remove all unwanted coverages libs. +# Boost.uBLAS depends uses many internal boost libs, we don't want them to be in coverage. + +lcov --rc lcov_branch_coverage=1 --extract coverage.info "*/boost/numeric/ublas/tensor/*" "*/libs/numeric/ublas/tensor/*" --output-file coverage.info +lcov --rc lcov_branch_coverage=1 --list coverage.info diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..448ebcf4e --- /dev/null +++ b/.clang-format @@ -0,0 +1,394 @@ +--- +Language: Cpp +# BasedOnStyle: Microsoft +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +# someLongFunction(argument1, +# argument2); +# +AlignConsecutiveMacros: true +# #define SHORT_NAME 42 +# #define LONGER_NAME 0x007f +# #define EVEN_LONGER_NAME (2) +# +AlignConsecutiveAssignments: true +# int aaaa = 12; +# int b = 23; +# int ccc = 23; +# +AlignConsecutiveDeclarations: false +# +AlignEscapedNewlines: Left +# #define A \ +# int aaaa; \ +# int b; \ +# int dddddddddd; +# +AlignOperands: true +# int aaa = bbbbbbbbbbbbbbb + +# ccccccccccccccc; +# +AlignTrailingComments: true +# int a; // My comment a +# int b = 2; // comment b +# +AllowAllArgumentsOnNextLine: true +# callFunction( +# a, b, c, d); +# +AllowAllConstructorInitializersOnNextLine: true +# MyClass::MyClass() : +# member0(0), +# member1(2) {} +# +AllowAllParametersOfDeclarationOnNextLine: true +# void myFunction( +# int a, int b, int c, int d, int e); +# +AllowShortBlocksOnASingleLine: true +# if (a) { return; } +# +AllowShortCaseLabelsOnASingleLine: false +# switch (a) { +# case 1: x = 1; break; +# case 2: return; +# } +# +AllowShortFunctionsOnASingleLine: All +# class Foo { +# void f() { foo(); } +# }; +# void f() { bar(); } +# +AllowShortLambdasOnASingleLine: All +# auto lambda = [](int a) {} +# auto lambda2 = [](int a) { return a; }; +# +# Not found in clang 9.0.0 +# AllowShortIfStatementsOnASingleLine: All +# +AllowShortLoopsOnASingleLine: true +# while (true) continue; +# +# Depcrated according to clang 9.0.0 +# AlwaysBreakAfterDefinitionReturnType: None +# +AlwaysBreakAfterReturnType: None +# class A { +# int f() { return 0; }; +# }; +# int f(); +# int f() { return 1; } +# +AlwaysBreakBeforeMultilineStrings: true +# aaaa = +# "bbbb" +# "cccc"; +# +AlwaysBreakTemplateDeclarations: MultiLine +# template T foo() { +# } +# template +# T foo(int aaaaaaaaaaaaaaaaaaaaa, +# int bbbbbbbbbbbbbbbbbbbbb) { +# } +# +BinPackArguments: false +# void f() { +# f(aaaaaaaaaaaaaaaaaaaa, +# aaaaaaaaaaaaaaaaaaaa, +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); +# } +# +BinPackParameters: false +# void f(int aaaaaaaaaaaaaaaaaaaa, +# int aaaaaaaaaaaaaaaaaaaa, +# int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {} +# +BraceWrapping: + AfterCaseLabel: false + AfterClass: false +# class foo +# { +# int x; +# }; + AfterControlStatement: false +# if (foo()) { +# } else { +# } +# for (int i = 0; i < 10; ++i) { +#} + AfterEnum: false +# enum X : int { B }; + AfterFunction: true +# void foo() +# { +# bar(); +# bar2(); +# } + AfterNamespace: true +# namespace +# { +# int foo(); +# int bar(); +# } + AfterObjCDeclaration: true + AfterStruct: true +# struct foo +# { +# int x; +# }; + AfterUnion: true +# union foo +# { +# int x; +# } + AfterExternBlock: true +# extern "C" +# { +# int foo(); +# } + BeforeCatch: true +# try { +# foo(); +# } +# catch () { +# } + BeforeElse: true +# if (foo()) { +# } +# else { +# } + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: None +# LooooooooooongType loooooooooooooooooooooongVariable = +# someLooooooooooooooooongFunction(); +# +# bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > +# ccccccccccccccccccccccccccccccccccccccccc; +# +BreakBeforeBraces: Stroustrup +# try { +# foo(); +# } +# catch () { +# } +# void foo() { bar(); } +# class foo { +# }; +# if (foo()) { +# } +# else { +# } +# +# enum X : int { A, B }; +# +# Not found in clang 9.0.0 +# BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeComma +# class Foo +# : Base1 +# , Base2 +# {}; +BreakBeforeTernaryOperators: true +# veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription +# ? firstValue +# : SecondValueVeryVeryVeryVeryLong; +# +# Not found in clang 9.0.0 +# BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeComma +# Constructor() +# : initializer1() +# , initializer2() +# +# Not found in clang 9.0.0 +# BreakAfterJavaFieldAnnotations: false +# +BreakStringLiterals: true +ColumnLimit: 80 +# the column limit is based on GNU, Google and Mozilla coding style +# for 1080p two split windows can be shown side by side with font size 10 +# +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +# namespace Foo { +# namespace Bar { +# } +# } +# +ConstructorInitializerAllOnOneLineOrOnePerLine: false +# SomeClass::Constructor() +# : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa), +# aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa) { +# return 0; +# } +# +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +# int i = // VeryVeryVeryVeryVeryLongComment +# longFunction( // Again a long comment +# arg); +# +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +# namespace a { +# foo(); +# } // namespace a +# +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +# #include "b.h" into #include "a.h" +# #include "b.h" +# #include +# #include "a.h" #include +# +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +# #if FOO +# #if BAR +# #include +# #endif +# #endif +# +IndentWidth: 2 +IndentWrappedFunctionNames: false +# LoooooooooooooooooooooooooooooooooooooooongReturnType +# LoooooooooooooooooooooooooooooooongFunctionDeclaration(); +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +# if (foo) { +# bar(); +# } +# +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +# Zero of consecutive empty lines to keep. +# +NamespaceIndentation: None +# namespace out { +# int i; +# namespace in { +# int i; +# } +# } +# +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1000 +PointerAlignment: Left +# int* a; +# +ReflowComments: true +# // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of +# // information +# /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of +# * information */ +# +SortIncludes: false +# #include "b.h" +# #include "a.h" +# +SortUsingDeclarations: false +# using std::cout; +# using std::cin; +# +SpaceAfterCStyleCast: false +# (int)i; +# +SpaceAfterLogicalNot: false +# !someExpression(); +# +SpaceAfterTemplateKeyword: true +# template void foo(); +# +SpaceBeforeAssignmentOperators: true +# int a = 5; +# a += 42; +# +SpaceBeforeCpp11BracedList: false +# Foo foo{ bar }; +# Foo{}; +# vector{ 1, 2, 3 }; +# new int[3]{ 1, 2, 3 }; +# +SpaceBeforeCtorInitializerColon: true +# Foo::Foo() : a(a) {} +# +SpaceBeforeInheritanceColon: true +# class Foo : Bar {} +# +SpaceBeforeParens: ControlStatements +# void f() { +# if (true) { +# f(); +# } +# } +# +SpaceBeforeRangeBasedForLoopColon: false +# for(auto v: values) {} +# +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 3 +# void f() { +# if (true) { // foo1 +# f(); // bar +# } // foo +# } +# +SpacesInAngles: false +# static_cast(arg); +# std::function fct; +# +SpacesInContainerLiterals: false +# var arr = [1, 2, 3]; +# f({a: 1, b: 2, c: 3}); +SpacesInCStyleCastParentheses: false +# x = (int32)y +# +SpacesInParentheses: false +# t f(Deleted &) & = delete; +# +SpacesInSquareBrackets: false +# int a[5]; +# +Standard: Cpp11 +# In Clang 10.0.0: Cpp11, Cpp14, Cpp17 and Cpp20 +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 2 +UseTab: Never +... + diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..e17df9a0e --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,11 @@ +--- +Checks: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements' +WarningsAsErrors: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements' +HeaderFilterRegex: 'boost\/numeric\/ublas\/tensor\/.*' +AnalyzeTemporaryDtors: false +FormatStyle: file +User: ublas-developers +CheckOptions: + - key: modernize-use-nullptr.NullMacros + value: 'NULL' +... diff --git a/.github/workflows/address_san.yml b/.github/workflows/address_san.yml new file mode 100644 index 000000000..25e77eab9 --- /dev/null +++ b/.github/workflows/address_san.yml @@ -0,0 +1,67 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: Address Sanitizer +# Trigger on Push to the repository, regardless of the branch. +# For fine tune, You can add specific branches or tags. +on: [push, pull_request] + +jobs: + build: + name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early + matrix: + config: + - {cc: gcc-9, cxx: g++-9, cxxstd: 2a, name: gcc} + - {cc: clang-9, cxx: clang++-9, cxxstd: 2a, name: clang} + steps: + - uses: actions/checkout@v2 + + - name: Prepare BOOST_ROOT + run: | + cd ${GITHUB_WORKSPACE} + cd .. + + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + + git submodule update --init --depth=1 --jobs 8 tools/build + git submodule update --init --depth=1 --jobs 8 libs/config + git submodule update --init --depth=1 --jobs 8 tools/boostdep + + mkdir -p libs/numeric/ + cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas + python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + + ./bootstrap.sh + ./b2 -j 8 headers + + echo ::set-env name=BOOST_ROOT::${PWD} + + - name: Prepare Build + run: | + echo $BOOST_ROOT + cd $BOOST_ROOT + echo "using ${{matrix.config.name}} : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; + + - name: Test Benchmarks + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 benchmarks toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} + + - name: Test Tensor Examples + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=address -fno-omit-frame-pointer" linkflags="-fsanitize=address" + + - name: Test Tensor + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=address -fno-omit-frame-pointer" linkflags="-fsanitize=address" diff --git a/.github/workflows/apple_clang.yml b/.github/workflows/apple_clang.yml new file mode 100644 index 000000000..fe7f43036 --- /dev/null +++ b/.github/workflows/apple_clang.yml @@ -0,0 +1,65 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: Apple Clang + +on: [push, pull_request] + +jobs: + build: + name: "Darwin 11.0 -std=c++${{matrix.cxxstd}}" + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + cxxstd: [11, 17, 2a] + + steps: + - uses: actions/checkout@v2 + + - name: Prepare BOOST_ROOT + run: | + cd ${GITHUB_WORKSPACE} + cd .. + + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + + git submodule update --init --depth=1 --jobs 8 tools/build + git submodule update --init --depth=1 --jobs 8 libs/config + git submodule update --init --depth=1 --jobs 8 tools/boostdep + + mkdir -p libs/numeric/ + cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas + python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + + ./bootstrap.sh + ./b2 -j 8 headers + + echo ::set-env name=BOOST_ROOT::${PWD} + + - name: Prepare Build + run: | + echo $BOOST_ROOT + cd $BOOST_ROOT + + echo "using clang : : clang++ ;" >> ~/user-config.jam; + + - name: Test Benchmarks + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 benchmarks toolset=clang cxxstd=${{matrix.cxxstd}} + + - name: Test Tensor Examples + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 examples/tensor toolset=clang cxxstd=${{matrix.cxxstd}} + + - name: Test Tensor + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 test/tensor toolset=clang cxxstd=${{matrix.cxxstd}} diff --git a/.github/workflows/clangtidy_check.yml b/.github/workflows/clangtidy_check.yml new file mode 100644 index 000000000..45e51ea07 --- /dev/null +++ b/.github/workflows/clangtidy_check.yml @@ -0,0 +1,37 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: Clang tidy checks + +on: [push] + +jobs: + check: + name: Clang tidy Check + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - name: "Install dependencies" + run: | + sudo apt-get install -y clang-10 clang-tidy-10 + + - name: "Install Boost from Source" + run: | + cd .. + git clone --depth 1 https://github.com/boostorg/boost.git --recursive --shallow-submodules + cd boost + ./bootstrap.sh + ./b2 headers + sudo cp -r -L boost /usr/include + rm -rf boost + + - name: "Run clang-tidy check" + run: | + clang-tidy-10 examples/tensor/*.cpp -- -Iinclude -std=c++17 > reports.txt + + - name: "Show clang tidy report" + if: always() + run: | + cat reports.txt diff --git a/.github/workflows/clangtidy_review.yml b/.github/workflows/clangtidy_review.yml new file mode 100644 index 000000000..b60fa69ee --- /dev/null +++ b/.github/workflows/clangtidy_review.yml @@ -0,0 +1,44 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: Clang tidy Review + +on: [pull_request] + +jobs: + check: + name: Clang tidy Review + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - name: "Install dependencies" + run: | + sudo apt-get install -y clang-10 clang-tidy-10 + + - name: "Install Boost from Source" + run: | + cd .. + git clone --depth 1 https://github.com/boostorg/boost.git --recursive --shallow-submodules + cd boost + ./bootstrap.sh + ./b2 headers + sudo cp -r -L boost /usr/include + rm -rf boost + + - uses: actions/setup-python@v2 + + - name: "Run clang-tidy check" + run: | + clang-tidy-10 examples/tensor/*.cpp -- -Iinclude -std=c++17 > reports.txt + + - name: "Post review comments" + if: always() + run: | + pip3 install 'unidiff~=0.6.0' --force-reinstall + pip3 install 'PyGithub~=1.51' --force-reinstall + pip3 install 'requests~=2.23' --force-reinstall + + python ./.ci/post_review.py --repository ${{ github.repository }} --token ${{ github.token}} --pr ${{ github.event.pull_request.number }} --path reports.txt + diff --git a/.github/workflows/code_format.yml b/.github/workflows/code_format.yml new file mode 100644 index 000000000..17f9a308c --- /dev/null +++ b/.github/workflows/code_format.yml @@ -0,0 +1,24 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: "Code Format" + +on: [push, pull_request] + +jobs: + format: + name: "Code Formatting Check" + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - name: Install Clang Format 10 + run: | + sudo apt-get install -y clang-format-10 + + - name: "Format Codes" + run: clang-format-10 -i examples/tensor/*.cpp test/tensor/*.cpp include/boost/numeric/ublas/tensor/*.hpp include/boost/numeric/ublas/tensor/*/*.hpp + + - name: Check diff + run: git diff --exit-code HEAD \ No newline at end of file diff --git a/.github/workflows/linux_clang.yml b/.github/workflows/linux_clang.yml new file mode 100644 index 000000000..0e3a19b6c --- /dev/null +++ b/.github/workflows/linux_clang.yml @@ -0,0 +1,82 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: Linux Clang Release +# Trigger on Push to the repository, regardless of the branch. +# For fine tune, You can add specific branches or tags. +on: [push, pull_request] + +jobs: + build: + name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early + matrix: + config: + - { cc: clang-6.0, cxx: clang++-6.0, cxxstd: 11} + - { cc: clang-8, cxx: clang++-8, cxxstd: 11} + - { cc: clang-9, cxx: clang++-9, cxxstd: 11} + - { cc: clang-10, cxx: clang++-10, cxxstd: 11} + - { cc: clang-6.0, cxx: clang++-6.0, cxxstd: 17} + - { cc: clang-8, cxx: clang++-8, cxxstd: 17} + - { cc: clang-9, cxx: clang++-9, cxxstd: 17} + - { cc: clang-10, cxx: clang++-10, cxxstd: 17} + - { cc: clang-10, cxx: clang++-10, cxxstd: 2a} + + steps: + - uses: actions/checkout@v2 + + - name: Install Clang 10 + if: matrix.config.cxx == 'clang++-10' + run: | + sudo apt-get update + sudo apt-get install -y clang-10 + + - name: Prepare BOOST_ROOT + run: | + cd ${GITHUB_WORKSPACE} + cd .. + + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + + git submodule update --init --depth=1 --jobs 8 tools/build + git submodule update --init --depth=1 --jobs 8 libs/config + git submodule update --init --depth=1 --jobs 8 tools/boostdep + + mkdir -p libs/numeric/ + cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas + python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + + ./bootstrap.sh + ./b2 -j 8 headers + + echo ::set-env name=BOOST_ROOT::${PWD} + + - name: Prepare Build + run: | + echo $BOOST_ROOT + cd $BOOST_ROOT + + echo "using clang : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; + + - name: Test Benchmarks + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 benchmarks toolset=clang cxxstd=${{matrix.config.cxxstd}} cxxflags="-O3" + + - name: Test Tensor Examples + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 examples/tensor toolset=clang cxxstd=${{matrix.config.cxxstd}} cxxflags="-O3" + + - name: Test Tensor + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 test/tensor toolset=clang cxxstd=${{matrix.config.cxxstd}} cxxflags="-O3" \ No newline at end of file diff --git a/.github/workflows/linux_gcc.yml b/.github/workflows/linux_gcc.yml new file mode 100644 index 000000000..8a071efa7 --- /dev/null +++ b/.github/workflows/linux_gcc.yml @@ -0,0 +1,91 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: Linux GCC Debug +# Trigger on Push to the repository, regardless of the branch. +# For fine tune, You can add specific branches or tags. +on: [push, pull_request] + +jobs: + build: + name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early + matrix: + config: + - {cc: gcc-7, cxx: g++-7, cxxstd: 11} + - {cc: gcc-8, cxx: g++-8, cxxstd: 11} + - {cc: gcc-9, cxx: g++-9, cxxstd: 11} + - {cc: gcc-10, cxx: g++-10, cxxstd: 11} + - {cc: gcc-7, cxx: g++-7, cxxstd: 17} + - {cc: gcc-8, cxx: g++-8, cxxstd: 17} + - {cc: gcc-9, cxx: g++-9, cxxstd: 17} + - {cc: gcc-10, cxx: g++-10, cxxstd: 17} + - {cc: gcc-10, cxx: g++-10, cxxstd: 2a} + steps: + - uses: actions/checkout@v2 + + - name: Install GCC-10 + if: matrix.config.cxx == 'g++-10' + run: | + sudo apt update + sudo apt-get install -y g++-10 + + - name: Prepare BOOST_ROOT + run: | + cd ${GITHUB_WORKSPACE} + cd .. + + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + + git submodule update --init --depth=1 --jobs 8 tools/build + git submodule update --init --depth=1 --jobs 8 libs/config + git submodule update --init --depth=1 --jobs 8 tools/boostdep + + mkdir -p libs/numeric/ + cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas + python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + + ./bootstrap.sh + ./b2 -j 8 headers + + echo ::set-env name=BOOST_ROOT::${PWD} + + - name: Prepare Build + run: | + echo $BOOST_ROOT + cd $BOOST_ROOT + + echo "using gcc : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; + + - name: Test Benchmarks + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 benchmarks toolset=gcc cxxstd=${{matrix.config.cxxstd}} + + - name: Test Tensor Examples + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 examples/tensor toolset=gcc cxxstd=${{matrix.config.cxxstd}} cxxflags="-O0" + + - name: Test Tensor + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 test/tensor toolset=gcc cxxstd=${{matrix.config.cxxstd}} cxxflags="-O0 -g --coverage" linkflags="--coverage" + + - name: Report Code coverage + if: matrix.config.cxxstd == '17' && matrix.config.cxx == 'g++-9' + run: | + ${GITHUB_WORKSPACE}/.ci/report_coverage.sh + + curl -s https://codecov.io/bash > cov.sh + chmod +x cov.sh + ./cov.sh -f coverage.info || echo "Codecov did not collect coverage reports" + diff --git a/.github/workflows/thread_san.yml b/.github/workflows/thread_san.yml new file mode 100644 index 000000000..6bd0c928f --- /dev/null +++ b/.github/workflows/thread_san.yml @@ -0,0 +1,68 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: Thread Sanitizer +# Trigger on Push to the repository, regardless of the branch. +# For fine tune, You can add specific branches or tags. +on: [push, pull_request] + +jobs: + build: + name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early + matrix: + config: + - {cc: gcc-9, cxx: g++-9, cxxstd: 2a, name: gcc} + - {cc: clang-9, cxx: clang++-9, cxxstd: 2a, name: clang} + steps: + - uses: actions/checkout@v2 + + - name: Prepare BOOST_ROOT + run: | + cd ${GITHUB_WORKSPACE} + cd .. + + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + + git submodule update --init --depth=1 --jobs 8 tools/build + git submodule update --init --depth=1 --jobs 8 libs/config + git submodule update --init --depth=1 --jobs 8 tools/boostdep + + mkdir -p libs/numeric/ + cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas + python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + + ./bootstrap.sh + ./b2 -j 8 headers + + echo ::set-env name=BOOST_ROOT::${PWD} + + - name: Prepare Build + run: | + echo $BOOST_ROOT + cd $BOOST_ROOT + + echo "using ${{matrix.config.name}} : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; + + - name: Test Benchmarks + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 benchmarks toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} + + - name: Test Tensor Examples + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=thread -O2" linkflags="-fsanitize=thread" + + - name: Test Tensor + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=thread -O2" linkflags="-fsanitize=thread" diff --git a/.github/workflows/ub_san.yml b/.github/workflows/ub_san.yml new file mode 100644 index 000000000..0cf8f22b7 --- /dev/null +++ b/.github/workflows/ub_san.yml @@ -0,0 +1,68 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: Undefined Behaviour Sanitizer +# Trigger on Push to the repository, regardless of the branch. +# For fine tune, You can add specific branches or tags. +on: [push, pull_request] + +jobs: + build: + name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early + matrix: + config: + - {cc: gcc-9, cxx: g++-9, cxxstd: 2a, name: gcc} + - {cc: clang-9, cxx: clang++-9, cxxstd: 2a, name: clang} + steps: + - uses: actions/checkout@v2 + + - name: Prepare BOOST_ROOT + run: | + cd ${GITHUB_WORKSPACE} + cd .. + + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + + git submodule update --init --depth=1 --jobs 8 tools/build + git submodule update --init --depth=1 --jobs 8 libs/config + git submodule update --init --depth=1 --jobs 8 tools/boostdep + + mkdir -p libs/numeric/ + cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas + python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + + ./bootstrap.sh + ./b2 -j 8 headers + + echo ::set-env name=BOOST_ROOT::${PWD} + + - name: Prepare Build + run: | + echo $BOOST_ROOT + cd $BOOST_ROOT + + echo "using ${{matrix.config.name}} : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; + + - name: Test Benchmarks + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 benchmarks toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} + + - name: Test Tensor Examples + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=undefined" linkflags="-fsanitize=undefined" + + - name: Test Tensor + run: | + cd $BOOST_ROOT + cd libs/numeric/ublas + $BOOST_ROOT/b2 -j 4 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=undefined" linkflags="-fsanitize=undefined" diff --git a/.github/workflows/windows_msvc.yml b/.github/workflows/windows_msvc.yml new file mode 100644 index 000000000..b066f4151 --- /dev/null +++ b/.github/workflows/windows_msvc.yml @@ -0,0 +1,85 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: "Windows MSVC" +on: [push, pull_request] + +jobs: + build: + name: "${{matrix.config.version}} -std=c++${{matrix.config.cxxstd}}" + runs-on: ${{matrix.config.os}} + strategy: + fail-fast: false + matrix: + config: + - {os: windows-2016, toolset: msvc, version: 14.16, cxxstd: 11} + - {os: windows-2019, toolset: msvc, version: 14.26, cxxstd: 11} + - {os: windows-2019, toolset: msvc, version: 14.26, cxxstd: 17} + - {os: windows-2019, toolset: msvc, version: 14.26, cxxstd: latest} + + steps: + - uses: actions/checkout@v2 + + - name: Enable Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1.2.0 + with: + toolset: ${{matrix.config.version}} + + - name: Setup BOOST_ROOT + shell: cmd + run: | + cd %GITHUB_WORKSPACE% + cd .. + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + git submodule update --init --depth=1 tools/build + git submodule update --init --depth=1 libs/config + git submodule update --init --depth=1 tools/boostdep + + xcopy /s /e /q %GITHUB_WORKSPACE% libs\numeric\ublas + + python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + + echo ::set-env name=BOOST_ROOT::%cd% + echo ::set-env name=TOOLSET::${{matrix.config.toolset}}-${{matrix.config.version}} + + - name: Prepare BOOST_ROOT + shell: powershell + run: | + echo $env:TOOLSET + # Creating %USERPROFILE%/user-config.jam file + @' + import os regex toolset ; + local toolset = [ regex.split [ os.environ TOOLSET ] "-" ] ; + using $(toolset[1]) : $(toolset[2-]:J="-") : ; + '@ | sc "$env:USERPROFILE/user-config.jam" + + - name: Bootstrap BOOST_ROOT + shell: cmd + run: | + cd %BOOST_ROOT% + cmd /c bootstrap + b2 -j8 headers + + - name: Test Benchmarks + shell: cmd + run: | + cd %BOOST_ROOT% + cd libs\numeric\ublas + %BOOST_ROOT%\b2 -j 4 benchmarks toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 + + - name: Test Tensor Examples + shell: cmd + run: | + cd %BOOST_ROOT% + cd libs\numeric\ublas + %BOOST_ROOT%\b2 -j 4 examples/tensor toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 + + - name: Test Tensor + shell: cmd + run: | + cd %BOOST_ROOT% + cd libs\numeric\ublas + %BOOST_ROOT%\b2 -j 4 test/tensor toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 + \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index ff6bf3a47..f4578d1b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,6 @@ branches: - develop - doc - ci - - expr_template - - framework # env: specifies additional global variables to define per row in build matrix env: @@ -55,7 +53,6 @@ addons: - clinfo - opencl-headers - ocl-icd-opencl-dev - - lcov before_install: - if [ ${TRAVIS_OS_NAME} == "linux" ]; then .ci/install-ocl-ubuntu.sh; fi @@ -78,10 +75,6 @@ install: - ./b2 -j 8 headers - export BOOST_ROOT="`pwd`" -# Use before_script: to run configure steps -before_script: - - # use script: to execute build steps script: - |- @@ -90,19 +83,8 @@ script: cp $TRAVIS_BUILD_DIR/opencl.jam ~/ cp $TRAVIS_BUILD_DIR/clblas.jam ~/ - cd libs/numeric/ublas - - travis_wait 120 sleep infinity & $BOOST_ROOT/b2 -j 8 test/tensor toolset=$TOOLSET cxxstd=$CXXSTD - - $BOOST_ROOT/b2 -j 8 benchmarks toolset=$TOOLSET cxxstd=$CXXSTD - - $BOOST_ROOT/b2 -j 8 examples/tensor toolset=$TOOLSET cxxstd=$CXXSTD - -after_success: - - .ci/report_coverage.sh - # Uploading to CodeCov - # '-f' specifies file(s) to use and disables manual coverage gathering and file search which has already been done above - - curl -s https://codecov.io/bash > cov.sh - - chmod +x cov.sh - - ./cov.sh -f coverage.info || echo "Codecov did not collect coverage reports" - + - $BOOST_ROOT/b2 -j 8 test toolset=$TOOLSET cxxstd=$CXXSTD notifications: email: - on_success: always + on_success: always \ No newline at end of file diff --git a/README.md b/README.md index c435b8ca9..22ae6db18 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ Boost Linear and Multilinear Algebra Library ===== + [![Language](https://img.shields.io/badge/C%2B%2B-11-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) [![License](https://img.shields.io/badge/license-BSL-blue.svg)](https://opensource.org/licenses/BSL-1.0) [![Documentation](https://img.shields.io/badge/ublas-documentation-blue.svg)](https://www.boost.org/doc/libs/1_69_0/libs/numeric/ublas/doc/index.html) @@ -19,29 +20,62 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org ## Properties * Header-only -* Tensor extension requires C++17 compatible compiler, compiles with - * gcc 7.3.0 - * clang 6.0 - * msvc 14.1 +* Tensor extension requires C++17 compatible compiler * Unit-tests require Boost.Test ## Build Status -Branch | Travis | Appveyor | Regression | codecov.io | Docs | -:-----: | ------ | --------- | ----------- | ----------- | ----- | - [`master`](https://github.com/boostorg/ublas/tree/master) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=master)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/master?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/master) | [![ublas](https://img.shields.io/badge/ublas-master-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | - [`develop`](https://github.com/boostorg/ublas/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=develop)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/develop?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/develop) | [![ublas](https://img.shields.io/badge/ublas-develop-blue.svg)](https://www.boost.org/development/tests/develop/developer/numeric-ublas.html) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) | +#### Tensor Build & Test + +| Operating System | Compiler | [`master`](https://github.com/boostorg/ublas/tree/master) | [`develop`](https://github.com/boostorg/ublas/tree/develop) | +| :-------------------------: | :-----------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | +| Linux (Ubuntu 20.04 x86_64) | gcc-{7, 8, 9, 10} | [![Linux GCC Debug](https://github.com/boostorg/ublas/workflows/Linux%20GCC%20Debug/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Linux+GCC%22+branch%3Amaster) | [![Linux GCC Debug](https://github.com/boostorg/ublas/workflows/Linux%20GCC%20Debug/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Linux+GCC%22+branch%3Adevelop) | +| Linux (Ubuntu 20.04 x86_64) | clang-{6, 8, 9, 10} | [![Linux Clang Release](https://github.com/boostorg/ublas/workflows/Linux%20Clang%20Release/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Linux+Clang%22+branch%3Amaster) | [![Linux Clang Release](https://github.com/boostorg/ublas/workflows/Linux%20Clang%20Release/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Linux+Clang%22+branch%3Adevelop) | +| Windows 10 (x86_64) | msvc-{14.16, 14.26} | [![Windows MSVC](https://github.com/boostorg/ublas/workflows/Windows%20MSVC/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Windows+MSVC%22+branch%3Amaster) | [![Windows MSVC](https://github.com/boostorg/ublas/workflows/Windows%20MSVC/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Windows+MSVC%22+branch%3Adevelop) | +| MacOS Catalina (x86_64) | clang-11 | [![Apple Clang](https://github.com/boostorg/ublas/workflows/Apple%20Clang/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Apple+Clang%22+branch%3Amaster) | [![Apple Clang](https://github.com/boostorg/ublas/workflows/Apple%20Clang/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Apple+Clang%22+branch%3Adevelop) | + +#### Tensor Additional Checks + +| Checks | [`master`](https://github.com/boostorg/ublas/tree/master) | [`develop`](https://github.com/boostorg/ublas/tree/develop) | +| :-----------: | :----------------------------------------------------------: | :----------------------------------------------------------: | +| UB Sanitizer | [![Undefined Behaviour Sanitizer](https://github.com/boostorg/ublas/workflows/Undefined%20Behaviour%20Sanitizer/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Undefined+Behaviour+Sanitizer%22+branch%3Amaster) | [![Undefined Behaviour Sanitizer](https://github.com/boostorg/ublas/workflows/Undefined%20Behaviour%20Sanitizer/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Undefined+Behaviour+Sanitizer%22+branch%3Adevelop) | +| TH Sanitizer | [![Thread Sanitizer](https://github.com/boostorg/ublas/workflows/Thread%20Sanitizer/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Thread+Sanitizer%22+branch%3Amaster) | [![Thread Sanitizer](https://github.com/boostorg/ublas/workflows/Thread%20Sanitizer/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Thread+Sanitizer%22+branch%3Adevelop) | +| ADD Sanitizer | [![Address Sanitizer](https://github.com/boostorg/ublas/workflows/Address%20Sanitizer/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Address+Sanitizer%22+branch%3Amaster) | [![Address Sanitizer](https://github.com/boostorg/ublas/workflows/Address%20Sanitizer/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Address+Sanitizer%22+branch%3Adevelop) | +| Codecov | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/develop) | +| Clang-Format | [![Code Format](https://github.com/boostorg/ublas/workflows/Code%20Format/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Code+Format%22+branch%3Amaster) | [![Code Format](https://github.com/boostorg/ublas/workflows/Code%20Format/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Code+Format%22+branch%3Adevelop) | +| Clang-Tidy | [![Clang tidy checks](https://github.com/boostorg/ublas/workflows/Clang%20tidy%20checks/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Clang+tidy+checks%22+branch%3Amaster) | [![Clang tidy checks](https://github.com/boostorg/ublas/workflows/Clang%20tidy%20checks/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Clang+tidy+checks%22+branch%3Adevelop) | + +#### Tensor Build Information + +| OS | Toolchain | Compiler Flags | +| :----------------: | :-------------: | :-----------------------------------------------: | +| Linux Ubuntu 20.04 | GCC | `-O0` | +| Linux Ubuntu 20.04 | Clang | `-O3` | +| Windows 10 | MSVC | No Special Flags | +| MacOS Catalina | Clang | No Special Flags | +| UB Sanitizer | GCC and Clang | `"-g -fsanitize=undefined"` | +| TH Sanitizer | GCC and Clang | `"-g -fsanitize=thread -O2"` | +| ADD Sanitizer | GCC and Clang | `"-g -fsanitize=address -fno-omit-frame-pointer"` | +| Clang Tidy | Clang-Tidy-10 | [Configuration File](.clang-tidy) | +| Clang Format | Clang-Format-10 | [Configuration File](.clang-format) | + +#### uBLAS CI + +Branch | Travis | Appveyor | Regression | Docs +:-----: | ------ | --------- | ----------- | ----- + [`master`](https://github.com/boostorg/ublas/tree/master) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=master)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/master?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/master) | [![ublas](https://img.shields.io/badge/ublas-master-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) + [`develop`](https://github.com/boostorg/ublas/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=develop)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/develop?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/develop) | [![ublas](https://img.shields.io/badge/ublas-develop-blue.svg)](https://www.boost.org/development/tests/develop/developer/numeric-ublas.html) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) ## Directories -| Name | Purpose | -| ----------- | ------------------------------ | -| `doc` | documentation | -| `examples` | example files | -| `include` | headers | -| `test` | unit tests | -| `benchmarks`| timing and benchmarking | +| Name | Purpose | +| ------------ | ----------------------- | +| `doc` | documentation | +| `examples` | example files | +| `include` | headers | +| `test` | unit tests | +| `benchmarks` | timing and benchmarking | ## More information diff --git a/benchmarks/opencl/Jamfile b/benchmarks/opencl/Jamfile index 670ec66b8..282d00711 100644 --- a/benchmarks/opencl/Jamfile +++ b/benchmarks/opencl/Jamfile @@ -17,6 +17,7 @@ project boost/ublas/benchmarks/opencl : requirements /boost/program_options//boost_program_options gcc:-Wno-ignored-attributes + clang:-Wno-ignored-attributes [ ac.check-library /clblas//clblas : /clblas//clblas /opencl//opencl : no ] ; diff --git a/examples/tensor/.clang-tidy b/examples/tensor/.clang-tidy new file mode 100644 index 000000000..5b4892c35 --- /dev/null +++ b/examples/tensor/.clang-tidy @@ -0,0 +1,11 @@ +--- +Checks: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers' +WarningsAsErrors: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers' +HeaderFilterRegex: 'boost\/numeric\/ublas\/tensor\/.*' +AnalyzeTemporaryDtors: false +FormatStyle: file +User: ublas-developers +CheckOptions: + - key: modernize-use-nullptr.NullMacros + value: 'NULL' +... diff --git a/examples/tensor/Jamfile b/examples/tensor/Jamfile index 25e5f415f..5e333dcad 100644 --- a/examples/tensor/Jamfile +++ b/examples/tensor/Jamfile @@ -14,8 +14,8 @@ project boost-ublas-tensor-example 11:no BOOST_UBLAS_NO_EXCEPTIONS vacpp:"BOOST_UBLAS_NO_ELEMENT_PROXIES" - gcc:"-Wall -pedantic -Wextra -std=c++17" - gcc:"-Wno-unknown-pragmas" + gcc:"-Wall -pedantic -Wextra -Wno-unknown-pragmas" + clang:"-Wall -pedantic -Wextra -Wno-unknown-pragmas" msvc:"/W4" # == all ; diff --git a/test/Jamfile b/test/Jamfile index 26b67b045..f1e100f94 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -254,5 +254,3 @@ test-suite numeric/uBLAS ] ; -build-project opencl ; -build-project tensor ; diff --git a/test/opencl/Jamfile b/test/opencl/Jamfile index 51c74675e..cc8679223 100644 --- a/test/opencl/Jamfile +++ b/test/opencl/Jamfile @@ -16,6 +16,7 @@ using clblas ; project boost/ublas/test/opencl : requirements gcc:-Wno-ignored-attributes + clang:-Wno-ignored-attributes [ ac.check-library /clblas//clblas : /clblas//clblas /opencl//opencl : no ] ; diff --git a/test/tensor/Jamfile b/test/tensor/Jamfile index 3ce59e748..8264a6bc1 100644 --- a/test/tensor/Jamfile +++ b/test/tensor/Jamfile @@ -15,7 +15,8 @@ project boost/ublas/test/tensor : requirements # these tests require C++17 11:no - gcc:"-Wall -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-but-set-variable -O0 --coverage -g" --coverage + gcc:"-Wall -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-but-set-variable" + clang:"-Wall -Wno-unknown-pragmas -Wno-sign-compare" ; alias unit_test_framework From 7cc02bf0a10ad1820db83e5d4ed19b0510da2f1e Mon Sep 17 00:00:00 2001 From: Ashar Date: Sun, 12 Jul 2020 13:21:09 +0000 Subject: [PATCH 16/36] Disable brranch coverage (#91) Branch coverage needs to be explicitly enabled and is not the defaault configuration of lcov. It is better to disable branch coverage because then we will have only 2 things for each line in coverage report. Either a line is hit or a miss. This is even the defaault behaviour of llvm-cov for coverage reporting. For reference check [this](https://codecov.io/gh/tzlaine/text/tree/master/boost/text) Zach's Library for Unicode which recently got partially approved for Boost. This library also uses default coverage settings. **After this commit coverage will be 95%** --- .ci/report_coverage.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.ci/report_coverage.sh b/.ci/report_coverage.sh index 19ec243e6..e8bcc9664 100755 --- a/.ci/report_coverage.sh +++ b/.ci/report_coverage.sh @@ -1,10 +1,10 @@ #! /bin/bash -e sudo apt-get install lcov -lcov --rc lcov_branch_coverage=1 --directory $BOOST_ROOT --capture --output-file coverage.info +lcov --directory $BOOST_ROOT --capture --output-file coverage.info # Remove all unwanted coverages libs. # Boost.uBLAS depends uses many internal boost libs, we don't want them to be in coverage. -lcov --rc lcov_branch_coverage=1 --extract coverage.info "*/boost/numeric/ublas/tensor/*" "*/libs/numeric/ublas/tensor/*" --output-file coverage.info -lcov --rc lcov_branch_coverage=1 --list coverage.info +lcov --extract coverage.info "*/boost/numeric/ublas/tensor/*" "*/libs/numeric/ublas/tensor/*" --output-file coverage.info +lcov --list coverage.info From 464032249267ee90d52c5a2caeff7b94921978ff Mon Sep 17 00:00:00 2001 From: Ashar Date: Wed, 5 Aug 2020 01:47:12 +0530 Subject: [PATCH 17/36] hotfix: no review for outside repo PR (#98) Outside repositories do not have permission to post review comments on ublas repository. It fails to review and CI fails. This issue has been fixed. Reviews are only run if a PR originates from our the ublas repository. --- .github/workflows/clangtidy_review.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/clangtidy_review.yml b/.github/workflows/clangtidy_review.yml index b60fa69ee..58e496d44 100644 --- a/.github/workflows/clangtidy_review.yml +++ b/.github/workflows/clangtidy_review.yml @@ -10,6 +10,7 @@ jobs: check: name: Clang tidy Review runs-on: ubuntu-20.04 + if: github.event.pull_request.head.repo.full_name == github.repository steps: - uses: actions/checkout@v2 From a31e5cffa85f58b64a39fa7c4a1bd3bd9228b069 Mon Sep 17 00:00:00 2001 From: Conrad Poelman Date: Tue, 4 Aug 2020 17:20:40 -0400 Subject: [PATCH 18/36] Remove deprecated inheritance from std::iterator (#97) std::iterator was deprecated in C++17 and removed in C++20. I replaced the inheritance with the 5 equivalent typedefs, even though they're not all used by ublas, for compatibility in case clients depend on them. --- .../boost/numeric/ublas/detail/iterator.hpp | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/include/boost/numeric/ublas/detail/iterator.hpp b/include/boost/numeric/ublas/detail/iterator.hpp index 1723a301c..7aebf2f9f 100644 --- a/include/boost/numeric/ublas/detail/iterator.hpp +++ b/include/boost/numeric/ublas/detail/iterator.hpp @@ -107,8 +107,12 @@ namespace boost { namespace numeric { namespace ublas { * via the post increment operator. */ template - struct forward_iterator_base: - public std::iterator { + struct forward_iterator_base { + typedef IC iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; typedef I derived_iterator_type; typedef T derived_value_type; @@ -145,8 +149,12 @@ namespace boost { namespace numeric { namespace ublas { * via the post increment and post decrement operator. */ template - struct bidirectional_iterator_base: - public std::iterator { + struct bidirectional_iterator_base { + typedef IC iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; typedef I derived_iterator_type; typedef T derived_value_type; @@ -200,8 +208,12 @@ namespace boost { namespace numeric { namespace ublas { */ template // ISSUE the default for D seems rather dangerous as it can easily be (silently) incorrect - struct random_access_iterator_base: - public std::iterator { + struct random_access_iterator_base { + typedef IC iterator_category; + typedef T value_type; + typedef D difference_type; + typedef T* pointer; + typedef T& reference; typedef I derived_iterator_type; typedef T derived_value_type; typedef D derived_difference_type; From a23a903f9a36c082c0f5d10f574d264d6a5d7b83 Mon Sep 17 00:00:00 2001 From: Glen Fernandes Date: Wed, 12 Aug 2020 02:12:04 -0400 Subject: [PATCH 19/36] Support the C++ allocator model (#103) --- include/boost/numeric/ublas/matrix.hpp | 8 +-- include/boost/numeric/ublas/storage.hpp | 47 +++++------------ .../boost/numeric/ublas/storage_sparse.hpp | 4 +- include/boost/numeric/ublas/vector.hpp | 12 ++--- test/Jamfile | 1 + test/minimal_allocator_test.cpp | 51 +++++++++++++++++++ 6 files changed, 76 insertions(+), 47 deletions(-) create mode 100644 test/minimal_allocator_test.cpp diff --git a/include/boost/numeric/ublas/matrix.hpp b/include/boost/numeric/ublas/matrix.hpp index 6e405d849..c2ac1958f 100644 --- a/include/boost/numeric/ublas/matrix.hpp +++ b/include/boost/numeric/ublas/matrix.hpp @@ -3460,8 +3460,8 @@ namespace boost { namespace numeric { #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS using matrix_container::operator (); #endif - typedef typename ALLOC::size_type size_type; - typedef typename ALLOC::difference_type difference_type; + typedef typename boost::allocator_size_type::type size_type; + typedef typename boost::allocator_difference_type::type difference_type; typedef T value_type; typedef const T &const_reference; typedef T &reference; @@ -3935,8 +3935,8 @@ namespace boost { namespace numeric { #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS using matrix_container::operator (); #endif - typedef typename ALLOC::size_type size_type; - typedef typename ALLOC::difference_type difference_type; + typedef typename boost::allocator_size_type::type size_type; + typedef typename boost::allocator_difference_type::type difference_type; typedef T value_type; typedef const T &const_reference; typedef T &reference; diff --git a/include/boost/numeric/ublas/storage.hpp b/include/boost/numeric/ublas/storage.hpp index fd0c58d24..4f7365248 100644 --- a/include/boost/numeric/ublas/storage.hpp +++ b/include/boost/numeric/ublas/storage.hpp @@ -18,6 +18,7 @@ #include #endif +#include #include #include #include @@ -45,8 +46,8 @@ namespace boost { namespace numeric { namespace ublas { typedef unbounded_array self_type; public: typedef ALLOC allocator_type; - typedef typename ALLOC::size_type size_type; - typedef typename ALLOC::difference_type difference_type; + typedef typename boost::allocator_size_type::type size_type; + typedef typename boost::allocator_difference_type::type difference_type; typedef T value_type; typedef const T &const_reference; typedef T &reference; @@ -76,11 +77,7 @@ namespace boost { namespace numeric { namespace ublas { #pragma warning(pop) #endif for (pointer d = data_; d != data_ + size_; ++d) -#if __cplusplus >= 201703L - std::allocator_traits::construct (alloc_, d, value_type()); -#else - alloc_.construct(d, value_type()); -#endif + boost::allocator_construct(alloc_, d); } } else @@ -153,29 +150,17 @@ namespace boost { namespace numeric { namespace ublas { pointer di = data_; if (size < size_) { for (; di != data_ + size; ++di) { -#if __cplusplus >= 201703L - std::allocator_traits::construct (alloc_, di, *si); -#else - alloc_.construct (di, *si); -#endif + boost::allocator_construct(alloc_, di, *si); ++si; } } else { for (; si != p_data + size_; ++si) { -#if __cplusplus >= 201703L - std::allocator_traits::construct (alloc_, di, *si); -#else - alloc_.construct (di, *si); -#endif + boost::allocator_construct(alloc_, di, *si); ++di; } for (; di != data_ + size; ++di) { -#if __cplusplus >= 201703L - std::allocator_traits::construct (alloc_, di, init); -#else - alloc_.construct (di, init); -#endif + boost::allocator_construct(alloc_, di, init); } } } @@ -190,11 +175,7 @@ namespace boost { namespace numeric { namespace ublas { #pragma warning(pop) #endif for (pointer di = data_; di != data_ + size; ++di) -#if __cplusplus >= 201703L - std::allocator_traits::construct(alloc_, di, value_type()); -#else - alloc_.construct (di, value_type()); -#endif + boost::allocator_construct(alloc_, di); } } } @@ -210,11 +191,7 @@ namespace boost { namespace numeric { namespace ublas { #pragma warning(pop) #endif for (pointer si = p_data; si != p_data + size_; ++si) -#if __cplusplus >= 201703L - std::allocator_traits::destroy (alloc_, si); -#else - alloc_.destroy (si); -#endif + boost::allocator_destroy(alloc_, si); } alloc_.deallocate (p_data, size_); } @@ -237,7 +214,7 @@ namespace boost { namespace numeric { namespace ublas { // Random Access Container BOOST_UBLAS_INLINE size_type max_size () const { - return ALLOC ().max_size(); + return boost::allocator_max_size(alloc_); } BOOST_UBLAS_INLINE @@ -385,8 +362,8 @@ namespace boost { namespace numeric { namespace ublas { typedef bounded_array self_type; public: // No allocator_type as ALLOC is not used for allocation - typedef typename ALLOC::size_type size_type; - typedef typename ALLOC::difference_type difference_type; + typedef typename boost::allocator_size_type::type size_type; + typedef typename boost::allocator_difference_type::type difference_type; typedef T value_type; typedef const T &const_reference; typedef T &reference; diff --git a/include/boost/numeric/ublas/storage_sparse.hpp b/include/boost/numeric/ublas/storage_sparse.hpp index f87685c79..eae3bc58f 100644 --- a/include/boost/numeric/ublas/storage_sparse.hpp +++ b/include/boost/numeric/ublas/storage_sparse.hpp @@ -214,8 +214,8 @@ namespace boost { namespace numeric { namespace ublas { class map_array { public: typedef ALLOC allocator_type; - typedef typename ALLOC::size_type size_type; - typedef typename ALLOC::difference_type difference_type; + typedef typename boost::allocator_size_type::type size_type; + typedef typename boost::allocator_difference_type::type difference_type; typedef std::pair value_type; typedef I key_type; typedef T mapped_type; diff --git a/include/boost/numeric/ublas/vector.hpp b/include/boost/numeric/ublas/vector.hpp index 73a387dcd..41ab8c175 100644 --- a/include/boost/numeric/ublas/vector.hpp +++ b/include/boost/numeric/ublas/vector.hpp @@ -1691,8 +1691,8 @@ namespace boost { namespace numeric { namespace ublas { #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS using vector_container::operator (); #endif - typedef typename ALLOC::size_type size_type; - typedef typename ALLOC::difference_type difference_type; + typedef typename boost::allocator_size_type::type size_type; + typedef typename boost::allocator_difference_type::type difference_type; typedef T value_type; typedef const T &const_reference; typedef T &reference; @@ -1912,8 +1912,8 @@ namespace boost { namespace numeric { namespace ublas { #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS using vector_container::operator (); #endif - typedef typename ALLOC::size_type size_type; - typedef typename ALLOC::difference_type difference_type; + typedef typename boost::allocator_size_type::type size_type; + typedef typename boost::allocator_difference_type::type difference_type; typedef T value_type; typedef const T &const_reference; typedef T &reference; @@ -2175,8 +2175,8 @@ namespace boost { namespace numeric { namespace ublas { #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS using vector_container::operator (); #endif - typedef typename ALLOC::size_type size_type; - typedef typename ALLOC::difference_type difference_type; + typedef typename boost::allocator_size_type::type size_type; + typedef typename boost::allocator_difference_type::type difference_type; typedef T value_type; typedef const T &const_reference; typedef T &reference; diff --git a/test/Jamfile b/test/Jamfile index f1e100f94..f6716e2c6 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -252,5 +252,6 @@ test-suite numeric/uBLAS ] [ run test_matrix_vector.cpp ] + [ compile minimal_allocator_test.cpp ] ; diff --git a/test/minimal_allocator_test.cpp b/test/minimal_allocator_test.cpp new file mode 100644 index 000000000..d0ca531d1 --- /dev/null +++ b/test/minimal_allocator_test.cpp @@ -0,0 +1,51 @@ +/* +Copyright 2020 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#if !defined(BOOST_NO_CXX11_ALLOCATOR) +#include +#include + +template +struct Allocator { + typedef T value_type; + + Allocator() BOOST_NOEXCEPT { } + + template + Allocator(const Allocator&) BOOST_NOEXCEPT { } + + T* allocate(std::size_t size) { + return static_cast(::operator new(sizeof(T) * size)); + } + + void deallocate(T* ptr, std::size_t) { + ::operator delete(ptr); + } +}; + +template +bool operator==(const Allocator&, const Allocator&) BOOST_NOEXCEPT +{ + return true; +} + +template +bool operator!=(const Allocator&, const Allocator&) BOOST_NOEXCEPT +{ + return false; +} + +int main() +{ + boost::numeric::ublas::matrix > > matrix(4, 4); + matrix(1, 2) = 3; +} +#endif From 92177ce9199e9d30f29570940bc6af541601929f Mon Sep 17 00:00:00 2001 From: Ashar Date: Wed, 12 Aug 2020 20:11:32 +0530 Subject: [PATCH 20/36] Do not trigger Github Actions for doc or Readme changes (#102) Ignore documentation and markdown changes for CI --- .github/workflows/address_san.yml | 11 +++++++++-- .github/workflows/apple_clang.yml | 11 +++++++++-- .github/workflows/clangtidy_check.yml | 11 +++++++++-- .github/workflows/code_format.yml | 13 ++++++++++--- .github/workflows/linux_clang.yml | 14 +++++++++++--- .github/workflows/linux_gcc.yml | 11 +++++++++-- .github/workflows/thread_san.yml | 11 +++++++++-- .github/workflows/ub_san.yml | 11 +++++++++-- .github/workflows/windows_msvc.yml | 13 ++++++++++--- 9 files changed, 85 insertions(+), 21 deletions(-) diff --git a/.github/workflows/address_san.yml b/.github/workflows/address_san.yml index 25e77eab9..efac3aab9 100644 --- a/.github/workflows/address_san.yml +++ b/.github/workflows/address_san.yml @@ -5,8 +5,15 @@ name: Address Sanitizer # Trigger on Push to the repository, regardless of the branch. # For fine tune, You can add specific branches or tags. -on: [push, pull_request] - +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' jobs: build: name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" diff --git a/.github/workflows/apple_clang.yml b/.github/workflows/apple_clang.yml index fe7f43036..da1047330 100644 --- a/.github/workflows/apple_clang.yml +++ b/.github/workflows/apple_clang.yml @@ -4,8 +4,15 @@ name: Apple Clang -on: [push, pull_request] - +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' jobs: build: name: "Darwin 11.0 -std=c++${{matrix.cxxstd}}" diff --git a/.github/workflows/clangtidy_check.yml b/.github/workflows/clangtidy_check.yml index 45e51ea07..c3420971e 100644 --- a/.github/workflows/clangtidy_check.yml +++ b/.github/workflows/clangtidy_check.yml @@ -4,8 +4,15 @@ name: Clang tidy checks -on: [push] - +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' jobs: check: name: Clang tidy Check diff --git a/.github/workflows/code_format.yml b/.github/workflows/code_format.yml index 17f9a308c..f1ba49372 100644 --- a/.github/workflows/code_format.yml +++ b/.github/workflows/code_format.yml @@ -4,8 +4,15 @@ name: "Code Format" -on: [push, pull_request] - +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' jobs: format: name: "Code Formatting Check" @@ -21,4 +28,4 @@ jobs: run: clang-format-10 -i examples/tensor/*.cpp test/tensor/*.cpp include/boost/numeric/ublas/tensor/*.hpp include/boost/numeric/ublas/tensor/*/*.hpp - name: Check diff - run: git diff --exit-code HEAD \ No newline at end of file + run: git diff --exit-code HEAD diff --git a/.github/workflows/linux_clang.yml b/.github/workflows/linux_clang.yml index 0e3a19b6c..b8c642855 100644 --- a/.github/workflows/linux_clang.yml +++ b/.github/workflows/linux_clang.yml @@ -5,8 +5,16 @@ name: Linux Clang Release # Trigger on Push to the repository, regardless of the branch. # For fine tune, You can add specific branches or tags. -on: [push, pull_request] - +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' + jobs: build: name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" @@ -79,4 +87,4 @@ jobs: run: | cd $BOOST_ROOT cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 test/tensor toolset=clang cxxstd=${{matrix.config.cxxstd}} cxxflags="-O3" \ No newline at end of file + $BOOST_ROOT/b2 -j 4 test/tensor toolset=clang cxxstd=${{matrix.config.cxxstd}} cxxflags="-O3" diff --git a/.github/workflows/linux_gcc.yml b/.github/workflows/linux_gcc.yml index 8a071efa7..7da00063d 100644 --- a/.github/workflows/linux_gcc.yml +++ b/.github/workflows/linux_gcc.yml @@ -5,8 +5,15 @@ name: Linux GCC Debug # Trigger on Push to the repository, regardless of the branch. # For fine tune, You can add specific branches or tags. -on: [push, pull_request] - +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' jobs: build: name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" diff --git a/.github/workflows/thread_san.yml b/.github/workflows/thread_san.yml index 6bd0c928f..128a337eb 100644 --- a/.github/workflows/thread_san.yml +++ b/.github/workflows/thread_san.yml @@ -5,8 +5,15 @@ name: Thread Sanitizer # Trigger on Push to the repository, regardless of the branch. # For fine tune, You can add specific branches or tags. -on: [push, pull_request] - +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' jobs: build: name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" diff --git a/.github/workflows/ub_san.yml b/.github/workflows/ub_san.yml index 0cf8f22b7..52db9fd17 100644 --- a/.github/workflows/ub_san.yml +++ b/.github/workflows/ub_san.yml @@ -5,8 +5,15 @@ name: Undefined Behaviour Sanitizer # Trigger on Push to the repository, regardless of the branch. # For fine tune, You can add specific branches or tags. -on: [push, pull_request] - +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' jobs: build: name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" diff --git a/.github/workflows/windows_msvc.yml b/.github/workflows/windows_msvc.yml index b066f4151..8ba306f9d 100644 --- a/.github/workflows/windows_msvc.yml +++ b/.github/workflows/windows_msvc.yml @@ -3,8 +3,15 @@ # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) name: "Windows MSVC" -on: [push, pull_request] - +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' jobs: build: name: "${{matrix.config.version}} -std=c++${{matrix.config.cxxstd}}" @@ -82,4 +89,4 @@ jobs: cd %BOOST_ROOT% cd libs\numeric\ublas %BOOST_ROOT%\b2 -j 4 test/tensor toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 - \ No newline at end of file + From 799ef707a55e34563e2c7c80965a90dad2242103 Mon Sep 17 00:00:00 2001 From: amitsingh19975 Date: Thu, 10 Dec 2020 18:58:54 +0530 Subject: [PATCH 21/36] Introducing a new and versatile way to create the tensor interface. (#90) * improving the tensor design using tensor engine to support any configuration * fixing and refactoring extents and strides * making extents and strides class declarations contestants * syncing with develop branch * fixing examples * fixing type aliasing bug * fixing clang-tidy errors * adding move assignment operator * fixing clang-tidy errors * fixing clang-tidy errors * Fix all clang-tidy warnings & Improve Review action (#92) * Fix all clang-tidy warnings * Update clangtidy_check.yml * Do not run review for PR from forks In order to run review from forks we need to create a Github bot that has full access to all forks and can perform review even from forks. * Update clangtidy_review.yml * Update clangtidy_review.yml * improving the tensor design using tensor engine to support any configuration * fixing and refactoring extents and strides * making extents and strides class declarations contestants * fixing examples * fixing type aliasing bug * fixing clang-tidy errors * adding move assignment operator * fixing clang-tidy errors * fixing clang-tidy errors * Fix all clang-tidy warnings & Improve Review action (#92) * Fix all clang-tidy warnings * Update clangtidy_check.yml * Do not run review for PR from forks In order to run review from forks we need to create a Github bot that has full access to all forks and can perform review even from forks. * Update clangtidy_review.yml * Update clangtidy_review.yml * changing tensor engine APIs * adding std::enable_if to tensor_core to remove redundant parameter for static_tensor * fixing template name * removing first_order and last_order form namespace ublas and moving to ublas::layout * removing always_false * improving strides construction for dynamic and fixed_rank * refactoring code * refactoring code and adding static checks * Moving tensor_engine to it's own header file and removing static_product * adding checking and fixing expression * refactoring code * refactoring static_extents_traits.hpp * fixing static_assert in strides.hpp and adding inline and constexpr to the functions * adding fixed rank example and making trans second argument template type * removing rebind_storage and adding rebind_storage_size for static products * refactoring directory and moving static_extents_traits.hpp into extents_functions.hpp with function implementation * fixing github action * fixing msvc compiler bug * refactoring make_static_strides code * fixing: removing push_front and push_back in static_strides.hpp * fix for msvc 14.27, it is unable to treat basic_static_extents::at constexpr * changing name from valid to is_valid for naming consistency * moving extents_result_type_* functions inside the respective prod functions * fixing broken license * removing the unnecessary headers * improving error and fixing error messages Co-authored-by: Ashar --- .github/workflows/clangtidy_check.yml | 3 + .github/workflows/clangtidy_review.yml | 8 +- .github/workflows/linux_clang.yml | 6 + .github/workflows/windows_msvc.yml | 8 +- examples/tensor/.clang-tidy | 4 +- examples/tensor/Jamfile | 1 - examples/tensor/construction_access.cpp | 8 +- examples/tensor/dynamic_prod_expressions.cpp | 16 +- examples/tensor/einstein_notation.cpp | 22 +- .../tensor/fixed_rank_prod_expressions.cpp | 37 +- examples/tensor/fixed_rank_tensor.cpp | 22 +- examples/tensor/simple_expressions.cpp | 2 +- examples/tensor/static_prod_expressions.cpp | 120 --- examples/tensor/static_tensor.cpp | 26 +- examples/tensor/tensor_construction.cpp | 24 +- include/boost/numeric/ublas/tensor.hpp | 4 +- .../boost/numeric/ublas/tensor/algorithms.hpp | 14 +- .../tensor/detail/static_extents_traits.hpp | 150 --- .../tensor/detail/type_traits_tensor.hpp | 166 ---- .../numeric/ublas/tensor/dynamic_extents.hpp | 91 +- .../numeric/ublas/tensor/dynamic_strides.hpp | 103 +- .../numeric/ublas/tensor/dynamic_tensor.hpp | 203 ---- .../boost/numeric/ublas/tensor/expression.hpp | 69 +- .../ublas/tensor/expression_evaluation.hpp | 103 +- .../tensor/{detail => }/extents_functions.hpp | 136 ++- .../ublas/tensor/fixed_rank_extents.hpp | 128 ++- .../ublas/tensor/fixed_rank_strides.hpp | 134 ++- .../ublas/tensor/fixed_rank_tensor.hpp | 217 ----- .../boost/numeric/ublas/tensor/functions.hpp | 726 ++++++++------ include/boost/numeric/ublas/tensor/layout.hpp | 26 + .../numeric/ublas/tensor/multi_index.hpp | 7 +- .../ublas/tensor/multi_index_utility.hpp | 18 +- .../numeric/ublas/tensor/multiplication.hpp | 20 +- .../ublas/tensor/operators_arithmetic.hpp | 342 +++++-- .../ublas/tensor/operators_comparison.hpp | 24 +- .../boost/numeric/ublas/tensor/ostream.hpp | 10 +- .../numeric/ublas/tensor/static_extents.hpp | 93 +- .../numeric/ublas/tensor/static_strides.hpp | 196 ++-- .../numeric/ublas/tensor/static_tensor.hpp | 212 ----- .../boost/numeric/ublas/tensor/strides.hpp | 48 +- include/boost/numeric/ublas/tensor/tags.hpp | 31 + include/boost/numeric/ublas/tensor/tensor.hpp | 632 +------------ .../numeric/ublas/tensor/tensor_core.hpp | 886 ++++++++++++++++++ .../numeric/ublas/tensor/tensor_engine.hpp | 50 + .../{detail => traits}/basic_type_traits.hpp | 4 +- .../{detail => traits}/storage_traits.hpp | 49 +- .../type_traits_dynamic_extents.hpp | 4 +- .../type_traits_dynamic_strides.hpp | 27 +- .../type_traits_extents.hpp | 14 +- .../type_traits_fixed_rank_extents.hpp | 6 +- .../type_traits_fixed_rank_strides.hpp | 29 +- .../type_traits_static_extents.hpp | 6 +- .../type_traits_static_strides.hpp | 31 +- .../type_traits_strides.hpp | 19 +- .../tensor/traits/type_traits_tensor.hpp | 41 + .../numeric/ublas/tensor/type_traits.hpp | 10 +- test/tensor/Jamfile | 1 - test/tensor/test_algorithms.cpp | 114 +-- test/tensor/test_einstein_notation.cpp | 4 +- test/tensor/test_expression.cpp | 43 +- test/tensor/test_expression_evaluation.cpp | 53 +- test/tensor/test_extents.cpp | 44 +- .../test_fixed_rank_expression_evaluation.cpp | 66 +- test/tensor/test_fixed_rank_extents.cpp | 104 +- test/tensor/test_fixed_rank_functions.cpp | 12 +- .../test_fixed_rank_operators_arithmetic.cpp | 6 +- .../test_fixed_rank_operators_comparison.cpp | 6 +- test/tensor/test_fixed_rank_strides.cpp | 50 +- test/tensor/test_fixed_rank_tensor.cpp | 40 +- .../test_fixed_rank_tensor_matrix_vector.cpp | 6 +- test/tensor/test_functions.cpp | 57 +- test/tensor/test_multi_index.cpp | 10 +- test/tensor/test_multiplication.cpp | 22 +- test/tensor/test_operators_arithmetic.cpp | 2 +- test/tensor/test_operators_comparison.cpp | 6 +- .../test_static_expression_evaluation.cpp | 48 +- test/tensor/test_static_extents.cpp | 185 ++-- test/tensor/test_static_functions.cpp | 496 ---------- .../test_static_operators_arithmetic.cpp | 4 +- .../test_static_operators_comparison.cpp | 6 +- test/tensor/test_static_strides.cpp | 52 +- test/tensor/test_static_tensor.cpp | 22 +- .../test_static_tensor_matrix_vector.cpp | 4 +- test/tensor/test_strides.cpp | 8 +- test/tensor/test_tensor.cpp | 22 +- test/tensor/test_tensor_matrix_vector.cpp | 4 +- test/tensor/utility.hpp | 6 +- 87 files changed, 3178 insertions(+), 3711 deletions(-) delete mode 100644 examples/tensor/static_prod_expressions.cpp delete mode 100644 include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp delete mode 100644 include/boost/numeric/ublas/tensor/detail/type_traits_tensor.hpp delete mode 100644 include/boost/numeric/ublas/tensor/dynamic_tensor.hpp rename include/boost/numeric/ublas/tensor/{detail => }/extents_functions.hpp (63%) delete mode 100644 include/boost/numeric/ublas/tensor/fixed_rank_tensor.hpp create mode 100644 include/boost/numeric/ublas/tensor/layout.hpp delete mode 100644 include/boost/numeric/ublas/tensor/static_tensor.hpp create mode 100644 include/boost/numeric/ublas/tensor/tags.hpp create mode 100644 include/boost/numeric/ublas/tensor/tensor_core.hpp create mode 100644 include/boost/numeric/ublas/tensor/tensor_engine.hpp rename include/boost/numeric/ublas/tensor/{detail => traits}/basic_type_traits.hpp (95%) rename include/boost/numeric/ublas/tensor/{detail => traits}/storage_traits.hpp (61%) rename include/boost/numeric/ublas/tensor/{detail => traits}/type_traits_dynamic_extents.hpp (90%) rename include/boost/numeric/ublas/tensor/{detail => traits}/type_traits_dynamic_strides.hpp (66%) rename include/boost/numeric/ublas/tensor/{detail => traits}/type_traits_extents.hpp (67%) rename include/boost/numeric/ublas/tensor/{detail => traits}/type_traits_fixed_rank_extents.hpp (86%) rename include/boost/numeric/ublas/tensor/{detail => traits}/type_traits_fixed_rank_strides.hpp (63%) rename include/boost/numeric/ublas/tensor/{detail => traits}/type_traits_static_extents.hpp (83%) rename include/boost/numeric/ublas/tensor/{detail => traits}/type_traits_static_strides.hpp (64%) rename include/boost/numeric/ublas/tensor/{detail => traits}/type_traits_strides.hpp (67%) create mode 100644 include/boost/numeric/ublas/tensor/traits/type_traits_tensor.hpp delete mode 100644 test/tensor/test_static_functions.cpp diff --git a/.github/workflows/clangtidy_check.yml b/.github/workflows/clangtidy_check.yml index c3420971e..1b5236352 100644 --- a/.github/workflows/clangtidy_check.yml +++ b/.github/workflows/clangtidy_check.yml @@ -22,6 +22,9 @@ jobs: - name: "Install dependencies" run: | + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add - + sudo add-apt-repository 'deb http://apt.llvm.org/focal llvm-toolchain-focal-10 main' -y + sudo apt-get update -q sudo apt-get install -y clang-10 clang-tidy-10 - name: "Install Boost from Source" diff --git a/.github/workflows/clangtidy_review.yml b/.github/workflows/clangtidy_review.yml index 58e496d44..b14c5bb9f 100644 --- a/.github/workflows/clangtidy_review.yml +++ b/.github/workflows/clangtidy_review.yml @@ -12,11 +12,13 @@ jobs: runs-on: ubuntu-20.04 if: github.event.pull_request.head.repo.full_name == github.repository steps: - - uses: actions/checkout@v2 - + - uses: actions/checkout@v2 - name: "Install dependencies" run: | - sudo apt-get install -y clang-10 clang-tidy-10 + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add - + sudo add-apt-repository 'deb http://apt.llvm.org/focal llvm-toolchain-focal-10 main' -y + sudo apt-get update -q + sudo apt-get install -y clang-10 clang-tidy-10 - name: "Install Boost from Source" run: | diff --git a/.github/workflows/linux_clang.yml b/.github/workflows/linux_clang.yml index b8c642855..5f1e86773 100644 --- a/.github/workflows/linux_clang.yml +++ b/.github/workflows/linux_clang.yml @@ -42,6 +42,12 @@ jobs: run: | sudo apt-get update sudo apt-get install -y clang-10 + + - name: Install Clang 6 + if: matrix.config.cxx == 'clang++-6.0' + run: | + sudo apt-get update + sudo apt-get install -y clang-6.0 - name: Prepare BOOST_ROOT run: | diff --git a/.github/workflows/windows_msvc.yml b/.github/workflows/windows_msvc.yml index 8ba306f9d..a50cab40d 100644 --- a/.github/workflows/windows_msvc.yml +++ b/.github/workflows/windows_msvc.yml @@ -21,15 +21,15 @@ jobs: matrix: config: - {os: windows-2016, toolset: msvc, version: 14.16, cxxstd: 11} - - {os: windows-2019, toolset: msvc, version: 14.26, cxxstd: 11} - - {os: windows-2019, toolset: msvc, version: 14.26, cxxstd: 17} - - {os: windows-2019, toolset: msvc, version: 14.26, cxxstd: latest} + - {os: windows-2019, toolset: msvc, version: 14.27, cxxstd: 11} + - {os: windows-2019, toolset: msvc, version: 14.27, cxxstd: 17} + - {os: windows-2019, toolset: msvc, version: 14.27, cxxstd: latest} steps: - uses: actions/checkout@v2 - name: Enable Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1.2.0 + uses: ilammy/msvc-dev-cmd@v1.3.0 with: toolset: ${{matrix.config.version}} diff --git a/examples/tensor/.clang-tidy b/examples/tensor/.clang-tidy index 5b4892c35..50e8131ae 100644 --- a/examples/tensor/.clang-tidy +++ b/examples/tensor/.clang-tidy @@ -1,6 +1,6 @@ --- -Checks: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers' -WarningsAsErrors: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers' +Checks: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-bugprone-exception-escape' +WarningsAsErrors: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-bugprone-exception-escape' HeaderFilterRegex: 'boost\/numeric\/ublas\/tensor\/.*' AnalyzeTemporaryDtors: false FormatStyle: file diff --git a/examples/tensor/Jamfile b/examples/tensor/Jamfile index 5e333dcad..7a5b95137 100644 --- a/examples/tensor/Jamfile +++ b/examples/tensor/Jamfile @@ -23,7 +23,6 @@ exe construction_access : construction_access.cpp ; exe simple_expressions : simple_expressions.cpp ; exe dynamic_prod_expressions : dynamic_prod_expressions.cpp ; exe fixed_rank_prod_expressions : fixed_rank_prod_expressions.cpp ; -exe static_prod_expressions : static_prod_expressions.cpp ; exe fixed_rank_tensor : fixed_rank_tensor.cpp ; exe static_tensor : static_tensor.cpp ; exe einstein_notation : einstein_notation.cpp ; diff --git a/examples/tensor/construction_access.cpp b/examples/tensor/construction_access.cpp index cee695fa6..b70bf7268 100644 --- a/examples/tensor/construction_access.cpp +++ b/examples/tensor/construction_access.cpp @@ -43,7 +43,7 @@ int main() // according to the last-order storage format // and initializes it with the default value. using ctype = std::complex; - auto B = dynamic_tensor(dynamic_extents<>{5,4,3,2},ctype{}); + auto B = dynamic_tensor(extents<>{5,4,3,2},ctype{}); // initializes the tensor with increasing values along the last-index // using a single-index @@ -58,7 +58,7 @@ int main() - auto C = dynamic_tensor(B.extents()); + auto C = dynamic_tensor(B.extents()); // computes the complex conjugate of elements of B // using multi-index notation. for(auto i = 0u; i < B.size(0); ++i) @@ -74,7 +74,7 @@ int main() // computes the complex conjugate of elements of B // using iterators. - auto D = dynamic_tensor(B.extents()); + auto D = dynamic_tensor(B.extents()); std::transform(B.begin(), B.end(), D.begin(), [](auto const& b){ return std::conj(b); }); std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; @@ -83,7 +83,7 @@ int main() // reshaping tensors. auto new_extents = B.extents().base(); std::next_permutation( new_extents.begin(), new_extents.end() ); - D.reshape( dynamic_extents<>(new_extents) ); + D.reshape( extents<>(new_extents) ); std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "newD=" << D << ";" << std::endl << std::endl; diff --git a/examples/tensor/dynamic_prod_expressions.cpp b/examples/tensor/dynamic_prod_expressions.cpp index e39ae62fd..c0b0ed793 100644 --- a/examples/tensor/dynamic_prod_expressions.cpp +++ b/examples/tensor/dynamic_prod_expressions.cpp @@ -29,7 +29,7 @@ int main() // Tensor-Vector-Multiplications - Including Transposition { - auto n = dynamic_extents<>{3,4,2}; + auto n = extents<>{3,4,2}; auto A = tensor_t(n,2); auto q = 0u; // contraction mode @@ -79,14 +79,14 @@ int main() // Tensor-Matrix-Multiplications - Including Transposition { - auto n = dynamic_extents<>{3,4,2}; + auto n = extents<>{3,4,2}; auto A = tensor_t(n,2); auto m = 5u; auto q = 0u; // contraction mode // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); q = 1u; - tensor_t C1 = tensor_t(dynamic_extents<>{m,n[1],n[2]},2) + prod(A,matrix_t(m,n[q-1],1),q); + tensor_t C1 = tensor_t(extents<>{m,n[1],n[2]},2) + prod(A,matrix_t(m,n[q-1],1),q); // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; q = 2u; @@ -145,14 +145,14 @@ int main() using perm_t = std::vector; - auto na = dynamic_extents<>{3,4,5}; - auto nb = dynamic_extents<>{4,6,3,2}; + auto na = extents<>{3,4,5}; + auto nb = extents<>{4,6,3,2}; auto A = tensor_t(na,2); auto B = tensor_t(nb,3); // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; - tensor_t C1 = tensor_t(dynamic_extents<>{na[2],na[2]},2) + prod(A,A,perm_t{1,2}) + 5; + tensor_t C1 = tensor_t(extents<>{na[2],na[2]},2) + prod(A,A,perm_t{1,2}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -162,7 +162,7 @@ int main() // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; - tensor_t C2 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + tensor_t C2 = tensor_t(extents<>{na[2],nb[1],nb[3]},2) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -172,7 +172,7 @@ int main() // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; - tensor_t C3 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; + tensor_t C3 = tensor_t(extents<>{na[2],nb[1],nb[3]},2) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; diff --git a/examples/tensor/einstein_notation.cpp b/examples/tensor/einstein_notation.cpp index b91f7a0ff..9a2e1cc50 100644 --- a/examples/tensor/einstein_notation.cpp +++ b/examples/tensor/einstein_notation.cpp @@ -29,11 +29,11 @@ int main() // Tensor-Vector-Multiplications - Including Transposition { - auto n = dynamic_extents<>{3,4,2}; + auto n = extents<>{3,4,2}; auto A = tensor_t(n,1); auto B1 = matrix_t(n[1],n[2],2); - auto v1 = tensor_t(dynamic_extents<>{n[0],1},2); - auto v2 = tensor_t(dynamic_extents<>{n[1],1},2); + auto v1 = tensor_t(extents<>{n[0],1},2); + auto v2 = tensor_t(extents<>{n[1],1},2); // auto v3 = tensor_t(shape{n[2],1},2); // C1(j,k) = B1(j,k) + A(i,j,k)*v1(i); @@ -66,12 +66,12 @@ int main() // Tensor-Matrix-Multiplications - Including Transposition { - auto n = dynamic_extents<>{3,4,2}; + auto n = extents<>{3,4,2}; auto m = 5u; auto A = tensor_t(n,2); - auto B = tensor_t(dynamic_extents<>{n[1],n[2],m},2); - auto B1 = tensor_t(dynamic_extents<>{m,n[0]},1); - auto B2 = tensor_t(dynamic_extents<>{m,n[1]},1); + auto B = tensor_t(extents<>{n[1],n[2],m},2); + auto B1 = tensor_t(extents<>{m,n[0]},1); + auto B2 = tensor_t(extents<>{m,n[1]},1); // C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i); @@ -107,12 +107,12 @@ int main() // Tensor-Tensor-Multiplications Including Transposition { - auto na = dynamic_extents<>{3,4,5}; - auto nb = dynamic_extents<>{4,6,3,2}; + auto na = extents<>{3,4,5}; + auto nb = extents<>{4,6,3,2}; auto A = tensor_t(na,2); auto B = tensor_t(nb,3); - auto T1 = tensor_t(dynamic_extents<>{na[2],na[2]},2); - auto T2 = tensor_t(dynamic_extents<>{na[2],nb[1],nb[3]},2); + auto T1 = tensor_t(extents<>{na[2],na[2]},2); + auto T2 = tensor_t(extents<>{na[2],nb[1],nb[3]},2); // C1(j,l) = T1(j,l) + A(i,j,k)*A(i,j,l) + 5; diff --git a/examples/tensor/fixed_rank_prod_expressions.cpp b/examples/tensor/fixed_rank_prod_expressions.cpp index 78949035a..5c217c94a 100644 --- a/examples/tensor/fixed_rank_prod_expressions.cpp +++ b/examples/tensor/fixed_rank_prod_expressions.cpp @@ -24,15 +24,15 @@ int main() using value_t = float; // std::complex; using matrix_t = matrix; using vector_t = vector; - using extents_3_t = dynamic_extents<3>; - using extents_4_t = dynamic_extents<4>; + using extents_3_t = extents<3>; + using extents_4_t = extents<4>; // Tensor-Vector-Multiplications - Including Transposition // dynamic_extents with static rank { auto n = extents_3_t{3,4,2}; - auto A = fixed_rank_tensor(n,value_t(2)); + auto A = fixed_rank_tensor(n,value_t(2)); using tensor_t = fixed_rank_tensor< value_t, 2>; auto q = 0u; // contraction mode @@ -73,14 +73,14 @@ int main() { auto n = extents_3_t{3,4,2}; - auto A = fixed_rank_tensor(n,value_t(2)); + auto A = fixed_rank_tensor(n,value_t(2)); using tensor_t = decltype(A); auto m = 5u; auto q = 0u; // contraction mode // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); q = 1u; - tensor_t C1 = fixed_rank_tensor( extents_3_t{m,n[1],n[2]},value_t(2) ) + prod(A,matrix_t(m,n[q-1],1),q); + tensor_t C1 = fixed_rank_tensor( extents_3_t{m,n[1],n[2]},value_t(2) ) + prod(A,matrix_t(m,n[q-1],1),q); // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; q = 2u; @@ -124,12 +124,12 @@ int main() // dynamic_extents with static rank { - using perm_t = std::vector; + using perm_t = std::array; auto na = extents_3_t{3,4,5}; auto nb = extents_4_t{4,6,3,2}; - auto A = fixed_rank_tensor(na,value_t(2)); - auto B = fixed_rank_tensor(nb,value_t(3)); + auto A = fixed_rank_tensor(na,value_t(2)); + auto B = fixed_rank_tensor(nb,value_t(3)); using tensor_t = dynamic_tensor< value_t >; @@ -137,7 +137,7 @@ int main() // Right now there exist no tensor other than dynamic_extents with // dynamic rank so every tensor times tensor operator automatically // to dynamic tensor - tensor_t C1 = dynamic_tensor(dynamic_extents<>{na[2],na[2]},value_t(2)) + prod(A,A,perm_t{1,2}) + 5; + tensor_t C1 = dynamic_tensor(extents<>{na[2],na[2]},value_t(2)) + prod(A,A,perm_t{1,2}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -148,7 +148,7 @@ int main() // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; // Similar Problem as above - tensor_t C2 = dynamic_tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + tensor_t C2 = dynamic_tensor(extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -156,16 +156,15 @@ int main() std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; + // Similar Problem as above + tensor_t C3 = dynamic_tensor(extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; - // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; - // Similar Problem as above - tensor_t C3 = dynamic_tensor(dynamic_extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; } } diff --git a/examples/tensor/fixed_rank_tensor.cpp b/examples/tensor/fixed_rank_tensor.cpp index faa2a968a..04ec87579 100644 --- a/examples/tensor/fixed_rank_tensor.cpp +++ b/examples/tensor/fixed_rank_tensor.cpp @@ -27,39 +27,39 @@ int main() { /** * fixed rank tensor with - * Layout: first_order by default if not + * Layout: layout::first_order by default if not * provided * Value Type: float - * Extents Type: dynamic_extents<5>{1,2,3,4,5} + * Extents Type: extents<5>{1,2,3,4,5} **/ auto t11 = ub::fixed_rank_tensor{1,2,3,4,5}; /** * fixed rank tensor using deduction guide - * Layout: last_order + * Layout: layout::last_order * provided * Value Type: float - * Extents Type: dynamic_extents<5>{1,2,2,3,4} + * Extents Type: extents<5>{1,2,2,3,4} **/ - auto t12 = ub::fixed_rank_tensor{ ub::dynamic_extents<5>{1,2,2,3,4}, 5.f }; + auto t12 = ub::fixed_rank_tensor{ ub::extents<5>{1,2,2,3,4}, 5.f }; /** * fixed rank tensor using deduction guide - * Layout: first_order by default if not + * Layout: layout::first_order by default if not * provided * Value Type: float - * Extents Type: dynamic_extents<5>{1,2,2,3,4} + * Extents Type: extents<5>{1,2,2,3,4} **/ - auto t2 = ub::fixed_rank_tensor( ub::dynamic_extents<5>{1,2,2,3,4}, 5.f ); + auto t2 = ub::fixed_rank_tensor( ub::extents<5>{1,2,2,3,4}, 5.f ); /*--------------------------Expressions------------------------------*/ using f_tensor = ub::fixed_rank_tensor; using s_tensor = ub::static_tensor >; - auto t3 = ub::fixed_rank_tensor( ub::dynamic_extents<5>{1,2,3,4,5}, 5.f ); + auto t3 = ub::fixed_rank_tensor( ub::extents<5>{1,2,3,4,5}, 5.f ); auto st1 = s_tensor{ 5.f }; - auto dt1 = ub::dynamic_tensor( ub::dynamic_extents<>{1,2,3,4,5}, 5.f ); + auto dt1 = ub::dynamic_tensor( ub::extents<>{1,2,3,4,5}, 5.f ); f_tensor exp1 = t3 + t3 * 2 + t3*t3; @@ -82,7 +82,7 @@ int main() { ub::fixed_rank_tensor t4 = st1; // Assigning dynamic_tensor into fixed_rank_tensor - ub::dynamic_tensor t5 = dt1; + ub::dynamic_tensor const& t5 = dt1; std::cout<<"( t4 == t3 ) => "<<( t4 == t3 )<{3,4}; + auto n = extents<>{3,4}; auto D = matrixf(n[0],n[1],1); auto e = vectorf(n[1],1); auto f = vectorf(n[0],2); diff --git a/examples/tensor/static_prod_expressions.cpp b/examples/tensor/static_prod_expressions.cpp deleted file mode 100644 index 458fac22f..000000000 --- a/examples/tensor/static_prod_expressions.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - - -#include -#include -#include -#include - -int main() -{ - using namespace boost::numeric::ublas; - - using format_t = column_major; - using value_t = float; // std::complex; - using matrix_t = matrix; - using vector_t = vector; - - // Tensor-Vector-Multiplications - Including Transposition - // static_extents - { - auto n = static_extents<3,4,2>{}; - auto A = static_tensor>(value_t(2)); - auto q = 0u; // contraction mode - - // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); - q = 1u; - static_tensor< value_t, static_extents<4,2> > C1 = matrix_t(n[1],n[2],2) + prod<1ul /* q = 1 */ >(A,vector_t(n[q-1],1)); - - // C2(i,k) = A(i,j,k)*T1(j) + 4; - q = 2u; - static_tensor< value_t, static_extents<3,2> > C2 = prod<2ul /* q = 2 */ >(A,vector_t(n[q-1],1)) + 4; - - // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - auto C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); - - - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; - std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; - - } - - // Tensor-Matrix-Multiplications - Including Transposition - // static_extents - { - - auto n = static_extents<3,4,2>{}; - auto A = static_tensor>(value_t(2)); - static constexpr auto m = 5u; - auto q = 0u; // contraction mode - - // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); - q = 1ul; - static_tensor< value_t, static_extents<5,4,2> > C1 = static_tensor>( value_t(2) ) - + prod < 1ul /* q */, m /*n[q-1] => n[1-1] => n[0]*/ > (A, matrix_t(m,n[q-1],value_t(1) )) ; - - // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; - q = 2u; - static_tensor< value_t, static_extents<3,5,2> > C2 = prod<2ul/* q = 2 */, m>(A,matrix_t(m,n[q-1],1)) + 4 ; - - // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); - q = 3u; - auto C3 = prod<3ul, m + 2>( prod<2ul /* q(3) - 1 = 2 */, m + 1 >(A,matrix_t(m+1,n[q-2],1)), matrix_t(m+2,n[q-1],1) ) ; - - // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); - auto C4 = prod<2ul, m + 1>( prod<3ul, m + 2>(A,matrix_t(m+2,n[q-1],1)), matrix_t(m+1,n[q-2],1) ) ; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; - std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; - - } - -} diff --git a/examples/tensor/static_tensor.cpp b/examples/tensor/static_tensor.cpp index 7062c358c..e5f6e2b2f 100644 --- a/examples/tensor/static_tensor.cpp +++ b/examples/tensor/static_tensor.cpp @@ -27,29 +27,29 @@ int main() { /** * static rank tensor with - * Layout: first_order by default if not + * Layout: layout::first_order by default if not * provided * Value Type: float - * Extents Type: dynamic_extents<5>{1,2,3,4,5} + * Extents Type: extents<5>{1,2,3,4,5} **/ auto t1 = ub::static_tensor >{5.f}; /** * static rank tensor with - * Layout: first_order by default if not + * Layout: layout::first_order by default if not * provided * Value Type: float - * Extents Type: dynamic_extents<5>{1,2,3,4,5} + * Extents Type: extents<5>{1,2,3,4,5} **/ - auto t2 = ub::static_tensor, ub::last_order >{5.f}; + auto t2 = ub::static_tensor, ub::layout::last_order >{5.f}; /*--------------------------Expressions------------------------------*/ using s_tensor = ub::static_tensor >; - auto t3 = ub::fixed_rank_tensor( ub::dynamic_extents<5>{1,2,3,4,5}, 5.f ); + auto t3 = ub::fixed_rank_tensor( ub::extents<5>{1,2,3,4,5}, 5.f ); auto st1 = s_tensor{ 5.f }; - auto dt1 = ub::dynamic_tensor( ub::dynamic_extents<>{1,2,3,4,5}, 5.f ); + auto dt1 = ub::dynamic_tensor( ub::extents<>{1,2,3,4,5}, 5.f ); s_tensor exp1 = st1 + st1 * 2 + st1*st1; @@ -66,17 +66,5 @@ int main() { std::cout<<"( exp2 == exp3 ) => "<<( exp2 == exp3)< "<<( t4 == t3)< "<<( t5 == dt1)<{1,2,3,4}; /** Dynamic extents but static rank * Storage Type: std::array of static rank - * Layout: first_order + * Layout: layout::first_order * Initial Value: 0 **/ - auto tensor_dynamic_extents_and_static_rank_1 = ub::fixed_rank_tensor{ub::dynamic_extents<4>{1,2,3,4}}; + auto tensor_dynamic_extents_and_static_rank_1 = ub::fixed_rank_tensor{ub::extents<4>{1,2,3,4}}; /** Dynamic extents but dynamic rank * Storage Type: std::vector - * Layout: first_order + * Layout: layout::first_order * Initial Value: 0 **/ - auto tensor_dynamic_extents_and_dynamic_rank_2 = ub::dynamic_tensor{ub::dynamic_extents<>{1,2,3,4}}; + auto tensor_dynamic_extents_and_dynamic_rank_2 = ub::dynamic_tensor{ub::extents<>{1,2,3,4}}; /** Dynamic extents but dynamic rank * Storage Type: std::vector - * Layout: first_order + * Layout: layout::first_order * Initial Value: 0.1f **/ - auto tensor_dynamic_extents_and_dynamic_rank_3 = ub::dynamic_tensor{ub::dynamic_extents<>{1,2,3,4},0.1}; + auto tensor_dynamic_extents_and_dynamic_rank_3 = ub::dynamic_tensor{ub::extents<>{1,2,3,4},0.1}; /** Static extents but static rank * Storage Type: std::array - * Layout: first_order + * Layout: layout::first_order * Initial Value: 0 **/ auto tensor_static_extents_and_static_rank_4 = ub::static_tensor>(); /** Static extents but static rank * Storage Type: std::array - * Layout: first_order + * Layout: layout::first_order * Initial Value: 0 **/ - auto tensor_static_extents_and_static_rank_5 = ub::static_tensor,ub::first_order>(); + auto tensor_static_extents_and_static_rank_5 = ub::static_tensor,ub::layout::first_order>(); /** Dynamic extents but dynamic rank * Storage Type: std::array - * Layout: first_order + * Layout: layout::first_order * Initial Value: 0 **/ - auto tensor_dynamic_extents_and_dynamic_rank_6 = ub::dynamic_tensor{1,2,3,4}; + auto tensor_dynamic_extents_and_dynamic_rank_6 = ub::dynamic_tensor{1,2,3,4}; auto t1_e = tensor_dynamic_extents_and_dynamic_rank_0.extents(); auto t2_e = tensor_dynamic_extents_and_static_rank_1.extents(); diff --git a/include/boost/numeric/ublas/tensor.hpp b/include/boost/numeric/ublas/tensor.hpp index d3f6a0754..ec86ac925 100644 --- a/include/boost/numeric/ublas/tensor.hpp +++ b/include/boost/numeric/ublas/tensor.hpp @@ -18,9 +18,7 @@ #include "tensor/operators_arithmetic.hpp" #include "tensor/operators_comparison.hpp" #include "tensor/ostream.hpp" -#include "tensor/static_tensor.hpp" -#include "tensor/dynamic_tensor.hpp" -#include "tensor/fixed_rank_tensor.hpp" #include "tensor/functions.hpp" +#include "tensor/tensor.hpp" #endif // BOOST_NUMERIC_UBLAS_TENSOR_HPP diff --git a/include/boost/numeric/ublas/tensor/algorithms.hpp b/include/boost/numeric/ublas/tensor/algorithms.hpp index d929fca8d..8ca98ba61 100644 --- a/include/boost/numeric/ublas/tensor/algorithms.hpp +++ b/include/boost/numeric/ublas/tensor/algorithms.hpp @@ -37,7 +37,7 @@ namespace ublas { * @param[in] wa pointer to the strides of input tensor a */ template -void copy(const SizeType p, SizeType const*const n, +constexpr void copy(const SizeType p, SizeType const*const n, PointerOut c, SizeType const*const wc, PointerIn a, SizeType const*const wa) { @@ -87,7 +87,7 @@ void copy(const SizeType p, SizeType const*const n, * @param[in] op unary operation */ template -void transform(const SizeType p, +constexpr void transform(const SizeType p, SizeType const*const n, PointerOut c, SizeType const*const wc, PointerIn a, SizeType const*const wa, @@ -136,7 +136,8 @@ void transform(const SizeType p, * @param[in] k accumulated value */ template -ValueType accumulate(SizeType const p, SizeType const*const n, +[[nodiscard]] +constexpr ValueType accumulate(SizeType const p, SizeType const*const n, PointerIn a, SizeType const*const w, ValueType k) { @@ -185,7 +186,8 @@ ValueType accumulate(SizeType const p, SizeType const*const n, */ template -ValueType accumulate(SizeType const p, SizeType const*const n, +[[nodiscard]] +constexpr ValueType accumulate(SizeType const p, SizeType const*const n, PointerIn a, SizeType const*const w, ValueType k, BinaryOp op) { @@ -238,7 +240,7 @@ ValueType accumulate(SizeType const p, SizeType const*const n, */ template -void trans( SizeType const p, SizeType const*const na, SizeType const*const pi, +constexpr void trans( SizeType const p, SizeType const*const na, SizeType const*const pi, PointerOut c, SizeType const*const wc, PointerIn a, SizeType const*const wa) { @@ -297,7 +299,7 @@ void trans( SizeType const p, SizeType const*const na, SizeType const*const pi, */ template -void trans( SizeType const p, +constexpr void trans( SizeType const p, SizeType const*const na, SizeType const*const pi, std::complex* c, SizeType const*const wc, diff --git a/include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp b/include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp deleted file mode 100644 index 36745e607..000000000 --- a/include/boost/numeric/ublas/tensor/detail/static_extents_traits.hpp +++ /dev/null @@ -1,150 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - -#ifndef _BOOST_NUMERIC_UBLAS_TENSOR_STATIC_TRAITS_HPP_ -#define _BOOST_NUMERIC_UBLAS_TENSOR_STATIC_TRAITS_HPP_ - -#include - -namespace boost::numeric::ublas{ - - template struct basic_static_extents; - template struct basic_fixed_rank_extents; - template class basic_extents; - -} // namespace boost::numeric::ublas - -namespace boost::numeric::ublas::static_traits{ - - template - struct is_valid : std::integral_constant{}; - - template - inline static constexpr bool const is_valid_v = is_valid::value; - - template - struct is_valid< basic_static_extents >{ - static constexpr bool const value = ( E0 == ExtentsType(1) ); - }; - - template - struct is_valid< basic_static_extents >{ - static constexpr bool const value = ( E0 > ExtentsType(0) ) && ( E1 > ExtentsType(0) ); - }; - - template - struct is_valid< basic_static_extents >{ - static constexpr bool const value = ( E0 > ExtentsType(0) ) - && is_valid_v< basic_static_extents >; - }; - - - template - struct is_scalar : std::integral_constant{}; - - template - inline static constexpr bool const is_scalar_v = is_scalar::value; - - template - struct is_scalar< basic_static_extents >{ - static constexpr bool const value = is_scalar_v< basic_static_extents > && is_scalar_v< basic_static_extents >; - }; - - template - struct is_scalar< basic_static_extents >{ - static constexpr bool const value = (E0 == 1); - }; - - template - struct is_scalar< basic_static_extents > : std::false_type{}; - - template - struct is_vector : std::integral_constant{}; - - template - inline static constexpr bool const is_vector_v = is_vector::value; - - template - struct is_vector< basic_static_extents >{ - static constexpr bool const value = - is_vector_v< basic_static_extents > && - is_scalar_v< basic_static_extents >; - }; - - template - struct is_vector< basic_static_extents >{ - static constexpr bool const value = - ( E0 > ExtentsType(1) || E1 > ExtentsType(1) ) - && ( E0 == ExtentsType(1) || E1 == ExtentsType(1) ); - }; - - template - struct is_vector< basic_static_extents >{ - static constexpr bool const value = ( E0 > ExtentsType(1) ); - }; - - template - struct is_matrix : std::integral_constant{}; - - template - inline static constexpr bool const is_matrix_v = is_matrix::value; - - template - struct is_matrix< basic_static_extents > : std::false_type{}; - - template - struct is_matrix< basic_static_extents >{ - static constexpr bool const value = - is_matrix_v< basic_static_extents > && - is_scalar_v< basic_static_extents >; - }; - - template - struct is_matrix< basic_static_extents >{ - static constexpr bool const value = ( E0 > ExtentsType(1) && E1 > ExtentsType(1) ); - }; - - template - struct is_any_greater_than_one : std::integral_constant{}; - - template - inline static constexpr bool const is_any_greater_than_one_v = is_any_greater_than_one::value; - - template - struct is_any_greater_than_one< basic_static_extents > : std::false_type{}; - - template - struct is_any_greater_than_one< basic_static_extents > { - static constexpr bool const value = ( E0 > ExtentsType(1) ); - }; - - template - struct is_any_greater_than_one< basic_static_extents > { - static constexpr bool const value = is_any_greater_than_one_v< basic_static_extents > || is_any_greater_than_one_v< basic_static_extents >; - }; - - template - struct is_tensor : std::integral_constant{}; - - template - inline static constexpr bool const is_tensor_v = is_tensor::value; - - template - struct is_tensor< basic_static_extents > : std::false_type{}; - - template - struct is_tensor< basic_static_extents >{ - static constexpr bool const value = is_any_greater_than_one_v< basic_static_extents >; - }; - -} // namespace boost::numeric::ublas::static_traits -#endif diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_tensor.hpp b/include/boost/numeric/ublas/tensor/detail/type_traits_tensor.hpp deleted file mode 100644 index 563bbc326..000000000 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_tensor.hpp +++ /dev/null @@ -1,166 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_TENSOR_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_TENSOR_HPP - -#include -#include - -namespace boost::numeric::ublas{ - template class basic_tensor; - - template< typename T, typename F > struct dynamic_tensor; - - template< typename T, std::size_t R, typename F > struct fixed_rank_tensor; - - template< typename T, typename E, typename F > struct static_tensor; -} // namespace boost::numeric::ublas - - -namespace boost::numeric::ublas { - - template - struct tensor_traits; - - template - struct is_valid_tensor: std::is_base_of< basic_tensor, T >{}; - - template - inline static constexpr bool is_valid_tensor_v = is_valid_tensor::value; - - template - struct tensor_rebind; - - template - using tensor_rebind_t = typename tensor_rebind::type; - - template - struct result_tensor; - - template - using result_tensor_t = typename result_tensor::type; - - struct tensor_tag {}; - - struct dynamic_tensor_tag : tensor_tag{}; - struct static_tensor_tag : tensor_tag{}; - -} // namespace boost::numeric::ublas - -namespace boost::numeric::ublas{ - - template - struct tensor_rebind< dynamic_tensor, NewValue > { - using type = dynamic_tensor< NewValue, F >; - }; - - template - struct tensor_rebind< dynamic_tensor, NewValue, NewLayout > { - using type = dynamic_tensor< NewValue, NewLayout >; - }; - - template - struct is_static< dynamic_tensor > : std::false_type{}; - - template - struct is_static_rank< dynamic_tensor > : std::false_type{}; - - template - struct is_dynamic< dynamic_tensor > : std::true_type{}; - - template - struct is_dynamic_rank< dynamic_tensor > : std::true_type{}; - - template - struct result_tensor< V, dynamic_extents<>, F >{ - using type = dynamic_tensor< V, F >; - }; - -} // namespace boost::numeric::ublas::detail - - -namespace boost::numeric::ublas{ - - template - struct tensor_rebind< fixed_rank_tensor, NewValue > { - using type = fixed_rank_tensor< NewValue, R, F >; - }; - - template - struct tensor_rebind< fixed_rank_tensor, NewValue, NewExtents > { - using type = fixed_rank_tensor< NewValue, NewExtents::_size, F >; - }; - - template - struct tensor_rebind< fixed_rank_tensor, NewValue, NewExtents, NewLayout > { - using type = fixed_rank_tensor< NewValue, NewExtents::_size, NewLayout >; - }; - - template - struct is_static< fixed_rank_tensor > : std::false_type{}; - - template - struct is_static_rank< fixed_rank_tensor > : std::true_type{}; - - template - struct is_dynamic< fixed_rank_tensor > : std::true_type{}; - - template - struct is_dynamic_rank< fixed_rank_tensor > : std::false_type{}; - - template - struct result_tensor< V, basic_fixed_rank_extents, F >{ - using type = fixed_rank_tensor< V, R, F >; - }; - -} // namespace boost::numeric::ublas::detail - -namespace boost::numeric::ublas{ - - template - struct tensor_rebind< static_tensor, NewValue > { - using type = static_tensor< NewValue, E, F >; - }; - - template - struct tensor_rebind< static_tensor, NewValue, NewExtents > { - using type = static_tensor< NewValue, NewExtents, F >; - }; - - template - struct tensor_rebind< static_tensor, NewValue, NewExtents, NewLayout > { - using type = static_tensor< NewValue, NewExtents, NewLayout >; - }; - - - template - struct is_static< static_tensor > : std::true_type{}; - - template - struct is_static_rank< static_tensor > : std::true_type{}; - - template - struct is_dynamic< static_tensor > : std::false_type{}; - - template - struct is_dynamic_rank< static_tensor > : std::false_type{}; - - template - struct result_tensor< V, basic_static_extents, F >{ - using type = static_tensor< V, basic_static_extents, F >; - }; - -} // namespace boost::numeric::ublas::detail - - -#endif diff --git a/include/boost/numeric/ublas/tensor/dynamic_extents.hpp b/include/boost/numeric/ublas/tensor/dynamic_extents.hpp index 77446976e..b8d2bdeb5 100644 --- a/include/boost/numeric/ublas/tensor/dynamic_extents.hpp +++ b/include/boost/numeric/ublas/tensor/dynamic_extents.hpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include namespace boost { namespace numeric { @@ -44,34 +44,16 @@ class basic_extents using size_type = typename base_type::size_type; using const_pointer = typename base_type::const_pointer; using const_iterator = typename base_type::const_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; /** @brief Default constructs basic_extents * * @code auto ex = basic_extents{}; */ - basic_extents() - : _base{} - { - } + constexpr basic_extents() = default; /** @brief Copy constructs basic_extents from a one-dimensional container - * - * @code auto ex = basic_extents( std::vector(3u,3u) ); - * - * @note checks if size > 1 and all elements > 0 - * - * @param b one-dimensional std::vector container - */ - explicit basic_extents(base_type const& b) - : _base(b) - { - if ( !valid(*this) ){ - throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); - } - } - - /** @brief Move constructs basic_extents from a one-dimensional container * * @code auto ex = basic_extents( std::vector(3u,3u) ); * @@ -79,10 +61,10 @@ class basic_extents * * @param b one-dimensional container of type std::vector */ - explicit basic_extents(base_type && b) + explicit basic_extents(base_type b) : _base(std::move(b)) { - if (!valid(*this)){ + if (!is_valid(*this)){ throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); } } @@ -109,55 +91,64 @@ class basic_extents * @param first iterator pointing to the first element * @param last iterator pointing to the next position after the last element */ - basic_extents(const_iterator first, const_iterator last) + constexpr basic_extents(const_iterator first, const_iterator last) : basic_extents ( base_type( first,last ) ) { } /** @brief Copy constructs basic_extents */ - basic_extents(basic_extents const& l ) + constexpr basic_extents(basic_extents const& l ) : _base(l._base) { } /** @brief Move constructs basic_extents */ - basic_extents(basic_extents && l ) noexcept + constexpr basic_extents(basic_extents && l ) noexcept : _base(std::move(l._base)) { } - template::value - ,int > = 0 - > - basic_extents(OtherExtentsType const& e) + template + constexpr basic_extents(OtherExtents const& e) : _base(e.size()) { + static_assert( is_extents_v, "boost::numeric::ublas::basic_extents(OtherExtents const&) : " + "OtherExtents should be a valid tensor extents" + ); std::copy(e.begin(),e.end(), _base.begin()); } ~basic_extents() = default; - basic_extents& operator=(basic_extents other) noexcept + constexpr basic_extents& operator=(basic_extents && other) + noexcept(std::is_nothrow_swappable_v) { swap (*this, other); return *this; } + constexpr basic_extents& operator=(basic_extents const& other) + noexcept(std::is_nothrow_swappable_v) + { + basic_extents temp(other); + swap (*this, temp); + return *this; + } - friend void swap(basic_extents& lhs, basic_extents& rhs) { + friend void swap(basic_extents& lhs, basic_extents& rhs) + noexcept(std::is_nothrow_swappable_v) + { std::swap(lhs._base , rhs._base ); } [[nodiscard]] inline - constexpr const_pointer data() const + constexpr const_pointer data() const noexcept { return this->_base.data(); } [[nodiscard]] inline - constexpr const_reference operator[] (size_type p) const noexcept + constexpr const_reference operator[] (size_type p) const { return this->_base[p]; } @@ -188,43 +179,57 @@ class basic_extents [[nodiscard]] inline - constexpr bool empty() const + constexpr bool empty() const noexcept { return this->_base.empty(); } [[nodiscard]] inline - constexpr size_type size() const + constexpr size_type size() const noexcept { return this->_base.size(); } inline - constexpr void clear() + constexpr void clear() noexcept { this->_base.clear(); } [[nodiscard]] inline constexpr const_iterator - begin() const + begin() const noexcept { return _base.begin(); } [[nodiscard]] inline constexpr const_iterator - end() const + end() const noexcept { return _base.end(); } [[nodiscard]] inline - constexpr base_type const& base() const { return _base; } + constexpr const_reverse_iterator + rbegin() const noexcept + { + return _base.rbegin(); + } + + [[nodiscard]] inline + constexpr const_reverse_iterator + rend() const noexcept + { + return _base.rend(); + } + + [[nodiscard]] inline + constexpr base_type const& base() const noexcept { return _base; } private: - base_type _base; + base_type _base{}; }; diff --git a/include/boost/numeric/ublas/tensor/dynamic_strides.hpp b/include/boost/numeric/ublas/tensor/dynamic_strides.hpp index d8e6ba94b..3f26eb345 100644 --- a/include/boost/numeric/ublas/tensor/dynamic_strides.hpp +++ b/include/boost/numeric/ublas/tensor/dynamic_strides.hpp @@ -18,14 +18,12 @@ #include #include #include +#include namespace boost { namespace numeric { namespace ublas { -using first_order = column_major; -using last_order = row_major; - template class basic_extents; @@ -46,7 +44,7 @@ class basic_strides "Static error in boost::numeric::ublas::basic_strides: type must be of type integer."); static_assert(!std::numeric_limits::is_signed, "Static error in boost::numeric::ublas::basic_strides: type must be of type unsigned integer."); - static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value, + static_assert(std::is_same<__layout,layout::first_order>::value || std::is_same<__layout,layout::last_order>::value, "Static error in boost::numeric::ublas::basic_strides: layout type must either first or last order"); @@ -57,78 +55,87 @@ class basic_strides using size_type = typename base_type::size_type; using const_pointer = typename base_type::const_pointer; using const_iterator = typename base_type::const_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; /** @brief Default constructs basic_strides * * @code auto ex = basic_strides{}; */ - constexpr explicit basic_strides() - : _base{} - { - } + constexpr explicit basic_strides() = default; /** @brief Constructs basic_strides from basic_extents for the first- and last-order storage formats * * @code auto strides = basic_strides( basic_extents{2,3,4} ); * */ - template - basic_strides(basic_extents const& s) + template + constexpr basic_strides(ExtentsType const& s) : _base(s.size(),1) { + static_assert( is_extents_v, "boost::numeric::ublas::basic_strides(ExtentsType const&) : " + "ExtentsType is not a tensor extents" + ); if( s.empty() ) return; - if( !valid(s) ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : shape is not valid."); + if( !is_valid(s) ) + throw std::runtime_error("Error in boost::numeric::ublas::basic_strides(ExtentsType const&) : " + "shape is not valid." + ); if( is_vector(s) || is_scalar(s) ) return; if( this->size() < 2 ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : size of strides must be greater or equal 2."); + throw std::runtime_error("Error in boost::numeric::ublas::basic_strides(ExtentsType const&) : " + "size of strides must be greater or equal to 2." + ); - if constexpr (std::is_same::value){ - size_type k = 1ul, kend = this->size(); - for(; k < kend; ++k) - _base[k] = _base[k-1] * s[k-1]; - } - else { - size_type k = this->size()-2, kend = 0ul; - for(; k > kend; --k) - _base[k] = _base[k+1] * s[k+1]; - _base[0] = _base[1] * s[1]; + if constexpr (std::is_same::value){ + std::transform(s.begin(), s.end() - 1, _base.begin(), _base.begin() + 1, std::multiplies{}); + }else { + std::transform(s.rbegin(), s.rend() - 1, _base.rbegin(), _base.rbegin() + 1, std::multiplies{}); } } - basic_strides(basic_strides const& l) + constexpr basic_strides(basic_strides const& l) : _base(l._base) {} - basic_strides(basic_strides && l ) + constexpr basic_strides(basic_strides && l ) noexcept : _base(std::move(l._base)) {} - basic_strides(base_type const& l ) + constexpr basic_strides(base_type const& l ) : _base(l) {} - basic_strides(base_type && l ) - : _base(std::move(l)) + constexpr basic_strides(base_type && l ) noexcept + : _base(std::move(l)) {} ~basic_strides() = default; - - basic_strides& operator=(basic_strides other) + constexpr basic_strides& operator=(basic_strides&& other) + noexcept(std::is_nothrow_swappable_v) { swap (*this, other); return *this; } - friend void swap(basic_strides& lhs, basic_strides& rhs) { + constexpr basic_strides& operator=(basic_strides const& other) + noexcept(std::is_nothrow_swappable_v) + { + basic_strides temp(other); + swap (*this, temp); + return *this; + } + + friend void swap(basic_strides& lhs, basic_strides& rhs) + noexcept(std::is_nothrow_swappable_v) + { std::swap(lhs._base , rhs._base); } @@ -149,46 +156,60 @@ class basic_strides [[nodiscard]] inline constexpr const_reference back () const{ - return _base[_base.size() - 1]; + return _base.back(); } [[nodiscard]] inline constexpr reference back (){ - return _base[_base.size() - 1]; + return _base.back(); } [[nodiscard]] inline - constexpr bool empty() const{ + constexpr bool empty() const noexcept{ return _base.empty(); } [[nodiscard]] inline - constexpr size_type size() const{ + constexpr size_type size() const noexcept{ return _base.size(); } [[nodiscard]] inline - constexpr const_iterator begin() const{ + constexpr const_iterator begin() const noexcept{ return _base.begin(); } [[nodiscard]] inline - constexpr const_iterator end() const{ + constexpr const_iterator end() const noexcept{ return _base.end(); } inline - constexpr void clear() { + constexpr void clear() noexcept{ this->_base.clear(); } [[nodiscard]] inline - constexpr base_type const& base() const{ + constexpr base_type const& base() const noexcept{ return this->_base; } + + [[nodiscard]] inline + constexpr const_reverse_iterator + rbegin() const noexcept + { + return _base.rbegin(); + } + + [[nodiscard]] inline + constexpr const_reverse_iterator + rend() const noexcept + { + return _base.rend(); + } -protected: - base_type _base; +private: + base_type _base{}; }; } diff --git a/include/boost/numeric/ublas/tensor/dynamic_tensor.hpp b/include/boost/numeric/ublas/tensor/dynamic_tensor.hpp deleted file mode 100644 index 273db7c12..000000000 --- a/include/boost/numeric/ublas/tensor/dynamic_tensor.hpp +++ /dev/null @@ -1,203 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - - -#ifndef BOOST_UBLAS_DYNAMIC_TENSOR_IMPL_HPP -#define BOOST_UBLAS_DYNAMIC_TENSOR_IMPL_HPP - -#include - -namespace boost::numeric::ublas { - - template< typename T = float, typename F = first_order > - struct dynamic_tensor: - public basic_tensor< dynamic_tensor< T, F > > - { - using self_type = dynamic_tensor< T, F >; - using super_type = basic_tensor< self_type >; - - template - using tensor_expression_type = typename super_type::template tensor_expression_type; - - template - using matrix_expression_type = typename super_type::template matrix_expression_type; - - template - using vector_expression_type = typename super_type::template vector_expression_type; - - using array_type = typename tensor_traits::container_type; - using layout_type = typename tensor_traits::layout_type; - - using size_type = typename array_type::size_type; - using difference_type = typename array_type::difference_type; - using value_type = typename array_type::value_type; - - using reference = typename array_type::reference; - using const_reference = typename array_type::const_reference; - - using pointer = typename array_type::pointer; - using const_pointer = typename array_type::const_pointer; - - using iterator = typename array_type::iterator; - using const_iterator = typename array_type::const_iterator; - - using reverse_iterator = typename array_type::reverse_iterator; - using const_reverse_iterator = typename array_type::const_reverse_iterator; - - using tensor_temporary_type = self_type; - using storage_category = dense_tag; - - using extents_type = typename tensor_traits::extents_type; - using strides_type = strides_t; - - using matrix_type = typename super_type::matrix_type; - using vector_type = typename super_type::vector_type; - - constexpr dynamic_tensor() = default; - - dynamic_tensor( std::initializer_list< size_type > li ) - : super_type( std::move(li) ) - {} - - constexpr dynamic_tensor( extents_type const& e, value_type const& i ) - : super_type(e,i) - {} - - constexpr dynamic_tensor( extents_type const& e, array_type const& a ) - : super_type(e,a) - {} - - constexpr dynamic_tensor( extents_type const& e ) - : super_type(e) - {} - - constexpr dynamic_tensor( matrix_type const& v ) - : super_type( extents_type{v.size1(), v.size2()} ) - { - std::copy(v.data().begin(), v.data().end(),super_type::data_.begin()); - } - - constexpr dynamic_tensor( matrix_type && v ) - : super_type( extents_type{v.size1(), v.size2()} ) - { - std::move(v.data().begin(), v.data().end(),super_type::begin()); - } - - constexpr dynamic_tensor (const vector_type &v) - : super_type( extents_type{ v.size(), typename extents_type::value_type{1} } ) - { - std::copy(v.data().begin(), v.data().end(),super_type::data_.begin()); - } - - constexpr dynamic_tensor (vector_type &&v) - : super_type( extents_type{ v.size(), typename extents_type::value_type{1} } ) - { - std::move(v.data().begin(), v.data().end(),super_type::begin()); - } - - template - constexpr dynamic_tensor (const dynamic_tensor &expr) - : super_type(expr) - { - - } - - template - constexpr dynamic_tensor (const tensor_expression_type &expr) - : super_type(expr) - {} - - template - inline - constexpr dynamic_tensor& operator= (const tensor_expression_type &expr) - { - dynamic_tensor temp( expr ); - swap(*this,temp); - return *this; - } - - template - constexpr dynamic_tensor (const matrix_expression_type &expr) - : dynamic_tensor( matrix_type(expr) ) - {} - - template - constexpr dynamic_tensor (const vector_expression_type &expr) - : dynamic_tensor( vector_type(expr) ) - {} - - - template - constexpr dynamic_tensor (const basic_tensor & other) - : super_type(other.extents()) - { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::dynamic_tensor( const OtherTensor& ) : The OtherTensor should have a tensor type" - ); - - static_assert( std::is_same_v, - "boost::numeric::ublas::dynamic_tensor( const OtherTensor& ) : The tensor should have same value type" - ); - - std::copy(other.begin(), other.end(), super_type::begin()); - } - - template - constexpr dynamic_tensor (basic_tensor && other) - : super_type(other.extents()) - { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::dynamic_tensor( OtherTensor&& ) : The OtherTensor should have a tensor type" - ); - - static_assert( std::is_same_v, - "boost::numeric::ublas::dynamic_tensor( OtherTensor&& ) : The tensor should have same value type" - ); - - std::move(other.begin(), other.end(), super_type::begin()); - - } - - inline - constexpr dynamic_tensor& operator=(const_reference v) noexcept{ - std::fill(super_type::begin(), super_type::end(), v); - return *this; - } - - }; - - template - dynamic_tensor(dynamic_extents<> const&, V const&) -> dynamic_tensor; - - dynamic_tensor(dynamic_extents<> const&) -> dynamic_tensor; - - template - dynamic_tensor(basic_tensor const&) -> dynamic_tensor< typename T::value_type, typename T::layout_type >; - - template - dynamic_tensor(basic_tensor &&) -> dynamic_tensor< typename T::value_type, typename T::layout_type >; - -} // boost::numeric::ublas - -namespace boost::numeric::ublas{ - - template - struct tensor_traits< dynamic_tensor > { - using container_type= std::vector< T >; - using extents_type = dynamic_extents<>; - using layout_type = F; - using container_tag = dynamic_tensor_tag; - }; - -} // boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/expression.hpp b/include/boost/numeric/ublas/tensor/expression.hpp index 821a7f2b0..9b3c44d2c 100644 --- a/include/boost/numeric/ublas/tensor/expression.hpp +++ b/include/boost/numeric/ublas/tensor/expression.hpp @@ -14,7 +14,8 @@ #include #include -#include +#include +#include namespace boost { namespace numeric { @@ -39,12 +40,17 @@ struct tensor_expression using tensor_type = T; inline - auto const& operator()() const { return *static_cast (this); } + constexpr auto const& operator()() const noexcept { return *static_cast (this); } + + ~tensor_expression() = default; + tensor_expression(const tensor_expression&) = delete; + tensor_expression(tensor_expression&&) noexcept = delete; + tensor_expression& operator=(const tensor_expression&) = delete; + tensor_expression& operator=(tensor_expression&&) noexcept = delete; + protected : explicit tensor_expression() = default; - tensor_expression(const tensor_expression&) = delete; - tensor_expression& operator=(const tensor_expression&) = delete; }; @@ -61,15 +67,19 @@ struct binary_tensor_expression using size_type = typename tensor_type::size_type; - explicit binary_tensor_expression(expression_type_left const& l, expression_type_right const& r, binary_operation o) + explicit constexpr binary_tensor_expression(expression_type_left const& l, expression_type_right const& r, binary_operation o) : el(l) , er(r) , op(o) {} binary_tensor_expression() = delete; binary_tensor_expression(const binary_tensor_expression& l) = delete; - binary_tensor_expression(binary_tensor_expression&& l) - : el(l.el), er(l.er), op(l.op) {} + constexpr binary_tensor_expression(binary_tensor_expression&& l) noexcept + : el(l.el), er(l.er), op(std::move(l.op)) {} + constexpr binary_tensor_expression& operator=(binary_tensor_expression&& l) noexcept = default; + binary_tensor_expression& operator=(binary_tensor_expression const& l) noexcept = delete; - inline - decltype(auto) operator()(size_type i) const { return op(el(i), er(i)); } + ~binary_tensor_expression() = default; + + [[nodiscard]] inline + constexpr decltype(auto) operator()(size_type i) const { return op(el(i), er(i)); } expression_type_left const& el; expression_type_right const& er; @@ -78,7 +88,8 @@ struct binary_tensor_expression /// @brief helper function to simply instantiation of lambda proxy class template -auto make_binary_tensor_expression( tensor_expression const& el, tensor_expression const& er, OP op) +[[nodiscard]] inline +constexpr auto make_binary_tensor_expression( tensor_expression const& el, tensor_expression const& er, OP op) noexcept { static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, "boost::numeric::ublas::make_binary_tensor_expression(T1,T2) : LHS tensor and RHS tensor should have same value type" @@ -87,25 +98,29 @@ auto make_binary_tensor_expression( tensor_expression const& el, tensor_e } template -auto make_binary_tensor_expression( matrix_expression const& el, tensor_expression const& er, OP op) +[[nodiscard]] inline +constexpr auto make_binary_tensor_expression( matrix_expression const& el, tensor_expression const& er, OP op) noexcept { return binary_tensor_expression( el(), er(), op) ; } template -auto make_binary_tensor_expression( tensor_expression const& el, matrix_expression const& er, OP op) +[[nodiscard]] inline +constexpr auto make_binary_tensor_expression( tensor_expression const& el, matrix_expression const& er, OP op) noexcept { return binary_tensor_expression( el(), er(), op) ; } template -auto make_binary_tensor_expression( vector_expression const& el, tensor_expression const& er, OP op) +[[nodiscard]] inline +constexpr auto make_binary_tensor_expression( vector_expression const& el, tensor_expression const& er, OP op) noexcept { return binary_tensor_expression( el(), er(), op) ; } template -auto make_binary_tensor_expression( tensor_expression const& el, vector_expression const& er, OP op) +[[nodiscard]] inline +constexpr auto make_binary_tensor_expression( tensor_expression const& el, vector_expression const& er, OP op) noexcept { return binary_tensor_expression( el(), er(), op) ; } @@ -125,14 +140,19 @@ struct unary_tensor_expression using size_type = typename tensor_type::size_type; - explicit unary_tensor_expression(E const& ee, OP o) : e(ee) , op(o) {} - unary_tensor_expression() = delete; + explicit constexpr unary_tensor_expression(E const& ee, OP o) : e(ee) , op(o) {} + constexpr unary_tensor_expression() = delete; unary_tensor_expression(const unary_tensor_expression& l) = delete; - unary_tensor_expression(unary_tensor_expression&& l) - : e(l.e), op(op.l) {} + constexpr unary_tensor_expression(unary_tensor_expression&& l) noexcept + : e(l.e), op(std::move(l.op)) {} - inline - decltype(auto) operator()(size_type i) const { return op(e(i)); } + constexpr unary_tensor_expression& operator=(unary_tensor_expression&& l) noexcept = default; + + unary_tensor_expression& operator=(unary_tensor_expression const& l) noexcept = delete; + ~unary_tensor_expression() = default; + + [[nodiscard]] inline + constexpr decltype(auto) operator()(size_type i) const { return op(e(i)); } E const& e; OP op; @@ -140,19 +160,22 @@ struct unary_tensor_expression // \brief helper function to simply instantiation of lambda proxy class template -auto make_unary_tensor_expression( tensor_expression const& e, OP op) +[[nodiscard]] inline +constexpr auto make_unary_tensor_expression( tensor_expression const& e, OP op) noexcept { return unary_tensor_expression( e() , op); } template -auto make_unary_tensor_expression( matrix_expression const& e, OP op) +[[nodiscard]] inline +constexpr auto make_unary_tensor_expression( matrix_expression const& e, OP op) noexcept { return unary_tensor_expression( e() , op); } template -auto make_unary_tensor_expression( vector_expression const& e, OP op) +[[nodiscard]] inline +constexpr auto make_unary_tensor_expression( vector_expression const& e, OP op) noexcept { return unary_tensor_expression( e() , op); } diff --git a/include/boost/numeric/ublas/tensor/expression_evaluation.hpp b/include/boost/numeric/ublas/tensor/expression_evaluation.hpp index 90e1fa829..a169b4e62 100644 --- a/include/boost/numeric/ublas/tensor/expression_evaluation.hpp +++ b/include/boost/numeric/ublas/tensor/expression_evaluation.hpp @@ -10,8 +10,8 @@ // Google and Fraunhofer IOSB, Ettlingen, Germany // -#ifndef _BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP_ -#define _BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP_ +#ifndef BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP +#define BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP #include #include @@ -20,10 +20,10 @@ namespace boost::numeric::ublas { -template -class basic_tensor; +template +class tensor_core; -template +template class basic_extents; } @@ -55,7 +55,6 @@ template struct has_tensor_types> { static constexpr bool value = std::is_same::value || has_tensor_types::value; }; - template struct has_tensor_types> { static constexpr bool value = std::is_same::value || std::is_same::value || has_tensor_types::value || has_tensor_types::value; }; @@ -73,24 +72,21 @@ namespace boost::numeric::ublas::detail { -/** @brief Retrieves extents of the basic_tensor +/** @brief Retrieves extents of the tensor_core * */ -template +template [[nodiscard]] -constexpr auto& retrieve_extents(basic_tensor const& t) +constexpr auto& retrieve_extents(tensor_core const& t) { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::detailretrieve_extents() : tensor type should be valid tensor" - ); return t.extents(); } -/** @brief Retrieves extents of the basic_tensor expression +/** @brief Retrieves extents of the tensor_core expression * - * @note basic_tensor expression must be a binary tree with at least one basic_tensor type + * @note tensor_core expression must be a binary tree with at least one tensor_core type * - * @returns extents of the child expression if it is a basic_tensor or extents of one child of its child. + * @returns extents of the child expression if it is a tensor_core or extents of one child of its child. */ template [[nodiscard]] @@ -112,11 +108,11 @@ constexpr auto& retrieve_extents(tensor_expression const& expr) #pragma warning( push ) #pragma warning( disable : 4702 ) #endif -/** @brief Retrieves extents of the binary basic_tensor expression +/** @brief Retrieves extents of the binary tensor_core expression * - * @note basic_tensor expression must be a binary tree with at least one basic_tensor type + * @note tensor_core expression must be a binary tree with at least one tensor_core type * - * @returns extents of the (left and if necessary then right) child expression if it is a basic_tensor or extents of a child of its (left and if necessary then right) child. + * @returns extents of the (left and if necessary then right) child expression if it is a tensor_core or extents of a child of its (left and if necessary then right) child. */ template [[nodiscard]] @@ -142,11 +138,11 @@ constexpr auto& retrieve_extents(binary_tensor_expression const& exp #pragma warning( pop ) #endif -/** @brief Retrieves extents of the binary basic_tensor expression +/** @brief Retrieves extents of the binary tensor_core expression * - * @note basic_tensor expression must be a binary tree with at least one basic_tensor type + * @note tensor_core expression must be a binary tree with at least one tensor_core type * - * @returns extents of the child expression if it is a basic_tensor or extents of a child of its child. + * @returns extents of the child expression if it is a tensor_core or extents of a child of its child. */ template [[nodiscard]] @@ -170,18 +166,14 @@ constexpr auto& retrieve_extents(unary_tensor_expression const& expr) namespace boost::numeric::ublas::detail { -template +template [[nodiscard]] inline -constexpr auto all_extents_equal(basic_tensor const& t, Extents const& extents) +constexpr auto all_extents_equal(tensor_core const& t, Extents const& extents) { static_assert(is_extents_v, "Error in boost::numeric::ublas::detail::all_extents_equal: extents passed should be of extents type." ); - - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::all_extents_equal() : tensor type should be valid tensor" - ); - + return extents == t.extents(); } @@ -270,55 +262,84 @@ constexpr auto all_extents_equal(unary_tensor_expression const& expr, Ex namespace boost::numeric::ublas::detail { -/** @brief Evaluates expression for a basic_tensor +/** @brief Evaluates expression for a tensor_core * - * Assigns the results of the expression to the basic_tensor. + * Assigns the results of the expression to the tensor_core. * - * \note Checks if shape of the basic_tensor matches those of all tensors within the expression. + * \note Checks if shape of the tensor_core matches those of all tensors within the expression. */ template -void eval(tensor_type& lhs, tensor_expression const& expr) +inline void eval(tensor_type& lhs, tensor_expression const& expr) { if constexpr (detail::has_tensor_types >::value ) if(!detail::all_extents_equal(expr, lhs.extents() )) - throw std::runtime_error("Error in boost::numeric::ublas::basic_tensor: expression contains tensors with different shapes."); + throw std::runtime_error("Error in boost::numeric::ublas::tensor_core: expression contains tensors with different shapes."); #pragma omp parallel for for(auto i = 0u; i < lhs.size(); ++i) lhs(i) = expr()(i); } -/** @brief Evaluates expression for a basic_tensor +/** @brief Evaluates expression for a tensor_core + * + * Assigns the results of the expression to the tensor_core. + * + * \note Checks if shape of the tensor_core matches those of all tensors within the expression. +*/ +template +inline void eval(tensor_type& lhs, tensor_expression const& expr) +{ + + static_assert(is_valid_tensor_v && is_valid_tensor_v, + "boost::numeric::ublas::detail::eval(tensor_type&, tensor_expression const&) : " + "tensor_type and tensor_expresssion should be a valid tensor type" + ); + + static_assert(std::is_same_v, + "boost::numeric::ublas::detail::eval(tensor_type&, tensor_expression const&) : " + "tensor_type and tensor_expresssion should have same value type" + ); + + if ( !detail::all_extents_equal(expr, lhs.extents() ) ){ + throw std::runtime_error("Error in boost::numeric::ublas::tensor_core: expression contains tensors with different shapes."); + } + + #pragma omp parallel for + for(auto i = 0u; i < lhs.size(); ++i) + lhs(i) = expr()(i); +} + +/** @brief Evaluates expression for a tensor_core * * Applies a unary function to the results of the expressions before the assignment. * Usually applied needed for unary operators such as A += C; * - * \note Checks if shape of the basic_tensor matches those of all tensors within the expression. + * \note Checks if shape of the tensor_core matches those of all tensors within the expression. */ template -void eval(tensor_type& lhs, tensor_expression const& expr, unary_fn const fn) +inline void eval(tensor_type& lhs, tensor_expression const& expr, unary_fn const fn) { if constexpr (detail::has_tensor_types< tensor_type, tensor_expression >::value ) if(!detail::all_extents_equal( expr, lhs.extents() )) - throw std::runtime_error("Error in boost::numeric::ublas::basic_tensor: expression contains tensors with different shapes."); + throw std::runtime_error("Error in boost::numeric::ublas::tensor_core: expression contains tensors with different shapes."); -#pragma omp parallel for + #pragma omp parallel for for(auto i = 0u; i < lhs.size(); ++i) fn(lhs(i), expr()(i)); } -/** @brief Evaluates expression for a basic_tensor +/** @brief Evaluates expression for a tensor_core * * Applies a unary function to the results of the expressions before the assignment. * Usually applied needed for unary operators such as A += C; * - * \note Checks if shape of the basic_tensor matches those of all tensors within the expression. + * \note Checks if shape of the tensor_core matches those of all tensors within the expression. */ template -void eval(tensor_type& lhs, unary_fn const fn) +inline void eval(tensor_type& lhs, unary_fn const& fn) { #pragma omp parallel for for(auto i = 0u; i < lhs.size(); ++i) diff --git a/include/boost/numeric/ublas/tensor/detail/extents_functions.hpp b/include/boost/numeric/ublas/tensor/extents_functions.hpp similarity index 63% rename from include/boost/numeric/ublas/tensor/detail/extents_functions.hpp rename to include/boost/numeric/ublas/tensor/extents_functions.hpp index 0fbf28fd8..46f15f93a 100644 --- a/include/boost/numeric/ublas/tensor/detail/extents_functions.hpp +++ b/include/boost/numeric/ublas/tensor/extents_functions.hpp @@ -7,14 +7,13 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP_ #define _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP_ #include -#include #include #include #include @@ -29,8 +28,20 @@ namespace boost::numeric::ublas::detail{ template constexpr auto push_front(basic_static_extents) -> basic_static_extents; + template + constexpr auto pop_front(basic_static_extents) -> basic_static_extents; + + template + constexpr auto any_extents_greater_than_one([[maybe_unused]] basic_static_extents const& e) noexcept{ + constexpr auto sz = sizeof...(Es); + return sz && ( ( Es > T(1) ) || ... ); + } + template - constexpr auto squeeze_impl_remove_one( basic_static_extents, basic_static_extents num = basic_static_extents{} ){ + constexpr auto squeeze_impl_remove_one( + [[maybe_unused]] basic_static_extents e, + basic_static_extents num = basic_static_extents{} + ){ // executed when basic_static_extents is size of 1 // @code basic_static_extents @endcode if constexpr( sizeof...(E) == 0ul ){ @@ -158,9 +169,9 @@ namespace boost::numeric::ublas { /** @brief Returns true if size > 1 and all elements > 0 or size == 1 && e[0] == 1 */ template [[nodiscard]] inline -constexpr bool valid(ExtentsType const &e) { +constexpr bool is_valid(ExtentsType const &e) { - static_assert(is_extents_v, "boost::numeric::ublas::valid() : invalid type, type should be an extents"); + static_assert(is_extents_v, "boost::numeric::ublas::is_valid() : invalid type, type should be an extents"); auto greater_than_zero = [](auto const& a){ return a > 0u; }; @@ -168,6 +179,19 @@ constexpr bool valid(ExtentsType const &e) { return !e.empty() && std::all_of(e.begin(), e.end(), greater_than_zero ); } +/** @brief Returns true if size > 1 and all elements > 0 or size == 1 && e[0] == 1 */ +template +[[nodiscard]] inline +constexpr bool is_valid( [[maybe_unused]] basic_static_extents const &e) noexcept { + constexpr auto sz = sizeof...(Es); + /// if number of extents is 1 then extents at 0th pos should be 1 + /// else if number of extents is greater than 1 then all the extents + /// should be greater than 0 + /// else return false + return ( ( sz == 1ul ) && ( ( T(1) == Es ) && ... ) ) || + ( ( sz > 1ul ) && ( ( T(0) < Es ) && ... ) ); +} + /** * @code static_extents<4,1,2,3,4> s; * std::cout< +[[nodiscard]] inline +constexpr bool is_scalar( [[maybe_unused]] basic_static_extents const &e) noexcept { + constexpr auto sz = sizeof...(Es); + /// if number of extents is greater than 1 then all the extents should be 1 + /// else return false; + return sz && ( ( T(1) == Es ) && ... ); +} + /** @brief Returns true if this has a vector shape * * @returns true if (1,n,[1,...,1]) or (n,1,[1,...,1]) with n > 1 @@ -225,14 +262,42 @@ constexpr bool is_vector(ExtentsType const &e) { auto greater_one = [](auto const &a) { return a > 1u; }; auto equal_one = [](auto const &a) { return a == 1u; }; - if (e.size() == 0u) return false; - else if (e.size() == 1u) return e[0] > 1u; - else return std::any_of(e.begin(), e.begin() + 2, greater_one) && + if (e.empty()) return false; + if (e.size() == 1u) return e[0] > 1u; + return std::any_of(e.begin(), e.begin() + 2, greater_one) && std::any_of(e.begin(), e.begin() + 2, equal_one) && std::all_of(e.begin() + 2, e.end(), equal_one); } +/** @brief Returns true if this has a vector shape + * + * @returns true if (1,n,[1,...,1]) or (n,1,[1,...,1]) with n > 1 + */ +template +[[nodiscard]] inline +constexpr bool is_vector( [[maybe_unused]] basic_static_extents const &e) noexcept { + using extents_type = basic_static_extents; + + if constexpr (sizeof... (Es) == 1ul) return extents_type::at(0) > T(1); + else if constexpr (sizeof... (Es) >= 2ul){ + /// first two elements of the extents cannot be greater than 1 at the + /// same time which xor operation keeps in check + /// example: 0 xor 1 => 1, 1 xor 1 => 0, 1 xor 0 => 1, and 0 xor 0 => 0 + constexpr bool first_two_extents = ( extents_type::at(0) > T(1) ) ^ ( extents_type::at(1) > T(1) ); + + /// poping first two elements from the extents and checking is_scalar + /// basic_static_extents after poping two times becomes + /// basic_static_extents + using extents_after_removing_the_first_element = decltype( detail::pop_front( e ) ); + using extents_after_removing_the_second_element = decltype( detail::pop_front( extents_after_removing_the_first_element{} ) ); + return first_two_extents && + ( extents_after_removing_the_second_element::_size == 0ul || + is_scalar(extents_after_removing_the_second_element{}) + ); + } else return false; +} + /** @brief Returns true if this has a matrix shape * * @returns true if (m,n,[1,...,1]) with m > 1 and n > 1 @@ -250,6 +315,32 @@ constexpr bool is_matrix(ExtentsType const &e) { std::all_of(e.begin() + 2, e.end(), equal_one); } +/** @brief Returns true if this has a matrix shape + * + * @returns true if (m,n,[1,...,1]) with m > 1 and n > 1 + */ +template +[[nodiscard]] inline +constexpr bool is_matrix( [[maybe_unused]] basic_static_extents const &e) noexcept { + using extents_type = basic_static_extents; + + if constexpr (sizeof... (Es) >= 2ul){ + /// first two elements of the extents should be greater than 1 at the + /// same time and remaing range should be scalar or empty + constexpr bool first_two_extents = ( extents_type::at(0) > T(1) ) && ( extents_type::at(1) > T(1) ); + + /// poping first two elements from the extents and checking is_scalar + /// basic_static_extents after poping two times becomes + /// basic_static_extents + using extents_after_removing_the_first_element = decltype( detail::pop_front( e ) ); + using extents_after_removing_the_second_element = decltype( detail::pop_front( extents_after_removing_the_first_element{} ) ); + return first_two_extents && + ( extents_after_removing_the_second_element::_size == 0ul || + is_scalar(extents_after_removing_the_second_element{}) + ); + } else return false; +} + /** @brief Returns true if this is has a tensor shape * * @returns true if !empty() && !is_scalar() && !is_vector() && !is_matrix() @@ -265,6 +356,25 @@ constexpr bool is_tensor(ExtentsType const &e) { return ( e.size() >= 3u ) && std::any_of(e.begin() + 2, e.end(), greater_one); } +/** @brief Returns true if this is has a tensor shape + * + * @returns true if !empty() && !is_scalar() && !is_vector() && !is_matrix() + */ +template +[[nodiscard]] inline +constexpr bool is_tensor( [[maybe_unused]] basic_static_extents const &e) noexcept { + if constexpr( sizeof...(Es) >= 3ul ){ + /// poping first two elements from the extents and checking the remaining + /// extent, if any extent is greater than 1 + /// basic_static_extents after poping two times becomes + /// basic_static_extents + using extents_after_removing_the_first_element = decltype( detail::pop_front( e ) ); + using extents_after_removing_the_second_element = decltype( detail::pop_front( extents_after_removing_the_first_element{} ) ); + return detail::any_extents_greater_than_one(extents_after_removing_the_second_element{}); + + } else return false; +} + /** @brief Eliminates singleton dimensions when size > 2 * * squeeze { 1,1} -> { 1,1} @@ -294,7 +404,15 @@ constexpr auto product(ExtentsType const &e) { static_assert(is_extents_v, "boost::numeric::ublas::product() : invalid type, type should be an extents"); if ( e.empty() ) return 0u; - else return std::accumulate(e.begin(), e.end(), 1u, std::multiplies<>()) ; + return std::accumulate(e.begin(), e.end(), 1u, std::multiplies<>()) ; +} + +/** @brief Returns the product of static extents at compile-time */ +template +[[nodiscard]] inline +constexpr auto product( [[maybe_unused]] basic_static_extents const &e) noexcept { + if constexpr( sizeof...(Es) == 0 ) return T(0); + else return T( (Es * ...) ); } diff --git a/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp b/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp index 66ccef2f9..a3aa3603d 100644 --- a/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp +++ b/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp @@ -19,11 +19,9 @@ #include #include #include -#include +#include -namespace boost { -namespace numeric { -namespace ublas { +namespace boost::numeric::ublas { /** @brief Template class for storing tensor extents for compile time. * @@ -32,20 +30,21 @@ namespace ublas { * */ template -struct basic_fixed_rank_extents +class basic_fixed_rank_extents { - - static constexpr std::size_t const _size = N; +public: + static constexpr std::size_t const _size = N; using base_type = std::array; using value_type = typename base_type::value_type; - using const_reference = typename base_type::const_reference; + using size_type = typename base_type::size_type; using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; using const_pointer = typename base_type::const_pointer; using const_iterator = typename base_type::const_iterator; - using size_type = typename base_type::size_type; + using const_reverse_iterator = typename base_type::const_reverse_iterator; static_assert( std::numeric_limits::is_integer, "Static error in basic_fixed_rank_extents: type must be of type integer."); static_assert(!std::numeric_limits::is_signed, "Static error in basic_fixed_rank_extents: type must be of type unsigned integer."); @@ -74,30 +73,60 @@ struct basic_fixed_rank_extents return _base[k]; } - // default constructor constexpr basic_fixed_rank_extents() = default; + constexpr basic_fixed_rank_extents(basic_fixed_rank_extents const& other) + : _base(other._base) + {} + + constexpr basic_fixed_rank_extents(basic_fixed_rank_extents && other) noexcept + : _base( std::move(other._base) ) + {} + + constexpr basic_fixed_rank_extents& operator=(basic_fixed_rank_extents const& other) + noexcept(std::is_nothrow_swappable_v) + { + basic_fixed_rank_extents temp(other); + swap(*this,temp); + return *this; + } + + constexpr basic_fixed_rank_extents& operator=(basic_fixed_rank_extents && other) + noexcept(std::is_nothrow_swappable_v) + { + swap(*this,other); + return *this; + } + + ~basic_fixed_rank_extents() = default; + constexpr basic_fixed_rank_extents(std::initializer_list li){ if( li.size() > _size ){ - throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than _size"); + throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(std::initializer_list): " + "number of elements in std::initializer_list is greater than the size" + ); } std::copy(li.begin(), li.end(), _base.begin()); - if ( !valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + if ( !is_valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : " + "shape tuple is not a valid permutation: has zero elements." + ); } } constexpr basic_fixed_rank_extents(const_iterator begin, const_iterator end){ if( std::distance(begin,end) < 0 || static_cast(std::distance(begin,end)) > _size){ - throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than _size"); + throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than the rank"); } std::copy(begin, end, _base.begin()); - if ( !valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + if ( !is_valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents(const_iterator,const_iterator) : " + "shape tuple is not a valid permutation: has zero elements." + ); } } @@ -106,34 +135,51 @@ struct basic_fixed_rank_extents _base.fill(value); } - template::value - ,int > = 0 - > - constexpr basic_fixed_rank_extents(OtherExtentsType const& e){ + template + constexpr basic_fixed_rank_extents(OtherExtents const& e){ + static_assert( is_extents_v, "boost::numeric::ublas::basic_fixed_rank_extents(OtherExtents const&) : " + "OtherExtents should be a valid tensor extents" + ); + + if constexpr( is_static_rank_v< OtherExtents > ){ + static_assert( OtherExtents::_size == _size, + "basic_fixed_rank_extents::basic_fixed_rank_extents(OtherExtents const&) : " + "unequal rank found, rank should be equal" + ); + }else{ + if( e.size() != size() ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents(OtherExtents const&) : " + "unequal rank found, rank should be equal" + ); + } + } + std::copy_n(e.begin(),_size, _base.begin()); } constexpr basic_fixed_rank_extents(base_type const& data) : _base(data) { - if ( !valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + if ( !is_valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents(base_type const&) : " + "shape tuple is not a valid permutation: has zero elements." + ); } } constexpr basic_fixed_rank_extents(base_type&& data) : _base(std::move(data)) { - if ( !valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : shape tuple is not a valid permutation: has zero elements."); + if ( !is_valid(*this) ){ + throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents(base_type &&) : " + "shape tuple is not a valid permutation: has zero elements." + ); } } /** @brief Returns the std::vector containing extents */ [[nodiscard]] inline - constexpr base_type const& base() const { + constexpr base_type const& base() const noexcept{ return _base; } @@ -145,26 +191,28 @@ struct basic_fixed_rank_extents [[nodiscard]] inline constexpr bool empty() const noexcept { return _size == size_type{0}; } - friend void swap(basic_fixed_rank_extents& lhs, basic_fixed_rank_extents& rhs) { + friend void swap(basic_fixed_rank_extents& lhs, basic_fixed_rank_extents& rhs) + noexcept(std::is_nothrow_swappable_v) + { std::swap(lhs._base , rhs._base ); } [[nodiscard]] inline - constexpr const_pointer data() const + constexpr const_pointer data() const noexcept { return _base.data(); } [[nodiscard]] inline constexpr const_iterator - begin() const + begin() const noexcept { return _base.begin(); } [[nodiscard]] inline constexpr const_iterator - end() const + end() const noexcept { return _base.end(); } @@ -175,15 +223,25 @@ struct basic_fixed_rank_extents return _base.back(); } - ~basic_fixed_rank_extents() = default; + [[nodiscard]] inline + constexpr const_reverse_iterator + rbegin() const noexcept + { + return _base.rbegin(); + } + + [[nodiscard]] inline + constexpr const_reverse_iterator + rend() const noexcept + { + return _base.rend(); + } private: base_type _base{}; }; -} // namespace ublas -} // namespace numeric -} // namespace boost +} // namespace boost::numeric::ublass diff --git a/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp b/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp index 43eb79c8a..952f6e29e 100644 --- a/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp +++ b/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp @@ -15,15 +15,10 @@ #ifndef _BOOST_UBLAS_TENSOR_FIXED_RANK_STRIDES_HPP_ #define _BOOST_UBLAS_TENSOR_FIXED_RANK_STRIDES_HPP_ -#include #include +#include -namespace boost { -namespace numeric { -namespace ublas { - -using first_order = column_major; -using last_order = row_major; +namespace boost::numeric::ublas { /** @brief Template class for storing tensor strides for iteration with runtime variable size. * @@ -35,95 +30,120 @@ class basic_fixed_rank_strides { public: - using base_type = std::array; - - static_assert( std::numeric_limits::is_integer, - "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type integer."); - static_assert(!std::numeric_limits::is_signed, - "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type unsigned integer."); - static_assert(std::is_same::value || std::is_same::value, - "Static error in boost::numeric::ublas::basic_fixed_rank_strides: layout type must either first or last order"); - + static constexpr std::size_t const _size = N; using layout_type = L; + using base_type = std::array; using value_type = typename base_type::value_type; using reference = typename base_type::reference; using const_reference = typename base_type::const_reference; using size_type = typename base_type::size_type; using const_pointer = typename base_type::const_pointer; using const_iterator = typename base_type::const_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; + static_assert( std::numeric_limits::is_integer, + "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type integer."); + static_assert(!std::numeric_limits::is_signed, + "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type unsigned integer."); + static_assert(std::is_same::value || std::is_same::value, + "Static error in boost::numeric::ublas::basic_fixed_rank_strides: layout type must either first or last order"); /** @brief Default constructs basic_fixed_rank_strides * * @code auto ex = basic_fixed_rank_strides{}; */ - constexpr explicit basic_fixed_rank_strides() - : _base{} - { - } + constexpr basic_fixed_rank_strides() noexcept = default; /** @brief Constructs basic_fixed_rank_strides from basic_extents for the first- and last-order storage formats * * @code auto strides = basic_fixed_rank_strides( basic_extents{2,3,4} ); * */ - basic_fixed_rank_strides(basic_fixed_rank_extents const& s) + template + constexpr basic_fixed_rank_strides(ExtentsType const& s) { + static_assert( is_extents_v, "boost::numeric::ublas::basic_fixed_rank_strides(ExtentsType const&) : " + "ExtentsType is not a tensor extents" + ); + + if constexpr( is_static_rank_v< ExtentsType > ){ + static_assert( ExtentsType::_size == _size, + "boost::numeric::ublas::basic_fixed_rank_strides(ExtentsType const&) : " + "ExentsType size should be equal to the size of basic_fixed_rank_strides" + ); + }else{ + if ( s.size() != size() ){ + throw std::length_error( + "boost::numeric::ublas::basic_fixed_rank_strides(ExtentsType const&) : " + "ExentsType size should be equal to the size of basic_fixed_rank_strides" + ); + } + } + _base.fill(value_type(1)); if( s.empty() ) return; - if( !valid(s) ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides() : shape is not valid."); + if( !is_valid(s) ) + throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides(ExtentsType const&) : " + "shape is not valid." + ); if( is_vector(s) || is_scalar(s) ) return; if( this->size() < 2 ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides() : size of strides must be greater or equal 2."); + throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides(ExtentsType const&) : " + "size of strides must be greater or equal 2." + ); - if constexpr (std::is_same::value){ - size_type k = 1ul, kend = this->size(); - for(; k < kend; ++k) - _base[k] = _base[k-1] * s[k-1]; - } - else { - size_type k = this->size()-2, kend = 0ul; - for(; k > kend; --k) - _base[k] = _base[k+1] * s[k+1]; - _base[0] = _base[1] * s[1]; + if constexpr (std::is_same::value){ + std::transform(s.begin(), s.end() - 1, _base.begin(), _base.begin() + 1, std::multiplies{}); + }else { + std::transform(s.rbegin(), s.rend() - 1, _base.rbegin(), _base.rbegin() + 1, std::multiplies{}); } } - basic_fixed_rank_strides(basic_fixed_rank_strides const& l) + constexpr basic_fixed_rank_strides(basic_fixed_rank_strides const& l) : _base(l._base) {} - basic_fixed_rank_strides(basic_fixed_rank_strides && l ) + constexpr basic_fixed_rank_strides(basic_fixed_rank_strides && l ) noexcept : _base(std::move(l._base)) {} - basic_fixed_rank_strides(base_type const& l ) + constexpr basic_fixed_rank_strides(base_type const& l ) : _base(l) {} - basic_fixed_rank_strides(base_type && l ) + constexpr basic_fixed_rank_strides(base_type && l ) : _base(std::move(l)) {} ~basic_fixed_rank_strides() = default; - basic_fixed_rank_strides& operator=(basic_fixed_rank_strides other) + basic_fixed_rank_strides& operator=(basic_fixed_rank_strides const& other) + noexcept(std::is_nothrow_swappable_v) + { + basic_fixed_rank_strides temp(other); + swap (*this, temp); + return *this; + } + + basic_fixed_rank_strides& operator=(basic_fixed_rank_strides && other) + noexcept(std::is_nothrow_swappable_v) { swap (*this, other); return *this; } - friend void swap(basic_fixed_rank_strides& lhs, basic_fixed_rank_strides& rhs) { + friend void swap(basic_fixed_rank_strides& lhs, basic_fixed_rank_strides& rhs) + noexcept(std::is_nothrow_swappable_v) + { std::swap(lhs._base , rhs._base); } @@ -144,46 +164,58 @@ class basic_fixed_rank_strides [[nodiscard]] inline constexpr const_reference back () const{ - return _base[N - 1]; + return _base.back(); } [[nodiscard]] inline constexpr reference back (){ - return _base[N - 1]; + return _base.back(); } [[nodiscard]] inline - constexpr bool empty() const{ + constexpr bool empty() const noexcept{ return _base.empty(); } [[nodiscard]] inline - constexpr size_type size() const{ + constexpr size_type size() const noexcept{ return _base.size(); } [[nodiscard]] inline - constexpr const_iterator begin() const{ + constexpr const_iterator begin() const noexcept{ return _base.begin(); } [[nodiscard]] inline - constexpr const_iterator end() const{ + constexpr const_iterator end() const noexcept{ return _base.end(); } [[nodiscard]] inline - constexpr base_type const& base() const{ + constexpr base_type const& base() const noexcept{ return this->_base; } -protected: + [[nodiscard]] inline + constexpr const_reverse_iterator + rbegin() const noexcept + { + return _base.rbegin(); + } + + [[nodiscard]] inline + constexpr const_reverse_iterator + rend() const noexcept + { + return _base.rend(); + } + +private: base_type _base; }; -} -} -} +} // namespace boost::numeric::ublass #endif diff --git a/include/boost/numeric/ublas/tensor/fixed_rank_tensor.hpp b/include/boost/numeric/ublas/tensor/fixed_rank_tensor.hpp deleted file mode 100644 index b364fbc93..000000000 --- a/include/boost/numeric/ublas/tensor/fixed_rank_tensor.hpp +++ /dev/null @@ -1,217 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - - -#ifndef BOOST_UBLAS_FIXED_RANK_TENSOR_IMPL_HPP -#define BOOST_UBLAS_FIXED_RANK_TENSOR_IMPL_HPP - -#include - -namespace boost::numeric::ublas { - - template< typename T, std::size_t R, typename F = first_order > - struct fixed_rank_tensor: - public basic_tensor< fixed_rank_tensor< T, R, F > > - { - using self_type = fixed_rank_tensor< T, R, F >; - using super_type = basic_tensor< self_type >; - - template - using tensor_expression_type = typename super_type::template tensor_expression_type; - - template - using matrix_expression_type = typename super_type::template matrix_expression_type; - - template - using vector_expression_type = typename super_type::template vector_expression_type; - - using array_type = typename tensor_traits::container_type; - using layout_type = typename tensor_traits::layout_type; - - using size_type = typename array_type::size_type; - using difference_type = typename array_type::difference_type; - using value_type = typename array_type::value_type; - - using reference = typename array_type::reference; - using const_reference = typename array_type::const_reference; - - using pointer = typename array_type::pointer; - using const_pointer = typename array_type::const_pointer; - - using iterator = typename array_type::iterator; - using const_iterator = typename array_type::const_iterator; - - using reverse_iterator = typename array_type::reverse_iterator; - using const_reverse_iterator = typename array_type::const_reverse_iterator; - - using tensor_temporary_type = self_type; - using storage_category = dense_tag; - - using extents_type = typename tensor_traits::extents_type; - using strides_type = strides_t; - - using matrix_type = typename super_type::matrix_type; - using vector_type = typename super_type::vector_type; - - constexpr fixed_rank_tensor() = default; - - constexpr fixed_rank_tensor( extents_type const& e, value_type const& i ) - : super_type(e,i) - {} - - constexpr fixed_rank_tensor( extents_type const& e, array_type const& a ) - : super_type(e,a) - {} - - constexpr fixed_rank_tensor( extents_type const& e ) - : super_type(e) - {} - - fixed_rank_tensor( std::initializer_list< size_type > li ) - : super_type( std::move(li) ) - {} - - constexpr fixed_rank_tensor( matrix_type const& v ) - : super_type( extents_type{v.size1(), v.size2()} ) - { - static_assert( R == 2, "Error in boost::numeric::ublas::tensor(const matrix &v)" - " : rank of extents are not correct, please check!"); - - std::copy(v.data().begin(), v.data().end(), super_type::begin()); - } - - constexpr fixed_rank_tensor( matrix_type && v ) - : super_type( extents_type{v.size1(), v.size2()} ) - { - - static_assert( R == 2, "Error in boost::numeric::ublas::tensor(matrix &&v)" - " : rank of extents are not correct, please check!"); - - std::move(v.data().begin(), v.data().end(),super_type::begin()); - } - - constexpr fixed_rank_tensor (const vector_type &v) - : super_type( extents_type{ v.size(), typename extents_type::value_type{1} } ) - { - static_assert( R == 2, "Error in boost::numeric::ublas::tensor(const vector &v)" - " : rank of extents are not correct, please check!"); - - std::copy(v.data().begin(), v.data().end(), super_type::begin()); - - } - - constexpr fixed_rank_tensor (vector_type &&v) - : super_type( extents_type{ v.size(), typename extents_type::value_type{1} } ) - { - - static_assert( R == 2, "Error in boost::numeric::ublas::tensor(vector &&v)" - " : rank of extents are not correct, please check!"); - - std::move(v.data().begin(), v.data().end(),super_type::begin()); - - } - - template - constexpr fixed_rank_tensor (const fixed_rank_tensor &expr) - : super_type(static_cast(expr)) - {} - - template - constexpr fixed_rank_tensor (const tensor_expression_type &expr) - : super_type(expr) - {} - - template - inline - constexpr fixed_rank_tensor& operator= (const tensor_expression_type &expr) - { - fixed_rank_tensor temp( expr ); - swap(*this,temp); - return *this; - } - - template - constexpr fixed_rank_tensor (const matrix_expression_type &expr) - : fixed_rank_tensor( matrix_type(expr) ) - {} - - template - constexpr fixed_rank_tensor (const vector_expression_type &expr) - : fixed_rank_tensor( vector_type(expr) ) - {} - - template - constexpr fixed_rank_tensor (const basic_tensor & other) - : super_type(other.extents()) - { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::fixed_rank_tensor( const OtherTensor& ) : The OtherTensor should have a tensor type" - ); - - static_assert( std::is_same_v, - "boost::numeric::ublas::fixed_rank_tensor( const OtherTensor& ) : The tensor should have same value type" - ); - - if ( other.extents().size() != R ){ - throw std::runtime_error("boost::numeric::ublas::static_tensor( const OtherTensor& ) : The tensor should have equal number of extents"); - } - - std::copy(other.begin(), other.end(), super_type::begin()); - } - - template - constexpr fixed_rank_tensor (basic_tensor && other) - : super_type(other.extents()) - { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::fixed_rank_tensor( OtherTensor&& ) : The OtherTensor should have a tensor type" - ); - - static_assert( std::is_same_v, - "boost::numeric::ublas::fixed_rank_tensor( OtherTensor&& ) : The tensor should have same value type" - ); - - if ( other.extents().size() != R ){ - throw std::runtime_error("boost::numeric::ublas::static_tensor( OtherTensor&& ) : The tensor should have equal number of extents"); - } - - std::move(other.begin(), other.end(), super_type::begin()); - } - - inline - constexpr fixed_rank_tensor& operator=(const_reference v) noexcept{ - std::fill(super_type::begin(), super_type::end(), v); - return *this; - } - }; - - template - fixed_rank_tensor( E const&, V const& ) -> fixed_rank_tensor; - - template - fixed_rank_tensor( E const& ) -> fixed_rank_tensor; - -} // boost::numeric::ublas - -namespace boost::numeric::ublas{ - - template - struct tensor_traits< fixed_rank_tensor > { - using container_type= std::vector< T >; - using extents_type = dynamic_extents; - using layout_type = F; - using container_tag = dynamic_tensor_tag; - }; - -} // boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/functions.hpp b/include/boost/numeric/ublas/tensor/functions.hpp index 0d8c34e7f..2635c898a 100644 --- a/include/boost/numeric/ublas/tensor/functions.hpp +++ b/include/boost/numeric/ublas/tensor/functions.hpp @@ -14,97 +14,57 @@ #ifndef _BOOST_UBLAS_TENSOR_FUNCTIONS_HPP_ #define _BOOST_UBLAS_TENSOR_FUNCTIONS_HPP_ - -#include -#include -#include -#include - #include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost::numeric::ublas{ - template - struct dynamic_tensor; - - template - struct static_tensor; - - template - struct fixed_rank_tensor; + template class tensor_core; } // namespace boost::numeric::ublas -// dynamic_functions namespace boost::numeric::ublas { namespace detail{ - - template - constexpr auto extents_result_tensor_times_vector( E const& ){ - static_assert(is_static_rank::value, - "boost::numeric::ublas::extents_result_tensor_times_vector() : invalid type, type should be an extents"); - using size_type = typename E::size_type; - auto ret = dynamic_extents< std::max( size_type( E::_size - 1 ), size_type(2) )>(); - ret.fill(typename E::value_type(1)); - return ret; - } template - constexpr auto extents_result_tensor_times_vector( basic_extents const& e ){ - using size_type = typename basic_extents::size_type; - return dynamic_extents<>{ typename dynamic_extents<>::base_type(std::max( size_type( e.size() - 1), size_type(2) ),1) } ; - } - - template - constexpr auto extents_result_tensor_times_matrix( E const& a ){ - static_assert(is_static_rank::value, - "boost::numeric::ublas::extents_result_tensor_times_matrix() : invalid type, type should be an extents"); - return dynamic_extents(a); - } + struct is_complex : std::false_type{}; template - constexpr auto extents_result_tensor_times_matrix( basic_extents const& e ){ - return dynamic_extents<>{ e } ; - } - - template - constexpr auto extents_result_type_outer_prod( basic_static_extents const&, basic_static_extents const& ){ - return dynamic_extents(); - } - - template - constexpr auto extents_result_type_outer_prod( basic_static_extents const&, basic_fixed_rank_extents const& ){ - return dynamic_extents(); - } + struct is_complex< std::complex > : std::true_type{}; - template - constexpr auto extents_result_type_outer_prod( basic_fixed_rank_extents const&, basic_static_extents const& ){ - return dynamic_extents(); - } + template + inline static constexpr bool is_complex_v = is_complex::value; - template - auto extents_result_type_outer_prod( E1 const& e1, E2 const& e2){ - return dynamic_extents<>( std::vector( e1.size() + e2.size(), 1 ) ); - } + /// To check if the type is the std::array or not. + /// Can be extented by providing specialization. + /// Point to Remember: C-Style arrays are not supported. + template + struct is_bounded_array : std::false_type{}; template - struct is_complex : std::false_type{}; + inline static constexpr bool is_bounded_array_v = is_bounded_array::value; + template + struct is_bounded_array> : std::true_type{}; + + /// Gives the extent of rank one std::array. + /// Similar to is_bounded_array, it can also be + /// extented using specialization. + /// Custom Type should have similar APIs to + /// std::array. + /// Point to Remember: C-Style arrays are not supported. template - struct is_complex< std::complex > : std::true_type{}; + struct extent_of_rank_one_array; + + template + struct extent_of_rank_one_array> + : std::integral_constant + {}; template - inline static constexpr bool is_complex_v = is_complex::value; + inline static constexpr bool extent_of_rank_one_array_v = extent_of_rank_one_array::value; } // namespace detail @@ -120,23 +80,36 @@ namespace boost::numeric::ublas * * @returns tensor object C with order p-1, the same storage format and allocator type as A */ - template - inline decltype(auto) prod( basic_tensor< TensorType > const &a, - vector const &b, + template + inline decltype(auto) prod( tensor_core< TensorEngine > const &a, + vector::value_type, A> const &b, const std::size_t m) { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::prod(ttv) : tensor type should be valid tensor" + using tensor_type = tensor_core< TensorEngine >; + using extents_type = typename tensor_type::extents_type; + using value_type = typename tensor_type::value_type; + using array_type = typename tensor_type::array_type; + using size_type = typename extents_type::size_type; + using layout_type = typename tensor_type::layout_type; + + auto const p = a.rank(); + + static_assert( + std::is_same_v< + typename tensor_core::resizable_tag, + storage_resizable_container_tag + >, + "error in boost::numeric::ublas::prod(tensor_core const&, vector const& ): " + "tensor container should be resizable" ); - using tensor_type = TensorType; - using extents_type = typename tensor_type::extents_type; - using layout_type = typename tensor_type::layout_type; - using value_type = typename tensor_type::value_type; - using size_type = typename extents_type::size_type; - auto const p = std::size_t(a.rank()); + static_assert( + is_dynamic_v, + "error in boost::numeric::ublas::prod(tensor_core const&, vector const& ): " + "extents type should be dynamic" + ); - if (m == 0) + if (m == 0ul) throw std::length_error( "error in boost::numeric::ublas::prod(ttv): " "contraction mode must be greater than zero."); @@ -151,21 +124,50 @@ namespace boost::numeric::ublas "error in boost::numeric::ublas::prod(ttv): first " "argument tensor should not be empty."); - if (b.size() == 0) + if (b.empty()) throw std::length_error( "error in boost::numeric::ublas::prod(ttv): second " "argument vector should not be empty."); - auto nc = detail::extents_result_tensor_times_vector(a.extents()); - auto nb = std::vector{b.size(), 1}; + using extents_value_type = typename extents_type::value_type; auto a_extents = a.extents(); + + auto extents_result = [&a_extents](){ + using size_type = typename extents_type::size_type; + if constexpr( is_static_rank_v ){ + // To disable the warning for unused variable; + (void)a_extents; + constexpr size_type esz = extents_type::_size - 1u; + constexpr auto sz = std::max( esz, size_type(2) ); + auto ret = extents< sz >(); + ret.fill(1u); + return ret; + }else{ + using extents_base_type = typename extents_type::base_type; + auto const sz = std::max( a_extents.size() - 1, size_type(2) ); + auto arr = extents_base_type(sz,1); + return extents_type{ std::move(arr) } ; + } + }; + + auto nc = extents_result(); + auto nb = std::vector{b.size(), extents_value_type(1)}; + for (auto i = size_type(0), j = size_type(0); i < p; ++i) if (i != m - 1) nc[j++] = a_extents.at(i); + using c_extents_type = std::decay_t< decltype(nc) >; - auto c = result_tensor_t( nc, value_type{} ); + using t_engine = tensor_engine< + c_extents_type, + layout_type, + strides, + array_type + >; + + auto c = tensor_core( nc, value_type{} ); auto bb = &(b(0)); ttv(m, p, c.data(), c.extents().data(), c.strides().data(), @@ -186,23 +188,38 @@ namespace boost::numeric::ublas * * @returns tensor object C with order p, the same storage format and allocator type as A */ - template - inline decltype(auto) prod( basic_tensor< TensorType > const &a, - matrix const &b, + template + inline decltype(auto) prod( tensor_core< TensorEngine > const &a, + matrix::value_type, typename tensor_core< TensorEngine >::layout_type , A> const &b, const std::size_t m) { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::prod(ttm) : tensor type should be valid tensor" + + using tensor_type = tensor_core< TensorEngine >; + using extents_type = typename tensor_type::extents_type; + using value_type = typename tensor_type::value_type; + using layout_type = typename tensor_type::layout_type; + using array_type = typename tensor_type::array_type; + using dynamic_strides_type = basic_strides; + + + static_assert( + std::is_same_v< + typename tensor_core::resizable_tag, + storage_resizable_container_tag + >, + "error in boost::numeric::ublas::prod(tensor_core const&, matrix const& ): " + "tensor container should be resizable" ); - using tensor_type = TensorType; - using dynamic_strides_type = strides_t, typename tensor_type::layout_type>; - using value_type = typename tensor_type::value_type; - using layout_type = typename tensor_type::layout_type; + static_assert( + is_dynamic_v, + "error in boost::numeric::ublas::prod(tensor_core const&, matrix const& ): " + "extents type should be dynamic" + ); auto const p = a.rank(); - if (m == 0) + if (m == 0ul) throw std::length_error( "error in boost::numeric::ublas::prod(ttm): " "contraction mode must be greater than zero."); @@ -217,19 +234,28 @@ namespace boost::numeric::ublas "error in boost::numeric::ublas::prod(ttm): first " "argument tensor should not be empty."); - if (b.size1() * b.size2() == 0) + if (b.size1() * b.size2() == 0ul) throw std::length_error( "error in boost::numeric::ublas::prod(ttm): second " "argument matrix should not be empty."); - auto nc = detail::extents_result_tensor_times_matrix(a.extents()); - auto nb = dynamic_extents<>{b.size1(), b.size2()}; + auto nc = a.extents(); + auto nb = extents<>{b.size1(), b.size2()}; auto wb = dynamic_strides_type(nb); nc[m - 1] = nb[0]; - auto c = result_tensor_t(nc, value_type{}); + using c_extents_type = std::decay_t< decltype(nc) >; + + using t_engine = tensor_engine< + c_extents_type, + layout_type, + strides, + array_type + >; + + auto c = tensor_core(nc, value_type{}); auto bb = &(b(0, 0)); ttm(m, p, @@ -248,33 +274,55 @@ namespace boost::numeric::ublas * * na[phia[x]] = nb[phib[x]] for 1 <= x <= q * - * @param[in] phia one-based permutation tuple of length q for the first - * input tensor a - * @param[in] phib one-based permutation tuple of length q for the second - * input tensor b * @param[in] a left-hand side tensor with order r+q * @param[in] b right-hand side tensor with order s+q + * @param[in] phia one-based permutation tuple of length q for the first + * input tensor a can be of type std::vector or std::array + * @param[in] phib one-based permutation tuple of length q for the second + * input tensor b can be of type std::vector or std::array * @result tensor with order r+s */ - template - inline decltype(auto) prod(basic_tensor< TensorType1 > const &a, basic_tensor< TensorType2 > const &b, - std::vector const &phia, std::vector const &phib) + template , + std::enable_if_t< + !( is_static_v::extents_type> || + is_static_v::extents_type> ) + ,int> = 0 + > + inline decltype(auto) prod(tensor_core< TensorEngine1 > const &a, tensor_core< TensorEngine2 > const &b, + PermuType const &phia, PermuType const &phib) { - - static_assert( is_valid_tensor_v && is_valid_tensor_v, - "boost::numeric::ublas::prod(ttt) : tensor type should be valid tensor" + using tensor_type = tensor_core< TensorEngine1 >; + using extents_type = typename tensor_type::extents_type; + using value_type = typename tensor_type::value_type; + using layout_type = typename tensor_type::layout_type; + using extents_size_type = typename extents_type::size_type; + using array_type = typename tensor_type::array_type; + + static_assert( + std::is_same_v< + typename tensor_core::resizable_tag, + typename tensor_core::resizable_tag + > && + std::is_same_v< + typename tensor_core::resizable_tag, + storage_resizable_container_tag + >, + "error in boost::numeric::ublas::prod(tensor_core const&, tensor_core const&, " + "PermuType const&, PermuType const& ): " + "Both the tensor storage should have the same type of storage and both should be resizable" ); - using tensor_type = TensorType1; - using extents_type_1 = typename tensor_type::extents_type; - using value_type = typename tensor_type::value_type; - using layout_type = typename tensor_type::layout_type; - using size_type = typename extents_type_1::size_type; + static_assert( + std::is_same_v::value_type>, + "error in boost::numeric::ublas::prod(tensor_core< TensorEngine1 > const&, tensor_core< TensorEngine2 > const&, " + "PermuType const&, PermuType const&): " + "Both the tensor should have the same value_type" + ); auto const pa = a.rank(); auto const pb = b.rank(); - auto const q = size_type(phia.size()); + auto const q = static_cast(phia.size()); if (pa == 0ul) throw std::runtime_error("error in ublas::prod: order of left-hand side tensor must be greater than 0."); @@ -300,22 +348,43 @@ namespace boost::numeric::ublas if (na.at(phia.at(i) - 1) != nb.at(phib.at(i) - 1)) throw std::runtime_error("error in ublas::prod: permutations of the extents are not correct."); - auto const r = pa - q; - auto const s = pb - q; + std::size_t const r = pa - q; + std::size_t const s = pb - q; - std::vector phia1(pa), phib1(pb); + std::vector phia1(pa); + std::vector phib1(pb); std::iota(phia1.begin(), phia1.end(), 1ul); std::iota(phib1.begin(), phib1.end(), 1ul); - std::vector nc(std::max(r + s, size_type(2)), size_type(1)); + auto extents_result = [&e1 = na, &e2 = nb, &a1 = phia, &a2 = phib](){ + using lextents_type = std::decay_t< decltype(e1) >; + using rextents_type = std::decay_t< decltype(e2) >; + using array_type = std::decay_t< decltype(a1) >; + if constexpr( + detail::is_bounded_array_v && + is_static_rank_v && + is_static_rank_v + ){ + constexpr auto const N = detail::extent_of_rank_one_array_v; + constexpr auto const sz = lextents_type::_size + rextents_type::_size - 2 * N; + auto res = extents(); + res.fill(1u); + return res; + }else{ + extents_size_type const size = ( e1.size() + e2.size() ) - ( a1.size() + a2.size() ); + using extents_base_type = typename extents<>::base_type; + auto arr = extents_base_type( std::max(size, extents_size_type(2)), 1u ); + return extents<>(std::move(arr)); + } + }; + + auto nc = extents_result(); for (auto i = 0ul; i < phia.size(); ++i) *std::remove(phia1.begin(), phia1.end(), phia.at(i)) = phia.at(i); //phia1.erase( std::remove(phia1.begin(), phia1.end(), phia.at(i)), phia1.end() ) ; - assert(phia1.size() == pa); - for (auto i = 0ul; i < r; ++i) nc[i] = na[phia1[i] - 1]; @@ -323,17 +392,25 @@ namespace boost::numeric::ublas *std::remove(phib1.begin(), phib1.end(), phib.at(i)) = phib.at(i); //phib1.erase( std::remove(phib1.begin(), phib1.end(), phia.at(i)), phib1.end() ) ; - assert(phib1.size() == pb); - for (auto i = 0ul; i < s; ++i) nc[r + i] = nb[phib1[i] - 1]; // std::copy( phib.begin(), phib.end(), phib1.end() ); - + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(phia1.size() == pa); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(phib1.size() == pb); - auto c = dynamic_tensor( dynamic_extents<>(nc), value_type{} );//tensor(dynamic_extents<>(nc), value_type{}); + using c_extents_type = std::decay_t< decltype(nc) >; + + using t_engine = tensor_engine< + c_extents_type, + layout_type, + strides, + array_type + >; + + auto c = tensor_core( nc, value_type{} ); ttt(pa, pb, q, phia1.data(), phib1.data(), @@ -356,25 +433,20 @@ namespace boost::numeric::ublas * * na[phi[x]] = nb[phi[x]] for 1 <= x <= q * - * @param[in] phi one-based permutation tuple of length q for bot input - * tensors * @param[in] a left-hand side tensor with order r+q * @param[in] b right-hand side tensor with order s+q + * @param[in] phi one-based permutation tuple of length q for bot input + * tensors can be of type std::vector or std::array * @result tensor with order r+s */ - template - inline decltype(auto) prod(basic_tensor< TensorType1 > const &a, basic_tensor< TensorType2 > const &b, - std::vector const &phi) + template > + inline decltype(auto) prod(tensor_core< TensorEngine1 > const &a, tensor_core< TensorEngine2 > const &b, + PermuType const &phi) { - static_assert( is_valid_tensor_v && is_valid_tensor_v, - "boost::numeric::ublas::prod(ttt) : tensor type should be valid tensor" - ); - return prod(a, b, phi, phi); } - /** @brief Computes the inner product of two tensors - * + /** @brief Computes the inner product of two tensors * * Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,jp]) * * @note calls inner function @@ -384,19 +456,23 @@ namespace boost::numeric::ublas * * @returns a value type. */ - template - inline decltype(auto) inner_prod(basic_tensor< TensorType1 > const &a, basic_tensor< TensorType2 > const &b) + template + inline decltype(auto) inner_prod(tensor_core< TensorEngine1 > const &a, tensor_core< TensorEngine2 > const &b) { - static_assert( is_valid_tensor_v && is_valid_tensor_v, - "boost::numeric::ublas::prod(ttt) : tensor type should be valid tensor" - ); - using value_type = typename TensorType1::value_type; + + using value_type = typename tensor_core< TensorEngine1 >::value_type; + + static_assert( + std::is_same_v::value_type>, + "error in boost::numeric::ublas::inner_prod(tensor_core< TensorEngine1 > const&, tensor_core< TensorEngine2 > const&): " + "Both the tensor should have the same value_type" + ); if (a.rank() != b.rank()) - throw std::length_error("error in boost::numeric::ublas::inner_prod: Rank of both tensors must be the same."); + throw std::length_error("error in boost::numeric::ublas::inner_prod: Rank of both the tensors must be the same."); - if (a.empty() || b.empty()) + if (a.empty() || b.empty()) throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensors should not be empty."); if (a.extents() != b.extents()) @@ -418,19 +494,36 @@ namespace boost::numeric::ublas * * @returns tensor object C with the same storage format F and allocator type A1 */ - template ::value && - is_static::value ) + !( is_static_v::extents_type> || + is_static_v::extents_type> ) ,int> = 0 > - inline decltype(auto) outer_prod(basic_tensor< TensorType1 > const &a, basic_tensor< TensorType2 > const &b) + inline decltype(auto) outer_prod(tensor_core< TensorEngine1 > const &a, tensor_core< TensorEngine2 > const &b) { - using value_type = typename TensorType1::value_type; - using layout_type = typename TensorType1::layout_type; + using tensor_type = tensor_core< TensorEngine1 >; + using value_type = typename tensor_type::value_type; + using layout_type = typename tensor_type::layout_type; + using array_type = typename tensor_type::array_type; + + static_assert( + std::is_same_v< + typename tensor_core::resizable_tag, + typename tensor_core::resizable_tag + > && + std::is_same_v< + typename tensor_core::resizable_tag, + storage_resizable_container_tag + >, + "error in boost::numeric::ublas::outer_prod(tensor_core const&, tensor_core const&): " + "Both the tensor storage should have the same type of storage and both should be resizable" + ); - static_assert( is_valid_tensor_v && is_valid_tensor_v, - "boost::numeric::ublas::outer_prod() : tensor type should be valid tensor" + static_assert( + std::is_same_v::value_type>, + "error in boost::numeric::ublas::outer_prod(tensor_core< TensorEngine1 > const&, tensor_core< TensorEngine2 > const&): " + "Both the tensor should have the same value_type" ); if (a.empty() || b.empty()) @@ -438,9 +531,22 @@ namespace boost::numeric::ublas "error in boost::numeric::ublas::outer_prod: " "tensors should not be empty."); - auto nc = detail::extents_result_type_outer_prod(a.extents(), b.extents()); + auto extents_result = [&e1 = a.extents(), &e2 = b.extents()](){ + using lextents_type = std::decay_t< decltype(e1) >; + using rextents_type = std::decay_t< decltype(e2) >; - auto a_extents = a.extents(); + if constexpr( is_static_rank_v && is_static_rank_v ){ + return extents< lextents_type::_size + rextents_type::_size >{}; + }else { + using extents_base_type = typename extents<>::base_type; + auto arr = extents_base_type( e1.size() + e2.size(), 1 ); + return extents<>{std::move(arr)}; + } + }; + + auto nc = extents_result(); + + auto a_extents = a.extents(); auto b_extents = b.extents(); for(auto i = 0u; i < a.rank(); ++i) @@ -448,8 +554,17 @@ namespace boost::numeric::ublas for(auto i = 0u; i < b.rank(); ++i) nc.at(a.rank()+i) = b_extents.at(i); - - auto c = result_tensor_t( nc, value_type{} ); + + using c_extents_type = std::decay_t< decltype(nc) >; + + using t_engine = tensor_engine< + c_extents_type, + layout_type, + strides, + array_type + >; + + auto c = tensor_core( nc, value_type{} ); outer(c.data(), c.rank(), c.extents().data(), c.strides().data(), a.data(), a.rank(), a_extents.data(), a.strides().data(), @@ -468,44 +583,49 @@ namespace boost::numeric::ublas * @param[in] tau one-based permutation tuple of length p * @returns a transposed tensor object with the same storage format F and allocator type A */ - template - inline decltype(auto) trans(basic_tensor< TensorType > const &a, std::vector const &tau) + template > + inline decltype(auto) trans(tensor_core< TensorEngine > const &a, PermuType const &tau) { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::trans() : tensor type should be valid tensor" - ); + + using tensor_type = tensor_core< TensorEngine >; + using layout_type = typename tensor_type::layout_type; + using array_type = typename tensor_type::array_type; + using extents_type = typename tensor_type::extents_type; - using value_type = typename TensorType::value_type; - using layout_type = typename TensorType::layout_type; - using result_tensor_type = dynamic_tensor; - // using strides_type = typename tensor_type::strides_type; + static_assert( + is_dynamic_v< extents_type > , + "error in boost::numeric::ublas::trans(tensor_core< TensorEngine > const &a, " + "PermuType const &tau): " + "Tensor should have dynamic extents" + ); - if (a.empty()) - return result_tensor_type{}; + using t_engine = tensor_engine< + extents_type, + layout_type, + strides, + array_type + >; auto const p = a.rank(); auto const &na = a.extents(); + typename extents_type::base_type nc; + + if constexpr( is_dynamic_rank_v ){ + nc.resize(p); + } - auto nc = typename dynamic_extents<>::base_type(p); for (auto i = 0u; i < p; ++i) nc.at(tau.at(i) - 1) = na.at(i); - // auto wc = strides_type(extents_type(nc)); - auto c = result_tensor_type(dynamic_extents<>(nc)); + auto c = tensor_core( extents_type( std::move(nc) ) ); + + if (a.empty()) + return c; trans(a.rank(), a.extents().data(), tau.data(), c.data(), c.strides().data(), a.data(), a.strides().data()); - // auto wc_pi = typename strides_type::base_type (p); - // for(auto i = 0u; i < p; ++i) - // wc_pi.at(tau.at(i)-1) = c.strides().at(i); - - // copy(a.rank(), - // a.extents().data(), - // c.data(), wc_pi.data(), - // a.data(), a.strides().data() ); - return c; } /** @@ -523,26 +643,21 @@ namespace boost::numeric::ublas * @param a the tensor whose norm is expected of rank p. * @return the frobenius norm of a tensor. */ - template - inline decltype(auto) norm(basic_tensor< TensorType > const &a) + template + inline decltype(auto) norm(tensor_core< TensorEngine > const &a) { - - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::norm() : tensor type should be valid tensor" - ); - - using tensor_type = TensorType; + using tensor_type = tensor_core< TensorEngine >; using value_type = typename tensor_type::value_type; static_assert(std::is_default_constructible::value, "Value type of tensor must be default construct able in order " "to call boost::numeric::ublas::norm"); + if (a.empty()) { throw std::runtime_error( "error in boost::numeric::ublas::norm: tensors should not be empty."); } - return std::sqrt(accumulate(a.order(), a.extents().data(), a.data(), a.strides().data(), value_type{}, [](auto const &l, auto const &r) { return l + r * r; })); } @@ -553,12 +668,12 @@ namespace boost::numeric::ublas * @param[in] lhs tensor expression * @returns unary tensor expression */ - template, int > = 0 + template::value_type>, int > = 0 > - auto conj(detail::tensor_expression< basic_tensor, D > const& expr) + auto conj(detail::tensor_expression< tensor_core, D > const& expr) { - return detail::make_unary_tensor_expression< basic_tensor > (expr(), [] (auto const& l) { return std::conj( l ); } ); + return detail::make_unary_tensor_expression< tensor_core > (expr(), [] (auto const& l) { return std::conj( l ); } ); } /** @brief Computes the complex conjugate component of tensor elements within a tensor expression @@ -569,18 +684,29 @@ namespace boost::numeric::ublas template auto conj(detail::tensor_expression const& expr) { - using tensor_type = T ; - using value_type = typename tensor_type::value_type; + using old_tensor_type = T; + using value_type = typename old_tensor_type::value_type; + using layout_type = typename old_tensor_type::layout_type; + using array_type = typename old_tensor_type::array_type; + using extents_type = typename old_tensor_type::extents_type; - using new_value_type = std::complex; - - using tensor_complex_type = tensor_rebind_t;//decltype(ret); + using complex_type = std::complex; + using storage_traits_t = storage_traits; + + using t_engine = tensor_engine< + extents_type, + layout_type, + strides, + typename storage_traits_t::template rebind + >; + + using tensor_type = tensor_core; if( detail::retrieve_extents( expr ).empty() ) throw std::runtime_error("error in boost::numeric::ublas::conj: tensors should not be empty."); - auto a = tensor_type( expr ); - auto c = tensor_complex_type( a.extents() ); + auto a = old_tensor_type( expr ); + auto c = tensor_type( a.extents() ); std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::conj(l) ; } ); @@ -602,21 +728,33 @@ namespace boost::numeric::ublas * @param[in] lhs tensor expression * @returns unary tensor expression */ - template, int > = 0 + template::value_type>, int > = 0 > - auto real(detail::tensor_expression< basic_tensor< TensorType > ,D > const& expr) + auto real(detail::tensor_expression< tensor_core< TensorEngine > ,D > const& expr) { - using tensor_complex_type = TensorType; - using complex_type = typename tensor_complex_type::value_type; + + using old_tensor_type = tensor_core< TensorEngine >; + using complex_type = typename old_tensor_type::value_type; using value_type = typename complex_type::value_type; + using layout_type = typename old_tensor_type::layout_type; + using array_type = typename old_tensor_type::array_type; + using extents_type = typename old_tensor_type::extents_type; + using storage_traits_t = storage_traits; - using tensor_type = tensor_rebind_t; + using t_engine = tensor_engine< + extents_type, + layout_type, + strides, + typename storage_traits_t::template rebind + >; + + using tensor_type = tensor_core; if( detail::retrieve_extents( expr ).empty() ) throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); - auto a = tensor_complex_type( expr ); + auto a = old_tensor_type( expr ); auto c = tensor_type( a.extents() ); std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::real(l) ; } ); @@ -641,22 +779,32 @@ namespace boost::numeric::ublas * @param[in] lhs tensor expression * @returns unary tensor expression */ - template, int > = 0 + template::value_type>, int > = 0 > - auto imag(detail::tensor_expression< basic_tensor< TensorType > ,D> const& expr) + auto imag(detail::tensor_expression< tensor_core< TensorEngine > ,D> const& expr) { - using tensor_complex_type = TensorType; - using complex_type = typename tensor_complex_type::value_type; + using old_tensor_type = tensor_core< TensorEngine >; + using complex_type = typename old_tensor_type::value_type; using value_type = typename complex_type::value_type; + using layout_type = typename old_tensor_type::layout_type; + using array_type = typename old_tensor_type::array_type; + using extents_type = typename old_tensor_type::extents_type; + using storage_traits_t = storage_traits; - using tensor_complex_type = TensorType; - using tensor_type = tensor_rebind_t; + using t_engine = tensor_engine< + extents_type, + layout_type, + strides, + typename storage_traits_t::template rebind + >; + + using tensor_type = tensor_core; if( detail::retrieve_extents( expr ).empty() ) throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); - auto a = tensor_complex_type( expr ); + auto a = old_tensor_type( expr ); auto c = tensor_type( a.extents() ); std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::imag(l) ; } ); @@ -674,16 +822,20 @@ namespace boost::numeric::ublas template inline - constexpr auto extents_result_tensor_times_vector(basic_static_extents, - basic_static_extents, basic_static_extents) + constexpr auto extents_result_tensor_times_vector( + [[maybe_unused]] basic_static_extents e, + [[maybe_unused]] basic_static_extents te1, + [[maybe_unused]] basic_static_extents te2) { return basic_static_extents{}; } template inline - constexpr auto extents_result_tensor_times_vector(basic_static_extents, - basic_static_extents, basic_static_extents = basic_static_extents{}) + constexpr auto extents_result_tensor_times_vector( + [[maybe_unused]] basic_static_extents e1, + [[maybe_unused]] basic_static_extents e2, + [[maybe_unused]] basic_static_extents e3 = basic_static_extents{}) { if constexpr(I != M - 1){ return extents_result_tensor_times_vector @@ -706,8 +858,10 @@ namespace boost::numeric::ublas template inline - constexpr auto static_extents_set_at - ( basic_static_extents const&, basic_static_extents = basic_static_extents{}){ + constexpr auto static_extents_set_at( + [[maybe_unused]] basic_static_extents const& e1, + [[maybe_unused]] basic_static_extents e2 = basic_static_extents{} + ){ static_assert( I < sizeof...(E) + 1, "boost::numeric::ublas::detail::static_extents_set_at(): out of bound"); if constexpr( sizeof...(E) == 0 ){ if constexpr( I == 0 ){ @@ -724,13 +878,6 @@ namespace boost::numeric::ublas } } - namespace impl{ - template - struct concat< basic_static_extents, basic_static_extents >{ - using type = basic_static_extents; - }; - } - } // namespace detail /** @brief Computes the m-mode tensor-times-vector product @@ -739,29 +886,25 @@ namespace boost::numeric::ublas * * @note calls ublas::ttv * - * @tparam m contraction dimension with 1 <= m <= p + * @tparam M contraction dimension with 1 <= m <= p * @param[in] a tensor object A with order p * @param[in] b vector object B * * @returns tensor object C with order p-1, the same storage format and allocator type as A */ - template ::value,int> = 0 - > - inline decltype(auto) prod(basic_tensor< TensorType > const &a, vector const &b) + template + inline decltype(auto) prod(tensor_core< TensorType > const &a + , vector::value_type, A> const &b) { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::prod(ttv) : tensor type should be valid tensor" - ); - - using tensor_type = TensorType; - using extents_type = typename tensor_type::extents_type; - using value_type = typename tensor_type::value_type; - using layout_type = typename tensor_type::layout_type; + using tensor_type = tensor_core< TensorType >; + using array_type = typename tensor_type::array_type; + using extents_type = typename tensor_type::extents_type; + using value_type = typename tensor_type::value_type; + using layout_type = typename tensor_type::layout_type; auto const p = std::size_t(a.rank()); - static_assert( M != 0, + static_assert( M != 0ul, "error in boost::numeric::ublas::prod(ttv): " "contraction mode must be greater than zero."); @@ -773,15 +916,25 @@ namespace boost::numeric::ublas "error in boost::numeric::ublas::prod(ttv): first " "argument tensor should not be empty."); - if (b.size() == 0) + if (b.size() == 0ul) throw std::length_error( "error in boost::numeric::ublas::prod(ttv): second " "argument vector should not be empty."); - auto nc = detail::extents_result_tensor_times_vector(a.extents()); - auto nb = std::vector{b.size(), 1}; + using extents_value_type = typename extents_type::value_type; - auto c = static_tensor(value_type{}); + auto nc = detail::extents_result_tensor_times_vector(a.extents()); + auto nb = std::vector{b.size(), extents_value_type(1)}; + using c_extents_type = std::decay_t; + + using t_engine = tensor_engine< + c_extents_type, + layout_type, + strides, + rebind_storage_size_t + >; + + auto c = t_engine(value_type{}); auto bb = &(b(0)); auto& a_static_extents = a.extents().base(); @@ -804,31 +957,27 @@ namespace boost::numeric::ublas * * @note calls ublas::ttm * - * @tparam m contraction dimension with 1 <= m <= p + * @tparam M contraction dimension with 1 <= M <= p + * @tparam MatrixDimension is a non contracting dimension * @param[in] a tensor object A with order p * @param[in] b vector object B * * @returns tensor object C with order p, the same storage format and allocator type as A */ - template ::value,int> = 0 - > - inline decltype(auto) prod(basic_tensor< TensorType > const &a, - matrix const &b) + template + inline decltype(auto) prod(tensor_core< TensorType > const &a, + matrix::value_type, typename tensor_core< TensorType >::layout_type, A> const &b) { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::prod(ttm) : tensor type should be valid tensor" - ); - - using tensor_type = TensorType; - using extents_type = typename tensor_type::extents_type; - using layout_type = typename tensor_type::layout_type; - using dynamic_strides_type = strides_t, layout_type>; - using value_type = typename tensor_type::value_type; - + using tensor_type = tensor_core< TensorType >; + using extents_type = typename tensor_type::extents_type; + using layout_type = typename tensor_type::layout_type; + using value_type = typename tensor_type::value_type; + using array_type = typename tensor_type::array_type; + using dynamic_strides_type = strides_t, layout_type>; + auto const p = a.rank(); - static_assert(M != 0, + static_assert(M != 0ul, "error in boost::numeric::ublas::prod(ttm): " "contraction mode must be greater than zero."); @@ -840,17 +989,25 @@ namespace boost::numeric::ublas "error in boost::numeric::ublas::prod(ttm): first " "argument tensor should not be empty."); - if (b.size1() * b.size2() == 0) + if (b.size1() * b.size2() == 0ul) throw std::length_error( "error in boost::numeric::ublas::prod(ttm): second " "argument matrix should not be empty."); - auto nc = detail::static_extents_set_at< M - 1, MatricRow >( a.extents() ); - auto nb = dynamic_extents<>{b.size1(), b.size2()}; + auto nc = detail::static_extents_set_at< M - 1, MatrixDimension >( a.extents() ); + auto nb = extents<>{b.size1(), b.size2()}; auto wb = dynamic_strides_type(nb); - - auto c = static_tensor(value_type{}); + + using c_extents_type = std::decay_t; + + using t_engine = tensor_engine< + c_extents_type, + layout_type, + strides, + rebind_storage_size_t + >; + auto c = t_engine(value_type{}); auto bb = &(b(0, 0)); @@ -878,34 +1035,47 @@ namespace boost::numeric::ublas * * @returns tensor object C with the same storage format F and allocator type A1 */ - template ::value && - is_static< typename TensorType2::extents_type >::value + is_static_v< typename tensor_core< TensorEngine1 >::extents_type > && + is_static_v< typename tensor_core< TensorEngine2 >::extents_type > ,int> = 0 > - inline decltype(auto) outer_prod(basic_tensor< TensorType1 > const &a, basic_tensor< TensorType2 > const &b) + inline decltype(auto) outer_prod(tensor_core< TensorEngine1 > const &a, tensor_core< TensorEngine2 > const &b) { - static_assert( is_valid_tensor_v && is_valid_tensor_v, - "boost::numeric::ublas::outer_prod() : tensor type should be valid tensor" - ); - if (a.empty() || b.empty()) throw std::runtime_error( "error in boost::numeric::ublas::outer_prod: " "tensors should not be empty."); + using extents_type1 = std::decay_t< decltype(a.extents()) >; using extents_type2 = std::decay_t< decltype(b.extents()) >; - using value_type = typename TensorType1::value_type; - using layout_type = typename TensorType1::layout_type; + using array_type = typename tensor_core< TensorEngine1 >::array_type; + using value_type = typename tensor_core< TensorEngine1 >::value_type; + using layout_type = typename tensor_core< TensorEngine1 >::layout_type; + + static_assert( + std::is_same_v::value_type>, + "error in boost::numeric::ublas::outer_prod(tensor_core< TensorEngine1 > const&, tensor_core< TensorEngine2 > const&): " + "Both the tensor should have the same value_type" + ); auto nc = detail::impl::concat_t{}; auto a_extents = a.extents(); auto b_extents = b.extents(); - - auto c = static_tensor(value_type{}); + + using c_extents_type = std::decay_t; + + using t_engine = tensor_engine< + c_extents_type, + layout_type, + strides, + rebind_storage_size_t + >; + + auto c = t_engine(value_type{}); auto& a_static_extents = a_extents.base(); auto& a_static_strides = a.strides().base(); diff --git a/include/boost/numeric/ublas/tensor/layout.hpp b/include/boost/numeric/ublas/tensor/layout.hpp new file mode 100644 index 000000000..2d54702af --- /dev/null +++ b/include/boost/numeric/ublas/tensor/layout.hpp @@ -0,0 +1,26 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_LAYOUT_HPP +#define BOOST_UBLAS_TENSOR_LAYOUT_HPP + +#include + +namespace boost::numeric::ublas::layout{ + + using first_order = column_major; + using last_order = row_major; + +} // namespace boost::numeric::ublas::layout + + +#endif // BOOST_UBLAS_TENSOR_LAYOUT_HPP diff --git a/include/boost/numeric/ublas/tensor/multi_index.hpp b/include/boost/numeric/ublas/tensor/multi_index.hpp index 3a375de87..5b4638944 100644 --- a/include/boost/numeric/ublas/tensor/multi_index.hpp +++ b/include/boost/numeric/ublas/tensor/multi_index.hpp @@ -93,9 +93,10 @@ auto array_to_vector(multi_index const& lhs, multi_index const& rhs) for(auto i = 0u; i < N; ++i) for(auto j = 0u; j < M; ++j) - if ( lhs.at(i) == rhs.at(j) && lhs.at(i) != boost::numeric::ublas::index::_()) - (void)pair_of_vector.first .push_back( i+1 ), - pair_of_vector.second.push_back( j+1 ); + if ( lhs.at(i) == rhs.at(j) && lhs.at(i) != boost::numeric::ublas::index::_()){ + pair_of_vector.first .push_back( i+1 ); + pair_of_vector.second.push_back( j+1 ); + } return pair_of_vector; } diff --git a/include/boost/numeric/ublas/tensor/multi_index_utility.hpp b/include/boost/numeric/ublas/tensor/multi_index_utility.hpp index 168f29773..f4593e1fd 100644 --- a/include/boost/numeric/ublas/tensor/multi_index_utility.hpp +++ b/include/boost/numeric/ublas/tensor/multi_index_utility.hpp @@ -268,8 +268,12 @@ template struct index_position_pairs_impl { template - static constexpr void run([[maybe_unused]] array_type& out, tuple_left const& , tuple_right const& , [[maybe_unused]] std::size_t p) - { + static constexpr void run( + [[maybe_unused]] array_type& out, + [[maybe_unused]] tuple_left const& t1 , + [[maybe_unused]] tuple_right const& t2, + [[maybe_unused]] std::size_t p + ){ using index_type = std::tuple_element_t; using has_index_type = has_index; using get_index_type = index_position; @@ -282,8 +286,12 @@ template struct index_position_pairs_impl { template - static constexpr void run(array_type&, tuple_left const& , tuple_right const& , std::size_t) - {} + static constexpr void run( + [[maybe_unused]] array_type& a, + [[maybe_unused]] tuple_left const& t1, + [[maybe_unused]] tuple_right const& t2, + [[maybe_unused]] std::size_t sz + ){} }; @@ -329,7 +337,7 @@ namespace ublas { namespace detail { template -constexpr auto array_to_vector_impl( array_type const& array, std::index_sequence ) +constexpr auto array_to_vector_impl( array_type const& array, [[maybe_unused]] std::index_sequence sq) { return std::make_pair( std::vector{std::get<0>( std::get(array) )+1 ...} , diff --git a/include/boost/numeric/ublas/tensor/multiplication.hpp b/include/boost/numeric/ublas/tensor/multiplication.hpp index 9ffc775ea..934dd2d17 100644 --- a/include/boost/numeric/ublas/tensor/multiplication.hpp +++ b/include/boost/numeric/ublas/tensor/multiplication.hpp @@ -59,24 +59,28 @@ void ttt(SizeType const k, { if(k < r) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(nc[k] == na[phia[k]-1]); for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) ttt(k+1, r, s, q, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); } else if(k < r+s) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(nc[k] == nb[phib[k-r]-1]); for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); } else if(k < r+s+q-1) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); } else { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) *c += *a * *b; @@ -122,24 +126,28 @@ void ttt(SizeType const k, { if(k < r) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(nc[k] == na[k]); for(size_t ic = 0u; ic < nc[k]; a += wa[k], c += wc[k], ++ic) ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); } else if(k < r+s) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(nc[k] == nb[k-r]); for(size_t ic = 0u; ic < nc[k]; b += wb[k-r], c += wc[k], ++ic) ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); } else if(k < r+s+q-1) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(na[k-s] == nb[k-r]); for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); } else { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(na[k-s] == nb[k-r]); for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) *c += *a * *b; @@ -346,7 +354,7 @@ void ttv0(SizeType const r, */ template void mtv(SizeType const m, - PointerOut c, SizeType const*const , SizeType const*const wc, + PointerOut c, [[maybe_unused]] SizeType const*const nc, SizeType const*const wc, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b) { @@ -384,9 +392,11 @@ void mtm(PointerOut c, SizeType const*const nc, SizeType const*const wc, { // C(i,j) = A(i,k) * B(k,j) - + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(nc[0] == na[0]); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(nc[1] == nb[1]); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(na[1] == nb[0]); auto cj = c; auto bj = b; @@ -440,7 +450,7 @@ value_t inner(SizeType const r, SizeType const*const n, template void outer_2x2(SizeType const pa, - PointerOut c, SizeType const*const , SizeType const*const wc, + PointerOut c, [[maybe_unused]] SizeType const*const nc, SizeType const*const wc, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { @@ -543,18 +553,22 @@ void outer(SizeType const k, { if(k < r) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(nc[k] == na[phia[k]-1]); for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) outer(k+1, r, s, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); } else if(k < r+s-1) { + + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(nc[k] == nb[phib[k-r]-1]); for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) outer(k+1, r, s, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); } else { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) assert(nc[k] == nb[phib[k-r]-1]); for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) *c = *a * *b; diff --git a/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp b/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp index b32ed3900..c6679a3d7 100644 --- a/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp +++ b/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp @@ -28,7 +28,7 @@ namespace ublas { template -class basic_tensor; +class tensor_core; template class matrix_expression; @@ -41,55 +41,182 @@ class vector_expression; } } -#define FIRST_ORDER_OPERATOR_RIGHT(OP, EXPR_TYPE_L, EXPR_TYPE_R) \ -template \ -auto operator OP ( boost::numeric::ublas:: EXPR_TYPE_L const& lhs, boost::numeric::ublas:: EXPR_TYPE_R const& rhs) { \ - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), \ - [](auto const& l, auto const& r){ return l OP r; }); \ -} \ +template +inline +constexpr auto operator*( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::vector_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::multiplies<>{}); +} + +template +inline +constexpr auto operator+( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::vector_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::plus<>{}); +} + +template +inline +constexpr auto operator-( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::vector_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::minus<>{}); +} + +template +inline +constexpr auto operator/( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::vector_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::divides<>{}); +} + + +template +inline +constexpr auto operator*( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::multiplies<>{}); +} + +template +inline +constexpr auto operator+( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::plus<>{}); +} + +template +inline +constexpr auto operator-( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::minus<>{}); +} + +template +inline +constexpr auto operator/( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::divides<>{}); +} + + +template +inline +constexpr auto operator*( + boost ::numeric ::ublas ::vector_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::multiplies<>{}); +} -FIRST_ORDER_OPERATOR_RIGHT (*, detail:: tensor_expression , vector_expression) -FIRST_ORDER_OPERATOR_RIGHT (+, detail:: tensor_expression , vector_expression) -FIRST_ORDER_OPERATOR_RIGHT (-, detail:: tensor_expression , vector_expression) -FIRST_ORDER_OPERATOR_RIGHT (/, detail:: tensor_expression , vector_expression) +template +inline +constexpr auto operator+( + boost ::numeric ::ublas ::vector_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::plus<>{}); +} -FIRST_ORDER_OPERATOR_RIGHT (*, detail:: tensor_expression , matrix_expression) -FIRST_ORDER_OPERATOR_RIGHT (+, detail:: tensor_expression , matrix_expression) -FIRST_ORDER_OPERATOR_RIGHT (-, detail:: tensor_expression , matrix_expression) -FIRST_ORDER_OPERATOR_RIGHT (/, detail:: tensor_expression , matrix_expression) +template +inline +constexpr auto operator-( + boost ::numeric ::ublas ::vector_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::minus<>{}); +} +template +inline +constexpr auto operator/( + boost ::numeric ::ublas ::vector_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::divides<>{}); +} -#define FIRST_ORDER_OPERATOR_LEFT(OP, EXPR_TYPE_L, EXPR_TYPE_R) \ -template \ -auto operator OP ( boost::numeric::ublas:: EXPR_TYPE_L const& lhs, boost::numeric::ublas:: EXPR_TYPE_R const& rhs) { \ - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), \ - [](auto const& l, auto const& r){ return l OP r; }); \ -} \ -FIRST_ORDER_OPERATOR_LEFT (*, vector_expression, detail:: tensor_expression) -FIRST_ORDER_OPERATOR_LEFT (+, vector_expression, detail:: tensor_expression) -FIRST_ORDER_OPERATOR_LEFT (-, vector_expression, detail:: tensor_expression) -FIRST_ORDER_OPERATOR_LEFT (/, vector_expression, detail:: tensor_expression) +template +inline +constexpr auto operator*( + boost ::numeric ::ublas ::matrix_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::multiplies<>{}); +} -FIRST_ORDER_OPERATOR_LEFT (*, matrix_expression, detail:: tensor_expression) -FIRST_ORDER_OPERATOR_LEFT (+, matrix_expression, detail:: tensor_expression) -FIRST_ORDER_OPERATOR_LEFT (-, matrix_expression, detail:: tensor_expression) -FIRST_ORDER_OPERATOR_LEFT (/, matrix_expression, detail:: tensor_expression) +template +inline +constexpr auto operator+( + boost ::numeric ::ublas ::matrix_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::plus<>{}); +} +template +inline +constexpr auto operator-( + boost ::numeric ::ublas ::matrix_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::minus<>{}); +} +template +inline +constexpr auto operator/( + boost ::numeric ::ublas ::matrix_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept +{ + return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( + lhs(), rhs(), std::divides<>{}); +} template +inline constexpr auto operator+( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, - "operator+() : LHS tensor and RHS tensor should have same value type" + "operator+() : LHS tensor and RHS tensor should have the same value type" ); if constexpr( !std::is_same_v ){ - auto e = boost::numeric::ublas::detail::retrieve_extents(rhs); + auto const& e = boost::numeric::ublas::detail::retrieve_extents(rhs); if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); @@ -99,12 +226,13 @@ constexpr auto operator+( boost::numeric::ublas::detail::tensor_expression return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l + r; }); } template +inline constexpr auto operator-( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, - "operator-() : LHS tensor and RHS tensor should have same value type" + "operator-() : LHS tensor and RHS tensor should have the same value type" ); if constexpr( !std::is_same_v ){ @@ -119,16 +247,17 @@ constexpr auto operator-( boost::numeric::ublas::detail::tensor_expression // return boost::numeric::ublas::detail::make_lambda([&lhs,&rhs](std::size_t i){ return lhs(i) - rhs(i);}); } template +inline constexpr auto operator*( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, - "operator*() : LHS tensor and RHS tensor should have same value type" + "operator*() : LHS tensor and RHS tensor should have the same value type" ); if constexpr( !std::is_same_v ){ - auto e = boost::numeric::ublas::detail::retrieve_extents(rhs); + auto const& e = boost::numeric::ublas::detail::retrieve_extents(rhs); if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); @@ -138,12 +267,13 @@ constexpr auto operator*( boost::numeric::ublas::detail::tensor_expression return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l * r; }); } template +inline constexpr auto operator/( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, - "operator/() : LHS tensor and RHS tensor should have same value type" + "operator/() : LHS tensor and RHS tensor should have the same value type" ); if constexpr( !std::is_same_v ){ @@ -154,100 +284,111 @@ constexpr auto operator/( boost::numeric::ublas::detail::tensor_expression } } - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l / r; }); + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), std::divides<>{}); } // Overloaded Arithmetic Operators with Scalars template -constexpr auto operator+(typename T::const_reference lhs, - boost::numeric::ublas::detail::tensor_expression,R> const& rhs) +inline +constexpr auto operator+(typename boost::numeric::ublas::tensor_core::const_reference lhs, + boost::numeric::ublas::detail::tensor_expression,R> const& rhs) noexcept { - using basic_tensor_type = boost::numeric::ublas::basic_tensor; - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs + r; }); - //return boost::numeric::ublas::detail::make_lambda( [&lhs,&rhs](std::size_t i) {return lhs + rhs(i); } ); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs + r; }); } template -constexpr auto operator-(typename T::const_reference lhs, - boost::numeric::ublas::detail::tensor_expression,R> const& rhs) +inline +constexpr auto operator-(typename boost::numeric::ublas::tensor_core::const_reference lhs, + boost::numeric::ublas::detail::tensor_expression,R> const& rhs) noexcept { - using basic_tensor_type = boost::numeric::ublas::basic_tensor; - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs - r; }); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs - r; }); } template -constexpr auto operator*(typename T::const_reference lhs, - boost::numeric::ublas::detail::tensor_expression,R> const& rhs) +inline +constexpr auto operator*(typename boost::numeric::ublas::tensor_core::const_reference lhs, + boost::numeric::ublas::detail::tensor_expression,R> const& rhs) noexcept { - using basic_tensor_type = boost::numeric::ublas::basic_tensor; - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs * r; }); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs * r; }); } template -constexpr auto operator/(typename T::const_reference lhs, - boost::numeric::ublas::detail::tensor_expression,R> const& rhs) +inline +constexpr auto operator/(typename boost::numeric::ublas::tensor_core::const_reference lhs, + boost::numeric::ublas::detail::tensor_expression,R> const& rhs) noexcept { - using basic_tensor_type = boost::numeric::ublas::basic_tensor; - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs / r; }); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs / r; }); } template -constexpr auto operator+(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, - typename T::const_reference rhs) +inline +constexpr auto operator+(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + typename boost::numeric::ublas::tensor_core::const_reference rhs) noexcept { - using basic_tensor_type = boost::numeric::ublas::basic_tensor; - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l + rhs; } ); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l + rhs; } ); } template -constexpr auto operator-(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, - typename T::const_reference rhs) +inline +constexpr auto operator-(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + typename boost::numeric::ublas::tensor_core::const_reference rhs) noexcept { - using basic_tensor_type = boost::numeric::ublas::basic_tensor; - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l - rhs; } ); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l - rhs; } ); } template -constexpr auto operator*(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, - typename T::const_reference rhs) +inline +constexpr auto operator*(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + typename boost::numeric::ublas::tensor_core::const_reference rhs) noexcept { - using basic_tensor_type = boost::numeric::ublas::basic_tensor; - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l * rhs; } ); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l * rhs; } ); } template -constexpr auto operator/(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, - typename T::const_reference rhs) +inline +constexpr auto operator/(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + typename boost::numeric::ublas::tensor_core::const_reference rhs) noexcept { - using basic_tensor_type = boost::numeric::ublas::basic_tensor; - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l / rhs; } ); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l / rhs; } ); } template -constexpr auto& operator += (boost::numeric::ublas::basic_tensor& lhs, - const boost::numeric::ublas::detail::tensor_expression,D> &expr) +inline +constexpr auto& operator += (boost::numeric::ublas::tensor_core& lhs, + const boost::numeric::ublas::detail::tensor_expression,D> &expr) { boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l+=r; } ); return lhs; } template -constexpr auto& operator -= (boost::numeric::ublas::basic_tensor& lhs, - const boost::numeric::ublas::detail::tensor_expression,D> &expr) +inline +constexpr auto& operator -= (boost::numeric::ublas::tensor_core& lhs, + const boost::numeric::ublas::detail::tensor_expression,D> &expr) { boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l-=r; } ); return lhs; } template -constexpr auto& operator *= (boost::numeric::ublas::basic_tensor& lhs, - const boost::numeric::ublas::detail::tensor_expression,D> &expr) +inline +constexpr auto& operator *= (boost::numeric::ublas::tensor_core& lhs, + const boost::numeric::ublas::detail::tensor_expression,D> &expr) { boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l*=r; } ); return lhs; } template -constexpr auto& operator /= (boost::numeric::ublas::basic_tensor& lhs, - const boost::numeric::ublas::detail::tensor_expression,D> &expr) +inline +constexpr auto& operator /= (boost::numeric::ublas::tensor_core& lhs, + const boost::numeric::ublas::detail::tensor_expression,D> &expr) { boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l/=r; } ); return lhs; @@ -256,39 +397,38 @@ constexpr auto& operator /= (boost::numeric::ublas::basic_tensor& lhs, -template -constexpr auto& operator += (boost::numeric::ublas::basic_tensor& lhs, typename TensorType::const_reference r) { - static_assert( boost::numeric::ublas::is_valid_tensor_v, - "boost::numeric::ublas::operator +=() : tensor type should be valid tensor" - ); +template +inline +constexpr auto& operator += (boost::numeric::ublas::tensor_core& lhs, + typename boost::numeric::ublas::tensor_core::const_reference r) +{ boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l+=r; } ); return lhs; } -template -constexpr auto& operator -= (boost::numeric::ublas::basic_tensor& lhs, typename TensorType::const_reference r) { - static_assert( boost::numeric::ublas::is_valid_tensor_v, - "boost::numeric::ublas::operator -=() : tensor type should be valid tensor" - ); +template +inline +constexpr auto& operator -= (boost::numeric::ublas::tensor_core& lhs, + typename boost::numeric::ublas::tensor_core::const_reference r) +{ boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l-=r; } ); return lhs; } -template -constexpr auto& operator *= (boost::numeric::ublas::basic_tensor& lhs, typename TensorType::const_reference r) { - static_assert( boost::numeric::ublas::is_valid_tensor_v, - "boost::numeric::ublas::operator *=() : tensor type should be valid tensor" - ); +template +inline +constexpr auto& operator *= (boost::numeric::ublas::tensor_core& lhs, + typename boost::numeric::ublas::tensor_core::const_reference r) +{ boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l*=r; } ); return lhs; } -template -constexpr auto& operator /= (boost::numeric::ublas::basic_tensor& lhs, typename TensorType::const_reference r) { - static_assert( boost::numeric::ublas::is_valid_tensor_v, - "boost::numeric::ublas::operator /=() : tensor type should be valid tensor" - ); - boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l/=r; } ); +template +constexpr auto& operator /= (boost::numeric::ublas::tensor_core& lhs, + typename boost::numeric::ublas::tensor_core::const_reference r) +{ + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l/=r; } ); return lhs; } @@ -298,13 +438,15 @@ constexpr auto& operator /= (boost::numeric::ublas::basic_tensor& lh template -constexpr auto const& operator +(const boost::numeric::ublas::detail::tensor_expression& lhs) { +inline +constexpr auto const& operator +(const boost::numeric::ublas::detail::tensor_expression& lhs) noexcept{ return lhs; } template +inline constexpr auto operator -(boost::numeric::ublas::detail::tensor_expression const& lhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [] (auto const& l) { return -l; } ); + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), std::negate<>{} ); } diff --git a/include/boost/numeric/ublas/tensor/operators_comparison.hpp b/include/boost/numeric/ublas/tensor/operators_comparison.hpp index 13806b5f0..7516c1731 100644 --- a/include/boost/numeric/ublas/tensor/operators_comparison.hpp +++ b/include/boost/numeric/ublas/tensor/operators_comparison.hpp @@ -22,26 +22,26 @@ namespace boost::numeric::ublas { template -class basic_tensor; +class tensor_core; } namespace boost::numeric::ublas::detail { template [[nodiscard]] inline -constexpr bool compare(basic_tensor const& lhs, basic_tensor const& rhs, BinaryPred pred) +constexpr bool compare(tensor_core const& lhs, tensor_core const& rhs, BinaryPred pred) { - static_assert( is_valid_tensor_v && is_valid_tensor_v, - "boost::numeric::ublas::detail::compare() : LHS and RHS both should the tensor" - ); - - static_assert( std::is_same_v, - "boost::numeric::ublas::detail::compare() : LHS and RHS both should have same value type" + static_assert( std::is_same_v::value_type, typename tensor_core::value_type>, + "boost::numeric::ublas::detail::compare(tensor_core const&, tensor_core const&, BinaryPred) : " + "LHS and RHS both should have the same value type" ); if(lhs.extents() != rhs.extents()){ if constexpr(!std::is_same>::value && !std::is_same>::value) - throw std::runtime_error("Error in boost::numeric::ublas::detail::compare: cannot compare tensors with different shapes."); + throw std::runtime_error( + "boost::numeric::ublas::detail::compare(tensor_core const&, tensor_core const&, BinaryPred) : " + "cannot compare tensors with different shapes." + ); else return false; } @@ -58,12 +58,8 @@ constexpr bool compare(basic_tensor const& lhs, basic_tensor const& rhs, template [[nodiscard]] inline -constexpr bool compare(basic_tensor const& rhs, UnaryPred pred) +constexpr bool compare(tensor_core const& rhs, UnaryPred pred) { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::detail::compare() : Template typename T should the tensor type" - ); - for(auto i = 0u; i < rhs.size(); ++i) if(!pred(rhs(i))) return false; diff --git a/include/boost/numeric/ublas/tensor/ostream.hpp b/include/boost/numeric/ublas/tensor/ostream.hpp index ad61e470c..1940546a3 100644 --- a/include/boost/numeric/ublas/tensor/ostream.hpp +++ b/include/boost/numeric/ublas/tensor/ostream.hpp @@ -14,7 +14,7 @@ #include #include -#include +#include namespace boost { namespace numeric { @@ -44,7 +44,7 @@ void print(std::ostream& out, size_type r, const value_type* p, const size_type* for(auto row = 0u; row < n[0]; p += w[0], ++row) // iterate over one column { - auto p1 = p; + auto const* p1 = p; for(auto col = 0u; col < n[1]; p1 += w[1], ++col) // iterate over first row { print(out,*p1); @@ -80,8 +80,8 @@ namespace boost { namespace numeric { namespace ublas { -template -class tensor; +template +class tensor_core; template class matrix; @@ -95,7 +95,7 @@ class vector; template -std::ostream& operator << (std::ostream& out, boost::numeric::ublas::basic_tensor const& t) +std::ostream& operator << (std::ostream& out, boost::numeric::ublas::tensor_core const& t) { if(is_scalar(t.extents())){ diff --git a/include/boost/numeric/ublas/tensor/static_extents.hpp b/include/boost/numeric/ublas/tensor/static_extents.hpp index 675765e0e..cbd7be3d2 100644 --- a/include/boost/numeric/ublas/tensor/static_extents.hpp +++ b/include/boost/numeric/ublas/tensor/static_extents.hpp @@ -6,7 +6,8 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // -// The authors gratefully acknowledge the support of Google +// The authors gratefully acknowledge the support of +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef _BOOST_NUMERIC_UBLAS_TENSOR_STATIC_EXTENTS_HPP_ @@ -14,11 +15,11 @@ #include #include -#include +#include namespace boost::numeric::ublas { -template struct basic_static_extents; +template class basic_static_extents; /** @brief Template class for storing tensor extents for compile time. * @@ -27,17 +28,20 @@ template struct basic_static_extents; * */ template -struct basic_static_extents{ +class basic_static_extents{ + +public: static constexpr auto _size = sizeof...(E); using base_type = std::array; using value_type = typename base_type::value_type; - using const_reference = typename base_type::const_reference; + using size_type = typename base_type::size_type; using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; using const_pointer = typename base_type::const_pointer; using const_iterator = typename base_type::const_iterator; - using size_type = typename base_type::size_type; + using const_reverse_iterator = typename base_type::const_reverse_iterator; static_assert( std::numeric_limits::is_integer, "Static error in basic_static_extents: type must be of type integer."); static_assert(!std::numeric_limits::is_signed, "Static error in basic_static_extents: type must be of type unsigned integer."); @@ -56,13 +60,20 @@ struct basic_static_extents{ } [[nodiscard]] inline - constexpr const_reference operator[](size_type k) const noexcept{ + constexpr const_reference operator[](size_type k) const{ return m_data[k]; } - // default constructor constexpr basic_static_extents() = default; + constexpr basic_static_extents(basic_static_extents const&) noexcept = default; + constexpr basic_static_extents(basic_static_extents &&) noexcept = default; + + constexpr basic_static_extents& operator=(basic_static_extents const&) noexcept = default; + constexpr basic_static_extents& operator=(basic_static_extents &&) noexcept = default; + + ~basic_static_extents() = default; + /** @brief Returns ref to the std::array containing extents */ [[nodiscard]] inline constexpr base_type const& base() const noexcept{ @@ -84,7 +95,7 @@ struct basic_static_extents{ constexpr bool empty() const noexcept { return m_data.empty(); } [[nodiscard]] inline - constexpr const_reference back() const noexcept{ + constexpr const_reference back() const{ return m_data.back(); } @@ -98,50 +109,42 @@ struct basic_static_extents{ return m_data.end(); } - ~basic_static_extents() = default; + [[nodiscard]] inline + constexpr const_reverse_iterator + rbegin() const noexcept + { + return m_data.rbegin(); + } + [[nodiscard]] inline + constexpr const_reverse_iterator + rend() const noexcept + { + return m_data.rend(); + } + + /// msvc 14.27 does not consider 'at' function constexpr. + /// To make msvc happy get function is declared + /// and it will be removed when we start using boost.mp11 + template + static constexpr auto get() noexcept{ + static_assert(I < _size, + "boost::numeric::ublas::basic_static_extents::get() : " + "out of bound access" + ); + using element_at = std::tuple_element_t; + return element_at{}; + } private: static constexpr base_type const m_data{E...}; + /// will be removed when we start using boost.mp11 + using tuple_type = std::tuple< std::integral_constant... >; }; + template using static_extents = basic_static_extents; - -template struct static_product; - -template -inline static constexpr auto const static_product_v = static_product::value; - -template -struct static_product< basic_static_extents >{ - static constexpr auto const value = E0 * static_product_v< basic_static_extents >; -}; - -template -struct static_product< basic_static_extents >{ - static constexpr auto const value = E0 ; -}; - -template -struct static_product< basic_static_extents >{ - static constexpr auto const value = ExtentsType(0) ; -}; - } // namespace boost::numeric::ublas - - -namespace boost::numeric::ublas{ - - template - struct tensor_traits< static_tensor > { - using container_type= std::array< T, static_product_v >; - using extents_type = E; - using layout_type = F; - using container_tag = static_tensor_tag; - }; - -} // namespace boost::numeric::ublas - #endif diff --git a/include/boost/numeric/ublas/tensor/static_strides.hpp b/include/boost/numeric/ublas/tensor/static_strides.hpp index b36d8f5ed..f43101b8c 100644 --- a/include/boost/numeric/ublas/tensor/static_strides.hpp +++ b/include/boost/numeric/ublas/tensor/static_strides.hpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // /// \file strides.hpp Definition for the basic_strides template class @@ -15,27 +15,17 @@ #define BOOST_UBLAS_TENSOR_STATIC_STRIDES_HPP #include -#include +#include +#include namespace boost::numeric::ublas{ - using first_order = column_major; - using last_order = row_major; - - template struct basic_static_strides; + template class basic_static_strides; } // boost::numeric::ublas namespace boost::numeric::ublas::detail{ - // list for storing stides as types - template< typename T, T... P > - struct static_stride_list{ - using extents_type = basic_static_extents; - using type = std::array; - static constexpr type const value = {P...}; - }; - namespace impl{ // concat two static_stride_list togather @@ -44,8 +34,8 @@ namespace boost::numeric::ublas::detail{ struct concat; template - struct concat< static_stride_list, static_stride_list > { - using type = static_stride_list; + struct concat< basic_static_extents, basic_static_extents > { + using type = basic_static_extents; }; template @@ -65,11 +55,23 @@ namespace boost::numeric::ublas::detail{ template struct make_sequence_of_ones { - using type = static_stride_list; + using type = basic_static_extents; }; template struct make_sequence_of_ones{ - using type = static_stride_list; + using type = basic_static_extents; + }; + + template + struct extents_to_array; + + template + inline static constexpr auto extents_to_array_v = extents_to_array::value; + + template + struct extents_to_array< basic_static_extents > + { + static constexpr std::array const value = {Es...}; }; } // impl @@ -78,110 +80,74 @@ namespace boost::numeric::ublas::detail{ template using make_sequence_of_ones_t = impl::make_sequence_of_ones_t; - // @returns the static_stride_list containing strides - // It is a helper function or implementation - template - constexpr auto make_static_strides_helper( static_stride_list, - static_stride_list, static_stride_list) - { - if constexpr(sizeof...(E) == 0ul ){ - - if constexpr( std::is_same_v ){ - - return static_stride_list{}; - - }else{ - - return static_stride_list{}; - - } - - }else{ - // add extent to the list, which will be used for - // taking the product for next iteration - auto n = static_stride_list{}; - - // result list containing the strides - // on each iteration calculate the product - if constexpr( std::is_same_v ){ - auto np = static_stride_list< T, P..., static_product_v< basic_static_extents > >{}; - return make_static_strides_helper( static_stride_list{}, n, np ); - }else{ - auto np = static_stride_list< T, P..., static_product_v< basic_static_extents > >{}; - return make_static_strides_helper( static_stride_list{}, n, np ); - } - } + template + constexpr auto make_static_strides_first_order( [[maybe_unused]] E const& e, [[maybe_unused]] basic_static_extents const& res ){ + if constexpr( I >= E::_size - 1ul ){ + return impl::extents_to_array_v< basic_static_extents >; + }else{ + using res_type = basic_static_extents; + constexpr auto prod = E::template get().value * res_type::template get().value; + using nextents = basic_static_extents; + return make_static_strides_first_order(e, nextents{}); + } } + template + constexpr auto make_static_strides_last_order( [[maybe_unused]] E const& e, [[maybe_unused]] basic_static_extents const& res ){ + if constexpr( I >= E::_size - 1ul ){ + return impl::extents_to_array_v< basic_static_extents >; + }else{ + using res_type = basic_static_extents; - // @returns the static_stride_list containing strides for last order - template - constexpr auto make_static_strides( static_stride_list ) - { - using extents_type = typename static_stride_list::extents_type; - // checks if extents are vector or scalar - if constexpr( !( static_traits::is_scalar_v || static_traits::is_vector_v ) ){ - // if extent contains only one element return static_stride_list - if constexpr( sizeof...(E) == 0 ){ - - return static_stride_list{}; + constexpr auto J = E::_size - I - 1ul; + constexpr auto K = res_type::_size - I - 1ul; + constexpr auto prod = E::template get().value * res_type::template get().value; + using nextents = basic_static_extents; + return make_static_strides_last_order(e, nextents{}); + } + } + template + constexpr auto make_static_strides( [[maybe_unused]] E const& e ){ + using value_type = typename E::value_type; + if constexpr( E::_size == 0 ){ + return impl::extents_to_array_v; + }else if constexpr( is_scalar(E{}) || is_vector(E{}) ){ + using extents_with_ones = make_sequence_of_ones_t; + return impl::extents_to_array_v; + }else{ + if constexpr( std::is_same_v ){ + return make_static_strides_first_order(e, basic_static_extents{}); }else{ - - if constexpr( std::is_same_v ){ - - using ret_type = decltype( make_static_strides_helper(static_stride_list{}, static_stride_list{}, static_stride_list{}) ); - return impl::concat_t< static_stride_list, ret_type>{}; - - }else{ - - using ret_type = decltype( make_static_strides_helper(static_stride_list{}, static_stride_list{}, static_stride_list{}) ); - return impl::concat_t >{}; - - } - + return make_static_strides_last_order(e, basic_static_extents{}); } - }else{ - // @returns list contining ones if it is vector or scalar - return make_sequence_of_ones_t{}; } } - - // if extents are empty return empty list - template - constexpr auto make_static_strides( static_stride_list ) - { - return static_stride_list{}; - } // It is use for first order to // get std::array containing strides - template - struct strides_helper{ - using type = decltype( make_static_strides(static_stride_list{}) ); - static constexpr auto value = type::value; - }; - - template - inline static constexpr auto strides_helper_v = strides_helper::value; + template + inline static constexpr auto strides_helper_v = make_static_strides(ExtentsType{}); } // namespace boost::numeric::ublas::detail namespace boost::numeric::ublas { -/** @brief Partial Specialization for first_order or column_major +/** @brief Partial Specialization for layout::first_order or column_major * - * @code basic_static_strides, first_order> s @endcode + * @code basic_static_strides, layout::first_order> s @endcode * * @tparam R rank of basic_static_extents * @tparam Extents paramerter pack of extents * */ template -struct basic_static_strides, Layout> +class basic_static_strides, Layout> { +public: + static constexpr std::size_t const _size = sizeof...(Extents); using layout_type = Layout; @@ -193,6 +159,7 @@ struct basic_static_strides, Layout> using size_type = typename base_type::size_type; using const_pointer = typename base_type::const_pointer; using const_iterator = typename base_type::const_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; /** * @param k pos of extent @@ -205,14 +172,14 @@ struct basic_static_strides, Layout> } [[nodiscard]] inline - constexpr const_reference operator[](size_type k) const noexcept { return m_data[k]; } + constexpr const_reference operator[](size_type k) const { return m_data[k]; } //@returns the rank of basic_static_extents [[nodiscard]] inline constexpr size_type size() const noexcept { return static_cast(_size); } [[nodiscard]] inline - constexpr const_reference back () const noexcept{ + constexpr const_reference back () const{ return m_data.back(); } @@ -220,28 +187,35 @@ struct basic_static_strides, Layout> constexpr basic_static_strides() noexcept{ static_assert( _size == 0 || - ( static_traits::is_valid_v && - ( static_traits::is_vector_v || - static_traits::is_scalar_v || + ( is_valid(extents_type{}) && + ( is_vector(extents_type{}) || + is_scalar(extents_type{}) || _size >= 2 ) ) , "Error in boost::numeric::ublas::basic_static_strides() : " - "Size can be 0 or Shape should be valid and shape can be vector or shape can be scalar or size should be greater than" + "Size cannot be 0 or Shape should be valid and shape can be vector or shape can be scalar or size should be greater than" " or equal to 2" ); } - constexpr basic_static_strides(extents_type const&) noexcept{}; + constexpr basic_static_strides(extents_type const& e) noexcept{ (void)e; }; // default copy constructor constexpr basic_static_strides(basic_static_strides const &other) noexcept = default; + constexpr basic_static_strides(basic_static_strides &&other) noexcept = default; + // default assign constructor constexpr basic_static_strides & operator=(basic_static_strides const &other) noexcept = default; + + constexpr basic_static_strides & + operator=(basic_static_strides &&other) noexcept = default; + + ~basic_static_strides() = default; /** @brief Returns ref to the std::array containing extents */ [[nodiscard]] inline @@ -270,8 +244,22 @@ struct basic_static_strides, Layout> return m_data.empty(); } + [[nodiscard]] inline + constexpr const_reverse_iterator + rbegin() const noexcept + { + return m_data.rbegin(); + } + + [[nodiscard]] inline + constexpr const_reverse_iterator + rend() const noexcept + { + return m_data.rend(); + } + private: - static constexpr base_type const m_data{ detail::strides_helper_v }; + static constexpr base_type const m_data{ detail::strides_helper_v }; }; } // namespace boost::numeric::ublas diff --git a/include/boost/numeric/ublas/tensor/static_tensor.hpp b/include/boost/numeric/ublas/tensor/static_tensor.hpp deleted file mode 100644 index 87e9cd6f8..000000000 --- a/include/boost/numeric/ublas/tensor/static_tensor.hpp +++ /dev/null @@ -1,212 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - - -#ifndef BOOST_UBLAS_STATIC_TENSOR_IMPL_HPP -#define BOOST_UBLAS_STATIC_TENSOR_IMPL_HPP - -#include - -namespace boost::numeric::ublas { - - template< typename T, typename E, typename F = first_order > - struct static_tensor: - public basic_tensor< static_tensor< T, E, F > > - { - - static_assert( is_static_v, - "boost::numeric::static_tensor : extents type should be of static_extents, please check"); - - using self_type = static_tensor< T, E, F >; - using super_type = basic_tensor< self_type >; - - template - using tensor_expression_type = typename super_type::template tensor_expression_type; - - template - using matrix_expression_type = typename super_type::template matrix_expression_type; - - template - using vector_expression_type = typename super_type::template vector_expression_type; - - using array_type = typename tensor_traits::container_type; - using layout_type = typename tensor_traits::layout_type; - - using size_type = typename array_type::size_type; - using difference_type = typename array_type::difference_type; - using value_type = typename array_type::value_type; - - using reference = typename array_type::reference; - using const_reference = typename array_type::const_reference; - - using pointer = typename array_type::pointer; - using const_pointer = typename array_type::const_pointer; - - using iterator = typename array_type::iterator; - using const_iterator = typename array_type::const_iterator; - - using reverse_iterator = typename array_type::reverse_iterator; - using const_reverse_iterator = typename array_type::const_reverse_iterator; - - using tensor_temporary_type = self_type; - using storage_category = dense_tag; - - using extents_type = typename tensor_traits::extents_type; - using strides_type = strides_t; - - using matrix_type = typename super_type::matrix_type; - using vector_type = typename super_type::vector_type; - - constexpr static_tensor() = default; - - constexpr static_tensor( array_type const& a ){ - std::copy(a.begin(), a.end(), super_type::begin()); - } - - constexpr static_tensor( value_type const& i ){ - std::fill(super_type::begin(), super_type::end(), i); - } - - constexpr static_tensor( matrix_type const& v ) - { - static_assert(extents_type::_size == 2 - , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : invalid extents size"); - - if( !( super_type::size(0) == v.size1() || super_type::size(1) == v.size2() ) ){ - throw std::runtime_error("Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : rank of extents are not correct, please check!"); - } - std::copy(v.data().begin(), v.data().end(),super_type::begin()); - } - - constexpr static_tensor( matrix_type && v ) - { - static_assert(extents_type::_size == 2 - , "Error in boost::numeric::ublas::tensor(const matrix_type &v)" - " : invalid extents size"); - - if( !( super_type::size(0) == v.size1() || super_type::size(1) == v.size2() ) ){ - throw std::runtime_error("Error in boost::numeric::ublas::tensor(matrix_type &&v)" - " : rank of extents are not correct, please check!"); - } - - std::move(v.data().begin(), v.data().end(),super_type::begin()); - } - - constexpr static_tensor (const vector_type &v){ - - static_assert(extents_type::_size == 2 - , "Error in boost::numeric::ublas::tensor(const vector_type &v)" - " : invalid extents size"); - - if( !( super_type::size(0) == v.size() || super_type::size(1) == 1 ) ){ - throw std::runtime_error("Error in boost::numeric::ublas::tensor(const vector_type &v)" - " : rank of extents are not correct, please check!"); - } - - std::copy(v.data().begin(), v.data().end(),super_type::begin()); - - } - - constexpr static_tensor (vector_type &&v){ - - static_assert(extents_type::_size == 2 - , "Error in boost::numeric::ublas::tensor(const vector_type &&v)" - " : invalid extents size"); - - if( !( super_type::size(0) == v.size() || super_type::size(1) == 1 ) ){ - throw std::runtime_error("Error in boost::numeric::ublas::tensor(vector_type &&v)" - " : rank of extents are not correct, please check!"); - } - - std::move(v.data().begin(), v.data().end(),super_type::begin()); - - } - - template - constexpr static_tensor (const static_tensor &expr) - : super_type(static_cast(expr)) - {} - - template - constexpr static_tensor (const basic_tensor & other) - { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::static_tensor( const OtherTensor& ) : The OtherTensor should have a tensor type" - ); - - static_assert( std::is_same_v, - "boost::numeric::ublas::static_tensor( const OtherTensor& ) : The tensor should have same value type" - ); - - if ( other.extents() != super_type::extents() ){ - throw std::runtime_error("boost::numeric::ublas::static_tensor( const OtherTensor& ) : The tensor should have equal extents"); - } - - std::copy(other.begin(), other.end(), super_type::begin()); - } - - template - constexpr static_tensor (basic_tensor && other) - { - static_assert( is_valid_tensor_v, - "boost::numeric::ublas::static_tensor( OtherTensor&& ) : The OtherTensor should have a tensor type" - ); - - static_assert( std::is_same_v, - "boost::numeric::ublas::static_tensor( OtherTensor&& ) : The tensor should have same value type" - ); - - if ( other.extents() != super_type::extents() ){ - throw std::runtime_error("boost::numeric::ublas::static_tensor( OtherTensor&& ) : The tensor should have equal extents"); - } - - std::move(other.begin(), other.end(), super_type::begin()); - } - - template - constexpr static_tensor (const tensor_expression_type &expr) - : super_type(expr) - {} - - template - inline - constexpr static_tensor& operator= (const tensor_expression_type &expr) - { - static_tensor temp( expr ); - swap(*this,temp); - return *this; - } - - template - constexpr static_tensor (const matrix_expression_type &expr) - : static_tensor( matrix_type(expr) ) - {} - - template - constexpr static_tensor (const vector_expression_type &expr) - : static_tensor( vector_type(expr) ) - {} - - inline - constexpr static_tensor& operator=(const_reference v) noexcept{ - std::fill(super_type::begin(), super_type::end(), v); - return *this; - } - - void reshape (extents_type const&, value_type) = delete; - }; - -} // boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/strides.hpp b/include/boost/numeric/ublas/tensor/strides.hpp index d168ec11f..eb78c24da 100644 --- a/include/boost/numeric/ublas/tensor/strides.hpp +++ b/include/boost/numeric/ublas/tensor/strides.hpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // /// \file strides.hpp Definition for the basic_strides template class @@ -28,7 +28,7 @@ namespace boost::numeric::ublas{ [[nodiscard]] inline constexpr bool operator==(LStrides const& lhs, RStrides const& rhs) noexcept{ static_assert( std::is_same_v, - "boost::numeric::ublas::operator==(LStrides,RStrides) : LHS value type should be same as RHS value type"); + "boost::numeric::ublas::operator==(LStrides,RStrides) : LHS value type should be the same as the RHS value type"); return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); } @@ -41,7 +41,7 @@ namespace boost::numeric::ublas{ [[nodiscard]] inline constexpr bool operator!=(LStrides const& lhs, RStrides const& rhs) noexcept{ static_assert( std::is_same_v, - "boost::numeric::ublas::operator!=(LStrides,RStrides) : LHS value type should be same as RHS value type"); + "boost::numeric::ublas::operator!=(LStrides,RStrides) : LHS value type should be the same as the RHS value type"); return !( lhs == rhs ); } @@ -58,40 +58,40 @@ namespace boost::numeric::ublas::detail { * @param[in] w stride vector of length p * @returns relative memory location depending on \c i and \c w */ - template + template [[nodiscard]] inline - constexpr auto access(std::vector const& i, Stride const& w) + constexpr auto access(std::vector const& i, Stride const& w) { static_assert( is_strides_v, - "boost::numeric::ublas::detail::access() : invalid type, type should be a strides"); - - const auto p = i.size(); - size_type sum = 0u; - for(auto r = 0u; r < p; ++r) - sum += i[r]*w[r]; - return sum; + "boost::numeric::ublas::detail::access() : invalid type, the type should be a strides"); + + using value_type = typename Stride::value_type; + return std::inner_product(i.begin(), i.end(), w.begin(), value_type{}); } /** @brief Returns relative memory index with respect to a multi-index * - * @code auto j = access(0, strides{shape{4,2,3},first_order}, 2,3,4); @endcode + * @code auto j = access(strides{shape{4,2,3},first_order}, 2,3,4); @endcode * - * @param[in] i first element of the partial multi-index - * @param[in] is the following elements of the partial multi-index + * @param[in] is the elements of the partial multi-index * @param[in] sum the current relative memory index * @returns relative memory location depending on \c i and \c w */ - template - [[nodiscard]] - constexpr auto access(std::size_t sum, Stride const& w, std::size_t i, size_types ... is) + template + [[nodiscard]] inline + constexpr auto access(Stride const& w, Indices ... is) { static_assert( is_strides_v, - "boost::numeric::ublas::detail::access() : invalid type, type should be a strides"); - sum += i*w[r]; - if constexpr (sizeof...(is) == 0) - return sum; - else - return detail::access(sum,w,std::forward(is)...); + "boost::numeric::ublas::detail::access() : invalid type, the type should be a strides"); + + if constexpr( is_static_rank_v ){ + static_assert( Stride::_size >= sizeof...(is), + "boost::numeric::ublas::detail::access() : number of indices exceeds the size of the stride"); + } + + using value_type = typename Stride::value_type; + std::array i = {is...}; + return std::inner_product(i.begin(), i.end(), w.begin(), value_type{}); } } // namespace boost::numeric::ublas::detail diff --git a/include/boost/numeric/ublas/tensor/tags.hpp b/include/boost/numeric/ublas/tensor/tags.hpp new file mode 100644 index 000000000..079c2e783 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/tags.hpp @@ -0,0 +1,31 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_TAGS_IMPL_HPP +#define BOOST_UBLAS_TENSOR_TAGS_IMPL_HPP + +namespace boost::numeric::ublas{ + + struct tensor_tag{}; + + struct storage_resizable_container_tag{}; + + struct storage_static_container_tag{}; + + struct storage_seq_container_tag{}; + + struct storage_non_seq_container_tag{}; + +} // namespace boost::numeric::ublas::tag + + +#endif diff --git a/include/boost/numeric/ublas/tensor/tensor.hpp b/include/boost/numeric/ublas/tensor/tensor.hpp index 033a69ff3..f635f4fbe 100644 --- a/include/boost/numeric/ublas/tensor/tensor.hpp +++ b/include/boost/numeric/ublas/tensor/tensor.hpp @@ -10,612 +10,46 @@ // Google and Fraunhofer IOSB, Ettlingen, Germany // - -/// \file tensor.hpp Definition for the tensor template class - #ifndef BOOST_UBLAS_TENSOR_IMPL_HPP #define BOOST_UBLAS_TENSOR_IMPL_HPP -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { namespace numeric { namespace ublas { - -///** \brief Base class for Tensor container models -// * -// * it does not model the Tensor concept but all derived types should. -// * The class defines a common base type and some common interface for all -// * statically derived Tensor classes -// * We implement the casts to the statically derived type. -// */ -//template -//class tensor_container: -// public detail::tensor_expression -//{ -//public: -// static const unsigned complexity = 0; -// typedef C container_type; -// typedef tensor_tag type_category; - -// inline -// const container_type &operator () () const { -// return *static_cast (this); -// } -// inline -// container_type &operator () () { -// return *static_cast (this); -// } -//}; - -template< class T > -class basic_tensor: - public detail::tensor_expression< basic_tensor,basic_tensor > -{ - - using self_type = basic_tensor; - -public: - - template - using tensor_expression_type = detail::tensor_expression; - - template - using matrix_expression_type = matrix_expression; - - template - using vector_expression_type = vector_expression; - - using super_type = tensor_expression_type; - - using array_type = typename tensor_traits::container_type; - using layout_type = typename tensor_traits::layout_type; - - - using size_type = typename array_type::size_type; - using difference_type = typename array_type::difference_type; - using value_type = typename array_type::value_type; - - using reference = typename array_type::reference; - using const_reference = typename array_type::const_reference; - - using pointer = typename array_type::pointer; - using const_pointer = typename array_type::const_pointer; - - using iterator = typename array_type::iterator; - using const_iterator = typename array_type::const_iterator; - - using reverse_iterator = typename array_type::reverse_iterator; - using const_reverse_iterator = typename array_type::const_reverse_iterator; - - using tensor_temporary_type = self_type; - using storage_category = dense_tag; - using container_tag = typename tensor_traits::container_tag; - - using extents_type = typename tensor_traits::extents_type; - using strides_type = strides_t; - - using matrix_type = matrix >; - using vector_type = vector >; - - static_assert( std::is_same::value || - std::is_same::value, - "boost::numeric::basic_tensor template class only supports first- or last-order storage formats."); -protected: - - /** @brief Constructs a basic_tensor. - * - * @note the basic_tensor is empty. - * @note the basic_tensor needs to reshaped for further use. - * - */ - inline - constexpr basic_tensor () - : tensor_expression_type() // container_type - , extents_() - , strides_() - {} - - constexpr basic_tensor( extents_type const& e, dynamic_tensor_tag ) - : tensor_expression_type() - , extents_(e) - , strides_(extents_) - , data_( product(extents_) ) - {} - - constexpr basic_tensor( extents_type const& e, static_tensor_tag ) - : tensor_expression_type() - , extents_(e) - , strides_(extents_) - {} - - /** @brief Constructs a basic_tensor with an initializer list for dynamic_extents - * - * By default, its elements are initialized to 0. - * - * @code basic_tensor A{4,2,3}; @endcode - * - * @param l initializer list for setting the dimension extents of the basic_tensor - */ - explicit inline - basic_tensor (std::initializer_list l) - : basic_tensor( std::move(l), container_tag{} ) - {} - - /** @brief Constructs a basic_tensor with a \c shape - * - * By default, its elements are initialized to 0. - * - * @code basic_tensor A{extents{4,2,3}}; @endcode - * - * @param s initial basic_tensor dimension extents - */ - explicit inline - basic_tensor (extents_type const& s) - : basic_tensor( s, container_tag{} ) - {} - - /** @brief Constructs a basic_tensor with a \c shape - * - * By default, its elements are initialized to 0. - * - * @code basic_tensor A{extents{4,2,3}}; @endcode - * - * @param s initial basic_tensor dimension extents - * @param i initial basic_tensor with this value - */ - explicit inline - basic_tensor (extents_type const& s, value_type const& i) - : basic_tensor( s, container_tag{} ) - { - std::fill(begin(),end(),i); - } - - /** @brief Constructs a basic_tensor with a \c shape and initiates it with one-dimensional data - * - * @code basic_tensor A{extents{4,2,3}, array }; @endcode - * - * - * @param s initial basic_tensor dimension extents - * @param a container of \c array_type that is copied according to the storage layout - */ - basic_tensor (extents_type const& s, const array_type &a) - : basic_tensor( s, container_tag{} ) - { - if( product(extents_) != a.size() ){ - throw std::runtime_error("boost::numeric::ublas::basic_tensor(extents_type,array_type): array size mismatch with extents"); - } - std::copy(a.begin(),a.end(),begin()); - } - - // /** @brief Constructs a basic_tensor using a shape tuple and initiates it with a value. - // * - // * @code basic_tensor A{extents{4,2,3}, 1 }; @endcode - // * - // * @param e initial basic_tensor dimension extents - // * @param i initial value of all elements of type \c value_type - // */ - // template - // inline - // basic_tensor (shape_t const& e, const value_type &i, typename std::enable_if::value>::type* = nullptr) - // : tensor_expression_type() //tensor_container () - // , extents_ (e.begin(),e.end()) - // , strides_ (extents_) - // , data_ (product(extents_), i) - // {} - - -public: - - /** @brief Constructs a basic_tensor with another basic_tensor with a different layout - * - * @param other basic_tensor with a different layout to be copied. - */ - template - basic_tensor (const basic_tensor &other) - : basic_tensor( other.extents(), container_tag{} ) - { - copy(this->rank(), this->extents().data(), - this->data(), this->strides().data(), - other.data(), other.strides().data()); - - } - - - /** @brief Constructs a basic_tensor with an basic_tensor expression - * - * @code basic_tensor A = B + 3 * C; @endcode - * - * @note type must be specified of basic_tensor must be specified. - * @note dimension extents are extracted from tensors within the expression. - * - * @param expr basic_tensor expression - * @param size basic_tensor expression - */ - template - basic_tensor (const tensor_expression_type &expr) - : basic_tensor( detail::retrieve_extents(expr), container_tag{} ) - { - static_assert( detail::has_tensor_types>::value, - "Error in boost::numeric::ublas::basic_tensor: expression does not contain a basic_tensor. cannot retrieve shape."); - detail::eval( *this, expr ); - } - - /** @brief Constructs a basic_tensor with a matrix expression - * - * @code basic_tensor A = B + 3 * C; @endcode - * - * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. - * @note extents are automatically extracted from the temporary matrix - * - * @param expr matrix expression - */ - template - basic_tensor (const matrix_expression_type &expr) - : basic_tensor( matrix_type ( expr ) ) - { - } - - /** @brief Constructs a basic_tensor with a vector expression - * - * @code basic_tensor A = b + 3 * b; @endcode - * - * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. - * @note extents are automatically extracted from the temporary matrix - * - * @param expr vector expression - */ - template - basic_tensor (const vector_expression_type &expr) - : basic_tensor( vector_type ( expr ) ) - { - } - - - /** @brief Constructs a basic_tensor from another basic_tensor - * - * @param v basic_tensor to be copied. - */ - inline - basic_tensor (const basic_tensor &v) - : tensor_expression_type() - , extents_ (v.extents_) - , strides_ (v.strides_) - , data_ (v.data_ ) - {} - - - - /** @brief Constructs a basic_tensor from another basic_tensor - * - * @param v basic_tensor to be moved. - */ - inline - basic_tensor (basic_tensor &&v) - : tensor_expression_type() //tensor_container () - , extents_ (std::move(v.extents_)) - , strides_ (std::move(v.strides_)) - , data_ (std::move(v.data_ )) - {} - - /** @brief Evaluates the tensor_expression and assigns the results to the basic_tensor - * - * @code A = B + C * 2; @endcode - * - * @note rank and dimension extents of the tensors in the expressions must conform with this basic_tensor. - * - * @param expr expression that is evaluated. - */ - template - basic_tensor &operator = (const tensor_expression_type &expr) - { - detail::eval(*this, expr); - return *this; - } - - basic_tensor& operator=(basic_tensor other) - { - swap (*this, other); - return *this; - } - - basic_tensor& operator=(const_reference v) - { - std::fill(this->begin(), this->end(), v); - return *this; - } - - /** @brief Returns true if the basic_tensor is empty (\c size==0) */ - inline - bool empty () const { - return this->data_.empty(); - } - - - /** @brief Returns the size of the basic_tensor */ - inline - size_type size () const { - return this->data_.size (); - } - - /** @brief Returns the size of the basic_tensor */ - inline - size_type size (size_type r) const { - return this->extents_.at(r); - } - - /** @brief Returns the number of dimensions/modes of the basic_tensor */ - inline - size_type rank () const { - return this->extents_.size(); - } - - /** @brief Returns the number of dimensions/modes of the basic_tensor */ - inline - size_type order () const { - return this->extents_.size(); - } - - /** @brief Returns the strides of the basic_tensor */ - inline - strides_type const& strides () const { - return this->strides_; - } - - /** @brief Returns the extents of the basic_tensor */ - inline - extents_type const& extents () const { - return this->extents_; - } - - - /** @brief Returns a \c const reference to the container. */ - inline - const_pointer data () const { - return this->data_.data(); - } - - /** @brief Returns a \c const reference to the container. */ - inline - pointer data () { - return this->data_.data(); - } - - /** @brief Element access using a single index. - * - * @code auto a = A[i]; @endcode - * - * @param i zero-based index where 0 <= i < this->size() - */ - inline - const_reference operator [] (size_type i) const { - return this->data_[i]; - } - - /** @brief Element access using a single index. - * - * @code auto a = A[i]; @endcode - * - * @param i zero-based index where 0 <= i < this->size() - */ - inline - reference operator [] (size_type i) { - return this->data_[i]; - } - - /** @brief Element access using a multi-index or single-index. - * - * - * @code auto a = A.at(i,j,k); @endcode or - * @code auto a = A.at(i); @endcode - * - * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - inline - const_reference at (size_type i, size_types ... is) const { - if constexpr (sizeof...(is) == 0) - return this->data_[i]; - else - return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward(is)...)]; - } - - /** @brief Element access using a multi-index or single-index. - * - * - * @code A.at(i,j,k) = a; @endcode or - * @code A.at(i) = a; @endcode - * - * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - inline - reference at (size_type i, size_types ... is) { - if constexpr (sizeof...(is) == 0) - return this->data_[i]; - else{ - auto temp = detail::access<0ul>(size_type(0),this->strides_,i,std::forward(is)...); - return this->data_[temp]; - } - } - - /** @brief Element access using a single index. - * - * - * @code A(i) = a; @endcode - * - * @param i zero-based index where 0 <= i < this->size() - */ - inline - const_reference operator()(size_type i) const { - return this->data_[i]; - } - - - /** @brief Element access using a single index. - * - * @code A(i) = a; @endcode - * - * @param i zero-based index where 0 <= i < this->size() - */ - inline - reference operator()(size_type i){ - return this->data_[i]; - } - - /** @brief Generates a basic_tensor index for basic_tensor contraction - * - * - * @code auto Ai = A(_i,_j,k); @endcode - * - * @param i placeholder - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - inline - decltype(auto) operator() (index::index_type p, index_types ... ps) const - { - constexpr auto N = sizeof...(ps)+1; - if( N != this->rank() ) - throw std::runtime_error("Error in boost::numeric::ublas::operator(): size of provided index_types does not match with the rank."); - - return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward(ps)... ) ); - } - - /** @brief Reshapes the basic_tensor - * - * - * (1) @code A.reshape(extents{m,n,o}); @endcode or - * (2) @code A.reshape(extents{m,n,o},4); @endcode - * - * If the size of this smaller than the specified extents than - * default constructed (1) or specified (2) value is appended. - * - * @note rank of the basic_tensor might also change. - * - * @param e extents with which the basic_tensor is reshaped. - * @param v value which is appended if the basic_tensor is enlarged. - */ - inline - void reshape (extents_type const& e, value_type v = value_type{}) - { - static_assert(is_dynamic_v, - "Error in boost::numeric::ublas::basic_tensor: static extents cannot be reshaped"); - this->extents_ = e; - this->strides_ = strides_type(this->extents_); - - auto p = product(extents_); - if(p != this->size()) - this->data_.resize (p, v); - } - - friend void swap(basic_tensor& lhs, basic_tensor& rhs) { - std::swap(lhs.data_ , rhs.data_ ); - std::swap(lhs.extents_, rhs.extents_); - std::swap(lhs.strides_, rhs.strides_); - } - - - /// \brief return an iterator on the first element of the basic_tensor - inline - const_iterator begin () const { - return data_.begin (); - } - - /// \brief return an iterator on the first element of the basic_tensor - inline - const_iterator cbegin () const { - return data_.cbegin (); - } - - /// \brief return an iterator after the last element of the basic_tensor - inline - const_iterator end () const { - return data_.end(); - } - - /// \brief return an iterator after the last element of the basic_tensor - inline - const_iterator cend () const { - return data_.cend (); - } - - /// \brief Return an iterator on the first element of the basic_tensor - inline - iterator begin () { - return data_.begin(); - } - - /// \brief Return an iterator at the end of the basic_tensor - inline - iterator end () { - return data_.end(); - } - - /// \brief Return a const reverse iterator before the first element of the reversed basic_tensor (i.e. end() of normal basic_tensor) - inline - const_reverse_iterator rbegin () const { - return data_.rbegin(); - } - - /// \brief Return a const reverse iterator before the first element of the reversed basic_tensor (i.e. end() of normal basic_tensor) - inline - const_reverse_iterator crbegin () const { - return data_.crbegin(); - } - - /// \brief Return a const reverse iterator on the end of the reverse basic_tensor (i.e. first element of the normal basic_tensor) - inline - const_reverse_iterator rend () const { - return data_.rend(); - } - - /// \brief Return a const reverse iterator on the end of the reverse basic_tensor (i.e. first element of the normal basic_tensor) - inline - const_reverse_iterator crend () const { - return data_.crend(); - } - - /// \brief Return a const reverse iterator before the first element of the reversed basic_tensor (i.e. end() of normal basic_tensor) - inline - reverse_iterator rbegin () { - return data_.rbegin(); - } - - /// \brief Return a const reverse iterator on the end of the reverse basic_tensor (i.e. first element of the normal basic_tensor) - inline - reverse_iterator rend () { - return data_.rend(); - } - -protected: - - extents_type extents_; - strides_type strides_; - array_type data_; -}; - -}}} // namespaces - +#include +#include namespace boost::numeric::ublas{ - template - struct tensor_rebind,Ts...>{ - using type = tensor_rebind_t; - }; -} // namespace boost::numeric::ublas::detail + template + using dynamic_tensor = tensor_core< + tensor_engine< + extents<>, + Layout, + strides< extents<> >, + std::vector< ValueType, std::allocator > + > + >; + + template + using static_tensor = tensor_core< + tensor_engine< + ExtentsType, + Layout, + strides, + std::array< ValueType, product(ExtentsType{}) > + > + >; + + template + using fixed_rank_tensor = tensor_core< + tensor_engine< + extents, + Layout, + strides< extents >, + std::vector< ValueType, std::allocator > + > + >; + +} // namespace boost::numeric::ublas #endif diff --git a/include/boost/numeric/ublas/tensor/tensor_core.hpp b/include/boost/numeric/ublas/tensor/tensor_core.hpp new file mode 100644 index 000000000..609c9e15e --- /dev/null +++ b/include/boost/numeric/ublas/tensor/tensor_core.hpp @@ -0,0 +1,886 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +/// \file tensor_core.hpp Definition for the tensor template class + +#ifndef BOOST_UBLAS_TENSOR_CORE_IMPL_HPP +#define BOOST_UBLAS_TENSOR_CORE_IMPL_HPP + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost::numeric::ublas { + +template< class T > +class tensor_core: + public detail::tensor_expression< tensor_core,tensor_core > +{ + + using self_type = tensor_core; + +public: + using tensor_traits = T; + + template + using tensor_expression_type = detail::tensor_expression; + + template + using matrix_expression_type = matrix_expression; + + template + using vector_expression_type = vector_expression; + + using super_type = tensor_expression_type; + using storage_traits_type = typename tensor_traits::storage_traits_type; + + using array_type = typename storage_traits_type::array_type; + using layout_type = typename tensor_traits::layout_type; + + + using size_type = typename storage_traits_type::size_type; + using difference_type = typename storage_traits_type::difference_type; + using value_type = typename storage_traits_type::value_type; + + using reference = typename storage_traits_type::reference; + using const_reference = typename storage_traits_type::const_reference; + + using pointer = typename storage_traits_type::pointer; + using const_pointer = typename storage_traits_type::const_pointer; + + using iterator = typename storage_traits_type::iterator; + using const_iterator = typename storage_traits_type::const_iterator; + + using reverse_iterator = typename storage_traits_type::reverse_iterator; + using const_reverse_iterator = typename storage_traits_type::const_reverse_iterator; + + using tensor_temporary_type = self_type; + using storage_category = dense_tag; + using container_tag = typename storage_traits_type::container_tag; + using resizable_tag = typename storage_traits_type::resizable_tag; + + using extents_type = typename tensor_traits::extents_type; + using strides_type = typename tensor_traits::strides_type; + + using matrix_type = matrix >; + using vector_type = vector >; + + /** @brief Constructs a tensor_core. + * + * @note the tensor_core is empty. + * @note the tensor_core needs to reshaped for further use. + * + */ + inline + constexpr tensor_core () + { + if constexpr( is_static_v ){ + auto temp = tensor_core(extents_type{},resizable_tag{}); + swap(*this,temp); + } + } + + constexpr tensor_core( extents_type e, [[maybe_unused]] storage_resizable_container_tag t ) + : tensor_expression_type() + , extents_(std::move(e)) + , strides_(extents_) + , data_( product(extents_) ) + {} + + constexpr tensor_core( extents_type e, [[maybe_unused]] storage_static_container_tag t ) + : tensor_expression_type() + , extents_(std::move(e)) + , strides_(extents_) + { + if ( data_.size() < product(extents_) ){ + throw std::length_error("boost::numeric::ublas::tensor_core(extents_type const&, storage_static_container_tag): " + "size of requested storage exceeds the current container size" + ); + } + } + + /** @brief Constructs a tensor_core with an initializer list for dynamic_extents + * + * By default, its elements are initialized to 0. + * + * @code tensor_core A{4,2,3}; @endcode + * + * @param l initializer list for setting the dimension extents of the tensor_core + */ + template> + > + explicit inline + tensor_core (std::initializer_list l) + : tensor_core( std::move( extents_type( std::move(l) ) ), resizable_tag{} ) + {} + + /** @brief Constructs a tensor_core with a \c shape + * + * By default, its elements are initialized to 0. + * + * @code tensor_core A{extents{4,2,3}}; @endcode + * + * @param s initial tensor_core dimension extents + */ + template> + > + explicit inline + tensor_core (extents_type s) + : tensor_core( std::move(s), resizable_tag{} ) + {} + + /** @brief Constructs a tensor_core with a \c shape + * + * By default, its elements are initialized to 0. + * + * @code tensor_core A{extents{4,2,3}}; @endcode + * + * @param s initial tensor_core dimension extents + * @param i initial tensor_core with this value + */ + template> + > + explicit inline + tensor_core (extents_type s, value_type const& i) + : tensor_core( std::move(s), resizable_tag{} ) + { + std::fill(begin(),end(),i); + } + + /** @brief Constructs a tensor_core with a \c shape + * + * By default, its elements are initialized to 0. + * + * @code tensor_core A{}; @endcode + * + * @param i initial tensor_core with this value + */ + template> + > + explicit inline + tensor_core (value_type const& i) + : tensor_core() + { + std::fill(begin(),end(),i); + } + + /** @brief Constructs a tensor_core with a \c shape and initiates it with one-dimensional data + * + * @code tensor_core A{extents{4,2,3}, array }; @endcode + * + * + * @param s initial tensor_core dimension extents + * @param a container of \c array_type that is copied according to the storage layout + */ + template> + > + inline + tensor_core (extents_type s, const array_type &a) + : tensor_core( std::move(s), resizable_tag{} ) + { + if( size() != a.size() ){ + throw std::runtime_error("boost::numeric::ublas::tensor_core(extents_type,array_type): " + "array size mismatch with extents" + ); + } + std::copy(a.begin(),a.end(),begin()); + } + + /** @brief Constructs a tensor_core with a \c shape and initiates it with one-dimensional data + * + * @code tensor_core A{ array }; @endcode + * + * @param a container of \c array_type that is copied according to the storage layout + */ + template> + > + inline + tensor_core (const array_type &a) + : tensor_core() + { + if( size() != a.size() ){ + throw std::runtime_error("boost::numeric::ublas::tensor_core(extents_type,array_type): " + "array size mismatch with extents" + ); + } + std::copy(a.begin(),a.end(),begin()); + } + + + /** @brief Constructs a tensor_core with another tensor_core with a different layout + * + * @param other tensor_core with a different layout to be copied. + */ + template + tensor_core (const tensor_core &other) + : tensor_core( other.extents(), resizable_tag{} ) + { + copy(this->rank(), this->extents().data(), + this->data(), this->strides().data(), + other.data(), other.strides().data()); + + } + + + /** @brief Constructs a tensor_core with an tensor_core expression + * + * @code tensor_core A = B + 3 * C; @endcode + * + * @note type must be specified of tensor_core must be specified. + * @note dimension extents are extracted from tensors within the expression. + * + * @param expr tensor_core expression + * @param size tensor_core expression + */ + template + tensor_core (const detail::tensor_expression &expr) + : tensor_core( detail::retrieve_extents(expr), resizable_tag{} ) + { + static_assert(is_valid_tensor_v, + "boost::numeric::ublas::tensor_core(tensor_expression const&) : " + "other_tensor should be a valid tensor type" + ); + + static_assert(std::is_same_v, + "boost::numeric::ublas::tensor_core(tensor_expression const&) : " + "LHS and RHS should have the same value type" + ); + + detail::eval( *this, expr ); + } + + constexpr tensor_core( matrix_type const& v ) + : tensor_core() + { + if constexpr( is_dynamic_v< extents_type > ){ + auto temp = tensor_core(extents_type{v.size1(), v.size2()}); + swap(*this,temp); + } + + if constexpr( is_static_rank_v ){ + static_assert( extents_type::_size == 2ul, + "boost::numeric::ublas::tensor_core(const matrix &v)" + " : the rank of extents is not correct, it should be of the rank 2" + ); + }else{ + if( extents_.size() != 2ul ){ + throw std::runtime_error( + "boost::numeric::ublas::tensor_core(const matrix &v)" + " : the rank of extents is not correct, it should be of the rank 2" + ); + } + } + + + if( extents_[0] != v.size1() || extents_[1] != v.size2() ){ + throw std::runtime_error( + "boost::numeric::ublas::tensor_core(const matrix &v)" + " : please set the extents properly, the extents should contain the row and col of the matrix" + ); + } + + std::copy(v.data().begin(), v.data().end(), data_.begin()); + } + + constexpr tensor_core( matrix_type && v ) + : tensor_core() + { + if constexpr( is_dynamic_v< extents_type > ){ + auto temp = tensor_core(extents_type{v.size1(), v.size2()}); + swap(*this,temp); + } + + if constexpr( is_static_rank_v ){ + static_assert( extents_type::_size == 2ul, + "boost::numeric::ublas::tensor_core(matrix &&v)" + " : the rank of extents is not correct, it should be of the rank 2" + ); + }else{ + if( extents_.size() != 2ul ){ + throw std::runtime_error( + "boost::numeric::ublas::tensor_core(matrix &&v)" + " : the rank of extents is not correct, it should be of the rank 2" + ); + } + } + + if( extents_[0] != v.size1() || extents_[1] != v.size2() ){ + throw std::runtime_error( + "boost::numeric::ublas::tensor_core(matrix &&v)" + " : please set the extents properly, the extents should contain the row and col of the matrix" + ); + } + + std::move(v.data().begin(), v.data().end(),data_.begin()); + } + + constexpr tensor_core (const vector_type &v) + : tensor_core() + { + if constexpr( is_dynamic_v< extents_type > ){ + auto temp = tensor_core(extents_type{ v.size(), typename extents_type::value_type{1} }); + swap(*this,temp); + } + + if constexpr( is_static_rank_v ){ + static_assert( extents_type::_size == 2ul, + "boost::numeric::ublas::tensor_core(const vector_type &v)" + " : the rank of extents is not correct, it should be of the rank 2" + ); + }else{ + if( extents_.size() != 2ul ){ + throw std::runtime_error( + "boost::numeric::ublas::tensor_core(const vector_type &v)" + " : the rank of extents is not correct, it should be of the rank 2" + ); + } + } + + if( extents_[0] != v.size() || extents_[1] != 1ul ){ + throw std::runtime_error( + "boost::numeric::ublas::tensor_core(const vector_type &v)" + " : please set the extents properly, the first extent should be the size of the vector and 1 for the second extent" + ); + } + + std::copy(v.data().begin(), v.data().end(), data_.begin()); + + } + + constexpr tensor_core (vector_type &&v) + : tensor_core() + { + if constexpr( is_dynamic_v< extents_type > ){ + auto temp = tensor_core(extents_type{ v.size(), typename extents_type::value_type{1} }); + swap(*this,temp); + } + + if constexpr( is_static_rank_v ){ + static_assert( extents_type::_size == 2ul, + "boost::numeric::ublas::tensor_core(vector_type &&v)" + " : the rank of extents is not correct, it should be of the rank 2" + ); + }else{ + if( extents_.size() != 2ul ){ + throw std::runtime_error( + "boost::numeric::ublas::tensor_core(vector_type &&v)" + " : the rank of extents is not correct, it should be of the rank 2" + ); + } + } + + if( extents_[0] != v.size() || extents_[1] != 1ul ){ + throw std::runtime_error( + "boost::numeric::ublas::tensor_core(vector_type &&v)" + " : please set the extents properly, the first extent should be the size of the vector and 1 for the second extent" + ); + } + + std::move(v.data().begin(), v.data().end(),data_.begin()); + + } + + /** @brief Constructs a tensor_core with a matrix expression + * + * @code tensor_core A = B + 3 * C; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr matrix expression + */ + template + tensor_core (const matrix_expression_type &expr) + : tensor_core( matrix_type ( expr ) ) + { + } + + /** @brief Constructs a tensor_core with a vector expression + * + * @code tensor_core A = b + 3 * b; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr vector expression + */ + template + tensor_core (const vector_expression_type &expr) + : tensor_core( vector_type ( expr ) ) + { + } + + + /** @brief Constructs a tensor_core from another tensor_core + * + * @param v tensor_core to be copied. + */ + inline + tensor_core (const tensor_core &v) + : tensor_expression_type() + , extents_ (v.extents_) + , strides_ (v.strides_) + , data_ (v.data_ ) + {} + + + + /** @brief Constructs a tensor_core from another tensor_core + * + * @param v tensor_core to be moved. + */ + inline + tensor_core (tensor_core &&v) noexcept + : tensor_expression_type() //tensor_container () + , extents_ (std::move(v.extents_)) + , strides_ (std::move(v.strides_)) + , data_ (std::move(v.data_ )) + {} + + + /** @brief Move assignsment operator + * + * @param v tensor_core to be moved. + */ + inline + tensor_core& operator=(tensor_core &&v) noexcept + { + swap(*this,v); + return *this; + } + + /// @brief Default destructor + ~tensor_core() = default; + + /** @brief Evaluates the tensor_expression and assigns the results to the tensor_core + * + * @code A = B + C * 2; @endcode + * + * @note rank and dimension extents of the tensors in the expressions must conform with this tensor_core. + * + * @param expr expression that is evaluated. + */ + template + tensor_core &operator = (const tensor_expression_type &expr) + { + detail::eval(*this, expr); + return *this; + } + + tensor_core& operator=(tensor_core const& other) + { + tensor_core temp(other); + swap (*this, temp); + return *this; + } + + constexpr tensor_core& operator=(const_reference v) + { + std::fill_n(this->begin(), this->size(), v); + return *this; + } + + /** @brief Returns true if the tensor_core is empty (\c size==0) */ + [[nodiscard]] inline + constexpr bool empty () const noexcept{ + return this->data_.empty(); + } + + /** @brief Returns the upper bound or max size of the tensor_core */ + [[nodiscard]] inline + constexpr size_type size() const noexcept{ + return this->data_.size(); + } + + /** @brief Returns the size of the tensor_core */ + [[nodiscard]] inline + constexpr size_type size (size_type r) const { + return this->extents_.at(r); + } + + /** @brief Returns the number of dimensions/modes of the tensor_core */ + [[nodiscard]] inline + constexpr size_type rank () const noexcept{ + return this->extents_.size(); + } + + /** @brief Returns the number of dimensions/modes of the tensor_core */ + [[nodiscard]] inline + constexpr size_type order () const noexcept{ + return this->extents_.size(); + } + + /** @brief Returns the strides of the tensor_core */ + [[nodiscard]] inline + constexpr strides_type const& strides () const noexcept{ + return this->strides_; + } + + /** @brief Returns the extents of the tensor_core */ + [[nodiscard]] inline + constexpr extents_type const& extents () const noexcept{ + return this->extents_; + } + + /** @brief Returns the strides of the tensor_core */ + [[nodiscard]] inline + constexpr strides_type& strides () noexcept{ + return this->strides_; + } + + /** @brief Returns the extents of the tensor_core */ + [[nodiscard]] inline + constexpr extents_type& extents () noexcept{ + return this->extents_; + } + + /** @brief Returns a \c const reference to the container. */ + [[nodiscard]] inline + constexpr const_pointer data () const noexcept{ + return this->data_.data(); + } + + /** @brief Returns a \c const reference to the container. */ + [[nodiscard]] inline + constexpr pointer data () noexcept{ + return this->data_.data(); + } + + /** @brief Returns a \c const reference to the underlying container. */ + [[nodiscard]] inline + constexpr array_type const& base () const noexcept{ + return data_; + } + + /** @brief Returns a reference to the underlying container. */ + [[nodiscard]] inline + constexpr array_type& base () noexcept{ + return data_; + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + [[nodiscard]] inline + constexpr const_reference operator [] (size_type i) const { + return this->data_[i]; + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + [[nodiscard]] inline + constexpr reference operator [] (size_type i) { + return this->data_[i]; + } + + /** @brief Element access using a multi-index or single-index with bound checking + * and it throws the exception. + * + * @code auto a = A.at(i,j,k); @endcode or + * @code auto a = A.at(i); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline + constexpr const_reference at (size_type i, Indices ... is) const { + if constexpr( sizeof...(is) == 0ul ){ + return this->data_.at(i); + }else{ + if( sizeof...(is) + 1 > strides_.size() ){ + throw std::runtime_error("Error in boost::numeric::ublas::at(size_type, Indices...): " + "number of variadic argument exceeds the strides size." + ); + } + static_assert( + std::conjunction_v< std::is_convertible... >, + "boost::numeric::ublas::tensor_core::at(size_type,Indices...) : " + "provided variadic argument is not convertible to tensor size_type" + ); + using strides_value_type = typename strides_type::value_type; + auto const idx = detail::access(this->strides_, + static_cast(i), + static_cast(is)... + ); + return this->data_.at(idx); + } + } + + /** @brief Element access using a multi-index or single-index with bound checking + * and it throws the exception. + * + * + * @code A.at(i,j,k) = a; @endcode or + * @code A.at(i) = a; @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline + constexpr reference at (size_type i, Indices ... is) { + if constexpr( sizeof...(is) == 0ul ){ + return this->data_.at(i); + }else{ + if( sizeof...(is) + 1 > strides_.size() ){ + throw std::runtime_error("Error in boost::numeric::ublas::at(size_type, Indices...): " + "number of variadic argument exceeds the strides size." + ); + } + static_assert( + std::conjunction_v< std::is_convertible... >, + "boost::numeric::ublas::tensor_core::at(size_type,Indices...) : " + "provided variadic argument is not convertible to tensor size_type" + ); + using strides_value_type = typename strides_type::value_type; + auto const idx = detail::access(this->strides_, + static_cast(i), + static_cast(is)... + ); + return this->data_.at(idx); + } + } + + /** @brief Element access using a multi-index or single-index with no bound checking + * and it does not throw. + * + * + * @code auto a = A(i,j,k); @endcode or + * @code auto a = A(i); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline + constexpr const_reference operator() (size_type i, Indices ... is) const { + if constexpr( sizeof...(is) == 0ul ){ + return this->data_[i]; + }else{ + static_assert( + std::conjunction_v< std::is_convertible... >, + "boost::numeric::ublas::tensor_core::operator()(size_type,Indices...) : " + "provided variadic argument is not convertible to tensor size_type" + ); + using strides_value_type = typename strides_type::value_type; + auto const idx = detail::access(this->strides_, + static_cast(i), + static_cast(is)... + ); + return this->data_[idx]; + } + } + + /** @brief Element access using a multi-index or single-index with no bound checking + * and it does not throw. + * + * + * @code A(i,j,k) = a; @endcode or + * @code A(i) = a; @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline + constexpr reference operator() (size_type i, Indices ... is) { + if constexpr( sizeof...(is) == 0ul ){ + return this->data_[i]; + }else{ + static_assert( + std::conjunction_v< std::is_convertible... >, + "boost::numeric::ublas::tensor_core::operator()(size_type,Indices...) : " + "provided variadic argument is not convertible to tensor size_type" + ); + using strides_value_type = typename strides_type::value_type; + auto const idx = detail::access(this->strides_, + static_cast(i), + static_cast(is)... + ); + return this->data_[idx]; + } + } + + /** @brief Generates a tensor_core index for tensor_core contraction + * + * + * @code auto Ai = A(_i,_j,k); @endcode + * + * @param i placeholder + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline + constexpr decltype(auto) operator() (index::index_type p, index_types ... ps) const + { + constexpr auto N = sizeof...(ps)+1; + if( N != this->rank() ) + throw std::runtime_error("Error in boost::numeric::ublas::operator(index::index_type,index_types&&): " + "size of provided index_types does not match with the rank." + ); + + return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward(ps)... ) ); + } + + + /** @brief Reshapes the basic_tensor + * + * + * (1) @code A.reshape(extents{m,n,o}); @endcode or + * (2) @code A.reshape(extents{m,n,o},4); @endcode + * + * If the size of this smaller than the specified extents than + * default constructed (1) or specified (2) value is appended. + * + * @note rank of the basic_tensor might also change. + * + * @param e extents with which the basic_tensor is reshaped. + * @param v value which is appended if the basic_tensor is enlarged. + */ + inline + void reshape (extents_type const& e, value_type v = value_type{}) + { + static_assert(is_dynamic_v && is_dynamic_v, + "Error in boost::numeric::ublas::basic_tensor::reshape(extents_type const&,value_type) : " + "static extents or static strides cannot used inside reshape function" + ); + + this->extents_ = e; + this->strides_ = strides_type(this->extents_); + + auto p = product(extents_); + if constexpr( !std::is_same_v< resizable_tag, storage_resizable_container_tag > ){ + if( p != this->size() ){ + throw std::runtime_error( + "boost::numeric::ublas::basic_tensor::reshape(extents_type const&,value_type) : " + "cannot resize the non-resizable container, change the extents such a way that the product does not change" + ); + } + }else{ + if(p != this->size()) + this->data_.resize (p, v); + } + } + + friend void swap(tensor_core& lhs, tensor_core& rhs){ + std::swap(lhs.data_ , rhs.data_ ); + std::swap(lhs.extents_, rhs.extents_); + std::swap(lhs.strides_, rhs.strides_); + } + + + /// \brief return an iterator on the first element of the tensor_core + [[nodiscard]] inline + constexpr const_iterator begin () const noexcept{ + return data_.begin (); + } + + /// \brief return an iterator on the first element of the tensor_core + [[nodiscard]] inline + constexpr const_iterator cbegin () const noexcept{ + return data_.cbegin (); + } + + /// \brief return an iterator after the last element of the tensor_core + [[nodiscard]] inline + constexpr const_iterator end () const noexcept{ + return data_.end(); + } + + /// \brief return an iterator after the last element of the tensor_core + [[nodiscard]] inline + constexpr const_iterator cend () const noexcept{ + return data_.cend (); + } + + /// \brief Return an iterator on the first element of the tensor_core + [[nodiscard]] inline + constexpr iterator begin () noexcept{ + return data_.begin(); + } + + /// \brief Return an iterator at the end of the tensor_core + [[nodiscard]] inline + constexpr iterator end () noexcept{ + return data_.end(); + } + + /// \brief Return a const reverse iterator before the first element of the reversed tensor_core (i.e. end() of normal tensor_core) + [[nodiscard]] inline + constexpr const_reverse_iterator rbegin () const noexcept{ + return data_.rbegin(); + } + + /// \brief Return a const reverse iterator before the first element of the reversed tensor_core (i.e. end() of normal tensor_core) + [[nodiscard]] inline + constexpr const_reverse_iterator crbegin () const noexcept{ + return data_.crbegin(); + } + + /// \brief Return a const reverse iterator on the end of the reverse tensor_core (i.e. first element of the normal tensor_core) + [[nodiscard]] inline + constexpr const_reverse_iterator rend () const noexcept{ + return data_.rend(); + } + + /// \brief Return a const reverse iterator on the end of the reverse tensor_core (i.e. first element of the normal tensor_core) + [[nodiscard]] inline + constexpr const_reverse_iterator crend () const noexcept{ + return data_.crend(); + } + + /// \brief Return a const reverse iterator before the first element of the reversed tensor_core (i.e. end() of normal tensor_core) + [[nodiscard]] inline + constexpr reverse_iterator rbegin () noexcept{ + return data_.rbegin(); + } + + /// \brief Return a const reverse iterator on the end of the reverse tensor_core (i.e. first element of the normal tensor_core) + [[nodiscard]] inline + constexpr reverse_iterator rend () noexcept{ + return data_.rend(); + } + +private: + + extents_type extents_; + strides_type strides_; + array_type data_; +}; + +} // namespaces + +#endif diff --git a/include/boost/numeric/ublas/tensor/tensor_engine.hpp b/include/boost/numeric/ublas/tensor/tensor_engine.hpp new file mode 100644 index 000000000..8f9293e05 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/tensor_engine.hpp @@ -0,0 +1,50 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_ENGINE_IMPL_HPP +#define BOOST_UBLAS_TENSOR_ENGINE_IMPL_HPP + +#include + +namespace boost::numeric::ublas{ + + template + struct tensor_engine; + + template + struct tensor_engine{ + using extents_type = ExtentsType; + + static_assert(is_extents_v, + "boost::numeric::ublas::tensor_engine : please provide valid tensor extents type" + ); + + using layout_type = LayoutType; + using strides_type = typename StrideType::template type; + + static_assert(is_strides_v, + "boost::numeric::ublas::tensor_engine : please provide valid tensor layout type" + ); + + using storage_traits_type = storage_traits; + + }; + + template + struct tensor_engine + : tensor_engine< ExtentsType, LayoutType, strides, StorageType > + {}; + +} // namespace boost::numeric::ublas + + +#endif diff --git a/include/boost/numeric/ublas/tensor/detail/basic_type_traits.hpp b/include/boost/numeric/ublas/tensor/traits/basic_type_traits.hpp similarity index 95% rename from include/boost/numeric/ublas/tensor/detail/basic_type_traits.hpp rename to include/boost/numeric/ublas/tensor/traits/basic_type_traits.hpp index eead93a0c..7d75800ba 100644 --- a/include/boost/numeric/ublas/tensor/detail/basic_type_traits.hpp +++ b/include/boost/numeric/ublas/tensor/traits/basic_type_traits.hpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef BOOST_UBLAS_TENSOR_BASIC_TYPE_TRAITS_HPP @@ -60,6 +60,6 @@ struct is_static_rank : std::false_type {}; template inline static constexpr bool const is_static_rank_v = is_static_rank::value; -} // namespace boost::numeric::ublas::detail +} // namespace boost::numeric::ublas #endif diff --git a/include/boost/numeric/ublas/tensor/detail/storage_traits.hpp b/include/boost/numeric/ublas/tensor/traits/storage_traits.hpp similarity index 61% rename from include/boost/numeric/ublas/tensor/detail/storage_traits.hpp rename to include/boost/numeric/ublas/tensor/traits/storage_traits.hpp index 1b209e27c..4e5619966 100644 --- a/include/boost/numeric/ublas/tensor/detail/storage_traits.hpp +++ b/include/boost/numeric/ublas/tensor/traits/storage_traits.hpp @@ -11,11 +11,12 @@ // -#ifndef _BOOST_STORAGE_TRAITS_HPP_ -#define _BOOST_STORAGE_TRAITS_HPP_ +#ifndef BOOST_UBLAS_TRAITS_STORAGE_HPP +#define BOOST_UBLAS_TRAITS_STORAGE_HPP #include #include +#include namespace boost { namespace numeric { @@ -47,6 +48,9 @@ struct storage_traits> using reverse_iterator = typename array_type::reverse_iterator; using const_reverse_iterator = typename array_type::const_reverse_iterator; + using container_tag = storage_seq_container_tag; + using resizable_tag = storage_resizable_container_tag; + template using rebind = std::vector::template rebind_alloc>; }; @@ -73,13 +77,50 @@ struct storage_traits> using reverse_iterator = typename array_type::reverse_iterator; using const_reverse_iterator = typename array_type::const_reverse_iterator; + using container_tag = storage_seq_container_tag; + using resizable_tag = storage_static_container_tag; + template using rebind = std::array; + + template + using rebind_size = std::array; }; } // ublas } // numeric } // boost - -#endif // _BOOST_STORAGE_TRAITS_HPP_ +namespace boost::numeric::ublas +{ + namespace detail{ + template + struct rebind_storage_size_helper{ + using type = A; + }; + + template + struct rebind_storage_size_helper, A, storage_static_container_tag>{ + using type = typename storage_traits::template rebind_size< E0 * (Es * ...) >; + }; + + template + struct rebind_storage_size_helper, A, storage_static_container_tag>{ + using type = typename storage_traits::template rebind_size< 0 >; + }; + } + + template + struct rebind_storage_size + : detail::rebind_storage_size_helper::resizable_tag + > + {}; + + template + using rebind_storage_size_t = typename rebind_storage_size::type; + +} // namespace boost::numeric::ublas + + +#endif // BOOST_UBLAS_TRAITS_STORAGE_HPP diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_extents.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_extents.hpp similarity index 90% rename from include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_extents.hpp rename to include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_extents.hpp index 745659903..54a11a471 100644 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_extents.hpp +++ b/include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_extents.hpp @@ -7,13 +7,13 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_EXTENTS_HPP #define BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_EXTENTS_HPP -#include +#include namespace boost::numeric::ublas{ diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_strides.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_strides.hpp similarity index 66% rename from include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_strides.hpp rename to include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_strides.hpp index 5a9a13174..0eaf8ff9e 100644 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_dynamic_strides.hpp +++ b/include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_strides.hpp @@ -7,13 +7,13 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_STRIDES_HPP #define BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_STRIDES_HPP -#include +#include namespace boost::numeric::ublas{ @@ -35,23 +35,12 @@ namespace boost::numeric::ublas{ template struct is_dynamic_rank< basic_strides > : std::true_type {}; - namespace detail{ - - /** @brief Partial Specialization of strides for basic_extents - * - * - * @tparam Layout either first_order or last_order - * - * @tparam T extents type - * - */ - template - struct strides_impl, Layout> - { - using type = basic_strides; - }; - - } // detail + template + struct strides> + { + template + using type = basic_strides; + }; } // namespace boost::numeric::ublas diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_extents.hpp similarity index 67% rename from include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp rename to include/boost/numeric/ublas/tensor/traits/type_traits_extents.hpp index f7fc1927e..14ed34870 100644 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp +++ b/include/boost/numeric/ublas/tensor/traits/type_traits_extents.hpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_EXTENTS_HPP @@ -15,7 +15,7 @@ namespace boost::numeric::ublas { -// checks if type is extents or not +/// @brief checks if the type is tensor extents or not template struct is_extents : std::false_type {}; @@ -30,12 +30,12 @@ namespace detail{ } // detail template -using dynamic_extents = typename detail::dynamic_extents_impl::type; +using extents = typename detail::dynamic_extents_impl::type; -} // namespace boost::numeric::ublas::detail +} // namespace boost::numeric::ublas -#include -#include -#include +#include +#include +#include #endif diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_extents.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_extents.hpp similarity index 86% rename from include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_extents.hpp rename to include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_extents.hpp index e299f5d81..f1cbfba38 100644 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_extents.hpp +++ b/include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_extents.hpp @@ -7,17 +7,17 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_EXTENTS_HPP #define BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_EXTENTS_HPP -#include +#include namespace boost::numeric::ublas{ -template struct basic_fixed_rank_extents; +template class basic_fixed_rank_extents; } // namespace boost::numeric::ublas diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_strides.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_strides.hpp similarity index 63% rename from include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_strides.hpp rename to include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_strides.hpp index bb56052e4..2e378a269 100644 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_strides.hpp +++ b/include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_strides.hpp @@ -7,17 +7,17 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_STRIDES_HPP #define BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_STRIDES_HPP -#include +#include namespace boost::numeric::ublas{ -template struct basic_fixed_rank_extents; +template class basic_fixed_rank_extents; template class basic_fixed_rank_strides; @@ -34,23 +34,12 @@ namespace boost::numeric::ublas{ template struct is_static_rank< basic_fixed_rank_strides > : std::true_type {}; - namespace detail{ - - /** @brief Partial Specialization of strides for basic_fixed_rank_strides - * - * - * @tparam Layout either first_order or last_order - * - * @tparam T extents type - * - */ - template - struct strides_impl, Layout> - { - using type = basic_fixed_rank_strides; - }; - - } // detail + template + struct strides> + { + template + using type = basic_fixed_rank_strides; + }; } // namespace boost::numeric::ublas diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_static_extents.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_static_extents.hpp similarity index 83% rename from include/boost/numeric/ublas/tensor/detail/type_traits_static_extents.hpp rename to include/boost/numeric/ublas/tensor/traits/type_traits_static_extents.hpp index 54b13ae08..19662f0ae 100644 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_static_extents.hpp +++ b/include/boost/numeric/ublas/tensor/traits/type_traits_static_extents.hpp @@ -7,17 +7,17 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_EXTENTS_HPP #define BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_EXTENTS_HPP -#include +#include namespace boost::numeric::ublas{ -template struct basic_static_extents; +template class basic_static_extents; } // namespace boost::numeric::ublas diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_static_strides.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_static_strides.hpp similarity index 64% rename from include/boost/numeric/ublas/tensor/detail/type_traits_static_strides.hpp rename to include/boost/numeric/ublas/tensor/traits/type_traits_static_strides.hpp index bf8ce0604..47137287b 100644 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_static_strides.hpp +++ b/include/boost/numeric/ublas/tensor/traits/type_traits_static_strides.hpp @@ -7,19 +7,19 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_STRIDES_HPP #define BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_STRIDES_HPP -#include +#include namespace boost::numeric::ublas{ -template struct basic_static_extents; +template class basic_static_extents; -template struct basic_static_strides; +template class basic_static_strides; } // namespace boost::numeric::ublas @@ -34,25 +34,12 @@ namespace boost::numeric::ublas{ template struct is_static_rank< basic_static_strides< basic_static_extents, L > > : std::true_type {}; - namespace detail{ - - /** @brief Partial Specialization of strides for basic_static_extents - * - * - * @tparam Layout either first_order or last_order - * - * @tparam R rank of extents - * - * @tparam Extents parameter pack of extents - * - */ - template - struct strides_impl, Layout> - { + template + struct strides> + { + template using type = basic_static_strides, Layout>; - }; - - } // detail + }; } // namespace boost::numeric::ublas diff --git a/include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_strides.hpp similarity index 67% rename from include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp rename to include/boost/numeric/ublas/tensor/traits/type_traits_strides.hpp index 1b7c1381f..f31fb67a9 100644 --- a/include/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp +++ b/include/boost/numeric/ublas/tensor/traits/type_traits_strides.hpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_STRIDES_HPP @@ -15,16 +15,15 @@ namespace boost::numeric::ublas { - // checks if type is strides or not + /// @brief checks if the type is tensor strides or not template struct is_strides : std::false_type {}; template inline static constexpr bool const is_strides_v = is_strides::value; - namespace detail{ - template struct strides_impl; - } // detail + template + struct strides; /** @brief type alias of result of strides::type * @@ -34,12 +33,12 @@ namespace boost::numeric::ublas { * */ template - using strides_t = typename detail::strides_impl::type; + using strides_t = typename strides::template type; -} // namespace boost::numeric::ublas::detail +} // namespace boost::numeric::ublas -#include -#include -#include +#include +#include +#include #endif diff --git a/include/boost/numeric/ublas/tensor/traits/type_traits_tensor.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_tensor.hpp new file mode 100644 index 000000000..b2bb161cc --- /dev/null +++ b/include/boost/numeric/ublas/tensor/traits/type_traits_tensor.hpp @@ -0,0 +1,41 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_TENSOR_HPP +#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_TENSOR_HPP + +#include +#include +#include + +namespace boost::numeric::ublas{ + + template class tensor_core; + +} // namespace boost::numeric::ublas + + +namespace boost::numeric::ublas { + + /// @brief Checks if the type is valid tensor + template + struct is_valid_tensor: std::false_type{}; + + template + struct is_valid_tensor< tensor_core >: std::true_type{}; + + template + inline static constexpr bool is_valid_tensor_v = is_valid_tensor::value; + +} // namespace boost::numeric::ublas + +#endif diff --git a/include/boost/numeric/ublas/tensor/type_traits.hpp b/include/boost/numeric/ublas/tensor/type_traits.hpp index 3a24b3845..cf1b865c7 100644 --- a/include/boost/numeric/ublas/tensor/type_traits.hpp +++ b/include/boost/numeric/ublas/tensor/type_traits.hpp @@ -7,16 +7,16 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_HPP #define BOOST_UBLAS_TENSOR_TYPE_TRAITS_HPP -#include -#include +#include +#include -#include -#include +#include +#include #endif diff --git a/test/tensor/Jamfile b/test/tensor/Jamfile index 8264a6bc1..8409cfc63 100644 --- a/test/tensor/Jamfile +++ b/test/tensor/Jamfile @@ -54,7 +54,6 @@ test-suite boost-ublas-tensor-test test_static_operators_comparison.cpp test_static_expression_evaluation.cpp test_static_tensor_matrix_vector.cpp - test_static_functions.cpp unit_test_framework ] [ run test_fixed_rank_tensor.cpp diff --git a/test/tensor/test_algorithms.cpp b/test/tensor/test_algorithms.cpp index b6dcbd105..5a11a9c3a 100644 --- a/test/tensor/test_algorithms.cpp +++ b/test/tensor/test_algorithms.cpp @@ -31,12 +31,12 @@ BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms, // BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms) -using test_types = zip>::with_t; +using test_types = zip>::with_t; using test_types2 = std::tuple>; struct fixture { - using extents_type = boost::numeric::ublas::dynamic_extents<>; + using extents_type = boost::numeric::ublas::extents<>; fixture() : extents { extents_type{1,1}, // 1 @@ -69,9 +69,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_type auto b = vector_type(product(n)); auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wb = ublas::strides_t,ublas::last_order> (n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); + auto wb = ublas::strides_t,ublas::layout::last_order> (n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); auto v = value_type{}; for(auto i = 0ul; i < a.size(); ++i, v+=1){ @@ -84,7 +84,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_type for(auto i = 1ul; i < c.size(); ++i) BOOST_CHECK_EQUAL( c[i], a[i] ); - using size_type = typename ublas::strides_t,ublas::first_order>::value_type; + using size_type = typename ublas::strides_t,ublas::layout::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::runtime_error ); BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), p0, b.data(), wb.data() ), std::runtime_error ); @@ -96,16 +96,16 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_type // special case rank == 0 { - auto n = ublas::dynamic_extents<>{}; + auto n = ublas::extents<>{}; auto a = vector_type(product(n)); auto b = vector_type(product(n)); auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wb = ublas::strides_t,ublas::last_order> (n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); + auto wb = ublas::strides_t,ublas::layout::last_order> (n); + auto wc = ublas::strides_t,ublas::layout::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() ); @@ -134,8 +134,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, value_type* a = nullptr; auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); @@ -146,8 +146,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, value_type* a = nullptr; value_type* c = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); @@ -158,8 +158,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, auto a = vector_type(product(n)); value_type* c = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c, wc.data(), a.data(), wa.data() ), std::runtime_error ); @@ -171,7 +171,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, auto c = vector_type(product(n)); size_t* wa = nullptr; - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); @@ -183,7 +183,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, auto c = vector_type(product(n)); size_t* wc = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); @@ -195,8 +195,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, auto c = vector_type(product(n)); size_t* m = nullptr; - auto wc = ublas::strides_t,ublas::first_order>(n); - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::copy( n.size(), m, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); @@ -218,9 +218,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform, value, test auto b = vector_type(product(n)); auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wb = ublas::strides_t,ublas::last_order> (n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); + auto wb = ublas::strides_t,ublas::layout::last_order> (n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); auto v = value_type{}; for(auto i = 0ul; i < a.size(); ++i, v+=1){ @@ -230,7 +230,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform, value, test 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);} ); - using size_type = typename ublas::strides_t,ublas::first_order>::value_type; + using size_type = typename ublas::strides_t,ublas::layout::first_order>::value_type; size_type zero = 0; ublas::transform(zero, n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a + value_type(1);} ); @@ -262,8 +262,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform_exceptions, v value_type* a = nullptr; auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); @@ -274,8 +274,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform_exceptions, v value_type* a = nullptr; value_type* c = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c, wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); @@ -286,8 +286,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform_exceptions, v auto a = vector_type(product(n)); value_type* c = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c, wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); @@ -299,7 +299,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform_exceptions, v auto c = vector_type(product(n)); size_t* wa = nullptr; - auto wc = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc.data(), a.data(), wa, [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); @@ -311,7 +311,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform_exceptions, v auto c = vector_type(product(n)); size_t* wc = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); @@ -323,8 +323,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform_exceptions, v auto c = vector_type(product(n)); size_t* m = nullptr; - auto wc = ublas::strides_t,ublas::first_order>(n); - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wc = ublas::strides_t,ublas::layout::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); BOOST_REQUIRE_THROW( ublas::transform( n.size(), m, c.data(), wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); @@ -346,9 +346,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, tes // auto b = vector_type(product(n)); // auto c = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); - // auto wb = ublas::strides_t,ublas::last_order> (n); - // auto wc = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); + // auto wb = ublas::strides_t,ublas::layout::last_order> (n); + // auto wc = ublas::strides_t,ublas::layout::first_order>(n); auto v = value_type{}; for(auto i = 0ul; i < a.size(); ++i, v+=value_type(1)){ @@ -359,16 +359,16 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, tes BOOST_CHECK_EQUAL( acc, value_type( static_cast< inner_type_t >( s*(s+1) / 2 ) ) ); - using size_type = typename ublas::strides_t,ublas::first_order>::value_type; + using size_type = typename ublas::strides_t,ublas::layout::first_order>::value_type; size_type zero = 0; - ublas::accumulate(zero, n.data(), a.data(), wa.data(),v); + (void)ublas::accumulate(zero, n.data(), a.data(), wa.data(),v); value_type* c0 = nullptr; size_type const*const p0 = nullptr; - BOOST_CHECK_THROW(ublas::accumulate( n.size(), n.data(), c0, wa.data(), v), std::runtime_error); - BOOST_CHECK_THROW(ublas::accumulate( n.size(), n.data(), a.data(), p0, v), std::runtime_error); - BOOST_CHECK_THROW(ublas::accumulate( n.size(), p0, a.data(), wa.data(), v), std::runtime_error); + BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), n.data(), c0, wa.data(), v), std::runtime_error); + BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), n.data(), a.data(), p0, v), std::runtime_error); + BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), p0, a.data(), wa.data(), v), std::runtime_error); auto acc2 = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v, @@ -376,11 +376,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, tes BOOST_CHECK_EQUAL( acc2, value_type( static_cast< inner_type_t >( s*(s+1) / 2 ) ) ); - ublas::accumulate(zero, n.data(), a.data(), wa.data(), v, [](auto const& l, auto const& r){return l + r; }); + (void)ublas::accumulate(zero, n.data(), a.data(), wa.data(), v, [](auto const& l, auto const& r){return l + r; }); - BOOST_CHECK_THROW(ublas::accumulate( n.size(), n.data(), c0, wa.data(), v,[](auto const& l, auto const& r){return l + r; }), std::runtime_error); - BOOST_CHECK_THROW(ublas::accumulate( n.size(), n.data(), a.data(), p0, v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); - BOOST_CHECK_THROW(ublas::accumulate( n.size(), p0, a.data(), wa.data(),v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); + BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), n.data(), c0, wa.data(), v,[](auto const& l, auto const& r){return l + r; }), std::runtime_error); + BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), n.data(), a.data(), p0, v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); + BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), p0, a.data(), wa.data(),v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); } } @@ -396,9 +396,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, value_type* a = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); - BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0} ), std::runtime_error ); + BOOST_REQUIRE_THROW( (void)ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0} ), std::runtime_error ); } @@ -406,9 +406,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, value_type* a = nullptr; - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); - BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0},[](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); + BOOST_REQUIRE_THROW( (void)ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0},[](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); } @@ -416,7 +416,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, auto a = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); size_t p = 0u; BOOST_CHECK_EQUAL ( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0} ), value_type{0} ); @@ -426,7 +426,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, auto a = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); size_t p = 0u; BOOST_CHECK_EQUAL( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), value_type{0} ); @@ -438,7 +438,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, size_t* wa = nullptr; - BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), n.data(), a.data(), wa, value_type{0} ), std::runtime_error ); + BOOST_REQUIRE_THROW( (void)ublas::accumulate( n.size(), n.data(), a.data(), wa, value_type{0} ), std::runtime_error ); } @@ -446,11 +446,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, auto a = vector_type(product(n)); - auto wa = ublas::strides_t,ublas::first_order>(n); + auto wa = ublas::strides_t,ublas::layout::first_order>(n); size_t* m = nullptr; - BOOST_REQUIRE_THROW( ublas::accumulate( n.size(), m, a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); + BOOST_REQUIRE_THROW( (void)ublas::accumulate( n.size(), m, a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); } @@ -484,7 +484,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans, value, test_typ using value_type = typename value::first_type; using layout_type = typename value::second_type; using vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; + using extents_type = ublas::extents<>; using strides_type = ublas::strides_t; using size_type = typename extents_type::value_type; using permutation_type = std::vector; @@ -568,7 +568,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans_exceptions, value using value_type = typename value::first_type; using layout_type = typename value::second_type; using vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; + using extents_type = ublas::extents<>; using strides_type = ublas::strides_t; using size_type = typename extents_type::value_type; using permutation_type = std::vector; diff --git a/test/tensor/test_einstein_notation.cpp b/test/tensor/test_einstein_notation.cpp index f8508f08c..0abda5b96 100644 --- a/test/tensor/test_einstein_notation.cpp +++ b/test/tensor/test_einstein_notation.cpp @@ -23,9 +23,9 @@ BOOST_AUTO_TEST_SUITE ( test_einstein_notation, * boost::unit_test::depends_on("test_multi_index") ) -using test_types = zip>::with_t; +using test_types = zip>::with_t; -//using test_types = zip::with_t; +//using test_types = zip::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_einstein_multiplication, value, test_types ) { diff --git a/test/tensor/test_expression.cpp b/test/tensor/test_expression.cpp index 39cb84c46..64ce969df 100644 --- a/test/tensor/test_expression.cpp +++ b/test/tensor/test_expression.cpp @@ -13,7 +13,7 @@ #include -#include +#include #include #include "utility.hpp" @@ -22,12 +22,12 @@ -using test_types = zip>::with_t; +using test_types = zip>::with_t; struct fixture { - using extents_type = boost::numeric::ublas::dynamic_extents<>; + using extents_type = boost::numeric::ublas::extents<>; fixture() : extents { extents_type{}, // 0 @@ -58,8 +58,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_access, value, test_ty using value_type = typename value::first_type; using layout_type = typename value::second_type; using tensor_type = ublas::dynamic_tensor; - using basic_tensor_type = typename tensor_type::super_type; - using tensor_expression_type = typename basic_tensor_type::super_type; + using tensor_expression_type = typename tensor_type::super_type; for(auto const& e : extents) { @@ -84,7 +83,6 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_expression, value, test_typ using value_type = typename value::first_type; using layout_type = typename value::second_type; using tensor_type = ublas::dynamic_tensor; - using basic_tensor_type = typename tensor_type::super_type; auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); @@ -94,23 +92,23 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_expression, value, test_typ auto v = value_type{}; for(auto& tt: t) { tt = v; v+=value_type{1}; } - const auto uexpr = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + const auto uexpr = ublas::detail::make_unary_tensor_expression( 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( uexpr, uplus1 ); + auto uexpr_uexpr = ublas::detail::make_unary_tensor_expression( 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) >, basic_tensor_type > ) ); + 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) >, basic_tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_uexpr_e_e) >, tensor_type > ) ); } @@ -123,7 +121,6 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_expression, value, test_ty using value_type = typename value::first_type; using layout_type = typename value::second_type; using tensor_type = ublas::dynamic_tensor; - using basic_tensor_type = typename tensor_type::super_type; auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); auto uplus2 = std::bind( std::plus{}, std::placeholders::_1, value_type(2) ); @@ -136,11 +133,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_expression, value, test_ty auto v = value_type{}; for(auto& tt: t){ tt = v; v+=value_type{1}; } - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, basic_tensor_type > ) ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, basic_tensor_type > ) ); + 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)) ); @@ -148,21 +145,21 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_expression, value, test_ty 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, basic_tensor_type > ) ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, basic_tensor_type > ) ); + 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, basic_tensor_type > ) ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, basic_tensor_type > ) ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, basic_tensor_type > ) ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, basic_tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_type > ) ); for(auto i = 0ul; i < t.size(); ++i) BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) ); diff --git a/test/tensor/test_expression_evaluation.cpp b/test/tensor/test_expression_evaluation.cpp index c4188ea29..648134998 100644 --- a/test/tensor/test_expression_evaluation.cpp +++ b/test/tensor/test_expression_evaluation.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include "utility.hpp" #include @@ -22,12 +22,12 @@ BOOST_AUTO_TEST_SUITE(test_tensor_expression); -using test_types = zip>::with_t; +using test_types = zip>::with_t; struct fixture { - using extents_type = boost::numeric::ublas::dynamic_extents<>; + using extents_type = boost::numeric::ublas::extents<>; fixture() : extents{ extents_type{}, // 0 @@ -59,8 +59,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_retrieve_extents, value using value_type = typename value::first_type; using layout_type = typename value::second_type; using tensor_type = ublas::dynamic_tensor; - using basic_tensor_type = typename tensor_type::super_type; - + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); auto bplus = std::plus {}; @@ -78,20 +77,20 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_retrieve_extents, value // uexpr1 = t+1 // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); @@ -113,27 +112,27 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_retrieve_extents, value // uexpr1 = t1+1 // uexpr2 = 2+t2 - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t2, bminus ); + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( 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( t2, bexpr_uexpr, bminus ); + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( t2, bexpr_uexpr, bminus ); BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); } @@ -151,7 +150,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_all_extents_equal, valu using value_type = typename value::first_type; using layout_type = typename value::second_type; using tensor_type = ublas::dynamic_tensor; - using basic_tensor_type = typename tensor_type::super_type; + auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); @@ -170,20 +169,20 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_all_extents_equal, valu // uexpr1 = t+1 // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); @@ -206,39 +205,39 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_all_extents_equal, valu // uexpr1 = t1+1 // uexpr2 = 2+t2 - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t2, bminus ); + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( 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( t2, bexpr_uexpr, bminus ); + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( 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( uexpr1, t2, bplus ); + auto bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr2, t1, bplus ); + auto bexpr_bexpr_uexpr3 = ublas::detail::make_binary_tensor_expression( 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( t1, bexpr_bexpr_uexpr3, bplus ); + auto bexpr_bexpr_uexpr4 = ublas::detail::make_binary_tensor_expression( t1, bexpr_bexpr_uexpr3, bplus ); BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); } diff --git a/test/tensor/test_extents.cpp b/test/tensor/test_extents.cpp index d69a2ffb4..2dd9257ff 100644 --- a/test/tensor/test_extents.cpp +++ b/test/tensor/test_extents.cpp @@ -71,50 +71,50 @@ BOOST_AUTO_TEST_CASE(test_static_rank_extents_ctor) namespace ub = boost::numeric::ublas; - auto e0 = ub::dynamic_extents<0>{}; + auto e0 = ub::extents<0>{}; BOOST_CHECK( e0.empty()); BOOST_CHECK ( e0.size() == 0); - auto e1 = ub::dynamic_extents<2>{1,1}; + auto e1 = ub::extents<2>{1,1}; BOOST_CHECK(!e1.empty()); BOOST_CHECK ( e1.size() == 2); - auto e2 = ub::dynamic_extents<2>{1,2}; + auto e2 = ub::extents<2>{1,2}; BOOST_CHECK(!e2.empty()); BOOST_CHECK ( e2.size() == 2); - auto e3 = ub::dynamic_extents<2>{2,1}; + auto e3 = ub::extents<2>{2,1}; BOOST_CHECK (!e3.empty()); BOOST_CHECK ( e3.size() == 2); - auto e4 = ub::dynamic_extents<2>{2,3}; + auto e4 = ub::extents<2>{2,3}; BOOST_CHECK(!e4.empty()); BOOST_CHECK ( e4.size() == 2); - auto e5 = ub::dynamic_extents<3>{2,3,1}; + auto e5 = ub::extents<3>{2,3,1}; BOOST_CHECK (!e5.empty()); BOOST_CHECK ( e5.size() == 3); - auto e6 = ub::dynamic_extents<3>{1,2,3}; // 6 + auto e6 = ub::extents<3>{1,2,3}; // 6 BOOST_CHECK(!e6.empty()); BOOST_CHECK ( e6.size() == 3); - auto e7 = ub::dynamic_extents<3>{4,2,3}; // 7 + auto e7 = ub::extents<3>{4,2,3}; // 7 BOOST_CHECK(!e7.empty()); BOOST_CHECK ( e7.size() == 3); - BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,0}), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<1>({0} ), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<1>({3} ), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<2>({0,1}), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,1,2}), std::out_of_range); + BOOST_CHECK_THROW( ub::extents<2>({1,0}), std::length_error); + BOOST_CHECK_THROW( ub::extents<1>({0} ), std::length_error); + BOOST_CHECK_THROW( ub::extents<1>({3} ), std::length_error); + BOOST_CHECK_THROW( ub::extents<2>({0,1}), std::length_error); + BOOST_CHECK_THROW( ub::extents<2>({1,1,2}), std::out_of_range); } struct fixture { - using extents_type = boost::numeric::ublas::dynamic_extents<>; + using extents_type = boost::numeric::ublas::extents<>; template - using static_rank_extents_type = boost::numeric::ublas::dynamic_extents; + using static_rank_extents_type = boost::numeric::ublas::extents; fixture() : extents{ extents_type{}, // 0 @@ -576,16 +576,16 @@ BOOST_FIXTURE_TEST_CASE(test_extents_comparison, fixture, *boost::unit_test::lab auto s2 = ublas::static_extents<1,4,2,1,3,1>{}; auto s3 = ublas::static_extents<1,4,2,1,1,1>{}; - auto d0 = ublas::dynamic_extents<0>{}; - auto d1 = ublas::dynamic_extents<2>{1,1}; - auto d2 = ublas::dynamic_extents<6>{1,4,2,1,3,1}; - auto d3 = ublas::dynamic_extents<6>{1,4,2,1,1,1}; + auto d0 = ublas::extents<0>{}; + auto d1 = ublas::extents<2>{1,1}; + auto d2 = ublas::extents<6>{1,4,2,1,3,1}; + auto d3 = ublas::extents<6>{1,4,2,1,1,1}; auto e0 = extents[ 0]; // {} auto e1 = extents[ 1]; // {1,1} auto e2 = extents[12]; // {1,4,2,1,3,1} - // static_extents<...> == dynamic_extents<> + // static_extents<...> == extents<> BOOST_TEST( s0 == e0 ); BOOST_TEST( s1 == e1 ); BOOST_TEST( s2 == e2 ); @@ -614,7 +614,7 @@ BOOST_FIXTURE_TEST_CASE(test_extents_comparison, fixture, *boost::unit_test::lab BOOST_TEST( e1 != s3 ); BOOST_TEST( e2 != s3 ); - // dynamic_extents == dynamic_extents<> + // extents == extents<> BOOST_TEST( d0 == e0 ); BOOST_TEST( d1 == e1 ); BOOST_TEST( d2 == e2 ); @@ -643,7 +643,7 @@ BOOST_FIXTURE_TEST_CASE(test_extents_comparison, fixture, *boost::unit_test::lab BOOST_TEST( e1 != d3 ); BOOST_TEST( e2 != d3 ); - // static_extents<...> == dynamic_extents + // static_extents<...> == extents BOOST_TEST( s0 == d0 ); BOOST_TEST( s1 == d1 ); diff --git a/test/tensor/test_fixed_rank_expression_evaluation.cpp b/test/tensor/test_fixed_rank_expression_evaluation.cpp index 37498d2e9..97aba6aec 100644 --- a/test/tensor/test_fixed_rank_expression_evaluation.cpp +++ b/test/tensor/test_fixed_rank_expression_evaluation.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -20,13 +20,13 @@ BOOST_AUTO_TEST_SUITE(test_fixed_rank_tensor_expression); -using test_types = zip>::with_t; +using test_types = zip>::with_t; struct fixture { template - using extents_type = boost::numeric::ublas::dynamic_extents; + using extents_type = boost::numeric::ublas::extents; std::tuple< extents_type<0>, // 0 @@ -68,7 +68,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_retrieve_ext for_each_tuple(extents, [&](auto const&, auto & e){ using extents_type = std::decay_t; using tensor_type = ublas::fixed_rank_tensor; - using basic_tensor_type = typename tensor_type::super_type; + auto t = tensor_type(e); auto v = value_type{}; @@ -79,26 +79,26 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_retrieve_ext // uexpr1 = t+1 // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); }); - for_each_tuple(extents, [&](auto const& I, auto& e1){ + for_each_tuple(extents, [&](auto I, auto& e1){ if ( I >= std::tuple_size_v - 1 ){ return; @@ -106,16 +106,15 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_retrieve_ext using extents_type1 = std::decay_t; using tensor_type1 = ublas::fixed_rank_tensor; - using basic_tensor_type1 = typename tensor_type1::super_type; - for_each_tuple(extents, [&](auto const& J, auto& e2){ + for_each_tuple(extents, [&](auto J, auto& e2){ + if( J != I + 1 ){ return; } using extents_type2 = std::decay_t; using tensor_type2 = ublas::fixed_rank_tensor; - using basic_tensor_type2 = typename tensor_type2::super_type; auto v = value_type{}; @@ -129,8 +128,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_retrieve_ext // uexpr1 = t1+1 // uexpr2 = 2+t2 - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 ) ); @@ -138,19 +137,19 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_retrieve_ext if constexpr( extents_type1::_size == extents_type2::_size ){ // bexpr_uexpr = (t1+1) + (2+t2) - auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t2, bminus ); + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( 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( t2, bexpr_uexpr, bminus ); + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( t2, bexpr_uexpr, bminus ); BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); } @@ -179,7 +178,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_all_extents_ for_each_tuple(extents, [&](auto const&, auto& e){ using extents_type = std::decay_t; using tensor_type = ublas::fixed_rank_tensor; - using basic_tensor_type = typename tensor_type::super_type; + auto t = tensor_type(e); auto v = value_type{}; @@ -191,27 +190,27 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_all_extents_ // uexpr1 = t+1 // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); }); - for_each_tuple(extents, [&](auto const& I, auto& e1){ + for_each_tuple(extents, [&](auto I, auto& e1){ if ( I >= std::tuple_size_v - 1){ return; @@ -219,16 +218,15 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_all_extents_ using extents_type1 = std::decay_t; using tensor_type1 = ublas::fixed_rank_tensor; - using basic_tensor_type1 = typename tensor_type1::super_type; - for_each_tuple(extents, [&](auto const& J, auto& e2){ + for_each_tuple(extents, [&](auto J, auto& e2){ + if( J != I + 1 ){ return; } using extents_type2 = std::decay_t; using tensor_type2 = ublas::fixed_rank_tensor; - using basic_tensor_type2 = typename tensor_type2::super_type; auto v = value_type{}; @@ -243,40 +241,40 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_all_extents_ // uexpr1 = t1+1 // uexpr2 = 2+t2 - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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) ) ); if constexpr( extents_type1::_size == extents_type2::_size ){ // bexpr_uexpr = (t1+1) + (2+t2) - auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t2, bminus ); + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( 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( t2, bexpr_uexpr, bminus ); + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( 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( uexpr1, t2, bplus ); + auto bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr2, t1, bplus ); + auto bexpr_bexpr_uexpr3 = ublas::detail::make_binary_tensor_expression( 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( t1, bexpr_bexpr_uexpr3, bplus ); + auto bexpr_bexpr_uexpr4 = ublas::detail::make_binary_tensor_expression( t1, bexpr_bexpr_uexpr3, bplus ); BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); } diff --git a/test/tensor/test_fixed_rank_extents.cpp b/test/tensor/test_fixed_rank_extents.cpp index 2f026966f..5d55d6b01 100644 --- a/test/tensor/test_fixed_rank_extents.cpp +++ b/test/tensor/test_fixed_rank_extents.cpp @@ -26,72 +26,72 @@ BOOST_AUTO_TEST_CASE(test_fixed_rank_extents_ctor) namespace ub = boost::numeric::ublas; - auto e0 = ub::dynamic_extents<0>{}; + auto e0 = ub::extents<0>{}; BOOST_CHECK( e0.empty()); BOOST_CHECK ( e0.size() == 0); - auto e1 = ub::dynamic_extents<2>{1,1}; + auto e1 = ub::extents<2>{1,1}; BOOST_CHECK(!e1.empty()); BOOST_CHECK ( e1.size() == 2); - auto e2 = ub::dynamic_extents<2>{1,2}; + auto e2 = ub::extents<2>{1,2}; BOOST_CHECK(!e2.empty()); BOOST_CHECK ( e2.size() == 2); - auto e3 = ub::dynamic_extents<2>{2,1}; + auto e3 = ub::extents<2>{2,1}; BOOST_CHECK (!e3.empty()); BOOST_CHECK ( e3.size() == 2); - auto e4 = ub::dynamic_extents<2>{2,3}; + auto e4 = ub::extents<2>{2,3}; BOOST_CHECK(!e4.empty()); BOOST_CHECK ( e4.size() == 2); - auto e5 = ub::dynamic_extents<3>{2,3,1}; + auto e5 = ub::extents<3>{2,3,1}; BOOST_CHECK (!e5.empty()); BOOST_CHECK ( e5.size() == 3); - auto e6 = ub::dynamic_extents<3>{1,2,3}; // 6 + auto e6 = ub::extents<3>{1,2,3}; // 6 BOOST_CHECK(!e6.empty()); BOOST_CHECK ( e6.size() == 3); - auto e7 = ub::dynamic_extents<3>{4,2,3}; // 7 + auto e7 = ub::extents<3>{4,2,3}; // 7 BOOST_CHECK(!e7.empty()); BOOST_CHECK ( e7.size() == 3); - BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,0}), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<1>({0} ), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<1>({3} ), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<2>({0,1}), std::length_error); - BOOST_CHECK_THROW( ub::dynamic_extents<2>({1,1,2}), std::out_of_range); + BOOST_CHECK_THROW( ub::extents<2>({1,0}), std::length_error); + BOOST_CHECK_THROW( ub::extents<1>({0} ), std::length_error); + BOOST_CHECK_THROW( ub::extents<1>({3} ), std::length_error); + BOOST_CHECK_THROW( ub::extents<2>({0,1}), std::length_error); + BOOST_CHECK_THROW( ub::extents<2>({1,1,2}), std::out_of_range); } struct fixture { template - using dynamic_extents = boost::numeric::ublas::dynamic_extents; + using extents = boost::numeric::ublas::extents; - dynamic_extents<0> de0{}; // 0 + extents<0> de0{}; // 0 - dynamic_extents<2> de1{1,1}; // 1 - dynamic_extents<2> de2{1,2}; // 2 - dynamic_extents<2> de3{2,1}; // 3 + extents<2> de1{1,1}; // 1 + extents<2> de2{1,2}; // 2 + extents<2> de3{2,1}; // 3 - dynamic_extents<2> de4{2,3}; // 4 - dynamic_extents<3> de5{2,3,1}; // 5 - dynamic_extents<3> de6{1,2,3}; // 6 - dynamic_extents<4> de7{1,1,2,3}; // 7 - dynamic_extents<5> de8{1,2,3,1,1}; // 8 + extents<2> de4{2,3}; // 4 + extents<3> de5{2,3,1}; // 5 + extents<3> de6{1,2,3}; // 6 + extents<4> de7{1,1,2,3}; // 7 + extents<5> de8{1,2,3,1,1}; // 8 - dynamic_extents<3> de9{4,2,3}; // 9 - dynamic_extents<4> de10{4,2,1,3}; // 10 - dynamic_extents<5> de11{4,2,1,3,1}; // 11 - dynamic_extents<6> de12{1,4,2,1,3,1};// 12 + extents<3> de9{4,2,3}; // 9 + extents<4> de10{4,2,1,3}; // 10 + extents<5> de11{4,2,1,3,1}; // 11 + extents<6> de12{1,4,2,1,3,1};// 12 - dynamic_extents<3> de13{1,4,1}; // 13 - dynamic_extents<4> de14{1,1,1,1}; // 14 - dynamic_extents<5> de15{1,4,1,1,1}; // 15 - dynamic_extents<6> de16{1,1,2,1,1,1};// 16 - dynamic_extents<6> de17{1,1,2,3,1,1};// 17 + extents<3> de13{1,4,1}; // 13 + extents<4> de14{1,1,1,1}; // 14 + extents<5> de15{1,4,1,1,1}; // 15 + extents<6> de16{1,1,2,1,1,1};// 16 + extents<6> de17{1,1,2,3,1,1};// 17 }; BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_access, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("access")) @@ -485,26 +485,26 @@ BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_squeeze, fixture, *boost::unit_t auto e16 = squeeze(de16); // {2,1} auto e17 = squeeze(de17); // {2,3} - BOOST_CHECK( (e1 == dynamic_extents<2>{1,1}) ); - BOOST_CHECK( (e2 == dynamic_extents<2>{1,2}) ); - BOOST_CHECK( (e3 == dynamic_extents<2>{2,1}) ); - - BOOST_CHECK( (e4 == dynamic_extents<2>{2,3}) ); - BOOST_CHECK( (e5 == dynamic_extents<2>{2,3}) ); - BOOST_CHECK( (e6 == dynamic_extents<2>{2,3}) ); - BOOST_CHECK( (e7 == dynamic_extents<2>{2,3}) ); - BOOST_CHECK( (e8 == dynamic_extents<2>{2,3}) ); - - BOOST_CHECK( (e9 == dynamic_extents<3>{4,2,3}) ); - BOOST_CHECK( (e10 == dynamic_extents<3>{4,2,3}) ); - BOOST_CHECK( (e11 == dynamic_extents<3>{4,2,3}) ); - BOOST_CHECK( (e12 == dynamic_extents<3>{4,2,3}) ); - - BOOST_CHECK( (e13 == dynamic_extents<2>{1,4}) ); - BOOST_CHECK( (e14 == dynamic_extents<2>{1,1}) ); - BOOST_CHECK( (e15 == dynamic_extents<2>{1,4}) ); - BOOST_CHECK( (e16 == dynamic_extents<2>{2,1}) ); - BOOST_CHECK( (e17 == dynamic_extents<2>{2,3}) ); + BOOST_CHECK( (e1 == extents<2>{1,1}) ); + BOOST_CHECK( (e2 == extents<2>{1,2}) ); + BOOST_CHECK( (e3 == extents<2>{2,1}) ); + + BOOST_CHECK( (e4 == extents<2>{2,3}) ); + BOOST_CHECK( (e5 == extents<2>{2,3}) ); + BOOST_CHECK( (e6 == extents<2>{2,3}) ); + BOOST_CHECK( (e7 == extents<2>{2,3}) ); + BOOST_CHECK( (e8 == extents<2>{2,3}) ); + + BOOST_CHECK( (e9 == extents<3>{4,2,3}) ); + BOOST_CHECK( (e10 == extents<3>{4,2,3}) ); + BOOST_CHECK( (e11 == extents<3>{4,2,3}) ); + BOOST_CHECK( (e12 == extents<3>{4,2,3}) ); + + BOOST_CHECK( (e13 == extents<2>{1,4}) ); + BOOST_CHECK( (e14 == extents<2>{1,1}) ); + BOOST_CHECK( (e15 == extents<2>{1,4}) ); + BOOST_CHECK( (e16 == extents<2>{2,1}) ); + BOOST_CHECK( (e17 == extents<2>{2,3}) ); } diff --git a/test/tensor/test_fixed_rank_functions.cpp b/test/tensor/test_fixed_rank_functions.cpp index cf6e4332c..8ccea3f76 100644 --- a/test/tensor/test_fixed_rank_functions.cpp +++ b/test/tensor/test_fixed_rank_functions.cpp @@ -26,17 +26,17 @@ BOOST_AUTO_TEST_SUITE ( test_fixed_rank_tensor_functions) -using test_types = zip>::with_t; +using test_types = zip>::with_t; -//using test_types = zip::with_t; +//using test_types = zip::with_t; struct fixture { template - using fixed_rank_extents_type = boost::numeric::ublas::dynamic_extents; + using fixed_rank_extents_type = boost::numeric::ublas::extents; - using dynamic_extents_type = boost::numeric::ublas::dynamic_extents<>; + using dynamic_extents_type = boost::numeric::ublas::extents<>; fixture() : extents { dynamic_extents_type{1,1}, // 1 @@ -204,7 +204,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_prod_tensor_2, value, auto permute_extents_s_1 = [](auto const& pi, auto const& na){ - auto nb = ublas::dynamic_extents<>(na); + auto nb = ublas::extents<>(na); assert(pi.size() == na.size()); for(auto j = 0u; j < pi.size(); ++j) nb[pi[j]-1] = na[j]; @@ -215,7 +215,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_prod_tensor_2, value, assert(pi.size() == na.size()); for(auto j = 0u; j < pi.size(); ++j) tempn[pi[j]-1] = na[j]; - return ublas::dynamic_extents::type::_size>(tempn.begin(),tempn.end()); + return ublas::extents::type::_size>(tempn.begin(),tempn.end()); }; for_each_tuple(fixed_rank_extents,[&](auto const&, auto & n){ diff --git a/test/tensor/test_fixed_rank_operators_arithmetic.cpp b/test/tensor/test_fixed_rank_operators_arithmetic.cpp index 5a3980a8c..e5bbcf86a 100644 --- a/test/tensor/test_fixed_rank_operators_arithmetic.cpp +++ b/test/tensor/test_fixed_rank_operators_arithmetic.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -22,12 +22,12 @@ BOOST_AUTO_TEST_SUITE(test_fixed_rank_tensor_arithmetic_operations) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; -using test_types = zip::with_t; +using test_types = zip::with_t; struct fixture { template - using extents_type = boost::numeric::ublas::dynamic_extents; + using extents_type = boost::numeric::ublas::extents; std::tuple< extents_type<2>, // 1 diff --git a/test/tensor/test_fixed_rank_operators_comparison.cpp b/test/tensor/test_fixed_rank_operators_comparison.cpp index e8b901b4d..a4c60da0c 100644 --- a/test/tensor/test_fixed_rank_operators_comparison.cpp +++ b/test/tensor/test_fixed_rank_operators_comparison.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -21,11 +21,11 @@ BOOST_AUTO_TEST_SUITE(test_fixed_rank_tensor_comparison) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; -using test_types = zip::with_t; +using test_types = zip::with_t; struct fixture { template - using extents_type = boost::numeric::ublas::dynamic_extents; + using extents_type = boost::numeric::ublas::extents; std::tuple< extents_type<2>, // 1 diff --git a/test/tensor/test_fixed_rank_strides.cpp b/test/tensor/test_fixed_rank_strides.cpp index d5c24f2b0..c90cba953 100644 --- a/test/tensor/test_fixed_rank_strides.cpp +++ b/test/tensor/test_fixed_rank_strides.cpp @@ -20,41 +20,41 @@ BOOST_AUTO_TEST_SUITE(test_fixed_rank_strides) -using test_types = std::tuple; +using test_types = std::tuple; BOOST_AUTO_TEST_CASE_TEMPLATE( test_fixed_rank_strides_ctor, value, test_types) { namespace ub = boost::numeric::ublas; - ub::basic_fixed_rank_strides s0{ub::dynamic_extents<0>{}}; + ub::basic_fixed_rank_strides s0{ub::extents<0>{}}; BOOST_CHECK ( s0.empty()); BOOST_CHECK_EQUAL ( s0.size(), 0); - ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; + ub::basic_fixed_rank_strides s1{ub::extents<2>{1,1}}; BOOST_CHECK (!s1.empty()); BOOST_CHECK_EQUAL ( s1.size(), 2); - ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; + ub::basic_fixed_rank_strides s2{ub::extents<2>{1,2}}; BOOST_CHECK (!s2.empty()); BOOST_CHECK_EQUAL ( s2.size(), 2); - ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; + ub::basic_fixed_rank_strides s3{ub::extents<2>{2,1}}; BOOST_CHECK (!s3.empty()); BOOST_CHECK_EQUAL ( s3.size(), 2); - ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; + ub::basic_fixed_rank_strides s4{ub::extents<2>{2,3}}; BOOST_CHECK (!s4.empty()); BOOST_CHECK_EQUAL ( s4.size(), 2); - ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{2,3,1}}; + ub::basic_fixed_rank_strides s5{ub::extents<3>{2,3,1}}; BOOST_CHECK (!s5.empty()); BOOST_CHECK_EQUAL ( s5.size(), 3); - ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{1,2,3}}; + ub::basic_fixed_rank_strides s6{ub::extents<3>{1,2,3}}; BOOST_CHECK (!s6.empty()); BOOST_CHECK_EQUAL ( s6.size(), 3); - ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{4,2,3}}; + ub::basic_fixed_rank_strides s7{ub::extents<3>{4,2,3}}; BOOST_CHECK (!s7.empty()); BOOST_CHECK_EQUAL ( s7.size(), 3); } @@ -64,45 +64,45 @@ BOOST_AUTO_TEST_CASE( test_fixed_rank_strides_ctor_access_first_order) { namespace ub = boost::numeric::ublas; - ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; + ub::basic_fixed_rank_strides s1{ub::extents<2>{1,1}}; BOOST_REQUIRE_EQUAL( s1.size(),2); BOOST_CHECK_EQUAL ( s1[0], 1); BOOST_CHECK_EQUAL ( s1[1], 1); - ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; + ub::basic_fixed_rank_strides s2{ub::extents<2>{1,2}}; BOOST_REQUIRE_EQUAL ( s2.size(),2); BOOST_CHECK_EQUAL ( s2[0], 1); BOOST_CHECK_EQUAL ( s2[1], 1); - ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; + ub::basic_fixed_rank_strides s3{ub::extents<2>{2,1}}; BOOST_REQUIRE_EQUAL ( s3.size(),2); BOOST_CHECK_EQUAL ( s3[0], 1); BOOST_CHECK_EQUAL ( s3[1], 1); - ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; + ub::basic_fixed_rank_strides s4{ub::extents<2>{2,3}}; BOOST_REQUIRE_EQUAL ( s4.size(),2); BOOST_CHECK_EQUAL ( s4[0], 1); BOOST_CHECK_EQUAL ( s4[1], 2); - ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{2,3,1}}; + ub::basic_fixed_rank_strides s5{ub::extents<3>{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); - ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{1,2,3}}; + ub::basic_fixed_rank_strides s6{ub::extents<3>{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); - ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{2,1,3}}; + ub::basic_fixed_rank_strides s7{ub::extents<3>{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); - ub::basic_fixed_rank_strides s8{ub::dynamic_extents<3>{4,2,3}}; + ub::basic_fixed_rank_strides s8{ub::extents<3>{4,2,3}}; BOOST_REQUIRE_EQUAL ( s8.size(),3); BOOST_CHECK_EQUAL ( s8[0], 1); BOOST_CHECK_EQUAL ( s8[1], 4); @@ -113,45 +113,45 @@ BOOST_AUTO_TEST_CASE( test_fixed_rank_strides_ctor_access_last_order) { namespace ub = boost::numeric::ublas; - ub::basic_fixed_rank_strides s1{ub::dynamic_extents<2>{1,1}}; + ub::basic_fixed_rank_strides s1{ub::extents<2>{1,1}}; BOOST_REQUIRE_EQUAL( s1.size(),2); BOOST_CHECK_EQUAL ( s1[0], 1); BOOST_CHECK_EQUAL ( s1[1], 1); - ub::basic_fixed_rank_strides s2{ub::dynamic_extents<2>{1,2}}; + ub::basic_fixed_rank_strides s2{ub::extents<2>{1,2}}; BOOST_REQUIRE_EQUAL ( s2.size(),2); BOOST_CHECK_EQUAL ( s2[0], 1); BOOST_CHECK_EQUAL ( s2[1], 1); - ub::basic_fixed_rank_strides s3{ub::dynamic_extents<2>{2,1}}; + ub::basic_fixed_rank_strides s3{ub::extents<2>{2,1}}; BOOST_REQUIRE_EQUAL ( s3.size(),2); BOOST_CHECK_EQUAL ( s3[0], 1); BOOST_CHECK_EQUAL ( s3[1], 1); - ub::basic_fixed_rank_strides s4{ub::dynamic_extents<2>{2,3}}; + ub::basic_fixed_rank_strides s4{ub::extents<2>{2,3}}; BOOST_REQUIRE_EQUAL ( s4.size(),2); BOOST_CHECK_EQUAL ( s4[0], 3); BOOST_CHECK_EQUAL ( s4[1], 1); - ub::basic_fixed_rank_strides s5{ub::dynamic_extents<3>{2,3,1}}; + ub::basic_fixed_rank_strides s5{ub::extents<3>{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); - ub::basic_fixed_rank_strides s6{ub::dynamic_extents<3>{1,2,3}}; + ub::basic_fixed_rank_strides s6{ub::extents<3>{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); - ub::basic_fixed_rank_strides s7{ub::dynamic_extents<3>{2,1,3}}; + ub::basic_fixed_rank_strides s7{ub::extents<3>{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); - ub::basic_fixed_rank_strides s8{ub::dynamic_extents<3>{4,2,3}}; + ub::basic_fixed_rank_strides s8{ub::extents<3>{4,2,3}}; BOOST_REQUIRE_EQUAL ( s8.size(),3); BOOST_CHECK_EQUAL ( s8[0], 6); BOOST_CHECK_EQUAL ( s8[1], 3); diff --git a/test/tensor/test_fixed_rank_tensor.cpp b/test/tensor/test_fixed_rank_tensor.cpp index 5f63a5fab..0db25ef3b 100644 --- a/test/tensor/test_fixed_rank_tensor.cpp +++ b/test/tensor/test_fixed_rank_tensor.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -26,7 +26,7 @@ BOOST_AUTO_TEST_SUITE ( test_fixed_rank_tensor ) -using test_types = zip>::with_t; +using test_types = zip>::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) @@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) struct fixture { template - using extents_type = boost::numeric::ublas::dynamic_extents; + using extents_type = boost::numeric::ublas::extents; std::tuple< extents_type<2>, // 1 @@ -157,7 +157,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_typ using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; + using other_layout_type = std::conditional_t::value, ublas::layout::last_order, ublas::layout::first_order>; for_each_tuple(extents, [](auto const&, auto& e){ @@ -311,8 +311,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check2 = [](const auto& t) { std::array k; - auto r = std::is_same::value ? 1 : 0; - auto q = std::is_same::value ? 1 : 0; + auto r = std::is_same::value ? 1 : 0; + auto q = std::is_same::value ? 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]){ @@ -325,8 +325,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check3 = [](const auto& t) { std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 2 : 0; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 2 : 0; auto o = op_type{}; auto v = value_type{}; for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){ @@ -342,8 +342,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check4 = [](const auto& t) { std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 3 : 0; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 3 : 0; auto o = op_type{}; auto v = value_type{}; for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){ @@ -368,10 +368,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, 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); + if constexpr(extents_type::_size == 1) check1(t); + else if constexpr(extents_type::_size == 2) check2(t); + else if constexpr(extents_type::_size == 3) check3(t); + else if constexpr(extents_type::_size == 4) check4(t); }; @@ -393,8 +393,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixtu using tensor_type = ublas::fixed_rank_tensor; for_each_tuple(extents,[&](auto const&, auto& eto){ - - if ( efrom.size() == eto.size() ){ + using extents_type = std::decay_t; + using to_extents_type = std::decay_t; + if constexpr( extents_type::_size == to_extents_type::_size ){ auto v = value_type {}; v+=value_type{1}; @@ -434,8 +435,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_swap, value, test_types, fixture) using tensor_type = ublas::fixed_rank_tensor; for_each_tuple(extents,[&](auto const&, auto& e_r){ - - if ( e_t.size() == e_r.size() ){ + using extents_type = std::decay_t; + using r_extents_type = std::decay_t; + if constexpr( extents_type::_size == r_extents_type::_size ){ auto v = value_type {} + value_type{1}; auto w = value_type {} + value_type{2}; @@ -504,7 +506,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, value, test_types, fixture) auto t = tensor_type{{5,5}}; auto i = ublas::index::index_type<4>{}; - BOOST_CHECK_THROW(t.operator()(i,i,i), std::runtime_error); + BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::runtime_error); } diff --git a/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp b/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp index 30f0c3b82..e6cba14e9 100644 --- a/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp +++ b/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -21,7 +21,7 @@ BOOST_AUTO_TEST_SUITE ( test_fixed_rank_tensor_matrix_interoperability ) ; -using test_types = zip::with_t; +using test_types = zip::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types) @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, value, test_types) struct fixture { template - using extents_type = boost::numeric::ublas::dynamic_extents; + using extents_type = boost::numeric::ublas::extents; std::tuple< extents_type<2>, // 0 diff --git a/test/tensor/test_functions.cpp b/test/tensor/test_functions.cpp index 1f1fab3f0..e1d32bef0 100644 --- a/test/tensor/test_functions.cpp +++ b/test/tensor/test_functions.cpp @@ -26,14 +26,14 @@ BOOST_AUTO_TEST_SUITE ( test_tensor_functions) -using test_types = zip>::with_t; +using test_types = zip>::with_t; -//using test_types = zip::with_t; +//using test_types = zip::with_t; struct fixture { - using dynamic_extents_type = boost::numeric::ublas::dynamic_extents<>; + using dynamic_extents_type = boost::numeric::ublas::extents<>; fixture() : extents { dynamic_extents_type{1,1}, // 1 @@ -92,25 +92,16 @@ BOOST_AUTO_TEST_CASE( test_tensor_prod_vector_exception ) { using namespace boost::numeric; using value_type = float; - using layout_type = ublas::first_order; - using s_extents_type = ublas::static_extents<1,2,3>; + using layout_type = ublas::layout::first_order; using d_tensor_type = ublas::dynamic_tensor; - using s_tensor_type = ublas::static_tensor; using vector_type = typename d_tensor_type::vector_type; - auto t1 = d_tensor_type{ublas::dynamic_extents<>{},1.f}; + auto t1 = d_tensor_type{ublas::extents<>{},1.f}; auto v1 = vector_type{3,value_type{1}}; BOOST_REQUIRE_THROW(prod(t1,v1,0),std::length_error); BOOST_REQUIRE_THROW(prod(t1,v1,1),std::length_error); BOOST_REQUIRE_THROW(prod(t1,v1,3),std::length_error); - - auto t2 = s_tensor_type{}; - BOOST_REQUIRE_THROW(prod(t2,v1,2),std::length_error); - - auto t3 = s_tensor_type{value_type{1}}; - auto v2 = vector_type{0,value_type{1}}; - BOOST_REQUIRE_THROW(prod(t3,v2,2),std::length_error); } @@ -158,11 +149,9 @@ BOOST_AUTO_TEST_CASE( test_tensor_prod_matrix_exception ) { using namespace boost::numeric; using value_type = float; - using layout_type = ublas::first_order; - using d_extents_type = ublas::dynamic_extents<>; - using s_extents_type = ublas::static_extents<1,2,3>; + using layout_type = ublas::layout::first_order; + using d_extents_type = ublas::extents<>; using d_tensor_type = ublas::dynamic_tensor; - using s_tensor_type = ublas::static_tensor; using matrix_type = typename d_tensor_type::matrix_type; auto t1 = d_tensor_type{d_extents_type{},1.f}; @@ -172,14 +161,6 @@ BOOST_AUTO_TEST_CASE( test_tensor_prod_matrix_exception ) BOOST_REQUIRE_THROW(prod(t1,m1,0),std::length_error); BOOST_REQUIRE_THROW(prod(t1,m1,1),std::length_error); BOOST_REQUIRE_THROW(prod(t1,m1,3),std::length_error); - - auto t2 = s_tensor_type{}; - - BOOST_REQUIRE_THROW(prod(t2,m1,2),std::length_error); - - auto t3 = s_tensor_type{value_type{1}}; - auto m2 = matrix_type{0,0,value_type{1}}; - BOOST_REQUIRE_THROW(prod(t3,m2,2),std::length_error); } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_1, value, test_types, fixture ) @@ -223,20 +204,14 @@ BOOST_AUTO_TEST_CASE( test_tensor_prod_tensor_1_exception ) { using namespace boost::numeric; using value_type = float; - using layout_type = ublas::first_order; - using d_extents_type = ublas::dynamic_extents<>; - using s_extents_type = ublas::static_extents<1,2,3>; + using layout_type = ublas::layout::first_order; + using d_extents_type = ublas::extents<>; using d_tensor_type = ublas::dynamic_tensor; - using s_tensor_type = ublas::static_tensor; auto t1 = d_tensor_type{}; - auto t2 = s_tensor_type{1.f}; std::vector phia = {1,2,3}; std::vector phib = {1,2,3,4,5}; - BOOST_REQUIRE_THROW(prod(t1,t2,phia,phib),std::runtime_error); - BOOST_REQUIRE_THROW(prod(t2,t1,phia,phib),std::runtime_error); - auto t3 = d_tensor_type{d_extents_type{1,2},1.f}; auto t4 = d_tensor_type{d_extents_type{1,2},1.f}; @@ -368,19 +343,13 @@ BOOST_AUTO_TEST_CASE( test_tensor_inner_prod_exception ) { using namespace boost::numeric; using value_type = float; - using layout_type = ublas::first_order; - using d_extents_type = ublas::dynamic_extents<>; - using s_extents_type = ublas::static_extents<1,2,3>; + using layout_type = ublas::layout::first_order; + using d_extents_type = ublas::extents<>; using d_tensor_type = ublas::dynamic_tensor; - using s_tensor_type = ublas::static_tensor; auto t1 = d_tensor_type{d_extents_type{1,2},1.f}; auto t2 = d_tensor_type{d_extents_type{1,2,3},1.f}; BOOST_REQUIRE_THROW( ublas::inner_prod(t1, t2), std::length_error); - - auto t3 = s_tensor_type{1.f}; - auto t4 = d_tensor_type{d_extents_type{1,2,4,5},1.f}; - BOOST_REQUIRE_THROW( ublas::inner_prod(t3, t4), std::length_error); } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_norm, value, test_types, fixture ) @@ -420,7 +389,7 @@ BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) using namespace boost::numeric; using value_type = float; using complex_type = std::complex; - using layout_type = ublas::first_order; + using layout_type = ublas::layout::first_order; using tensor_complex_type = ublas::dynamic_tensor; using tensor_type = ublas::dynamic_tensor; @@ -580,7 +549,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_trans, value, test_types, fixture auto pi_inv = inverse(pi); a = ublas::trans( a, pi_inv ); } - bool res2 = a == aref; // it was an expression. so evaluate into bool + bool res2 = a == aref; // it was an expression. so evaluate into bool BOOST_CHECK( res2 ); } diff --git a/test/tensor/test_multi_index.cpp b/test/tensor/test_multi_index.cpp index 6665e980d..63289e52f 100644 --- a/test/tensor/test_multi_index.cpp +++ b/test/tensor/test_multi_index.cpp @@ -24,7 +24,7 @@ BOOST_AUTO_TEST_SUITE ( test_multi_index ) -using test_types = zip>::with_t; +using test_types = zip>::with_t; BOOST_AUTO_TEST_CASE ( test_index_classes ) @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, ); { - auto a = tensor_type(dynamic_extents<>{2,3}, value_type{2}); + auto a = tensor_type(extents<>{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 ) ) ; @@ -110,7 +110,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, } { - auto a = tensor_type(dynamic_extents<>{2,3}, value_type{2}); + auto a = tensor_type(extents<>{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 ) ) ; @@ -120,7 +120,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, } { - auto a = tensor_type(dynamic_extents<>{2,3}, value_type{2}); + auto a = tensor_type(extents<>{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 ) ) ; @@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, } { - auto a = tensor_type(dynamic_extents<>{2,3,4}, value_type{2}); + auto a = tensor_type(extents<>{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 ) ) ; diff --git a/test/tensor/test_multiplication.cpp b/test/tensor/test_multiplication.cpp index 13093b1af..19affdeb8 100644 --- a/test/tensor/test_multiplication.cpp +++ b/test/tensor/test_multiplication.cpp @@ -28,14 +28,14 @@ BOOST_AUTO_TEST_SUITE (test_tensor_contraction) -using test_types = zip>::with_t; +using test_types = zip>::with_t; -//using test_types = zip::with_t; +//using test_types = zip::with_t; struct fixture { - using extents_type = boost::numeric::ublas::dynamic_extents<>; + using extents_type = boost::numeric::ublas::extents<>; fixture() : extents { extents_type{1,1}, // 1 @@ -61,7 +61,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_mtv, value, test_types, fixture ) using value_type = typename value::first_type; using layout_type = typename value::second_type; using vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; + using extents_type = ublas::extents<>; using strides_type = ublas::strides_t; using extents_type_base = typename extents_type::base_type; using size_type = typename extents_type_base::value_type; @@ -110,7 +110,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_mtm, value, test_types, fixture ) using value_type = typename value::first_type; using layout_type = typename value::second_type; using vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; + using extents_type = ublas::extents<>; using strides_type = ublas::strides_t; // using extents_type_base = typename extents_type::base_type; @@ -152,7 +152,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttv, value, test_types, fixture ) using value_type = typename value::first_type; using layout_type = typename value::second_type; using vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; + using extents_type = ublas::extents<>; using strides_type = ublas::strides_t; using extents_type_base = typename extents_type::base_type; using size_type = typename extents_type_base::value_type; @@ -197,7 +197,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttm, value, test_types, fixture ) using value_type = typename value::first_type; using layout_type = typename value::second_type; using vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; + using extents_type = ublas::extents<>; using strides_type = ublas::strides_t; using size_type = typename extents_type::value_type; @@ -236,7 +236,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt_permutation, value, test_type using value_type = typename value::first_type; using layout_type = typename value::second_type; using vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; + using extents_type = ublas::extents<>; using strides_type = ublas::strides_t; using size_type = typename strides_type::value_type; @@ -344,7 +344,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt, value, test_types, fixture ) using value_type = typename value::first_type; using layout_type = typename value::second_type; using vector_type = std::vector; - using extents_type = ublas::dynamic_extents<>; + using extents_type = ublas::extents<>; using strides_type = ublas::strides_t; using size_type = typename strides_type::value_type; @@ -426,7 +426,7 @@ 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_t,layout_type>; + using strides_type = ublas::strides_t,layout_type>; using vector_type = std::vector; @@ -452,7 +452,7 @@ 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::dynamic_extents<>; + using extents_type = ublas::extents<>; using strides_type = ublas::strides_t; using vector_type = std::vector; diff --git a/test/tensor/test_operators_arithmetic.cpp b/test/tensor/test_operators_arithmetic.cpp index 1ff83402d..723fffe11 100644 --- a/test/tensor/test_operators_arithmetic.cpp +++ b/test/tensor/test_operators_arithmetic.cpp @@ -21,7 +21,7 @@ BOOST_AUTO_TEST_SUITE(test_tensor_arithmetic_operations, * boost::unit_test::dep using double_extended = boost::multiprecision::cpp_bin_float_double_extended; -using test_types = zip::with_t; +using test_types = zip::with_t; struct fixture { diff --git a/test/tensor/test_operators_comparison.cpp b/test/tensor/test_operators_comparison.cpp index f8f5b80cf..6e4932f41 100644 --- a/test/tensor/test_operators_comparison.cpp +++ b/test/tensor/test_operators_comparison.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include "utility.hpp" @@ -23,10 +23,10 @@ BOOST_AUTO_TEST_SUITE(test_tensor_comparison, * boost::unit_test::depends_on("te using double_extended = boost::multiprecision::cpp_bin_float_double_extended; -using test_types = zip::with_t; +using test_types = zip::with_t; struct fixture { - using extents_type = boost::numeric::ublas::dynamic_extents<>; + using extents_type = boost::numeric::ublas::extents<>; fixture() : extents{ extents_type{}, // 0 diff --git a/test/tensor/test_static_expression_evaluation.cpp b/test/tensor/test_static_expression_evaluation.cpp index 281f39d34..df66b1ee3 100644 --- a/test/tensor/test_static_expression_evaluation.cpp +++ b/test/tensor/test_static_expression_evaluation.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -20,7 +20,7 @@ BOOST_AUTO_TEST_SUITE(test_static_tensor_expression) -using test_types = zip>::with_t; +using test_types = zip>::with_t; struct fixture @@ -51,7 +51,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_retrieve_extents for_each_tuple(extents, [&](auto const&, auto& e){ using extents_type = std::decay_t; using tensor_type = ublas::static_tensor; - using basic_tensor_type = typename tensor_type::super_type; + auto t = tensor_type{}; auto v = value_type{}; @@ -63,43 +63,42 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_retrieve_extents // uexpr1 = t+1 // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); }); - for_each_tuple(extents, [&](auto const& I, auto& e1){ - + for_each_tuple(extents, [&](auto I, auto& e1){ + if ( I >= std::tuple_size_v - 1){ return; } using extents_type1 = std::decay_t; using tensor_type1 = ublas::static_tensor; - using basic_tensor_type1 = typename tensor_type1::super_type; - for_each_tuple(extents, [&](auto const& J, auto& e2){ + for_each_tuple(extents, [&](auto J, auto& e2){ + if( J != I + 1 ){ return; } using extents_type2 = std::decay_t; using tensor_type2 = ublas::static_tensor; - using basic_tensor_type2 = typename tensor_type2::super_type; auto v = value_type{}; @@ -113,8 +112,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_retrieve_extents // uexpr1 = t1+1 // uexpr2 = 2+t2 - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 ) ); @@ -144,7 +143,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_all_extents_equa for_each_tuple(extents, [&](auto const&, auto& e){ using extents_type = std::decay_t; using tensor_type = ublas::static_tensor; - using basic_tensor_type = typename tensor_type::super_type; + auto t = tensor_type{}; auto v = value_type{}; @@ -156,27 +155,27 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_all_extents_equa // uexpr1 = t+1 // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); }); - for_each_tuple(extents, [&](auto const& I, auto& e1){ + for_each_tuple(extents, [&](auto I, auto& e1){ if ( I >= std::tuple_size_v - 1){ return; @@ -184,16 +183,15 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_all_extents_equa using extents_type1 = std::decay_t; using tensor_type1 = ublas::static_tensor; - using basic_tensor_type1 = typename tensor_type1::super_type; - for_each_tuple(extents, [&](auto const& J, auto& e2){ + for_each_tuple(extents, [&](auto J, auto& e2){ + if( J != I + 1 ){ return; } using extents_type2 = std::decay_t; using tensor_type2 = ublas::static_tensor; - using basic_tensor_type2 = typename tensor_type2::super_type; auto v = value_type{}; @@ -208,8 +206,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_all_extents_equa // uexpr1 = t1+1 // uexpr2 = 2+t2 - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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) ) ); diff --git a/test/tensor/test_static_extents.cpp b/test/tensor/test_static_extents.cpp index c8bbecb64..e44040083 100644 --- a/test/tensor/test_static_extents.cpp +++ b/test/tensor/test_static_extents.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #include @@ -100,19 +100,19 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents_product, fixture, using namespace boost::numeric::ublas; - auto p0 = product( e0); // {} - auto p1 = product( e1); // {1,2,3,4} - auto p2 = product( e2); // {1,2,3} - auto p3 = product( e3); // {4,2,3} - auto p4 = product( e4); // {4,2,1,3} - auto p5 = product( e5); // {1,4,2,1,3,1} + auto p0 = product(e0); // {} + auto p1 = product(e1); // {1,2,3,4} + auto p2 = product(e2); // {1,2,3} + auto p3 = product(e3); // {4,2,3} + auto p4 = product(e4); // {4,2,1,3} + auto p5 = product(e5); // {1,4,2,1,3,1} - auto sp0 = static_product_v< std::decay_t >; // {} - auto sp1 = static_product_v< std::decay_t >; // {1,2,3,4} - auto sp2 = static_product_v< std::decay_t >; // {1,2,3} - auto sp3 = static_product_v< std::decay_t >; // {4,2,3} - auto sp4 = static_product_v< std::decay_t >; // {4,2,1,3} - auto sp5 = static_product_v< std::decay_t >; // {1,4,2,1,3,1} + auto sp0 = product(e0); // {} + auto sp1 = product(e1); // {1,2,3,4} + auto sp2 = product(e2); // {1,2,3} + auto sp3 = product(e3); // {4,2,3} + auto sp4 = product(e4); // {4,2,1,3} + auto sp5 = product(e5); // {1,4,2,1,3,1} BOOST_CHECK_EQUAL(p0, 0); BOOST_CHECK_EQUAL(p1, 24); @@ -186,60 +186,60 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, BOOST_CHECK( !is_vector( e0)); BOOST_CHECK( !is_matrix( e0)); BOOST_CHECK( !is_tensor( e0)); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar( e0)); + BOOST_CHECK( !is_vector( e0)); + BOOST_CHECK( !is_matrix( e0)); + BOOST_CHECK( !is_tensor( e0)); BOOST_CHECK( ! e1.empty( ) ); BOOST_CHECK( !is_scalar( e1) ); BOOST_CHECK( !is_vector( e1) ); BOOST_CHECK( !is_matrix( e1) ); BOOST_CHECK( is_tensor( e1) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar( e1) ); + BOOST_CHECK( !is_vector( e1) ); + BOOST_CHECK( !is_matrix( e1) ); + BOOST_CHECK( is_tensor( e1) ); BOOST_CHECK( ! e2.empty( ) ); BOOST_CHECK( !is_scalar( e2) ); BOOST_CHECK( !is_vector( e2) ); BOOST_CHECK( !is_matrix( e2) ); BOOST_CHECK( is_tensor( e2) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar( e2) ); + BOOST_CHECK( !is_vector( e2) ); + BOOST_CHECK( !is_matrix( e2) ); + BOOST_CHECK( is_tensor( e2) ); BOOST_CHECK( ! e3.empty( ) ); BOOST_CHECK( !is_scalar( e3) ); BOOST_CHECK( !is_vector( e3) ); BOOST_CHECK( !is_matrix( e3) ); BOOST_CHECK( is_tensor( e3) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar( e3) ); + BOOST_CHECK( !is_vector( e3) ); + BOOST_CHECK( !is_matrix( e3) ); + BOOST_CHECK( is_tensor( e3) ); BOOST_CHECK( ! e4.empty( ) ); BOOST_CHECK( !is_scalar( e4) ); BOOST_CHECK( !is_vector( e4) ); BOOST_CHECK( !is_matrix( e4) ); BOOST_CHECK( is_tensor( e4) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar( e4) ); + BOOST_CHECK( !is_vector( e4) ); + BOOST_CHECK( !is_matrix( e4) ); + BOOST_CHECK( is_tensor( e4) ); BOOST_CHECK( ! e5.empty( ) ); BOOST_CHECK( !is_scalar( e5) ); BOOST_CHECK( !is_vector( e5) ); BOOST_CHECK( !is_matrix( e5) ); BOOST_CHECK( is_tensor( e5) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar( e5) ); + BOOST_CHECK( !is_vector( e5) ); + BOOST_CHECK( !is_matrix( e5) ); + BOOST_CHECK( is_tensor( e5) ); boost::numeric::ublas::basic_static_extents e14; BOOST_CHECK( ! e14.empty( ) ); @@ -247,10 +247,10 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, BOOST_CHECK( is_vector(e14) ); BOOST_CHECK( ! is_matrix(e14) ); BOOST_CHECK( ! is_tensor(e14) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( ! is_scalar(e14) ); + BOOST_CHECK( is_vector(e14) ); + BOOST_CHECK( ! is_matrix(e14) ); + BOOST_CHECK( ! is_tensor(e14) ); for_each_tuple(rank_0_extents,[](auto const&, auto& e){ @@ -258,10 +258,10 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, BOOST_CHECK( !is_vector(e) ); BOOST_CHECK( !is_matrix(e) ); BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); }); @@ -271,19 +271,19 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, BOOST_CHECK( !is_vector(e) ); BOOST_CHECK( !is_matrix(e) ); BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); }else{ BOOST_CHECK( !is_scalar(e) ); BOOST_CHECK( is_vector(e) ); BOOST_CHECK( !is_matrix(e) ); BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); } }); @@ -293,19 +293,19 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, BOOST_CHECK( !is_vector(e) ); BOOST_CHECK( !is_matrix(e) ); BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); }else{ BOOST_CHECK( !is_scalar(e) ); BOOST_CHECK( !is_vector(e) ); BOOST_CHECK( is_matrix(e) ); BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); } }); @@ -314,10 +314,10 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, BOOST_CHECK( !is_vector(e) ); BOOST_CHECK( !is_matrix(e) ); BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); }); for_each_tuple(vectors,[](auto const&, auto& e){ @@ -325,10 +325,10 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, BOOST_CHECK( is_vector(e) ); BOOST_CHECK( !is_matrix(e) ); BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); }); for_each_tuple(matrices,[](auto const&, auto& e){ @@ -336,10 +336,10 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, BOOST_CHECK( !is_vector(e) ); BOOST_CHECK( is_matrix(e) ); BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( is_matrix(e) ); + BOOST_CHECK( !is_tensor(e) ); }); @@ -348,10 +348,10 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, BOOST_CHECK( !is_vector(e) ); BOOST_CHECK( !is_matrix(e) ); BOOST_CHECK( is_tensor(e) ); - BOOST_CHECK( !static_traits::is_scalar_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_vector_v< std::decay_t >); - BOOST_CHECK( !static_traits::is_matrix_v< std::decay_t >); - BOOST_CHECK( static_traits::is_tensor_v< std::decay_t >); + BOOST_CHECK( !is_scalar(e) ); + BOOST_CHECK( !is_vector(e) ); + BOOST_CHECK( !is_matrix(e) ); + BOOST_CHECK( is_tensor(e) ); }); } @@ -360,43 +360,42 @@ BOOST_FIXTURE_TEST_CASE(test_static_extents_valid, fixture, *boost::unit_test::l { using namespace boost::numeric::ublas; for_each_tuple(rank_0_extents,[](auto const&, auto& e){ - BOOST_CHECK(!valid(e)); - BOOST_CHECK(!static_traits::is_valid_v< std::decay_t >); + BOOST_CHECK(!is_valid(e)); + BOOST_CHECK(!is_valid(e)); }); for_each_tuple(rank_1_extents,[](auto const& I, auto const& e){ if( I== 0 ){ - BOOST_CHECK(valid(e)); - BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + BOOST_CHECK(is_valid(e)); }else{ - BOOST_CHECK(!valid(e)); - BOOST_CHECK(!static_traits::is_valid_v< std::decay_t >); + BOOST_CHECK(!is_valid(e)); + BOOST_CHECK(!is_valid(e)); } }); for_each_tuple(rank_2_extents,[](auto const&, auto& e){ - BOOST_CHECK(valid(e)); - BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + BOOST_CHECK(is_valid(e)); + BOOST_CHECK(is_valid(e)); }); for_each_tuple(scalars,[](auto const&, auto& e){ - BOOST_CHECK(valid(e)); - BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + BOOST_CHECK(is_valid(e)); + BOOST_CHECK(is_valid(e)); }); for_each_tuple(vectors,[](auto const&, auto& e){ - BOOST_CHECK(valid(e)); - BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + BOOST_CHECK(is_valid(e)); + BOOST_CHECK(is_valid(e)); }); for_each_tuple(matrices,[](auto const&, auto& e){ - BOOST_CHECK(valid(e)); - BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + BOOST_CHECK(is_valid(e)); + BOOST_CHECK(is_valid(e)); }); for_each_tuple(tensors,[](auto const&, auto& e){ - BOOST_CHECK(valid(e)); - BOOST_CHECK(static_traits::is_valid_v< std::decay_t >); + BOOST_CHECK(is_valid(e)); + BOOST_CHECK(is_valid(e)); }); } diff --git a/test/tensor/test_static_functions.cpp b/test/tensor/test_static_functions.cpp deleted file mode 100644 index c93e258c4..000000000 --- a/test/tensor/test_static_functions.cpp +++ /dev/null @@ -1,496 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// -// And we acknowledge the support from all contributors. - - -#include -#include -#include -#include -#include - -#include - -#include "utility.hpp" - -// BOOST_AUTO_TEST_SUITE ( test_tensor_functions, * boost::unit_test::depends_on("test_tensor_contraction") ) -BOOST_AUTO_TEST_SUITE ( test_tensor_functions) - - -using test_types = zip>::with_t; - -//using test_types = zip::with_t; - - -struct fixture -{ - template - using static_extents_type = boost::numeric::ublas::static_extents; - - using dynamic_extents_type = boost::numeric::ublas::dynamic_extents<>; - - fixture() - : extents { - dynamic_extents_type{1,1}, // 1 - dynamic_extents_type{2,3}, // 2 - dynamic_extents_type{2,3,1}, // 3 - dynamic_extents_type{4,2,3}, // 4 - dynamic_extents_type{4,2,3,5}} // 5 - { - } - - std::tuple< - static_extents_type<1,1>, // 1 - static_extents_type<2,3>, // 2 - static_extents_type<2,3,1>, // 3 - static_extents_type<4,2,3>, // 4 - static_extents_type<4,2,3,5> // 5 - > static_extents{}; - - - std::vector extents; -}; - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - for_each_tuple(static_extents,[](auto const&, auto& n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::static_tensor; - using vector_type = typename tensor_type::vector_type; - auto a = tensor_type(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( static_cast< inner_type_t >(n[m]) ) * a[i]); - } - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - for_each_tuple(static_extents,[](auto const&, auto & n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::static_tensor; - using matrix_type = typename tensor_type::matrix_type; - auto a = tensor_type(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( static_cast< inner_type_t >(n[m]) ) * a[i]); - } - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - auto const body = [](auto const& a, auto const& b){ - auto const pa = a.rank(); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phi = std::vector(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 *= value_type( static_cast< inner_type_t >( 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]); - } - }; - - std::apply ( - [&body](auto&& ... sextents) - { - ( - body( - ublas::static_tensor, layout_type>(value_type{2}) , - ublas::static_tensor, layout_type>(value_type{3}) ), ... - ); - }, - static_extents - ); - - - std::apply ( - [&body](auto&& ... sextents ) - { - ( - body( - ublas::static_tensor , layout_type>( value_type{2}) , - ublas::dynamic_tensor((sextents),value_type{3})), ... - ); - }, - static_extents - ); - - - std::apply ( - [&body](auto&& ... sextents ) - { - ( - body( - ublas::dynamic_tensor((sextents),value_type{2}), - ublas::static_tensor , layout_type>( value_type{3})), ... - ); - }, - static_extents - ); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - - - auto compute_factorial = [](auto const& p){ - auto f = 1ul; - for(auto i = 1u; i <= p; ++i) - f *= i; - return f; - }; - - auto permute_extents_s_1 = [](auto const& pi, auto const& na){ - auto nb = ublas::dynamic_extents<>(na); - assert(pi.size() == na.size()); - for(auto j = 0u; j < pi.size(); ++j) - nb[pi[j]-1] = na[j]; - return nb; - }; - auto permute_extents_s_2 = [](auto const& pi, auto const& na){ - auto tempn = na.base(); - assert(pi.size() == na.size()); - for(auto j = 0u; j < pi.size(); ++j) - tempn[pi[j]-1] = na[j]; - return ublas::dynamic_extents::type::_size>(tempn.begin(),tempn.end()); - }; - -// static and dynamic - for_each_tuple(static_extents,[&](auto const&, auto & n){ - auto na = n; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::static_tensor; - auto a = tensor_type_1(value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_s_1(pi, na); - using tensor_type_2 = ublas::dynamic_tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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 *= value_type( static_cast< inner_type_t >( 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()); - } - }); - - //static and static - for_each_tuple(static_extents,[&](auto const&, auto & n){ - auto na = n; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::static_tensor; - auto a = tensor_type_1(value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_s_2(pi, na); - - using tensor_type_2 = ublas::dynamic_tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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_static_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; - - auto const body = [&](auto const& a, auto const& b){ - if(a.size() == 0u || b.size() == 0u ) - return; - - 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 ); - }; - - for_each_tuple(static_extents,[&](auto const&, auto & n){ - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::static_tensor; - using tensor_type_2 = ublas::static_tensor; - - if constexpr(extents_type_1::_size == 0u || extents_type_2::_size == 0u) - return; - - auto a = tensor_type_1(value_type(2)); - auto b = tensor_type_2(value_type(1)); - body(a,b); - - }); - - for_each_tuple(static_extents,[&](auto const& I, auto & n){ - if(extents.empty() || std::tuple_size_v == 0u) - return; - - assert(extents.size() > I); - - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::static_tensor; - using tensor_type_2 = ublas::dynamic_tensor; - - if constexpr(extents_type_1::_size == 0u) - return; - - auto a = tensor_type_1(value_type(2)); - auto b = tensor_type_2(extents[I], value_type(1)); - body(a,b); - - - }); - - for_each_tuple(static_extents,[&](auto const& I, auto & n){ - - if(extents.empty()) - return; - - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::dynamic_tensor; - using tensor_type_2 = ublas::static_tensor; - - if constexpr(extents_type_2::_size == 0u) - return; - - assert(extents.size() > I); - - auto a = tensor_type_1(extents[I], value_type(2)); - auto b = tensor_type_2(value_type(1)); - body(a,b); - - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_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; - - for_each_tuple(static_extents,[&](auto const&, auto const& n1){ - using extents_type_1 = typename std::decay::type; - - if constexpr(extents_type_1::_size == 0u) - return; - - using tensor_type_1 = ublas::static_tensor; - auto a = tensor_type_1(value_type(2)); - for_each_tuple(static_extents,[&](auto const& /*J*/, auto const& n2){ - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::static_tensor; - - if constexpr(extents_type_2::_size == 0u) - return; - - auto b = tensor_type_2(value_type(1)); - auto c = ublas::outer_prod(a, b); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - - }); - - }); - - for_each_tuple(static_extents,[&](auto const& I, auto const& /*n1*/){ - using tensor_type_1 = ublas::dynamic_tensor; - - if(extents.empty() || std::tuple_size_v) - return; - - assert(extents.size() > I); - - auto a = tensor_type_1(extents[I], value_type(2)); - for_each_tuple(static_extents,[&](auto const& /*J*/, auto const& n2){ - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::static_tensor; - auto b = tensor_type_2(value_type(1)); - auto c = ublas::outer_prod(a, b); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - }); - - }); - - for_each_tuple(static_extents,[&](auto const&, auto const& n1){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::static_tensor; - auto a = tensor_type_1(value_type(2)); - for(auto n2 : extents){ - using tensor_type_2 = ublas::dynamic_tensor; - auto b = tensor_type_2(n2, value_type(1)); - auto c = ublas::outer_prod(a, b); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - } - - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_trans, value, test_types, fixture ) -{ - using namespace boost::numeric; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto fac = [](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_each_tuple(static_extents,[&](auto const&, auto & n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::static_tensor; - auto const p = n.size(); - auto const s = product(n); - auto aref = tensor_type(); - auto v = value_type{}; - for(auto i = 0u; i < s; ++i, v+=1) - aref[i] = v; - - auto pi = std::vector(p); - std::iota(pi.begin(), pi.end(), 1); - - auto a = ublas::trans( aref, pi ); - - for(auto i = 0ul; i < a.size(); i++){ - BOOST_CHECK( a[i] == aref[i] ); - } - - - auto const pfac = fac(p); - auto i = 0u; - for(; i < pfac-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 ); - } - - for(auto j = 0ul; j < a.size(); j++){ - BOOST_CHECK( a[j] == aref[j] ); - } - }); - -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_operators_arithmetic.cpp b/test/tensor/test_static_operators_arithmetic.cpp index 78e5a167e..97a75cc5d 100644 --- a/test/tensor/test_static_operators_arithmetic.cpp +++ b/test/tensor/test_static_operators_arithmetic.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -22,7 +22,7 @@ BOOST_AUTO_TEST_SUITE(test_static_tensor_arithmetic_operations) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; -using test_types = zip::with_t; +using test_types = zip::with_t; struct fixture { diff --git a/test/tensor/test_static_operators_comparison.cpp b/test/tensor/test_static_operators_comparison.cpp index b45817494..045cea23a 100644 --- a/test/tensor/test_static_operators_comparison.cpp +++ b/test/tensor/test_static_operators_comparison.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -21,7 +21,7 @@ BOOST_AUTO_TEST_SUITE(test_static_tensor_comparison) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; -using test_types = zip::with_t; +using test_types = zip::with_t; struct fixture { template @@ -191,7 +191,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_scalar, value, te }; -for_each_tuple(extents,check); + for_each_tuple(extents,check); } diff --git a/test/tensor/test_static_strides.cpp b/test/tensor/test_static_strides.cpp index fbe4a37d0..72b11c58c 100644 --- a/test/tensor/test_static_strides.cpp +++ b/test/tensor/test_static_strides.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #include @@ -18,8 +18,8 @@ BOOST_AUTO_TEST_SUITE(test_static_strides) -using test_types = std::tuple; +using test_types = std::tuple; template using extents_type = boost::numeric::ublas::basic_static_extents; @@ -29,31 +29,31 @@ using strides_type = boost::numeric::ublas::strides_t; BOOST_AUTO_TEST_CASE_TEMPLATE(test_static_strides_ctor, value, test_types) { using namespace boost::numeric; - strides_type, ublas::first_order> s1{}; + strides_type, ublas::layout::first_order> s1{}; BOOST_CHECK_EQUAL(s1.empty(), false); BOOST_CHECK_EQUAL(s1.size(), 2); - strides_type, ublas::first_order> s2{}; + strides_type, ublas::layout::first_order> s2{}; BOOST_CHECK_EQUAL(s2.empty(), false); BOOST_CHECK_EQUAL(s2.size(), 2); - strides_type, ublas::first_order> s3{}; + strides_type, ublas::layout::first_order> s3{}; BOOST_CHECK_EQUAL(s3.empty(), false); BOOST_CHECK_EQUAL(s3.size(), 2); - strides_type, ublas::first_order> s4{}; + strides_type, ublas::layout::first_order> s4{}; BOOST_CHECK_EQUAL(s4.empty(), false); BOOST_CHECK_EQUAL(s4.size(), 2); - strides_type, ublas::first_order> s5{}; + strides_type, ublas::layout::first_order> s5{}; BOOST_CHECK_EQUAL(s5.empty(), false); BOOST_CHECK_EQUAL(s5.size(), 3); - strides_type, ublas::first_order> s6{}; + strides_type, ublas::layout::first_order> s6{}; BOOST_CHECK_EQUAL(s6.empty(), false); BOOST_CHECK_EQUAL(s6.size(), 3); - strides_type, ublas::first_order> s7{}; + strides_type, ublas::layout::first_order> s7{}; BOOST_CHECK_EQUAL(s7.empty(), false); BOOST_CHECK_EQUAL(s7.size(), 3); } @@ -61,45 +61,45 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_static_strides_ctor, value, test_types) { BOOST_AUTO_TEST_CASE(test_static_strides_ctor_access_first_order) { using namespace boost::numeric; - strides_type, ublas::first_order> s1{}; + strides_type, ublas::layout::first_order> s1{}; BOOST_REQUIRE_EQUAL(s1.size(), 2); BOOST_CHECK_EQUAL(s1[0], 1); BOOST_CHECK_EQUAL(s1[1], 1); - strides_type, ublas::first_order> s2{}; + strides_type, ublas::layout::first_order> s2{}; BOOST_REQUIRE_EQUAL(s2.size(), 2); BOOST_CHECK_EQUAL(s2[0], 1); BOOST_CHECK_EQUAL(s2[1], 1); - strides_type, ublas::first_order> s3{}; + strides_type, ublas::layout::first_order> s3{}; BOOST_REQUIRE_EQUAL(s3.size(), 2); BOOST_CHECK_EQUAL(s3[0], 1); BOOST_CHECK_EQUAL(s3[1], 1); - strides_type, ublas::first_order> s4{}; + strides_type, ublas::layout::first_order> s4{}; BOOST_REQUIRE_EQUAL(s4.size(), 2); BOOST_CHECK_EQUAL(s4[0], 1); BOOST_CHECK_EQUAL(s4[1], 2); - strides_type, ublas::first_order> s5{}; + strides_type, ublas::layout::first_order> s5{}; 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, ublas::first_order> s6{}; + strides_type, ublas::layout::first_order> s6{}; 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, ublas::first_order> s7{}; + strides_type, ublas::layout::first_order> s7{}; 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, ublas::first_order> s8{}; + strides_type, ublas::layout::first_order> s8{}; BOOST_REQUIRE_EQUAL(s8.size(), 3); BOOST_CHECK_EQUAL(s8[0], 1); BOOST_CHECK_EQUAL(s8[1], 4); @@ -109,45 +109,45 @@ BOOST_AUTO_TEST_CASE(test_static_strides_ctor_access_first_order) { BOOST_AUTO_TEST_CASE(test_static_strides_ctor_access_last_order) { using namespace boost::numeric; - strides_type, ublas::last_order> s1{}; + strides_type, ublas::layout::last_order> s1{}; BOOST_REQUIRE_EQUAL(s1.size(), 2); BOOST_CHECK_EQUAL(s1[0], 1); BOOST_CHECK_EQUAL(s1[1], 1); - strides_type, ublas::last_order> s2{}; + strides_type, ublas::layout::last_order> s2{}; BOOST_REQUIRE_EQUAL(s2.size(), 2); BOOST_CHECK_EQUAL(s2[0], 1); BOOST_CHECK_EQUAL(s2[1], 1); - strides_type, ublas::last_order> s3{}; + strides_type, ublas::layout::last_order> s3{}; BOOST_REQUIRE_EQUAL(s3.size(), 2); BOOST_CHECK_EQUAL(s3[0], 1); BOOST_CHECK_EQUAL(s3[1], 1); - strides_type, ublas::last_order> s4{}; + strides_type, ublas::layout::last_order> s4{}; BOOST_REQUIRE_EQUAL(s4.size(), 2); BOOST_CHECK_EQUAL(s4[0], 3); BOOST_CHECK_EQUAL(s4[1], 1); - strides_type, ublas::last_order> s5{}; + strides_type, ublas::layout::last_order> s5{}; 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, ublas::last_order> s6{}; + strides_type, ublas::layout::last_order> s6{}; 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, ublas::last_order> s7{}; + strides_type, ublas::layout::last_order> s7{}; 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, ublas::last_order> s8{}; + strides_type, ublas::layout::last_order> s8{}; BOOST_REQUIRE_EQUAL(s8.size(), 3); BOOST_CHECK_EQUAL(s8[0], 6); BOOST_CHECK_EQUAL(s8[1], 3); diff --git a/test/tensor/test_static_tensor.cpp b/test/tensor/test_static_tensor.cpp index ebed2fab9..987428f4d 100644 --- a/test/tensor/test_static_tensor.cpp +++ b/test/tensor/test_static_tensor.cpp @@ -7,13 +7,13 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // #include -#include +#include #ifndef BOOST_TEST_DYN_LINK #define BOOST_TEST_DYN_LINK @@ -26,7 +26,7 @@ BOOST_AUTO_TEST_SUITE ( test_static_tensor ) -using test_types = zip>::with_t; +using test_types = zip>::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) @@ -142,7 +142,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_typ using namespace boost::numeric; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; + using other_layout_type = std::conditional_t::value, ublas::layout::last_order, ublas::layout::first_order>; for_each_tuple(extents, [](auto const&, auto& e){ @@ -294,8 +294,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check2 = [](const auto& t) { std::array k; - auto r = std::is_same::value ? 1 : 0; - auto q = std::is_same::value ? 1 : 0; + auto r = std::is_same::value ? 1 : 0; + auto q = std::is_same::value ? 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]){ @@ -308,8 +308,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check3 = [](const auto& t) { std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 2 : 0; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 2 : 0; auto o = op_type{}; auto v = value_type{}; for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){ @@ -325,8 +325,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check4 = [](const auto& t) { std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 3 : 0; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 3 : 0; auto o = op_type{}; auto v = value_type{}; for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){ @@ -397,7 +397,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, value, test_types, fixture) auto t = tensor_type{}; auto i = ublas::index::index_type<4>{}; - BOOST_CHECK_THROW(t.operator()(i,i,i), std::runtime_error); + BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::runtime_error); } diff --git a/test/tensor/test_static_tensor_matrix_vector.cpp b/test/tensor/test_static_tensor_matrix_vector.cpp index 3578886d7..bce3749ad 100644 --- a/test/tensor/test_static_tensor_matrix_vector.cpp +++ b/test/tensor/test_static_tensor_matrix_vector.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // // The authors gratefully acknowledge the support of -// Google +// Google and Fraunhofer IOSB, Ettlingen, Germany // @@ -23,7 +23,7 @@ BOOST_AUTO_TEST_SUITE ( test_static_tensor_matrix_interoperability ) ; -using test_types = zip::with_t; +using test_types = zip::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types) diff --git a/test/tensor/test_strides.cpp b/test/tensor/test_strides.cpp index e7a63585c..85d7bb230 100644 --- a/test/tensor/test_strides.cpp +++ b/test/tensor/test_strides.cpp @@ -20,14 +20,14 @@ BOOST_AUTO_TEST_SUITE(test_strides) -using test_types = std::tuple; +using test_types = std::tuple; BOOST_AUTO_TEST_CASE_TEMPLATE( test_strides_ctor, value, test_types) { using namespace boost::numeric; using extents_type = ublas::basic_extents; - using strides_type = ublas::strides_t; + using strides_type = ublas::strides_t; strides_type s0{}; BOOST_CHECK ( s0.empty()); @@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE( test_strides_ctor_access_first_order) using namespace boost::numeric; using extents_type = ublas::basic_extents; - using strides_type = ublas::strides_t; + using strides_type = ublas::strides_t; strides_type s1{extents_type{1,1}}; BOOST_REQUIRE_EQUAL( s1.size(),2); @@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE( test_strides_ctor_access_last_order) using namespace boost::numeric; using extents_type = ublas::basic_extents; - using strides_type = ublas::strides_t; + using strides_type = ublas::strides_t; strides_type s1{extents_type{1,1}}; BOOST_REQUIRE_EQUAL( s1.size(),2); diff --git a/test/tensor/test_tensor.cpp b/test/tensor/test_tensor.cpp index 5e09c57a0..d429fe5fd 100644 --- a/test/tensor/test_tensor.cpp +++ b/test/tensor/test_tensor.cpp @@ -13,7 +13,7 @@ #include -#include +#include #ifndef BOOST_TEST_DYN_LINK #define BOOST_TEST_DYN_LINK @@ -28,7 +28,7 @@ // BOOST_AUTO_TEST_SUITE ( test_tensor, * boost::unit_test::depends_on("test_extents") ) ; BOOST_AUTO_TEST_SUITE ( test_tensor ) -using test_types = zip>::with_t; +using test_types = zip>::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) @@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) struct fixture { - using extents_type = boost::numeric::ublas::dynamic_extents<>; + using extents_type = boost::numeric::ublas::extents<>; fixture() : extents { extents_type{}, // 0 @@ -164,7 +164,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_typ using value_type = typename value::first_type; using layout_type = typename value::second_type; using tensor_type = ublas::dynamic_tensor; - using other_layout_type = std::conditional_t::value, ublas::last_order, ublas::first_order>; + using other_layout_type = std::conditional_t::value, ublas::layout::last_order, ublas::layout::first_order>; using other_tensor_type = ublas::dynamic_tensor; @@ -308,8 +308,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check2 = [](const tensor_type& t) { std::array k; - auto r = std::is_same::value ? 1 : 0; - auto q = std::is_same::value ? 1 : 0; + auto r = std::is_same::value ? 1 : 0; + auto q = std::is_same::value ? 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]){ @@ -322,8 +322,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check3 = [](const tensor_type& t) { std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 2 : 0; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 2 : 0; auto o = op_type{}; auto v = value_type{}; for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){ @@ -339,8 +339,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check4 = [](const tensor_type& t) { std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 3 : 0; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 3 : 0; auto o = op_type{}; auto v = value_type{}; for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){ @@ -486,7 +486,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, value, test_types, fixture) auto t = tensor_type{{5,5}}; auto i = ublas::index::index_type<4>{}; - BOOST_CHECK_THROW(t.operator()(i,i,i), std::runtime_error); + BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::runtime_error); } diff --git a/test/tensor/test_tensor_matrix_vector.cpp b/test/tensor/test_tensor_matrix_vector.cpp index 313e5f7f8..7672bb31a 100644 --- a/test/tensor/test_tensor_matrix_vector.cpp +++ b/test/tensor/test_tensor_matrix_vector.cpp @@ -23,7 +23,7 @@ BOOST_AUTO_TEST_SUITE ( test_tensor_matrix_interoperability ) -using test_types = zip::with_t; +using test_types = zip::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types) @@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, value, test_types) struct fixture { - using extents_type = boost::numeric::ublas::dynamic_extents<>; + using extents_type = boost::numeric::ublas::extents<>; fixture() : extents{ extents_type{1,1}, // 1 diff --git a/test/tensor/utility.hpp b/test/tensor/utility.hpp index 859101ed1..6dc5f1a45 100644 --- a/test/tensor/utility.hpp +++ b/test/tensor/utility.hpp @@ -117,10 +117,10 @@ using inner_type_t = typename inner_type::type; // creates e.g. -// using test_types = zip::with_t; // equals -// using test_types = std::tuple< std::pair, std::pair, std::pair, std::pair +// using test_types = zip::with_t; // equals +// using test_types = std::tuple< std::pair, std::pair, std::pair, std::pair //>; //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 "); +//static_assert(std::is_same< std::tuple_element_t<1,std::tuple_element_t<0,test_types2>>, boost::numeric::ublas::layout::first_order>::value,"should be boost::numeric::ublas::layout::first_order "); #endif From a81712c3195183139fc7923dc32031dab2859ec9 Mon Sep 17 00:00:00 2001 From: Cem Bassoy Date: Thu, 10 Dec 2020 19:01:03 +0100 Subject: [PATCH 22/36] fixing github action ymls (#107) --- .github/workflows/address_san.yml | 3 ++- .github/workflows/apple_clang.yml | 3 ++- .github/workflows/linux_clang.yml | 3 ++- .github/workflows/linux_gcc.yml | 5 +++-- .github/workflows/thread_san.yml | 3 ++- .github/workflows/ub_san.yml | 3 ++- .github/workflows/windows_msvc.yml | 21 +++++++++++---------- 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.github/workflows/address_san.yml b/.github/workflows/address_san.yml index efac3aab9..5cf0c85db 100644 --- a/.github/workflows/address_san.yml +++ b/.github/workflows/address_san.yml @@ -47,7 +47,8 @@ jobs: ./bootstrap.sh ./b2 -j 8 headers - echo ::set-env name=BOOST_ROOT::${PWD} + #echo ::set-env name=BOOST_ROOT::${PWD} + echo "BOOST_ROOT=${PWD}" >> $GITHUB_ENV - name: Prepare Build run: | diff --git a/.github/workflows/apple_clang.yml b/.github/workflows/apple_clang.yml index da1047330..dfaa5d470 100644 --- a/.github/workflows/apple_clang.yml +++ b/.github/workflows/apple_clang.yml @@ -44,7 +44,8 @@ jobs: ./bootstrap.sh ./b2 -j 8 headers - echo ::set-env name=BOOST_ROOT::${PWD} + #echo ::set-env name=BOOST_ROOT::${PWD} + echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} - name: Prepare Build run: | diff --git a/.github/workflows/linux_clang.yml b/.github/workflows/linux_clang.yml index 5f1e86773..e03dfcc1a 100644 --- a/.github/workflows/linux_clang.yml +++ b/.github/workflows/linux_clang.yml @@ -68,7 +68,8 @@ jobs: ./bootstrap.sh ./b2 -j 8 headers - echo ::set-env name=BOOST_ROOT::${PWD} + #echo ::set-env name=BOOST_ROOT::${PWD} + echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} - name: Prepare Build run: | diff --git a/.github/workflows/linux_gcc.yml b/.github/workflows/linux_gcc.yml index 7da00063d..3fa47504e 100644 --- a/.github/workflows/linux_gcc.yml +++ b/.github/workflows/linux_gcc.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Mohammad Ashar Khan +# Copyright (c) 2020 Mohammad Ashar Khan, Cem Bassoy # Distributed under Boost Software License, Version 1.0 # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) @@ -60,7 +60,8 @@ jobs: ./bootstrap.sh ./b2 -j 8 headers - echo ::set-env name=BOOST_ROOT::${PWD} + #echo ::set-env name=BOOST_ROOT::${PWD} + echo "BOOST_ROOT=${PWD}" >> $GITHUB_ENV - name: Prepare Build run: | diff --git a/.github/workflows/thread_san.yml b/.github/workflows/thread_san.yml index 128a337eb..4fc416a0d 100644 --- a/.github/workflows/thread_san.yml +++ b/.github/workflows/thread_san.yml @@ -47,7 +47,8 @@ jobs: ./bootstrap.sh ./b2 -j 8 headers - echo ::set-env name=BOOST_ROOT::${PWD} + #echo ::set-env name=BOOST_ROOT::${PWD} + echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} - name: Prepare Build run: | diff --git a/.github/workflows/ub_san.yml b/.github/workflows/ub_san.yml index 52db9fd17..1985bf458 100644 --- a/.github/workflows/ub_san.yml +++ b/.github/workflows/ub_san.yml @@ -47,7 +47,8 @@ jobs: ./bootstrap.sh ./b2 -j 8 headers - echo ::set-env name=BOOST_ROOT::${PWD} + #echo ::set-env name=BOOST_ROOT::${PWD} + echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} - name: Prepare Build run: | diff --git a/.github/workflows/windows_msvc.yml b/.github/workflows/windows_msvc.yml index a50cab40d..59e6ff05d 100644 --- a/.github/workflows/windows_msvc.yml +++ b/.github/workflows/windows_msvc.yml @@ -14,29 +14,29 @@ on: - 'doc/**' jobs: build: - name: "${{matrix.config.version}} -std=c++${{matrix.config.cxxstd}}" + name: "windows=${{matrix.config.os}} msvc=${{matrix.config.version}} std=c++${{matrix.config.cxxstd}}" runs-on: ${{matrix.config.os}} strategy: fail-fast: false matrix: config: - {os: windows-2016, toolset: msvc, version: 14.16, cxxstd: 11} - - {os: windows-2019, toolset: msvc, version: 14.27, cxxstd: 11} - - {os: windows-2019, toolset: msvc, version: 14.27, cxxstd: 17} - - {os: windows-2019, toolset: msvc, version: 14.27, cxxstd: latest} + - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: 11} + - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: 17} + - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: latest} steps: - uses: actions/checkout@v2 - name: Enable Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1.3.0 + uses: ilammy/msvc-dev-cmd@v1 with: toolset: ${{matrix.config.version}} - name: Setup BOOST_ROOT - shell: cmd + shell: powershell run: | - cd %GITHUB_WORKSPACE% + cd $env:GITHUB_WORKSPACE cd .. git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root cd boost-root @@ -44,12 +44,13 @@ jobs: git submodule update --init --depth=1 libs/config git submodule update --init --depth=1 tools/boostdep - xcopy /s /e /q %GITHUB_WORKSPACE% libs\numeric\ublas + xcopy /s /e /q $env:GITHUB_WORKSPACE libs\numeric\ublas python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - echo ::set-env name=BOOST_ROOT::%cd% - echo ::set-env name=TOOLSET::${{matrix.config.toolset}}-${{matrix.config.version}} + + echo "BOOST_ROOT=$pwd" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + echo "TOOLSET=${{matrix.config.toolset}}-${{matrix.config.version}}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Prepare BOOST_ROOT shell: powershell From f0e0578b29121a049c6704ffd953a67e6923b484 Mon Sep 17 00:00:00 2001 From: Cem Bassoy Date: Tue, 12 Jan 2021 18:22:16 +0100 Subject: [PATCH 23/36] adjusting qt files and examples. (#109) --- IDEs/qtcreator/examples/configuration.pri | 19 +- .../example_construction_access.pro | 7 - .../example_einstein_notation.pro | 7 - .../examples/tensor/example_access_tensor.pro | 7 + .../tensor/example_instantiate_tensor.pro | 7 + ...ple_multiply_tensors_einstein_notation.pro | 7 + ...mple_multiply_tensors_product_function.pro | 7 + .../tensor/example_simple_expressions.pro | 7 + .../example_prod_expressions.pro | 7 - .../example_simple_expressions.pro | 7 - IDEs/qtcreator/examples/tensor/tensor.pro | 24 +- IDEs/qtcreator/include/include.pro | 5 +- IDEs/qtcreator/include/tensor/tensor.pri | 52 ++- IDEs/qtcreator/test/test_tensor.pro | 67 ++-- IDEs/qtcreator/ublas_develop.pro | 2 +- examples/tensor/Jamfile | 19 +- examples/tensor/access_tensor.cpp | 103 ++++++ examples/tensor/construction_access.cpp | 90 ----- examples/tensor/dynamic_prod_expressions.cpp | 184 ---------- .../tensor/fixed_rank_prod_expressions.cpp | 170 --------- examples/tensor/fixed_rank_tensor.cpp | 92 ----- examples/tensor/instantiate_tensor.cpp | 93 +++++ ...=> multiply_tensors_einstein_notation.cpp} | 70 ++-- .../multiply_tensors_product_function.cpp | 344 ++++++++++++++++++ examples/tensor/simple_expressions.cpp | 7 +- examples/tensor/static_tensor.cpp | 70 ---- examples/tensor/tensor_construction.cpp | 111 ------ include/boost/numeric/ublas/tensor.hpp | 1 + .../boost/numeric/ublas/tensor/functions.hpp | 6 +- test/tensor/Jamfile | 17 +- test/tensor/test_fixed_rank_tensor.cpp | 8 +- test/tensor/test_static_tensor.cpp | 8 +- test/tensor/test_strides.cpp | 5 +- test/tensor/test_tensor.cpp | 2 +- 34 files changed, 757 insertions(+), 875 deletions(-) delete mode 100644 IDEs/qtcreator/examples/tensor/construction_access/example_construction_access.pro delete mode 100644 IDEs/qtcreator/examples/tensor/einstein_notation/example_einstein_notation.pro create mode 100644 IDEs/qtcreator/examples/tensor/example_access_tensor.pro create mode 100644 IDEs/qtcreator/examples/tensor/example_instantiate_tensor.pro create mode 100644 IDEs/qtcreator/examples/tensor/example_multiply_tensors_einstein_notation.pro create mode 100644 IDEs/qtcreator/examples/tensor/example_multiply_tensors_product_function.pro create mode 100644 IDEs/qtcreator/examples/tensor/example_simple_expressions.pro delete mode 100644 IDEs/qtcreator/examples/tensor/prod_expressions/example_prod_expressions.pro delete mode 100644 IDEs/qtcreator/examples/tensor/simple_expressions/example_simple_expressions.pro create mode 100644 examples/tensor/access_tensor.cpp delete mode 100644 examples/tensor/construction_access.cpp delete mode 100644 examples/tensor/dynamic_prod_expressions.cpp delete mode 100644 examples/tensor/fixed_rank_prod_expressions.cpp delete mode 100644 examples/tensor/fixed_rank_tensor.cpp create mode 100644 examples/tensor/instantiate_tensor.cpp rename examples/tensor/{einstein_notation.cpp => multiply_tensors_einstein_notation.cpp} (65%) create mode 100644 examples/tensor/multiply_tensors_product_function.cpp delete mode 100644 examples/tensor/static_tensor.cpp delete mode 100644 examples/tensor/tensor_construction.cpp diff --git a/IDEs/qtcreator/examples/configuration.pri b/IDEs/qtcreator/examples/configuration.pri index 59e3f1a92..0c0c8650f 100644 --- a/IDEs/qtcreator/examples/configuration.pri +++ b/IDEs/qtcreator/examples/configuration.pri @@ -2,17 +2,16 @@ CONFIG -= qt CONFIG += depend_includepath win*: CONFIG += console -# ublas include directory -INCLUDEPATH += \ - ../../../../../include - -QMAKE_CXXFLAGS += -fno-inline -QMAKE_CXXFLAGS += -std=c++17 +QMAKE_CXXFLAGS += -std=c++17 -fopenmp -g # If ublas tests are build with boost source code then, # then boost headers and boost libraries should be used. -exists(../../../../../../boost-build.jam) { - INCLUDEPATH += ../../../../../../.. - LIBS += -L../../../../../../../stage/lib - QMAKE_RPATHDIR += ../../../../../../../stage/lib + +BOOST_ROOT=../../../../../.. + +exists( $$BOOST_ROOT/boost-build.jam ) { + message("Boost installed.") + INCLUDEPATH += $${BOOST_ROOT}/../libs/numeric/ublas/include + LIBS += -L$${BOOST_ROOT}/../stage/lib -lgomp + QMAKE_RPATHDIR += $${BOOST_ROOT}/../stage/lib } diff --git a/IDEs/qtcreator/examples/tensor/construction_access/example_construction_access.pro b/IDEs/qtcreator/examples/tensor/construction_access/example_construction_access.pro deleted file mode 100644 index 8d6abef37..000000000 --- a/IDEs/qtcreator/examples/tensor/construction_access/example_construction_access.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = construction_access - -include (../../configuration.pri) - -SOURCES += \ - ../../../../../examples/tensor/construction_access.cpp diff --git a/IDEs/qtcreator/examples/tensor/einstein_notation/example_einstein_notation.pro b/IDEs/qtcreator/examples/tensor/einstein_notation/example_einstein_notation.pro deleted file mode 100644 index 302b02a10..000000000 --- a/IDEs/qtcreator/examples/tensor/einstein_notation/example_einstein_notation.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = einstein_notation - -include (../../configuration.pri) - -SOURCES += \ - ../../../../../examples/tensor/einstein_notation.cpp diff --git a/IDEs/qtcreator/examples/tensor/example_access_tensor.pro b/IDEs/qtcreator/examples/tensor/example_access_tensor.pro new file mode 100644 index 000000000..c6d761159 --- /dev/null +++ b/IDEs/qtcreator/examples/tensor/example_access_tensor.pro @@ -0,0 +1,7 @@ +TEMPLATE = app +TARGET = access_tensor + +include (../configuration.pri) + +SOURCES += \ + ../../../../examples/tensor/access_tensor.cpp diff --git a/IDEs/qtcreator/examples/tensor/example_instantiate_tensor.pro b/IDEs/qtcreator/examples/tensor/example_instantiate_tensor.pro new file mode 100644 index 000000000..e98706b38 --- /dev/null +++ b/IDEs/qtcreator/examples/tensor/example_instantiate_tensor.pro @@ -0,0 +1,7 @@ +TEMPLATE = app +TARGET = instantiate_tensor + +include (../configuration.pri) + +SOURCES += \ + ../../../../examples/tensor/instantiate_tensor.cpp diff --git a/IDEs/qtcreator/examples/tensor/example_multiply_tensors_einstein_notation.pro b/IDEs/qtcreator/examples/tensor/example_multiply_tensors_einstein_notation.pro new file mode 100644 index 000000000..1aca61e34 --- /dev/null +++ b/IDEs/qtcreator/examples/tensor/example_multiply_tensors_einstein_notation.pro @@ -0,0 +1,7 @@ +TEMPLATE = app +TARGET = multiply_tensors_einstein_notation + +include (../configuration.pri) + +SOURCES += \ + ../../../../examples/tensor/multiply_tensors_einstein_notation.cpp diff --git a/IDEs/qtcreator/examples/tensor/example_multiply_tensors_product_function.pro b/IDEs/qtcreator/examples/tensor/example_multiply_tensors_product_function.pro new file mode 100644 index 000000000..bf02e0228 --- /dev/null +++ b/IDEs/qtcreator/examples/tensor/example_multiply_tensors_product_function.pro @@ -0,0 +1,7 @@ +TEMPLATE = app +TARGET = multiply_tensors_product_function + +include (../configuration.pri) + +SOURCES += \ + ../../../../examples/tensor/multiply_tensors_product_function.cpp diff --git a/IDEs/qtcreator/examples/tensor/example_simple_expressions.pro b/IDEs/qtcreator/examples/tensor/example_simple_expressions.pro new file mode 100644 index 000000000..1c65b9cc6 --- /dev/null +++ b/IDEs/qtcreator/examples/tensor/example_simple_expressions.pro @@ -0,0 +1,7 @@ +TEMPLATE = app +TARGET = simple_expressions + +include (../configuration.pri) + +SOURCES += \ + ../../../../examples/tensor/simple_expressions.cpp diff --git a/IDEs/qtcreator/examples/tensor/prod_expressions/example_prod_expressions.pro b/IDEs/qtcreator/examples/tensor/prod_expressions/example_prod_expressions.pro deleted file mode 100644 index 2e210c249..000000000 --- a/IDEs/qtcreator/examples/tensor/prod_expressions/example_prod_expressions.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = prod_expression - -include (../../configuration.pri) - -SOURCES += \ - ../../../../../examples/tensor/prod_expressions.cpp diff --git a/IDEs/qtcreator/examples/tensor/simple_expressions/example_simple_expressions.pro b/IDEs/qtcreator/examples/tensor/simple_expressions/example_simple_expressions.pro deleted file mode 100644 index 3b106c9f3..000000000 --- a/IDEs/qtcreator/examples/tensor/simple_expressions/example_simple_expressions.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = simple_expressions - -include (../../configuration.pri) - -SOURCES += \ - ../../../../../examples/tensor/simple_expressions.cpp diff --git a/IDEs/qtcreator/examples/tensor/tensor.pro b/IDEs/qtcreator/examples/tensor/tensor.pro index d50e56c61..feb833f62 100644 --- a/IDEs/qtcreator/examples/tensor/tensor.pro +++ b/IDEs/qtcreator/examples/tensor/tensor.pro @@ -1,9 +1,21 @@ -TEMPLATE = subdirs -SUBDIRS = construction_access simple_expressions prod_expressions einstein_notation +#TEMPLATE = subdirs +#SUBDIRS = \ +# construction_access \ +# simple_expressions \ +# multiply_tensors_prod \ +# einstein_notation \ +# instantiate_tensor +include ( example_instantiate_tensor.pro ) +include ( example_access_tensor.pro ) +include ( example_simple_expressions.pro ) +include ( example_multiply_tensors_product_function.pro ) +include ( example_multiply_tensors_einstein_notation.pro ) + +#instantiate_tensor.file = example_instantiate_tensor.pro +#construction_access.file = example_construction_access.pro +#simple_expressions.file = example_simple_expressions.pro +#multiply_tensors_prod.file = example_multiply_tensors_prod.pro +#einstein_notation.file = example_einstein_notation.pro -construction_access.file = construction_access/example_construction_access.pro -simple_expressions.file = simple_expressions/example_simple_expressions.pro -prod_expressions.file = prod_expressions/example_prod_expressions.pro -einstein_notation.file = einstein_notation/example_einstein_notation.pro diff --git a/IDEs/qtcreator/include/include.pro b/IDEs/qtcreator/include/include.pro index 185254103..17d199106 100644 --- a/IDEs/qtcreator/include/include.pro +++ b/IDEs/qtcreator/include/include.pro @@ -5,14 +5,13 @@ CONFIG += \ staticlib \ depend_includepath CONFIG -= qt - -INCLUDE_DIR = ../../../include +CONFIG += c++17 +INCLUDE_DIR=../../../include include(detail/detail.pri) include(experimental/experimental.pri) include(operation/operation.pri) include(traits/traits.pri) - include(tensor/tensor.pri) INCLUDEPATH += $${INCLUDE_DIR} diff --git a/IDEs/qtcreator/include/tensor/tensor.pri b/IDEs/qtcreator/include/tensor/tensor.pri index 503aacb68..4cfae5d9f 100644 --- a/IDEs/qtcreator/include/tensor/tensor.pri +++ b/IDEs/qtcreator/include/tensor/tensor.pri @@ -1,15 +1,39 @@ HEADERS += \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/extents.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/strides.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/expression.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/ostream.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/multiplication.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/functions.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/algorithms.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/expression_evaluation.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/operators_comparison.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/operators_arithmetic.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/multi_index.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/multi_index_utility.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/index.hpp + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/algorithms.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/dynamic_extents.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/dynamic_strides.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/expression.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/expression_evaluation.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/extents_functions.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/fixed_rank_extents.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/fixed_rank_strides.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/functions.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/index.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/layout.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/multi_index.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/multi_index_utility.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/multiplication.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/operators_arithmetic.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/operators_comparison.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/ostream.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/static_extents.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/static_strides.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/strides.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tags.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor_core.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor_engine.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/type_traits.hpp + +HEADERS += \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/basic_type_traits.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/storage_traits.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_dynamic_extents.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_dynamic_strides.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_extents.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_strides.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_static_extents.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_static_strides.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_tensor.hpp diff --git a/IDEs/qtcreator/test/test_tensor.pro b/IDEs/qtcreator/test/test_tensor.pro index 539546631..5966e27d6 100644 --- a/IDEs/qtcreator/test/test_tensor.pro +++ b/IDEs/qtcreator/test/test_tensor.pro @@ -5,9 +5,9 @@ CONFIG -= qt CONFIG += depend_includepath debug win*: CONFIG += console -QMAKE_CXXFLAGS += -fno-inline +#QMAKE_CXXFLAGS += -fno-inline QMAKE_CXXFLAGS += -std=c++17 -QMAKE_CXXFLAGS += -Wno-unknown-pragmas +#QMAKE_CXXFLAGS += -Wno-unknown-pragmas #QMAKE_CXXFLAGS += --coverage @@ -19,35 +19,54 @@ xlc: DEFINES += BOOST_UBLAS_NO_ELEMENT_PROXIES # If ublas tests are build with boost source code then, # then boost headers and boost libraries should be used. -exists(../../../../../../boost-build.jam) { - INCLUDEPATH += ../../../../../.. - LIBS += -L../../../../../../stage/lib - QMAKE_RPATHDIR += ../../../../../../stage/lib -} - +#exists(../../../../../../boost-build.jam) { +# INCLUDEPATH += ../../../../../.. +# LIBS += -L../../../../../../stage/lib +# QMAKE_RPATHDIR += ../../../../../../stage/lib +#} +INCLUDEPATH += /usr/local/include +INCLUDEPATH += ../../../include +LIBS += -L/usr/local/lib LIBS +=-lboost_unit_test_framework # -lgcov +TEST_DIR = ../../../test/tensor + HEADERS += \ - ../../../test/tensor/utility.hpp + $${TEST_DIR}/utility.hpp SOURCES += \ - ../../../test/tensor/test_tensor.cpp \ - ../../../test/tensor/test_extents.cpp \ - ../../../test/tensor/test_strides.cpp \ - ../../../test/tensor/test_expression.cpp \ - ../../../test/tensor/test_expression_evaluation.cpp \ - ../../../test/tensor/test_functions.cpp \ - ../../../test/tensor/test_operators_comparison.cpp \ - ../../../test/tensor/test_operators_arithmetic.cpp \ - ../../../test/tensor/test_tensor_matrix_vector.cpp \ - ../../../test/tensor/test_multiplication.cpp \ - ../../../test/tensor/test_algorithms.cpp \ - ../../../test/tensor/test_einstein_notation.cpp \ - ../../../test/tensor/test_multi_index.cpp \ - ../../../test/tensor/test_multi_index_utility.cpp - + $${TEST_DIR}/test_algorithms.cpp \ + $${TEST_DIR}/test_einstein_notation.cpp \ + $${TEST_DIR}/test_expression.cpp \ + $${TEST_DIR}/test_expression_evaluation.cpp \ + $${TEST_DIR}/test_extents.cpp \ + $${TEST_DIR}/test_fixed_rank_expression_evaluation.cpp \ + $${TEST_DIR}/test_fixed_rank_extents.cpp \ + $${TEST_DIR}/test_fixed_rank_functions.cpp \ + $${TEST_DIR}/test_fixed_rank_operators_arithmetic.cpp \ + $${TEST_DIR}/test_fixed_rank_operators_comparison.cpp \ + $${TEST_DIR}/test_fixed_rank_strides.cpp \ + $${TEST_DIR}/test_fixed_rank_tensor.cpp \ + $${TEST_DIR}/test_fixed_rank_tensor_matrix_vector.cpp \ + $${TEST_DIR}/test_functions.cpp \ + $${TEST_DIR}/test_multi_index.cpp \ + $${TEST_DIR}/test_multi_index_utility.cpp \ + $${TEST_DIR}/test_multiplication.cpp \ + $${TEST_DIR}/test_operators_arithmetic.cpp \ + $${TEST_DIR}/test_operators_comparison.cpp \ + $${TEST_DIR}/test_static_expression_evaluation.cpp \ + $${TEST_DIR}/test_static_extents.cpp \ + # $${TEST_DIR}/test_static_functions.cpp \ + $${TEST_DIR}/test_static_operators_arithmetic.cpp \ + $${TEST_DIR}/test_static_operators_comparison.cpp \ + $${TEST_DIR}/test_static_strides.cpp \ + $${TEST_DIR}/test_static_tensor.cpp \ + $${TEST_DIR}/test_static_tensor_matrix_vector.cpp \ + $${TEST_DIR}/test_strides.cpp \ + $${TEST_DIR}/test_tensor.cpp \ + $${TEST_DIR}/test_tensor_matrix_vector.cpp INCLUDEPATH += \ diff --git a/IDEs/qtcreator/ublas_develop.pro b/IDEs/qtcreator/ublas_develop.pro index 8139f2493..e509e747e 100644 --- a/IDEs/qtcreator/ublas_develop.pro +++ b/IDEs/qtcreator/ublas_develop.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS = include examples # benchmarks +SUBDIRS = include # examples # benchmarks OTHER_FILES += ../../changelog.txt diff --git a/examples/tensor/Jamfile b/examples/tensor/Jamfile index 7a5b95137..101a8a4c9 100644 --- a/examples/tensor/Jamfile +++ b/examples/tensor/Jamfile @@ -6,24 +6,21 @@ # Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) - +import ../../../../config/checks/config : requires ; + # Project settings project boost-ublas-tensor-example : requirements - # these tests require C++17 - 11:no BOOST_UBLAS_NO_EXCEPTIONS vacpp:"BOOST_UBLAS_NO_ELEMENT_PROXIES" gcc:"-Wall -pedantic -Wextra -Wno-unknown-pragmas" clang:"-Wall -pedantic -Wextra -Wno-unknown-pragmas" msvc:"/W4" # == all + [ requires cxx17_if_constexpr ] ; -exe construction_access : construction_access.cpp ; -exe simple_expressions : simple_expressions.cpp ; -exe dynamic_prod_expressions : dynamic_prod_expressions.cpp ; -exe fixed_rank_prod_expressions : fixed_rank_prod_expressions.cpp ; -exe fixed_rank_tensor : fixed_rank_tensor.cpp ; -exe static_tensor : static_tensor.cpp ; -exe einstein_notation : einstein_notation.cpp ; -exe tensor_construction : tensor_construction.cpp ; \ No newline at end of file +exe access_tensor : access_tensor.cpp ; +exe simple_expressions : simple_expressions.cpp ; +exe multiply_tensors_product_function : multiply_tensors_product_function.cpp ; +exe multiply_tensors_einstein_notation : multiply_tensors_einstein_notation.cpp ; +exe instantiate_tensor : instantiate_tensor.cpp ; diff --git a/examples/tensor/access_tensor.cpp b/examples/tensor/access_tensor.cpp new file mode 100644 index 000000000..ebd7b2fc6 --- /dev/null +++ b/examples/tensor/access_tensor.cpp @@ -0,0 +1,103 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include + +#include + +int main() +{ + using namespace boost::numeric::ublas; + using namespace boost::multiprecision; + + { + using value_t = float; + using format_t = boost::numeric::ublas::layout::first_order; // storage format + using tensor_t = boost::numeric::ublas::dynamic_tensor; + + // creates a three-dimensional tensor with extents 3,4 and 2 + // tensor A stores single-precision floating-point number according + // to the first-order storage format + + auto A = tensor_t{3,4,2}; + + // initializes the tensor with increasing values along the first-index + // using a single index. + auto vf = 1.0f; + for(auto i = 0u; i < A.size(); ++i, vf += 1.0f) + A[i] = vf; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "A=" << A << ";" << std::endl << std::endl; + } + + + { + using value_t = std::complex; + using format_t = boost::numeric::ublas::layout::last_order; // storage format + using tensor_t = boost::numeric::ublas::dynamic_tensor; + using shape_t = typename tensor_t::extents_type; + + // creates a four-dimensional tensor with extents 5,4,3 and 2 + // tensor A stores complex floating-point extended double precision numbers + // according to the last-order storage format + // and initializes it with the default value. + + auto B = tensor_t(shape_t{5,4,3,2},value_t{}); + + // initializes the tensor with increasing values along the last-index + // using a single-index + auto vc = value_t(0,0); + for(auto i = 0u; i < B.size(); ++i, vc += value_t(1,1)) + B[i] = vc; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "B=" << B << ";" << std::endl << std::endl; + + + auto C = tensor_t(B.extents()); + // computes the complex conjugate of elements of B + // using multi-index notation. + for(auto i = 0u; i < B.size(0); ++i) + for(auto j = 0u; j < B.size(1); ++j) + for(auto k = 0u; k < B.size(2); ++k) + for(auto l = 0u; l < B.size(3); ++l) + C.at(i,j,k,l) = std::conj(B.at(i,j,k,l)); + + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "C=" << C << ";" << std::endl << std::endl; + + + + // computes the complex conjugate of elements of B + // using iterators. + auto D = tensor_t(B.extents()); + std::transform(B.begin(), B.end(), D.begin(), [](auto const& b){ return std::conj(b); }); + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "D=" << D << ";" << std::endl << std::endl; + + // reshaping tensors. + auto new_extents = B.extents().base(); + std::next_permutation( new_extents.begin(), new_extents.end() ); + D.reshape( extents<>(new_extents) ); + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "newD=" << D << ";" << std::endl << std::endl; + } +} diff --git a/examples/tensor/construction_access.cpp b/examples/tensor/construction_access.cpp deleted file mode 100644 index b70bf7268..000000000 --- a/examples/tensor/construction_access.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#include -#include - -#include - -int main() -{ - using namespace boost::numeric::ublas; - using namespace boost::multiprecision; - - - // creates a three-dimensional tensor with extents 3,4 and 2 - // tensor A stores single-precision floating-point number according - // to the first-order storage format - using ftype = float; - auto A = dynamic_tensor{3,4,2}; - - // initializes the tensor with increasing values along the first-index - // using a single index. - auto vf = ftype(0); - for(auto i = 0u; i < A.size(); ++i, vf += ftype(1)) - A[i] = vf; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "A=" << A << ";" << std::endl << std::endl; - - // creates a four-dimensional tensor with extents 5,4,3 and 2 - // tensor A stores complex floating-point extended double precision numbers - // according to the last-order storage format - // and initializes it with the default value. - using ctype = std::complex; - auto B = dynamic_tensor(extents<>{5,4,3,2},ctype{}); - - // initializes the tensor with increasing values along the last-index - // using a single-index - auto vc = ctype(0,0); - for(auto i = 0u; i < B.size(); ++i, vc += ctype(1,1)) - B[i] = vc; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "B=" << B << ";" << std::endl << std::endl; - - - - auto C = dynamic_tensor(B.extents()); - // computes the complex conjugate of elements of B - // using multi-index notation. - for(auto i = 0u; i < B.size(0); ++i) - for(auto j = 0u; j < B.size(1); ++j) - for(auto k = 0u; k < B.size(2); ++k) - for(auto l = 0u; l < B.size(3); ++l) - C.at(i,j,k,l) = std::conj(B.at(i,j,k,l)); - - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "C=" << C << ";" << std::endl << std::endl; - - - // computes the complex conjugate of elements of B - // using iterators. - auto D = dynamic_tensor(B.extents()); - std::transform(B.begin(), B.end(), D.begin(), [](auto const& b){ return std::conj(b); }); - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "D=" << D << ";" << std::endl << std::endl; - - // reshaping tensors. - auto new_extents = B.extents().base(); - std::next_permutation( new_extents.begin(), new_extents.end() ); - D.reshape( extents<>(new_extents) ); - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "newD=" << D << ";" << std::endl << std::endl; -} diff --git a/examples/tensor/dynamic_prod_expressions.cpp b/examples/tensor/dynamic_prod_expressions.cpp deleted file mode 100644 index c0b0ed793..000000000 --- a/examples/tensor/dynamic_prod_expressions.cpp +++ /dev/null @@ -1,184 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#include -#include -#include -#include - -int main() -{ - using namespace boost::numeric::ublas; - - using format_t = column_major; - using value_t = float; // std::complex; - using tensor_t = dynamic_tensor;; - using matrix_t = matrix; - using vector_t = vector; - - // Tensor-Vector-Multiplications - Including Transposition - { - - auto n = extents<>{3,4,2}; - auto A = tensor_t(n,2); - auto q = 0u; // contraction mode - - // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); - q = 1u; - tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); - - // C2(i,k) = A(i,j,k)*T1(j) + 4; - q = 2u; - tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; - - // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); - - // C4(i,j) = A(k,i,j)*T1(k) + 4; - q = 1u; - tensor_t C4 = prod(trans(A,{2,3,1}),vector_t(n[2],1),q) + 4; - - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; - std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C4(i,j) = A(k,i,j)*T1(k) + 4;" << std::endl << std::endl; - std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - - } - - - // Tensor-Matrix-Multiplications - Including Transposition - { - - auto n = extents<>{3,4,2}; - auto A = tensor_t(n,2); - auto m = 5u; - auto q = 0u; // contraction mode - - // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); - q = 1u; - tensor_t C1 = tensor_t(extents<>{m,n[1],n[2]},2) + prod(A,matrix_t(m,n[q-1],1),q); - - // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; - q = 2u; - tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4; - - // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); - q = 3u; - tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q); - - // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); - tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1); - - // C5(i,k,l) = A(i,k,j)*T1(l,j) + 4; - q = 3u; - tensor_t C5 = prod(trans(A,{1,3,2}),matrix_t(m,n[1],1),q) + 4; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; - std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; - - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C5(i,k,l) = A(i,k,j)*T1(l,j) + 4;" << std::endl << std::endl; - std::cout << "C5=" << C5 << ";" << std::endl << std::endl; - } - - - - - - // Tensor-Tensor-Multiplications Including Transposition - { - - using perm_t = std::vector; - - auto na = extents<>{3,4,5}; - auto nb = extents<>{4,6,3,2}; - auto A = tensor_t(na,2); - auto B = tensor_t(nb,3); - - - // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; - tensor_t C1 = tensor_t(extents<>{na[2],na[2]},2) + prod(A,A,perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - - // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; - tensor_t C2 = tensor_t(extents<>{na[2],nb[1],nb[3]},2) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - - // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; - tensor_t C3 = tensor_t(extents<>{na[2],nb[1],nb[3]},2) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - } -} diff --git a/examples/tensor/fixed_rank_prod_expressions.cpp b/examples/tensor/fixed_rank_prod_expressions.cpp deleted file mode 100644 index 5c217c94a..000000000 --- a/examples/tensor/fixed_rank_prod_expressions.cpp +++ /dev/null @@ -1,170 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - - -#include -#include -#include -#include - -int main() -{ - using namespace boost::numeric::ublas; - - using format_t = column_major; - using value_t = float; // std::complex; - using matrix_t = matrix; - using vector_t = vector; - using extents_3_t = extents<3>; - using extents_4_t = extents<4>; - - // Tensor-Vector-Multiplications - Including Transposition - // dynamic_extents with static rank - { - - auto n = extents_3_t{3,4,2}; - auto A = fixed_rank_tensor(n,value_t(2)); - using tensor_t = fixed_rank_tensor< value_t, 2>; - auto q = 0u; // contraction mode - - // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); - q = 1u; - tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); - - // C2(i,k) = A(i,j,k)*T1(j) + 4; - q = 2u; - tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; - - // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); - - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; - std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; - - } - - // Tensor-Matrix-Multiplications - Including Transposition - // dynamic_extents with static rank - { - - auto n = extents_3_t{3,4,2}; - auto A = fixed_rank_tensor(n,value_t(2)); - using tensor_t = decltype(A); - auto m = 5u; - auto q = 0u; // contraction mode - - // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); - q = 1u; - tensor_t C1 = fixed_rank_tensor( extents_3_t{m,n[1],n[2]},value_t(2) ) + prod(A,matrix_t(m,n[q-1],1),q); - - // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; - q = 2u; - tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4 ; - - // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); - q = 3u; - tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q) ; - - // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); - tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1) ; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; - std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; - - } - - // Tensor-Tensor-Multiplications Including Transposition - // dynamic_extents with static rank - { - - using perm_t = std::array; - - auto na = extents_3_t{3,4,5}; - auto nb = extents_4_t{4,6,3,2}; - auto A = fixed_rank_tensor(na,value_t(2)); - auto B = fixed_rank_tensor(nb,value_t(3)); - using tensor_t = dynamic_tensor< value_t >; - - - // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; - // Right now there exist no tensor other than dynamic_extents with - // dynamic rank so every tensor times tensor operator automatically - // to dynamic tensor - tensor_t C1 = dynamic_tensor(extents<>{na[2],na[2]},value_t(2)) + prod(A,A,perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - - // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; - // Similar Problem as above - tensor_t C2 = dynamic_tensor(extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; - // Similar Problem as above - tensor_t C3 = dynamic_tensor(extents<>{na[2],nb[1],nb[3]},value_t(2)) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; - std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - - } -} diff --git a/examples/tensor/fixed_rank_tensor.cpp b/examples/tensor/fixed_rank_tensor.cpp deleted file mode 100644 index 04ec87579..000000000 --- a/examples/tensor/fixed_rank_tensor.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - - -#include -#include -#include - -namespace ub = boost::numeric::ublas; - -int main() { - - /** @brief How to create fixed_rank_tensor - * - * fixed_rank_tensor< / Value Type, / Extents Size /, / Layout Type / >( ... ); - * - **/ - - /** - * fixed rank tensor with - * Layout: layout::first_order by default if not - * provided - * Value Type: float - * Extents Type: extents<5>{1,2,3,4,5} - **/ - auto t11 = ub::fixed_rank_tensor{1,2,3,4,5}; - - /** - * fixed rank tensor using deduction guide - * Layout: layout::last_order - * provided - * Value Type: float - * Extents Type: extents<5>{1,2,2,3,4} - **/ - auto t12 = ub::fixed_rank_tensor{ ub::extents<5>{1,2,2,3,4}, 5.f }; - - /** - * fixed rank tensor using deduction guide - * Layout: layout::first_order by default if not - * provided - * Value Type: float - * Extents Type: extents<5>{1,2,2,3,4} - **/ - auto t2 = ub::fixed_rank_tensor( ub::extents<5>{1,2,2,3,4}, 5.f ); - - /*--------------------------Expressions------------------------------*/ - - using f_tensor = ub::fixed_rank_tensor; - using s_tensor = ub::static_tensor >; - - auto t3 = ub::fixed_rank_tensor( ub::extents<5>{1,2,3,4,5}, 5.f ); - auto st1 = s_tensor{ 5.f }; - auto dt1 = ub::dynamic_tensor( ub::extents<>{1,2,3,4,5}, 5.f ); - - f_tensor exp1 = t3 + t3 * 2 + t3*t3; - - // type of the expression will be whichever - // tensor type is present at the start of the - // expression - f_tensor exp2 = t3 + st1 * 2 + st1 * t3; - - f_tensor exp3 = t3 + dt1 * 2 + dt1 * t3; - - std::cout< "<<( exp1 == exp2 )< "<<( exp2 == exp3 )< t4 = st1; - - // Assigning dynamic_tensor into fixed_rank_tensor - ub::dynamic_tensor const& t5 = dt1; - - std::cout<<"( t4 == t3 ) => "<<( t4 == t3 )< "<<( t5 == dt1 )< +#include +#include +#include + +void instantiate_dynamic_tensor() +{ + + using value_t = float; + using format_t = boost::numeric::ublas::layout::first_order; // storage format + using tensor_t = boost::numeric::ublas::dynamic_tensor; + using shape_t = typename tensor_t::extents_type; + + // tensor type has dynamic order and dimensions + // elements are stored contiguously in memory using the 1st-format (column-major) + + auto t1 = tensor_t{3,4,2}; + std::cout << "t1 = " << t1 << std::endl; + + auto t2 = tensor_t(shape_t{3,4,2},2.0F); + std::cout << "t2 = " << t2 << std::endl; + + auto t3 = tensor_t(t2); + std::cout << "t3 = " << t3 << std::endl; + +} + + +void instantiate_dynamic_tensors_with_static_order() +{ + + constexpr auto order = 3U; + using value_t = float; + using format_t = boost::numeric::ublas::layout::first_order; // storage format + using tensor_t = boost::numeric::ublas::fixed_rank_tensor; + using shape_t = typename tensor_t::extents_type; + + // tensor type has static order and dynamic dimensions + // elements are stored contiguously in memory using the 1st-format (column-major) + + auto t1 = tensor_t{3,4,2}; + std::cout << "t1 = " << t1 << std::endl; + + auto t2 = tensor_t(shape_t{3,4,2},2.0F); + std::cout << "t2 = " << t2 << std::endl; + + auto t3 = tensor_t(t2); + std::cout << "t3 = " << t3 << std::endl; + +} + + +void instantiate_static_tensor() +{ + + using value_t = float; + using format_t = boost::numeric::ublas::layout::first_order; // storage format + using shape_t = boost::numeric::ublas::static_extents<3U,4U,2U>; + using tensor_t = boost::numeric::ublas::static_tensor; + + // tensor type has static order and static dimensions + // elements are stored contiguously in memory using the 1st-format (column-major) + + auto t1 = tensor_t{}; + std::cout << "t1 = " << t1 << std::endl; + + auto t2 = tensor_t(2.0F); + std::cout << "t2 = " << t2 << std::endl; + + auto t3 = tensor_t(t2); + std::cout << "t3 = " << t3 << std::endl; + +} + + +int main() +{ + instantiate_dynamic_tensor(); + instantiate_dynamic_tensors_with_static_order(); + instantiate_static_tensor(); +} diff --git a/examples/tensor/einstein_notation.cpp b/examples/tensor/multiply_tensors_einstein_notation.cpp similarity index 65% rename from examples/tensor/einstein_notation.cpp rename to examples/tensor/multiply_tensors_einstein_notation.cpp index 9a2e1cc50..3609feb95 100644 --- a/examples/tensor/einstein_notation.cpp +++ b/examples/tensor/multiply_tensors_einstein_notation.cpp @@ -20,29 +20,37 @@ int main() { using namespace boost::numeric::ublas; - using format_t = column_major; using value_t = float; - using tensor_t = dynamic_tensor; - using matrix_t = matrix; + using format_t = boost::numeric::ublas::layout::first_order; // storage format + using tensor_t = boost::numeric::ublas::dynamic_tensor; + using shape_t = typename tensor_t::extents_type; + + //using format_t = column_major; + //using value_t = float; + //using shape_t = dynamic_extents<>; + //using tensor_t = dynamic_tensor; + using matrix_t = matrix; + + using namespace boost::numeric::ublas::index; // Tensor-Vector-Multiplications - Including Transposition { - auto n = extents<>{3,4,2}; + auto n = shape_t{3,4,2}; auto A = tensor_t(n,1); auto B1 = matrix_t(n[1],n[2],2); - auto v1 = tensor_t(extents<>{n[0],1},2); - auto v2 = tensor_t(extents<>{n[1],1},2); + auto v1 = tensor_t(shape_t{n[0],1},2); + auto v2 = tensor_t(shape_t{n[1],1},2); // auto v3 = tensor_t(shape{n[2],1},2); // C1(j,k) = B1(j,k) + A(i,j,k)*v1(i); // tensor_t C1 = B1 + prod(A,vector_t(n[0],1),1); -// tensor_t C1 = B1 + A(_i,_,_) * v1(_i,_); + tensor_t C1 = B1 + A(_i,_,_) * v1(_i,_); // C2(i,k) = A(i,j,k)*v2(j) + 4; //tensor_t C2 = prod(A,vector_t(n[1],1),2) + 4; -// tensor_t C2 = A(_,_i,_) * v2(_i,_) + 4; + tensor_t C2 = A(_,_i,_) * v2(_i,_) + 4; // not yet implemented! // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); @@ -53,34 +61,34 @@ int main() std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C1(j,k) = B1(j,k) + A(i,j,k)*v1(i);" << std::endl << std::endl; -// std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; // formatted output std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C2(i,k) = A(i,j,k)*v2(j) + 4;" << std::endl << std::endl; -// std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; } // Tensor-Matrix-Multiplications - Including Transposition { - auto n = extents<>{3,4,2}; + auto n = shape_t{3,4,2}; auto m = 5u; auto A = tensor_t(n,2); - auto B = tensor_t(extents<>{n[1],n[2],m},2); - auto B1 = tensor_t(extents<>{m,n[0]},1); - auto B2 = tensor_t(extents<>{m,n[1]},1); + auto B = tensor_t(shape_t{n[1],n[2],m},2); + auto B1 = tensor_t(shape_t{m,n[0]},1); + auto B2 = tensor_t(shape_t{m,n[1]},1); // C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i); // tensor_t C1 = B + prod(A,B1,1); -// tensor_t C1 = B + A(_i,_,_) * B1(_,_i); + tensor_t C1 = B + A(_i,_,_) * B1(_,_i); // C2(i,l,k) = A(i,j,k)*B2(l,j) + 4; // tensor_t C2 = prod(A,B2) + 4; -// tensor_t C2 = A(_,_j,_) * B2(_,_j) + 4; + tensor_t C2 = A(_,_j,_) * B2(_,_j) + 4; // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); // not yet implemented. @@ -89,52 +97,52 @@ int main() std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i);" << std::endl << std::endl; -// std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; // formatted output std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C2(i,l,k) = A(i,j,k)*B2(l,j) + 4;" << std::endl << std::endl; -// std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; -// // formatted output -// std::cout << "% --------------------------- " << std::endl; -// std::cout << "% --------------------------- " << std::endl << std::endl; -// std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; -// std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + // formatted output +// std::cout << "% --------------------------- " << std::endl; +// std::cout << "% --------------------------- " << std::endl << std::endl; +// std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; +// std::cout << "C3=" << C3 << ";" << std::endl << std::endl; } // Tensor-Tensor-Multiplications Including Transposition { - auto na = extents<>{3,4,5}; - auto nb = extents<>{4,6,3,2}; + auto na = shape_t{3,4,5}; + auto nb = shape_t{4,6,3,2}; auto A = tensor_t(na,2); auto B = tensor_t(nb,3); - auto T1 = tensor_t(extents<>{na[2],na[2]},2); - auto T2 = tensor_t(extents<>{na[2],nb[1],nb[3]},2); + auto T1 = tensor_t(shape_t{na[2],na[2]},2); + auto T2 = tensor_t(shape_t{na[2],nb[1],nb[3]},2); // C1(j,l) = T1(j,l) + A(i,j,k)*A(i,j,l) + 5; // tensor_t C1 = T1 + prod(A,A,perm_t{1,2}) + 5; -// tensor_t C1 = T1 + A(_i,_j,_m)*A(_i,_j,_l) + 5; + tensor_t C1 = T1 + A(_i,_j,_m)*A(_i,_j,_l) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C1(k,l) = T1(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; -// std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; // C2(k,l,m) = T2(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; //tensor_t C2 = T2 + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; -// tensor_t C2 = T2 + A(_i,_j,_k)*B(_j,_l,_i,_m) + 5; + tensor_t C2 = T2 + A(_i,_j,_k)*B(_j,_l,_i,_m) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C2(k,l,m) = T2(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; -// std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; } } diff --git a/examples/tensor/multiply_tensors_product_function.cpp b/examples/tensor/multiply_tensors_product_function.cpp new file mode 100644 index 000000000..31a895370 --- /dev/null +++ b/examples/tensor/multiply_tensors_product_function.cpp @@ -0,0 +1,344 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#include +#include +#include +#include + +void multiply_tensors_with_dynamic_order() +{ + using namespace boost::numeric::ublas; + + using format_t = column_major; + using value_t = float; // std::complex; + using tensor_t = dynamic_tensor; + using shape_t = typename tensor_t::extents_type; + using matrix_t = matrix; + using vector_t = vector; + + // Tensor-Vector-Multiplications - Including Transposition + { + + auto n = shape_t{3,4,2}; + auto A = tensor_t(n,2); + auto q = 0u; // contraction mode + + // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); + q = 1u; + tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); + + // C2(i,k) = A(i,j,k)*T1(j) + 4; + q = 2u; + tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; + + // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); + tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); + + // C4(i,j) = A(k,i,j)*T1(k) + 4; + q = 1u; + tensor_t C4 = prod(trans(A,{2,3,1}),vector_t(n[2],1),q) + 4; + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; + std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,j) = A(k,i,j)*T1(k) + 4;" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + + } + + + // Tensor-Matrix-Multiplications - Including Transposition + { + + auto n = shape_t{3,4,2}; + auto A = tensor_t(n,2); + auto m = 5u; + auto q = 0u; // contraction mode + + // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); + q = 1u; + tensor_t C1 = tensor_t(shape_t{m,n[1],n[2]},2) + prod(A,matrix_t(m,n[q-1],1),q); + + // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; + q = 2u; + tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4; + + // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); + q = 3u; + tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q); + + // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); + tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1); + + // C5(i,k,l) = A(i,k,j)*T1(l,j) + 4; + q = 3u; + tensor_t C5 = prod(trans(A,{1,3,2}),matrix_t(m,n[1],1),q) + 4; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C5(i,k,l) = A(i,k,j)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C5=" << C5 << ";" << std::endl << std::endl; + } + + + + + + // Tensor-Tensor-Multiplications Including Transposition + { + + using perm_t = std::vector; + + auto na = shape_t{3,4,5}; + auto nb = shape_t{4,6,3,2}; + auto A = tensor_t(na,2); + auto B = tensor_t(nb,3); + + + // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; + tensor_t C1 = tensor_t(shape_t{na[2],na[2]},2) + prod(A,A,perm_t{1,2}) + 5.0F; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + + // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; + tensor_t C2 = tensor_t(shape_t{na[2],nb[1],nb[3]},2) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + + // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; + tensor_t C3 = tensor_t(shape_t{na[2],nb[1],nb[3]},2) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + } +} + + +void multiply_tensors_with_static_order() +{ + using namespace boost::numeric::ublas; + + using format_t = column_major; + using value_t = float; // std::complex; + using matrix_t = matrix; + using vector_t = vector; + using tensor2_t = fixed_rank_tensor; + using tensor3_t = fixed_rank_tensor; +// using tensor4_t = fixed_rank_tensor; +// using shape_t = typename tensor_t::extents_type; +// using shape2_t = typename tensor2_t::extents_type; + using shape3_t = typename tensor3_t::extents_type; +// using shape4_t = typename tensor4_t::extents_type; + + // Tensor-Vector-Multiplications - Including Transposition + // dynamic_extents with static rank + { + + auto n = shape3_t{3,4,2}; + auto A = tensor3_t(n,value_t(2)); + auto q = 0U; // contraction mode + + // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); + q = 1U; + tensor2_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); + + // C2(i,k) = A(i,j,k)*T1(j) + 4; + q = 2U; + tensor2_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; + + // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); + tensor2_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); + + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(j,k) = T2(j,k) + A(i,j,k)*T1(i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,k) = A(i,j,k)*T1(j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; + std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; + + } + + // Tensor-Matrix-Multiplications - Including Transposition + // dynamic_extents with static rank + { + + auto n = shape3_t{3,4,2}; + auto A = tensor3_t(n,value_t(2)); + auto m = 5U; + auto q = 0U; // contraction mode + + // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); + q = 1U; + tensor3_t C1 = tensor3_t( shape3_t{m,n[1],n[2]},value_t(2) ) + prod(A,matrix_t(m,n[q-1],1),q); + + // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; + q = 2U; + tensor3_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4 ; + + // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); + q = 3U; + tensor3_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q) ; + + // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); + tensor3_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1) ; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,l,k) = A(i,j,k)*T1(l,j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; + std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; + + } + + // Tensor-Tensor-Multiplications Including Transposition + // dynamic_extents with static rank + { + +// using perm_t = std::array; + +// auto na = shape3_t{3,4,5}; +// auto nb = shape4_t{4,6,3,2}; +// auto nc = shape2_t{5,5}; +// auto A = tensor3_t(na,2.0F); +// auto B = tensor4_t(nb,3.0F); +// auto C = tensor2_t(nc,2.0F); + + // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; + // Right now there exist no tensor other than dynamic_extents with + // dynamic rank so every tensor times tensor operator automatically + // to dynamic tensor +// auto C1 = C + prod(A,A,perm_t{1,2}) + 5.0F; + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; +// std::cout << "C1=" << tensor_t(C1) << ";" << std::endl << std::endl; + + + // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; + // Similar Problem as above +// tensor_t C2 = tensor_t(shape_t{na[2],nb[1],nb[3]},2.0F) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5.0F; + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; + //std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; + // Similar Problem as above +// tensor_t C3 = tensor_t(shape_t{na[2],nb[1],nb[3]},2.0F) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5.0F; + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; +// std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + + } +} + +int main() +{ + multiply_tensors_with_dynamic_order(); + multiply_tensors_with_static_order(); +} + + diff --git a/examples/tensor/simple_expressions.cpp b/examples/tensor/simple_expressions.cpp index 86fe74bf6..229bfbf5f 100644 --- a/examples/tensor/simple_expressions.cpp +++ b/examples/tensor/simple_expressions.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -29,8 +29,9 @@ int main() // Calling overloaded operators // and using simple tensor expression templates. - if( A != (B+1) ) + if( A != (B+1) ){ A += 2*B - 1; + } // formatted output std::cout << "% --------------------------- " << std::endl; diff --git a/examples/tensor/static_tensor.cpp b/examples/tensor/static_tensor.cpp deleted file mode 100644 index e5f6e2b2f..000000000 --- a/examples/tensor/static_tensor.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google -// - - -#include -#include -#include - -namespace ub = boost::numeric::ublas; - -int main() { - - /** @brief How to create static_tensor - * - * static_tensor< / Value Type, / Extents /, / Layout Type / >( ... ); - * - **/ - - /** - * static rank tensor with - * Layout: layout::first_order by default if not - * provided - * Value Type: float - * Extents Type: extents<5>{1,2,3,4,5} - **/ - auto t1 = ub::static_tensor >{5.f}; - - /** - * static rank tensor with - * Layout: layout::first_order by default if not - * provided - * Value Type: float - * Extents Type: extents<5>{1,2,3,4,5} - **/ - auto t2 = ub::static_tensor, ub::layout::last_order >{5.f}; - - /*--------------------------Expressions------------------------------*/ - - using s_tensor = ub::static_tensor >; - - auto t3 = ub::fixed_rank_tensor( ub::extents<5>{1,2,3,4,5}, 5.f ); - auto st1 = s_tensor{ 5.f }; - auto dt1 = ub::dynamic_tensor( ub::extents<>{1,2,3,4,5}, 5.f ); - - s_tensor exp1 = st1 + st1 * 2 + st1*st1; - - // type of the expression will be whichever - // tensor type is present at the start of the - // expression - s_tensor exp2 = st1 + t3 * 2 + t3 * st1; - - s_tensor exp3 = st1 + dt1 * 2 + dt1 * t3; - - std::cout< "<<( exp1 == exp2)< "<<( exp2 == exp3)< -#include -#include - -namespace ub = boost::numeric::ublas; - -int main() { - - using value_type = float; - - /** tensor initialization using type deduction - * Storage Type: std::vector - * Layout: layout::first_order - * Initial Value: 0 - **/ - auto tensor_dynamic_extents_and_dynamic_rank_0 = ub::dynamic_tensor{1,2,3,4}; - - /** Dynamic extents but static rank - * Storage Type: std::array of static rank - * Layout: layout::first_order - * Initial Value: 0 - **/ - auto tensor_dynamic_extents_and_static_rank_1 = ub::fixed_rank_tensor{ub::extents<4>{1,2,3,4}}; - - /** Dynamic extents but dynamic rank - * Storage Type: std::vector - * Layout: layout::first_order - * Initial Value: 0 - **/ - auto tensor_dynamic_extents_and_dynamic_rank_2 = ub::dynamic_tensor{ub::extents<>{1,2,3,4}}; - - /** Dynamic extents but dynamic rank - * Storage Type: std::vector - * Layout: layout::first_order - * Initial Value: 0.1f - **/ - auto tensor_dynamic_extents_and_dynamic_rank_3 = ub::dynamic_tensor{ub::extents<>{1,2,3,4},0.1}; - - /** Static extents but static rank - * Storage Type: std::array - * Layout: layout::first_order - * Initial Value: 0 - **/ - auto tensor_static_extents_and_static_rank_4 = ub::static_tensor>(); - - /** Static extents but static rank - * Storage Type: std::array - * Layout: layout::first_order - * Initial Value: 0 - **/ - auto tensor_static_extents_and_static_rank_5 = ub::static_tensor,ub::layout::first_order>(); - - /** Dynamic extents but dynamic rank - * Storage Type: std::array - * Layout: layout::first_order - * Initial Value: 0 - **/ - auto tensor_dynamic_extents_and_dynamic_rank_6 = ub::dynamic_tensor{1,2,3,4}; - - auto t1_e = tensor_dynamic_extents_and_dynamic_rank_0.extents(); - auto t2_e = tensor_dynamic_extents_and_static_rank_1.extents(); - auto t3_e = tensor_dynamic_extents_and_dynamic_rank_2.extents(); - auto t4_e = tensor_static_extents_and_static_rank_4.extents(); - auto t5_e = tensor_dynamic_extents_and_dynamic_rank_3.extents(); - auto t6_e = tensor_static_extents_and_static_rank_5.extents(); - auto t7_e = tensor_dynamic_extents_and_dynamic_rank_6.extents(); - - auto t1_s = tensor_dynamic_extents_and_dynamic_rank_0.strides(); - auto t2_s = tensor_dynamic_extents_and_static_rank_1.strides(); - auto t3_s = tensor_dynamic_extents_and_dynamic_rank_2.strides(); - auto t4_s = tensor_static_extents_and_static_rank_4.strides(); - auto t5_s = tensor_dynamic_extents_and_dynamic_rank_3.strides(); - auto t6_s = tensor_static_extents_and_static_rank_5.strides(); - auto t7_s = tensor_dynamic_extents_and_dynamic_rank_6.strides(); - - std::cout<<"\nExtents: "<<(t1_e)<> - inline decltype(auto) prod(tensor_core< TensorEngine1 > const &a, tensor_core< TensorEngine2 > const &b, - PermuType const &phi) + inline decltype(auto) prod( + tensor_core< TensorEngine1 > const &a, + tensor_core< TensorEngine2 > const &b, + PermuType const &phi) { return prod(a, b, phi, phi); } diff --git a/test/tensor/Jamfile b/test/tensor/Jamfile index 8409cfc63..839d3a323 100644 --- a/test/tensor/Jamfile +++ b/test/tensor/Jamfile @@ -1,7 +1,7 @@ # Boost.uBLAS # -# Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -# Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +# Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +# Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com # # Distributed under the Boost Software License, Version 1.0. (See # accompanying file LICENSE_1_0.txt or copy at @@ -11,12 +11,13 @@ # Google and Fraunhofer IOSB, Ettlingen, Germany # +import ../../../../config/checks/config : requires ; + project boost/ublas/test/tensor : requirements - # these tests require C++17 - 11:no gcc:"-Wall -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-but-set-variable" clang:"-Wall -Wno-unknown-pragmas -Wno-sign-compare" + [ requires cxx17_if_constexpr ] ; alias unit_test_framework @@ -45,18 +46,14 @@ test-suite boost-ublas-tensor-test test_algorithms.cpp test_tensor_matrix_vector.cpp test_functions.cpp - unit_test_framework - ] - [ run test_static_tensor.cpp + test_static_tensor.cpp test_static_extents.cpp test_static_strides.cpp test_static_operators_arithmetic.cpp test_static_operators_comparison.cpp test_static_expression_evaluation.cpp test_static_tensor_matrix_vector.cpp - unit_test_framework - ] - [ run test_fixed_rank_tensor.cpp + test_fixed_rank_tensor.cpp test_fixed_rank_extents.cpp test_fixed_rank_strides.cpp test_fixed_rank_operators_arithmetic.cpp diff --git a/test/tensor/test_fixed_rank_tensor.cpp b/test/tensor/test_fixed_rank_tensor.cpp index 0db25ef3b..918020ddf 100644 --- a/test/tensor/test_fixed_rank_tensor.cpp +++ b/test/tensor/test_fixed_rank_tensor.cpp @@ -13,13 +13,7 @@ #include -#include - -#ifndef BOOST_TEST_DYN_LINK -#define BOOST_TEST_DYN_LINK -#endif - -#define BOOST_TEST_MODULE TestFixedRankedTensor +#include #include #include "utility.hpp" diff --git a/test/tensor/test_static_tensor.cpp b/test/tensor/test_static_tensor.cpp index 987428f4d..1fef8617d 100644 --- a/test/tensor/test_static_tensor.cpp +++ b/test/tensor/test_static_tensor.cpp @@ -15,11 +15,11 @@ #include #include -#ifndef BOOST_TEST_DYN_LINK -#define BOOST_TEST_DYN_LINK -#endif +//#ifndef BOOST_TEST_DYN_LINK +//#define BOOST_TEST_DYN_LINK +//#endif -#define BOOST_TEST_MODULE TestStaticTensor +//#define BOOST_TEST_MODULE TestStaticTensor #include #include "utility.hpp" diff --git a/test/tensor/test_strides.cpp b/test/tensor/test_strides.cpp index 85d7bb230..25d292223 100644 --- a/test/tensor/test_strides.cpp +++ b/test/tensor/test_strides.cpp @@ -1,6 +1,5 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at diff --git a/test/tensor/test_tensor.cpp b/test/tensor/test_tensor.cpp index d429fe5fd..4ded6b1a0 100644 --- a/test/tensor/test_tensor.cpp +++ b/test/tensor/test_tensor.cpp @@ -19,7 +19,7 @@ #define BOOST_TEST_DYN_LINK #endif -#define BOOST_TEST_MODULE TestDynamicTensor +#define BOOST_TEST_MODULE Tensor #include From a880b91413cf552d21aa41e90ab7aed1812dad07 Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Sat, 23 Jan 2021 14:05:56 -0500 Subject: [PATCH 24/36] [skip ci] Add "cxxstd" json field (#110) * [skip ci] Add "cxxstd" json field. The "cxxstd" json field is being added to each Boost library's meta json information for libraries in order to specify the minumum C++ standard compilation level. The value of this field matches one of the values for 'cxxstd' in Boost.Build. The purpose of doing this is to provide information for the Boost website documentation for each library which will specify the minimum C++ standard compilation that an end-user must employ in order to use the particular library. This will aid end-users who want to know if they can successfully use a Boost library based on their C++ compiler's compilation level, without having to search the library's documentation to find this out. * Updated the minimum C++ standard requirement to C++11 based on the Ublas Wiki section mentioning C++11 as a prerequisite. --- meta/libraries.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meta/libraries.json b/meta/libraries.json index df121c3c3..f8ab27455 100644 --- a/meta/libraries.json +++ b/meta/libraries.json @@ -12,5 +12,6 @@ "maintainers": [ "David Bellot ", "Stefan Seefeld " - ] + ], + "cxxstd": "11" } From 32795e124ba66192f4ee3a4aaea0b76ae38a340a Mon Sep 17 00:00:00 2001 From: Cem Bassoy Date: Sat, 23 Jan 2021 20:08:09 +0100 Subject: [PATCH 25/36] Update libraries.json --- meta/libraries.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meta/libraries.json b/meta/libraries.json index f8ab27455..37807c0d1 100644 --- a/meta/libraries.json +++ b/meta/libraries.json @@ -5,12 +5,13 @@ "Joerg Walter", "Mathias Koch" ], - "description": "uBLAS provides tensor, matrix, and vector classes as well as basic linear algebra routines. Several dense, packed and sparse storage schemes are supported.", + "description": "uBLAS provides tensor, matrix, and vector classes as well as basic linear and multilinear algebra routines. Several dense, packed and sparse storage schemes are supported.", "category": [ "Math" ], "maintainers": [ "David Bellot ", + "Cem Bassoy ", "Stefan Seefeld " ], "cxxstd": "11" From 231ba5f7303f0f7d7ae5d5f9426e4908fb4df712 Mon Sep 17 00:00:00 2001 From: Cem Bassoy Date: Mon, 24 May 2021 12:00:38 +0200 Subject: [PATCH 26/36] refactor(core): simplify and eliminate auxiliary tensor types (#115) Auxiliary functions for extents and strides were using different functions. Additionally, many tags were used to distinguish between different tensor types. This patch simplifies interfaces of different core functions and unifies functions that can process different types of extent and stride types. --- .appveyor.yml | 74 -- .clang-tidy | 8 +- .github/workflows/address_san.yml | 75 -- .../workflows/{apple_clang.yml => apple.yml} | 41 +- .../{clangtidy_review.yml => clangtidy.yml} | 51 +- .github/workflows/clangtidy_check.yml | 47 - .github/workflows/code_format.yml | 12 +- .github/workflows/linux.yml | 99 ++ .github/workflows/linux_clang.yml | 97 -- .github/workflows/linux_gcc.yml | 99 -- .github/workflows/sanitizer.yml | 83 ++ .github/workflows/thread_san.yml | 76 -- .github/workflows/ub_san.yml | 76 -- .../{windows_msvc.yml => windows.yml} | 29 +- .travis.yml | 90 -- IDEs/qtcreator/examples/configuration.pri | 27 +- .../examples/tensor/example_access_tensor.pro | 7 - .../tensor/example_instantiate_tensor.pro | 7 - ...ple_multiply_tensors_einstein_notation.pro | 7 - ...mple_multiply_tensors_product_function.pro | 7 - .../tensor/example_simple_expressions.pro | 7 - IDEs/qtcreator/examples/tensor/tensor.pro | 25 +- IDEs/qtcreator/include/include.pro | 6 +- IDEs/qtcreator/include/tensor/tensor.pri | 58 +- IDEs/qtcreator/test/test_tensor.pro | 60 +- IDEs/qtcreator/tests.pri | 140 +-- IDEs/qtcreator/ublas_develop.pro | 4 +- README.md | 77 +- examples/tensor/.clang-tidy | 11 - examples/tensor/access_tensor.cpp | 179 +-- examples/tensor/instantiate_tensor.cpp | 108 +- .../multiply_tensors_einstein_notation.cpp | 277 +++-- .../multiply_tensors_product_function.cpp | 176 +-- examples/tensor/simple_expressions.cpp | 32 +- include/boost/numeric/ublas/tensor.hpp | 3 +- .../boost/numeric/ublas/tensor/algorithms.hpp | 357 +++--- .../boost/numeric/ublas/tensor/concepts.hpp | 34 + .../numeric/ublas/tensor/dynamic_extents.hpp | 241 ---- .../numeric/ublas/tensor/dynamic_strides.hpp | 219 ---- .../boost/numeric/ublas/tensor/expression.hpp | 48 +- .../ublas/tensor/expression_evaluation.hpp | 98 +- .../boost/numeric/ublas/tensor/extents.hpp | 53 + .../ublas/tensor/extents/extents_base.hpp | 54 + .../tensor/extents/extents_dynamic_size.hpp | 154 +++ .../tensor/extents/extents_functions.hpp | 247 ++++ .../ublas/tensor/extents/extents_static.hpp | 78 ++ .../extents/extents_static_functions.hpp | 637 ++++++++++ .../tensor/extents/extents_static_size.hpp | 148 +++ .../ublas/tensor/extents_functions.hpp | 449 ------- .../ublas/tensor/fixed_rank_extents.hpp | 248 ---- .../ublas/tensor/fixed_rank_strides.hpp | 180 ++- .../numeric/ublas/tensor/function/conj.hpp | 81 ++ .../numeric/ublas/tensor/function/imag.hpp | 82 ++ .../numeric/ublas/tensor/function/init.hpp | 120 ++ .../ublas/tensor/function/inner_prod.hpp | 68 + .../numeric/ublas/tensor/function/norm.hpp | 60 + .../ublas/tensor/function/outer_prod.hpp | 283 +++++ .../numeric/ublas/tensor/function/real.hpp | 80 ++ .../numeric/ublas/tensor/function/reshape.hpp | 87 ++ .../tensor/function/tensor_times_matrix.hpp | 256 ++++ .../tensor/function/tensor_times_tensor.hpp | 337 +++++ .../tensor/function/tensor_times_vector.hpp | 240 ++++ .../numeric/ublas/tensor/function/trans.hpp | 78 ++ .../boost/numeric/ublas/tensor/functions.hpp | 1108 +---------------- include/boost/numeric/ublas/tensor/index.hpp | 14 +- .../numeric/ublas/tensor/index_functions.hpp | 64 + .../numeric/ublas/tensor/multi_index.hpp | 66 +- .../ublas/tensor/multi_index_utility.hpp | 136 +- .../numeric/ublas/tensor/multiplication.hpp | 771 ++++++------ .../ublas/tensor/operators_arithmetic.hpp | 365 +++--- .../ublas/tensor/operators_comparison.hpp | 51 +- .../boost/numeric/ublas/tensor/ostream.hpp | 144 +-- .../numeric/ublas/tensor/static_extents.hpp | 150 --- .../numeric/ublas/tensor/static_strides.hpp | 267 ---- .../boost/numeric/ublas/tensor/strides.hpp | 99 -- include/boost/numeric/ublas/tensor/tags.hpp | 14 +- include/boost/numeric/ublas/tensor/tensor.hpp | 53 +- .../ublas/tensor/tensor/tensor_core.hpp | 27 + .../ublas/tensor/tensor/tensor_dynamic.hpp | 466 +++++++ .../ublas/tensor/tensor/tensor_engine.hpp | 29 + .../ublas/tensor/tensor/tensor_static.hpp | 456 +++++++ .../tensor/tensor/tensor_static_rank.hpp | 473 +++++++ .../numeric/ublas/tensor/tensor_core.hpp | 886 ------------- .../numeric/ublas/tensor/tensor_engine.hpp | 50 - .../ublas/tensor/traits/basic_type_traits.hpp | 53 +- .../ublas/tensor/traits/storage_traits.hpp | 105 +- .../traits/type_traits_dynamic_extents.hpp | 46 - .../traits/type_traits_dynamic_strides.hpp | 47 - .../tensor/traits/type_traits_extents.hpp | 41 - .../traits/type_traits_fixed_rank_extents.hpp | 45 - .../traits/type_traits_fixed_rank_strides.hpp | 46 - .../traits/type_traits_static_extents.hpp | 37 - .../traits/type_traits_static_strides.hpp | 46 - .../tensor/traits/type_traits_strides.hpp | 44 - .../tensor/traits/type_traits_tensor.hpp | 41 - .../numeric/ublas/tensor/type_traits.hpp | 11 +- test/tensor/Jamfile | 54 +- test/tensor/test_algorithms.cpp | 886 ++++++------- test/tensor/test_einstein_notation.cpp | 168 +-- test/tensor/test_expression.cpp | 159 +-- test/tensor/test_expression_evaluation.cpp | 156 ++- test/tensor/test_extents.cpp | 731 ----------- test/tensor/test_extents_dynamic.cpp | 190 +++ .../test_extents_dynamic_rank_static.cpp | 155 +++ test/tensor/test_extents_functions.cpp | 634 ++++++++++ .../test_fixed_rank_expression_evaluation.cpp | 349 +++--- test/tensor/test_fixed_rank_extents.cpp | 1027 ++++++++------- test/tensor/test_fixed_rank_functions.cpp | 679 +++++----- .../test_fixed_rank_operators_arithmetic.cpp | 277 ++--- .../test_fixed_rank_operators_comparison.cpp | 268 ++-- test/tensor/test_fixed_rank_strides.cpp | 281 +++-- test/tensor/test_fixed_rank_tensor.cpp | 759 +++++------ .../test_fixed_rank_tensor_matrix_vector.cpp | 637 +++++----- test/tensor/test_functions.cpp | 146 ++- test/tensor/test_multi_index.cpp | 107 +- test/tensor/test_multi_index_utility.cpp | 396 +++--- test/tensor/test_multiplication.cpp | 595 +++++---- test/tensor/test_operators_arithmetic.cpp | 48 +- test/tensor/test_operators_comparison.cpp | 394 +++--- .../test_static_expression_evaluation.cpp | 64 +- test/tensor/test_static_extents.cpp | 691 +++++----- .../test_static_operators_arithmetic.cpp | 34 +- .../test_static_operators_comparison.cpp | 35 +- test/tensor/test_static_strides.cpp | 251 ++-- test/tensor/test_static_tensor.cpp | 152 ++- .../test_static_tensor_matrix_vector.cpp | 415 +++--- test/tensor/test_strides.cpp | 252 ++-- test/tensor/test_tensor.cpp | 124 +- test/tensor/test_tensor_matrix_vector.cpp | 320 ++--- test/tensor/utility.hpp | 67 +- 130 files changed, 12540 insertions(+), 12404 deletions(-) delete mode 100644 .appveyor.yml delete mode 100644 .github/workflows/address_san.yml rename .github/workflows/{apple_clang.yml => apple.yml} (69%) rename .github/workflows/{clangtidy_review.yml => clangtidy.yml} (53%) delete mode 100644 .github/workflows/clangtidy_check.yml create mode 100644 .github/workflows/linux.yml delete mode 100644 .github/workflows/linux_clang.yml delete mode 100644 .github/workflows/linux_gcc.yml create mode 100644 .github/workflows/sanitizer.yml delete mode 100644 .github/workflows/thread_san.yml delete mode 100644 .github/workflows/ub_san.yml rename .github/workflows/{windows_msvc.yml => windows.yml} (77%) delete mode 100644 .travis.yml delete mode 100644 IDEs/qtcreator/examples/tensor/example_access_tensor.pro delete mode 100644 IDEs/qtcreator/examples/tensor/example_instantiate_tensor.pro delete mode 100644 IDEs/qtcreator/examples/tensor/example_multiply_tensors_einstein_notation.pro delete mode 100644 IDEs/qtcreator/examples/tensor/example_multiply_tensors_product_function.pro delete mode 100644 IDEs/qtcreator/examples/tensor/example_simple_expressions.pro delete mode 100644 examples/tensor/.clang-tidy create mode 100644 include/boost/numeric/ublas/tensor/concepts.hpp delete mode 100644 include/boost/numeric/ublas/tensor/dynamic_extents.hpp delete mode 100644 include/boost/numeric/ublas/tensor/dynamic_strides.hpp create mode 100644 include/boost/numeric/ublas/tensor/extents.hpp create mode 100644 include/boost/numeric/ublas/tensor/extents/extents_base.hpp create mode 100644 include/boost/numeric/ublas/tensor/extents/extents_dynamic_size.hpp create mode 100644 include/boost/numeric/ublas/tensor/extents/extents_functions.hpp create mode 100644 include/boost/numeric/ublas/tensor/extents/extents_static.hpp create mode 100644 include/boost/numeric/ublas/tensor/extents/extents_static_functions.hpp create mode 100644 include/boost/numeric/ublas/tensor/extents/extents_static_size.hpp delete mode 100644 include/boost/numeric/ublas/tensor/extents_functions.hpp delete mode 100644 include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/conj.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/imag.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/init.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/inner_prod.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/norm.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/outer_prod.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/real.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/reshape.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/tensor_times_matrix.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/tensor_times_tensor.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/tensor_times_vector.hpp create mode 100644 include/boost/numeric/ublas/tensor/function/trans.hpp create mode 100644 include/boost/numeric/ublas/tensor/index_functions.hpp delete mode 100644 include/boost/numeric/ublas/tensor/static_extents.hpp delete mode 100644 include/boost/numeric/ublas/tensor/static_strides.hpp delete mode 100644 include/boost/numeric/ublas/tensor/strides.hpp create mode 100644 include/boost/numeric/ublas/tensor/tensor/tensor_core.hpp create mode 100644 include/boost/numeric/ublas/tensor/tensor/tensor_dynamic.hpp create mode 100644 include/boost/numeric/ublas/tensor/tensor/tensor_engine.hpp create mode 100644 include/boost/numeric/ublas/tensor/tensor/tensor_static.hpp create mode 100644 include/boost/numeric/ublas/tensor/tensor/tensor_static_rank.hpp delete mode 100644 include/boost/numeric/ublas/tensor/tensor_core.hpp delete mode 100644 include/boost/numeric/ublas/tensor/tensor_engine.hpp delete mode 100644 include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_extents.hpp delete mode 100644 include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_strides.hpp delete mode 100644 include/boost/numeric/ublas/tensor/traits/type_traits_extents.hpp delete mode 100644 include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_extents.hpp delete mode 100644 include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_strides.hpp delete mode 100644 include/boost/numeric/ublas/tensor/traits/type_traits_static_extents.hpp delete mode 100644 include/boost/numeric/ublas/tensor/traits/type_traits_static_strides.hpp delete mode 100644 include/boost/numeric/ublas/tensor/traits/type_traits_strides.hpp delete mode 100644 include/boost/numeric/ublas/tensor/traits/type_traits_tensor.hpp delete mode 100644 test/tensor/test_extents.cpp create mode 100644 test/tensor/test_extents_dynamic.cpp create mode 100644 test/tensor/test_extents_dynamic_rank_static.cpp create mode 100644 test/tensor/test_extents_functions.cpp diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 2b2d8fd53..000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2018 Stefan Seefeld -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) - -version: 1.0.{build}-{branch} - -shallow_clone: true - -branches: - only: - - master - - develop - - /feature\/.*/ - -environment: - matrix: - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: msvc-14.2 - CXXSTD: latest - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: msvc-14.2 - CXXSTD: 17 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: msvc-14.0 - CXXSTD: 11 - -install: - - cd "C:\Tools\vcpkg" - - git pull - - .\bootstrap-vcpkg.bat - - cd %appveyor_build_folder% - # Install OpenCL runtime (driver) for Intel / Xeon package - - appveyor DownloadFile "http://registrationcenter-download.intel.com/akdlm/irc_nas/9022/opencl_runtime_16.1.1_x64_setup.msi" - - start /wait msiexec /i opencl_runtime_16.1.1_x64_setup.msi /qn /l*v msiexec2.log - # FIXME: To be removed https://help.appveyor.com/discussions/problems/13000-cmake_toolchain_filevcpkgcmake-conflicts-with-cmake-native-findboostcmake" - - ps: 'Write-Host "Installing latest vcpkg.cmake module" -ForegroundColor Magenta' - - appveyor DownloadFile https://raw.githubusercontent.com/Microsoft/vcpkg/master/scripts/buildsystems/vcpkg.cmake -FileName "c:\tools\vcpkg\scripts\buildsystems\vcpkg.cmake" - - set "TRIPLET=x64-windows" - - vcpkg --triplet %TRIPLET% install opencl clblas - - set PATH=C:\Tools\vcpkg\installed\%TRIPLET%\bin;%PATH% - - set VCPKG_I=C:\Tools\vcpkg\installed\%TRIPLET%\include - - set VCPKG_L=C:\Tools\vcpkg\installed\%TRIPLET%\lib - - set BOOST_BRANCH=develop - - if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master - - cd .. - - git clone -b %BOOST_BRANCH% https://github.com/boostorg/boost.git boost-root - - cd boost-root - - git submodule update --init tools/build - - git submodule update --init libs/config - - git submodule update --init tools/boostdep - - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\numeric\ublas - - python tools/boostdep/depinst/depinst.py -I benchmarks numeric/ublas - - xcopy %APPVEYOR_BUILD_FOLDER%\opencl.jam %USERPROFILE% - - xcopy %APPVEYOR_BUILD_FOLDER%\clblas.jam %USERPROFILE% - - ps: | - # Creating %USERPROFILE%/user-config.jam file - @' - import os regex toolset ; - local toolset = [ regex.split [ os.environ TOOLSET ] "-" ] ; - local vcpkg_i = [ os.environ VCPKG_I ] ; - local vcpkg_l = [ os.environ VCPKG_L ] ; - using $(toolset[1]) : $(toolset[2-]:J="-") : ; - using opencl : : $(vcpkg_i) $(vcpkg_l) ; - using clblas : : $(vcpkg_i) $(vcpkg_l) ; - '@ | sc "$env:USERPROFILE/user-config.jam" - - cmd /c bootstrap - - b2 -j3 headers - -build: off - -test_script: - - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% - - set ADDRMD=address-model=64 - - b2 -j3 libs/numeric/ublas/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% \ No newline at end of file diff --git a/.clang-tidy b/.clang-tidy index e17df9a0e..4a0edffcd 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,6 +1,6 @@ --- -Checks: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements' -WarningsAsErrors: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements' +Checks: '-*,clang-*,bugprone-*,cppcoreguidelines-*,google-*,hicpp-*,modernize-*,performance-*,readability-*,portability-*, +-modernize-use-trailing-return-type, -readability-uppercase-literal-suffix, -readability-braces-around-statements, -hicpp-uppercase-literal-suffix, -hicpp-braces-around-statements, -hicpp-no-array-decay, -cppcoreguidelines-pro-bounds-constant-array-index, -cppcoreguidelines-pro-bounds-pointer-arithmetic, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -readability-avoid-const-params-in-decls, -google-readability-braces-around-statements,-google-explicit-constructor,-hicpp-vararg,-cppcoreguidelines-pro-type-vararg, -cppcoreguidelines-avoid-non-const-global-variables, -google-readability-todo, -cppcoreguidelines-pro-type-member-init, -hicpp-member-init, -cppcoreguidelines-special-member-functions, -hicpp-special-member-functions' HeaderFilterRegex: 'boost\/numeric\/ublas\/tensor\/.*' AnalyzeTemporaryDtors: false FormatStyle: file @@ -8,4 +8,8 @@ User: ublas-developers CheckOptions: - key: modernize-use-nullptr.NullMacros value: 'NULL' + - key: readability-magic-numbers.IgnoredIntegerValues + value: '1;2;3;4;5;6;7;8;9;' + - key: cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues + value: '1;2;3;4;5;6;7;8;9;' ... diff --git a/.github/workflows/address_san.yml b/.github/workflows/address_san.yml deleted file mode 100644 index 5cf0c85db..000000000 --- a/.github/workflows/address_san.yml +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (c) 2020 Mohammad Ashar Khan -# Distributed under Boost Software License, Version 1.0 -# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) - -name: Address Sanitizer -# Trigger on Push to the repository, regardless of the branch. -# For fine tune, You can add specific branches or tags. -on: - push: - paths-ignore: - - '**.md' - - 'doc/**' - pull_request: - paths-ignore: - - '**.md' - - 'doc/**' -jobs: - build: - name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early - matrix: - config: - - {cc: gcc-9, cxx: g++-9, cxxstd: 2a, name: gcc} - - {cc: clang-9, cxx: clang++-9, cxxstd: 2a, name: clang} - steps: - - uses: actions/checkout@v2 - - - name: Prepare BOOST_ROOT - run: | - cd ${GITHUB_WORKSPACE} - cd .. - - git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root - cd boost-root - - git submodule update --init --depth=1 --jobs 8 tools/build - git submodule update --init --depth=1 --jobs 8 libs/config - git submodule update --init --depth=1 --jobs 8 tools/boostdep - - mkdir -p libs/numeric/ - cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas - python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - - ./bootstrap.sh - ./b2 -j 8 headers - - #echo ::set-env name=BOOST_ROOT::${PWD} - echo "BOOST_ROOT=${PWD}" >> $GITHUB_ENV - - - name: Prepare Build - run: | - echo $BOOST_ROOT - cd $BOOST_ROOT - echo "using ${{matrix.config.name}} : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; - - - name: Test Benchmarks - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 benchmarks toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} - - - name: Test Tensor Examples - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=address -fno-omit-frame-pointer" linkflags="-fsanitize=address" - - - name: Test Tensor - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=address -fno-omit-frame-pointer" linkflags="-fsanitize=address" diff --git a/.github/workflows/apple_clang.yml b/.github/workflows/apple.yml similarity index 69% rename from .github/workflows/apple_clang.yml rename to .github/workflows/apple.yml index dfaa5d470..f0c8df792 100644 --- a/.github/workflows/apple_clang.yml +++ b/.github/workflows/apple.yml @@ -1,8 +1,9 @@ # Copyright (c) 2020 Mohammad Ashar Khan +# Copyright (c) 2021 Cem Bassoy # Distributed under Boost Software License, Version 1.0 # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) -name: Apple Clang +name: "Apple MacOS" on: push: @@ -15,24 +16,26 @@ on: - 'doc/**' jobs: build: - name: "Darwin 11.0 -std=c++${{matrix.cxxstd}}" - runs-on: macos-latest + name: "MacOS 10.15 clang -std=c++${{matrix.cxxstd}}" + runs-on: macos-10.15 strategy: - fail-fast: false + fail-fast: true matrix: - cxxstd: [11, 17, 2a] + cxxstd: [2a] steps: - uses: actions/checkout@v2 - - name: Prepare BOOST_ROOT + - name: Git Clone Boost.uBlas run: | cd ${GITHUB_WORKSPACE} cd .. git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root cd boost-root - + echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} + echo $BOOST_ROOT + git submodule update --init --depth=1 --jobs 8 tools/build git submodule update --init --depth=1 --jobs 8 libs/config git submodule update --init --depth=1 --jobs 8 tools/boostdep @@ -41,33 +44,29 @@ jobs: cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - ./bootstrap.sh - ./b2 -j 8 headers - - #echo ::set-env name=BOOST_ROOT::${PWD} - echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} - - - name: Prepare Build + - name: Bootstrap and Compile Boost.uBlas run: | - echo $BOOST_ROOT cd $BOOST_ROOT - - echo "using clang : : clang++ ;" >> ~/user-config.jam; - + ./bootstrap.sh + ./b2 -j8 headers + echo "using clang : : $(brew --prefix llvm)/bin/clang++ ;" >> ~/user-config.jam; + + - name: Test Benchmarks run: | cd $BOOST_ROOT cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 benchmarks toolset=clang cxxstd=${{matrix.cxxstd}} + $BOOST_ROOT/b2 -j8 benchmarks cxxstd=${{matrix.cxxstd}} - name: Test Tensor Examples run: | cd $BOOST_ROOT cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 examples/tensor toolset=clang cxxstd=${{matrix.cxxstd}} + $BOOST_ROOT/b2 -j8 examples/tensor cxxstd=${{matrix.cxxstd}} - name: Test Tensor run: | cd $BOOST_ROOT cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 test/tensor toolset=clang cxxstd=${{matrix.cxxstd}} + $BOOST_ROOT/b2 -j8 test/tensor cxxstd=${{matrix.cxxstd}} + diff --git a/.github/workflows/clangtidy_review.yml b/.github/workflows/clangtidy.yml similarity index 53% rename from .github/workflows/clangtidy_review.yml rename to .github/workflows/clangtidy.yml index b14c5bb9f..11b1aea41 100644 --- a/.github/workflows/clangtidy_review.yml +++ b/.github/workflows/clangtidy.yml @@ -1,26 +1,30 @@ # Copyright (c) 2020 Mohammad Ashar Khan +# Copyright (c) 2021 Cem Bassoy # Distributed under Boost Software License, Version 1.0 # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) -name: Clang tidy Review - -on: [pull_request] - +name: "Static Analysis" + +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' jobs: check: - name: Clang tidy Review + name: Linux Clang-Tidy runs-on: ubuntu-20.04 - if: github.event.pull_request.head.repo.full_name == github.repository steps: - - uses: actions/checkout@v2 - - name: "Install dependencies" - run: | - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add - - sudo add-apt-repository 'deb http://apt.llvm.org/focal llvm-toolchain-focal-10 main' -y - sudo apt-get update -q - sudo apt-get install -y clang-10 clang-tidy-10 + - uses: actions/checkout@v2 + + - name: Install Clang 11 + run: sudo apt-get update && sudo apt-get install -y clang-11 clang-tidy-11 - - name: "Install Boost from Source" + - name: "Install Boost from Source" run: | cd .. git clone --depth 1 https://github.com/boostorg/boost.git --recursive --shallow-submodules @@ -29,19 +33,20 @@ jobs: ./b2 headers sudo cp -r -L boost /usr/include rm -rf boost + + - name: "Run Clang-Tidy" + run: clang-tidy-11 examples/tensor/*.cpp test/tensor/*.cpp -- -Iinclude -std=c++20 > reports.txt + - name: "Print Clang-Tidy Report" + run: cat reports.txt + - uses: actions/setup-python@v2 - - - name: "Run clang-tidy check" - run: | - clang-tidy-10 examples/tensor/*.cpp -- -Iinclude -std=c++17 > reports.txt - + - name: "Post review comments" - if: always() + if: github.event.pull_request.head.repo.full_name == github.repository run: | pip3 install 'unidiff~=0.6.0' --force-reinstall pip3 install 'PyGithub~=1.51' --force-reinstall pip3 install 'requests~=2.23' --force-reinstall - - python ./.ci/post_review.py --repository ${{ github.repository }} --token ${{ github.token}} --pr ${{ github.event.pull_request.number }} --path reports.txt - + python ./.ci/post_review.py --repository ${{ github.repository }} --token ${{ github.token}} --pr ${{ github.event.pull_request.number }} --path reports.txt + diff --git a/.github/workflows/clangtidy_check.yml b/.github/workflows/clangtidy_check.yml deleted file mode 100644 index 1b5236352..000000000 --- a/.github/workflows/clangtidy_check.yml +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2020 Mohammad Ashar Khan -# Distributed under Boost Software License, Version 1.0 -# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) - -name: Clang tidy checks - -on: - push: - paths-ignore: - - '**.md' - - 'doc/**' - pull_request: - paths-ignore: - - '**.md' - - 'doc/**' -jobs: - check: - name: Clang tidy Check - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - - name: "Install dependencies" - run: | - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add - - sudo add-apt-repository 'deb http://apt.llvm.org/focal llvm-toolchain-focal-10 main' -y - sudo apt-get update -q - sudo apt-get install -y clang-10 clang-tidy-10 - - - name: "Install Boost from Source" - run: | - cd .. - git clone --depth 1 https://github.com/boostorg/boost.git --recursive --shallow-submodules - cd boost - ./bootstrap.sh - ./b2 headers - sudo cp -r -L boost /usr/include - rm -rf boost - - - name: "Run clang-tidy check" - run: | - clang-tidy-10 examples/tensor/*.cpp -- -Iinclude -std=c++17 > reports.txt - - - name: "Show clang tidy report" - if: always() - run: | - cat reports.txt diff --git a/.github/workflows/code_format.yml b/.github/workflows/code_format.yml index f1ba49372..a7c53648b 100644 --- a/.github/workflows/code_format.yml +++ b/.github/workflows/code_format.yml @@ -2,7 +2,7 @@ # Distributed under Boost Software License, Version 1.0 # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) -name: "Code Format" +name: "Clang Code Format" on: push: @@ -15,7 +15,7 @@ on: - 'doc/**' jobs: format: - name: "Code Formatting Check" + name: "Clang Code Formatting Check" runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -24,8 +24,8 @@ jobs: run: | sudo apt-get install -y clang-format-10 - - name: "Format Codes" - run: clang-format-10 -i examples/tensor/*.cpp test/tensor/*.cpp include/boost/numeric/ublas/tensor/*.hpp include/boost/numeric/ublas/tensor/*/*.hpp +# - name: "Format Codes" +# run: clang-format-10 -i examples/tensor/*.cpp test/tensor/*.cpp include/boost/numeric/ublas/tensor/*.hpp include/boost/numeric/ublas/tensor/*/*.hpp - - name: Check diff - run: git diff --exit-code HEAD +# - name: Check diff +# run: git diff --exit-code HEAD diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 000000000..20b9c5311 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,99 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Copyright (c) 2021 Cem Bassoy +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: "Linux" + +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' + +jobs: + build: + name: Ubuntu 20.04 "cxx=${{matrix.config.cxx}}, std=c++${{matrix.config.cxxstd}}, variant=c++${{matrix.config.variant}}" + runs-on: ubuntu-20.04 + strategy: + fail-fast: true + # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early + matrix: + config: + - { name: clang, cc: clang-10, cxx: clang++-10, cxxstd: 20, variant: debug, opt: off} + - { name: clang, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off} + - { name: clang, cc: clang-10, cxx: clang++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp, ldflags: -lgomp=libomp5} + - { name: clang, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp, ldflags: -lgomp=libomp5} + - { name: gcc, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: debug, opt: off} + - { name: gcc, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp, ldflags: -lgomp} + + steps: + - uses: actions/checkout@v2 + + - name: Install g++-10 + if: matrix.config.cxx == 'g++-10' + run: sudo apt update && sudo apt-get install -y g++-10 libomp-dev + + - name: Install Clang 10 + if: matrix.config.cxx == 'clang++-10' + run: sudo apt-get update && sudo apt-get install -y clang-10 + + - name: Install Clang 11 + if: matrix.config.cxx == 'clang++-11' + run: sudo apt-get update && sudo apt-get install -y clang-11 + + - name: Git Clone Boost.uBlas + run: | + cd ${GITHUB_WORKSPACE} + cd .. + + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} + echo $BOOST_ROOT + + git submodule update --init --depth=1 --jobs 8 tools/build + git submodule update --init --depth=1 --jobs 8 libs/config + git submodule update --init --depth=1 --jobs 8 tools/boostdep + + mkdir -p libs/numeric/ + cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas + python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + + - name: Bootstrap Boost and Compile Boost + run: | + cd $BOOST_ROOT + ./bootstrap.sh + ./b2 -j8 headers + echo "using ${{ matrix.config.name }} : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; + +# - name: Test Benchmarks +# run: | +# cd $BOOST_ROOT +# cd libs/numeric/ublas +# $BOOST_ROOT/b2 -j 4 benchmarks toolset=clang cxxstd=${{matrix.config.cxxstd}} cxxflags="-O3" + + - name: Test Tensor Examples + run: | + cd $BOOST_ROOT/libs/numeric/ublas + if [ -z "$cxxflags" ] + then + $BOOST_ROOT/b2 -j8 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} + else + $BOOST_ROOT/b2 -j8 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} cxxflags="${{matrix.config.cxxflags}}" linkflags="${{matrix.config.ldflags}}" + fi + + - name: Test Tensor Unit-Tests + run: | + cd $BOOST_ROOT/libs/numeric/ublas + if [ -z "$cxxflags" ] + then + $BOOST_ROOT/b2 -j8 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} + else + $BOOST_ROOT/b2 -j8 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} cxxflags="${{matrix.config.cxxflags}}" linkflags="${{matrix.config.ldflags}}" + fi + diff --git a/.github/workflows/linux_clang.yml b/.github/workflows/linux_clang.yml deleted file mode 100644 index e03dfcc1a..000000000 --- a/.github/workflows/linux_clang.yml +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (c) 2020 Mohammad Ashar Khan -# Distributed under Boost Software License, Version 1.0 -# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) - -name: Linux Clang Release -# Trigger on Push to the repository, regardless of the branch. -# For fine tune, You can add specific branches or tags. -on: - push: - paths-ignore: - - '**.md' - - 'doc/**' - pull_request: - paths-ignore: - - '**.md' - - 'doc/**' - -jobs: - build: - name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early - matrix: - config: - - { cc: clang-6.0, cxx: clang++-6.0, cxxstd: 11} - - { cc: clang-8, cxx: clang++-8, cxxstd: 11} - - { cc: clang-9, cxx: clang++-9, cxxstd: 11} - - { cc: clang-10, cxx: clang++-10, cxxstd: 11} - - { cc: clang-6.0, cxx: clang++-6.0, cxxstd: 17} - - { cc: clang-8, cxx: clang++-8, cxxstd: 17} - - { cc: clang-9, cxx: clang++-9, cxxstd: 17} - - { cc: clang-10, cxx: clang++-10, cxxstd: 17} - - { cc: clang-10, cxx: clang++-10, cxxstd: 2a} - - steps: - - uses: actions/checkout@v2 - - - name: Install Clang 10 - if: matrix.config.cxx == 'clang++-10' - run: | - sudo apt-get update - sudo apt-get install -y clang-10 - - - name: Install Clang 6 - if: matrix.config.cxx == 'clang++-6.0' - run: | - sudo apt-get update - sudo apt-get install -y clang-6.0 - - - name: Prepare BOOST_ROOT - run: | - cd ${GITHUB_WORKSPACE} - cd .. - - git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root - cd boost-root - - git submodule update --init --depth=1 --jobs 8 tools/build - git submodule update --init --depth=1 --jobs 8 libs/config - git submodule update --init --depth=1 --jobs 8 tools/boostdep - - mkdir -p libs/numeric/ - cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas - python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - - ./bootstrap.sh - ./b2 -j 8 headers - - #echo ::set-env name=BOOST_ROOT::${PWD} - echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} - - - name: Prepare Build - run: | - echo $BOOST_ROOT - cd $BOOST_ROOT - - echo "using clang : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; - - - name: Test Benchmarks - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 benchmarks toolset=clang cxxstd=${{matrix.config.cxxstd}} cxxflags="-O3" - - - name: Test Tensor Examples - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 examples/tensor toolset=clang cxxstd=${{matrix.config.cxxstd}} cxxflags="-O3" - - - name: Test Tensor - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 test/tensor toolset=clang cxxstd=${{matrix.config.cxxstd}} cxxflags="-O3" diff --git a/.github/workflows/linux_gcc.yml b/.github/workflows/linux_gcc.yml deleted file mode 100644 index 3fa47504e..000000000 --- a/.github/workflows/linux_gcc.yml +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (c) 2020 Mohammad Ashar Khan, Cem Bassoy -# Distributed under Boost Software License, Version 1.0 -# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) - -name: Linux GCC Debug -# Trigger on Push to the repository, regardless of the branch. -# For fine tune, You can add specific branches or tags. -on: - push: - paths-ignore: - - '**.md' - - 'doc/**' - pull_request: - paths-ignore: - - '**.md' - - 'doc/**' -jobs: - build: - name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early - matrix: - config: - - {cc: gcc-7, cxx: g++-7, cxxstd: 11} - - {cc: gcc-8, cxx: g++-8, cxxstd: 11} - - {cc: gcc-9, cxx: g++-9, cxxstd: 11} - - {cc: gcc-10, cxx: g++-10, cxxstd: 11} - - {cc: gcc-7, cxx: g++-7, cxxstd: 17} - - {cc: gcc-8, cxx: g++-8, cxxstd: 17} - - {cc: gcc-9, cxx: g++-9, cxxstd: 17} - - {cc: gcc-10, cxx: g++-10, cxxstd: 17} - - {cc: gcc-10, cxx: g++-10, cxxstd: 2a} - steps: - - uses: actions/checkout@v2 - - - name: Install GCC-10 - if: matrix.config.cxx == 'g++-10' - run: | - sudo apt update - sudo apt-get install -y g++-10 - - - name: Prepare BOOST_ROOT - run: | - cd ${GITHUB_WORKSPACE} - cd .. - - git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root - cd boost-root - - git submodule update --init --depth=1 --jobs 8 tools/build - git submodule update --init --depth=1 --jobs 8 libs/config - git submodule update --init --depth=1 --jobs 8 tools/boostdep - - mkdir -p libs/numeric/ - cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas - python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - - ./bootstrap.sh - ./b2 -j 8 headers - - #echo ::set-env name=BOOST_ROOT::${PWD} - echo "BOOST_ROOT=${PWD}" >> $GITHUB_ENV - - - name: Prepare Build - run: | - echo $BOOST_ROOT - cd $BOOST_ROOT - - echo "using gcc : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; - - - name: Test Benchmarks - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 benchmarks toolset=gcc cxxstd=${{matrix.config.cxxstd}} - - - name: Test Tensor Examples - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 examples/tensor toolset=gcc cxxstd=${{matrix.config.cxxstd}} cxxflags="-O0" - - - name: Test Tensor - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 test/tensor toolset=gcc cxxstd=${{matrix.config.cxxstd}} cxxflags="-O0 -g --coverage" linkflags="--coverage" - - - name: Report Code coverage - if: matrix.config.cxxstd == '17' && matrix.config.cxx == 'g++-9' - run: | - ${GITHUB_WORKSPACE}/.ci/report_coverage.sh - - curl -s https://codecov.io/bash > cov.sh - chmod +x cov.sh - ./cov.sh -f coverage.info || echo "Codecov did not collect coverage reports" - diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml new file mode 100644 index 000000000..a2edff34b --- /dev/null +++ b/.github/workflows/sanitizer.yml @@ -0,0 +1,83 @@ +# Copyright (c) 2020 Mohammad Ashar Khan +# Copyright (c) 2021 Cem Bassoy +# Distributed under Boost Software License, Version 1.0 +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: "Clang Sanitizer" + +on: + push: + paths-ignore: + - '**.md' + - 'doc/**' + pull_request: + paths-ignore: + - '**.md' + - 'doc/**' +jobs: + build: + name: "${{matrix.config.name}} with ${{matrix.config.description}} sanitizer with std=${{matrix.config.cxx}} and variant=${{matrix.config.variant}}" + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early + matrix: + config: + - { name: clang, description: address and leak, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off , cxxflags: -fsanitize=address -fno-omit-frame-pointer, ldflags: -fsanitize=address } + - { name: clang, description: undefined behavior, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off , cxxflags: -fsanitize=undefined, ldflags: -fsanitize=undefined } + - { name: clang, description: thread, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off , cxxflags: -fsanitize=thread, ldflags: -fsanitize=thread } + - { name: gcc, description: address and leak, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp -fsanitize=address -fno-omit-frame-pointer, ldflags: -fsanitize=address -fopenmp} +# - { name: gcc, description: undefined behavior, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp -fsanitize=undefined, ldflags: -fsanitize=undefined -fopenmp} +# - { name: gcc, description: thread, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp -fsanitize=thread, ldflags: -fsanitize=thread -fopenmp} + + steps: + - uses: actions/checkout@v2 + + - name: Install Clang 11 + run: sudo apt-get update && sudo apt-get install -y clang-11 clang-tools-11 + + - name: Install GCC 10 + run: sudo apt-get update && sudo apt-get install -y g++-10 libomp-dev + + - name: Git Clone Boost.uBlas + run: | + cd ${GITHUB_WORKSPACE} + cd .. + + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} + echo $BOOST_ROOT + + git submodule update --init --depth=1 --jobs 8 tools/build + git submodule update --init --depth=1 --jobs 8 libs/config + git submodule update --init --depth=1 --jobs 8 tools/boostdep + + mkdir -p libs/numeric/ + cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas + python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + + - name: Bootstrap Boost and Compile Boost + run: | + cd $BOOST_ROOT + ./bootstrap.sh + ./b2 -j8 headers + echo "using ${{ matrix.config.name }} : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; + export ASAN_OPTIONS=symbolize=1 + export ASAN_OPTIONS=detect_leaks=1 + + - name: Run Tensor Examples with "${{matrix.config.description}}" sanitizer + run: | + cd $BOOST_ROOT/libs/numeric/ublas + ASAN_OPTIONS=detect_leaks=1 + ASAN_OPTIONS=symbolize=1 + $BOOST_ROOT/b2 -j8 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} cxxflags="${{matrix.config.cxxflags}}" linkflags="${{matrix.config.ldflags}}" + + - name: Run Tensor Tests with "${{matrix.config.description}}" sanitizer + run: | + cd $BOOST_ROOT/libs/numeric/ublas + ASAN_OPTIONS=detect_leaks=1 + ASAN_OPTIONS=symbolize=1 + $BOOST_ROOT/b2 -j8 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} cxxflags="${{matrix.config.cxxflags}}" linkflags="${{matrix.config.ldflags}}" + + diff --git a/.github/workflows/thread_san.yml b/.github/workflows/thread_san.yml deleted file mode 100644 index 4fc416a0d..000000000 --- a/.github/workflows/thread_san.yml +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (c) 2020 Mohammad Ashar Khan -# Distributed under Boost Software License, Version 1.0 -# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) - -name: Thread Sanitizer -# Trigger on Push to the repository, regardless of the branch. -# For fine tune, You can add specific branches or tags. -on: - push: - paths-ignore: - - '**.md' - - 'doc/**' - pull_request: - paths-ignore: - - '**.md' - - 'doc/**' -jobs: - build: - name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early - matrix: - config: - - {cc: gcc-9, cxx: g++-9, cxxstd: 2a, name: gcc} - - {cc: clang-9, cxx: clang++-9, cxxstd: 2a, name: clang} - steps: - - uses: actions/checkout@v2 - - - name: Prepare BOOST_ROOT - run: | - cd ${GITHUB_WORKSPACE} - cd .. - - git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root - cd boost-root - - git submodule update --init --depth=1 --jobs 8 tools/build - git submodule update --init --depth=1 --jobs 8 libs/config - git submodule update --init --depth=1 --jobs 8 tools/boostdep - - mkdir -p libs/numeric/ - cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas - python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - - ./bootstrap.sh - ./b2 -j 8 headers - - #echo ::set-env name=BOOST_ROOT::${PWD} - echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} - - - name: Prepare Build - run: | - echo $BOOST_ROOT - cd $BOOST_ROOT - - echo "using ${{matrix.config.name}} : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; - - - name: Test Benchmarks - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 benchmarks toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} - - - name: Test Tensor Examples - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=thread -O2" linkflags="-fsanitize=thread" - - - name: Test Tensor - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=thread -O2" linkflags="-fsanitize=thread" diff --git a/.github/workflows/ub_san.yml b/.github/workflows/ub_san.yml deleted file mode 100644 index 1985bf458..000000000 --- a/.github/workflows/ub_san.yml +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (c) 2020 Mohammad Ashar Khan -# Distributed under Boost Software License, Version 1.0 -# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) - -name: Undefined Behaviour Sanitizer -# Trigger on Push to the repository, regardless of the branch. -# For fine tune, You can add specific branches or tags. -on: - push: - paths-ignore: - - '**.md' - - 'doc/**' - pull_request: - paths-ignore: - - '**.md' - - 'doc/**' -jobs: - build: - name: "${{matrix.config.cxx}} -std=c++${{matrix.config.cxxstd}}" - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early - matrix: - config: - - {cc: gcc-9, cxx: g++-9, cxxstd: 2a, name: gcc} - - {cc: clang-9, cxx: clang++-9, cxxstd: 2a, name: clang} - steps: - - uses: actions/checkout@v2 - - - name: Prepare BOOST_ROOT - run: | - cd ${GITHUB_WORKSPACE} - cd .. - - git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root - cd boost-root - - git submodule update --init --depth=1 --jobs 8 tools/build - git submodule update --init --depth=1 --jobs 8 libs/config - git submodule update --init --depth=1 --jobs 8 tools/boostdep - - mkdir -p libs/numeric/ - cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas - python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - - ./bootstrap.sh - ./b2 -j 8 headers - - #echo ::set-env name=BOOST_ROOT::${PWD} - echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} - - - name: Prepare Build - run: | - echo $BOOST_ROOT - cd $BOOST_ROOT - - echo "using ${{matrix.config.name}} : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; - - - name: Test Benchmarks - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 benchmarks toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} - - - name: Test Tensor Examples - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=undefined" linkflags="-fsanitize=undefined" - - - name: Test Tensor - run: | - cd $BOOST_ROOT - cd libs/numeric/ublas - $BOOST_ROOT/b2 -j 4 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} cxxflags="-g -fsanitize=undefined" linkflags="-fsanitize=undefined" diff --git a/.github/workflows/windows_msvc.yml b/.github/workflows/windows.yml similarity index 77% rename from .github/workflows/windows_msvc.yml rename to .github/workflows/windows.yml index 59e6ff05d..7bdfc69be 100644 --- a/.github/workflows/windows_msvc.yml +++ b/.github/workflows/windows.yml @@ -1,8 +1,9 @@ # Copyright (c) 2020 Mohammad Ashar Khan +# Copyright (c) 2021 Cem Bassoy # Distributed under Boost Software License, Version 1.0 # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) -name: "Windows MSVC" +name: "Windows" on: push: paths-ignore: @@ -14,15 +15,15 @@ on: - 'doc/**' jobs: build: - name: "windows=${{matrix.config.os}} msvc=${{matrix.config.version}} std=c++${{matrix.config.cxxstd}}" + name: "Windows=${{matrix.config.os}} msvc=${{matrix.config.version}} std=c++${{matrix.config.cxxstd}}" runs-on: ${{matrix.config.os}} strategy: - fail-fast: false + fail-fast: true matrix: config: - - {os: windows-2016, toolset: msvc, version: 14.16, cxxstd: 11} - - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: 11} - - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: 17} +# - {os: windows-2016, toolset: msvc, version: 14.16, cxxstd: 11} +# - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: 11} +# - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: 17} - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: latest} steps: @@ -70,24 +71,24 @@ jobs: cmd /c bootstrap b2 -j8 headers - - name: Test Benchmarks - shell: cmd - run: | - cd %BOOST_ROOT% - cd libs\numeric\ublas - %BOOST_ROOT%\b2 -j 4 benchmarks toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 +# - name: Test Benchmarks +# shell: cmd +# run: | +# cd %BOOST_ROOT% +# cd libs\numeric\ublas +# %BOOST_ROOT%\b2 -j 4 benchmarks toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 - name: Test Tensor Examples shell: cmd run: | cd %BOOST_ROOT% cd libs\numeric\ublas - %BOOST_ROOT%\b2 -j 4 examples/tensor toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 + %BOOST_ROOT%\b2 -j8 examples/tensor toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 - name: Test Tensor shell: cmd run: | cd %BOOST_ROOT% cd libs\numeric\ublas - %BOOST_ROOT%\b2 -j 4 test/tensor toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 + %BOOST_ROOT%\b2 -j8 test/tensor toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f4578d1b4..000000000 --- a/.travis.yml +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2018 Stefan Seefeld -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) - - -language: cpp - -dist: bionic - -sudo: required - -branches: - only: - - master - - develop - - doc - - ci - -# env: specifies additional global variables to define per row in build matrix -env: - global: - - CLBLAS_PREFIX=${TRAVIS_BUILD_DIR}/CLBLAS/ - - PATH=${CLBLAS_PREFIX}/bin:$PATH - - LD_LIBRARY_PATH=${CLBLAS_PREFIX}/lib:$LD_LIBRARY_PATH - -matrix: - include: - - os: linux - env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=11 - - os: linux - env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=17 - - os: linux - env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=2a - - os: linux - env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=17 - - os: linux - env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=2a - -addons: - apt: - sources: - - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' - key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - - sourceline: 'ppa:ubuntu-toolchain-r/test' - packages: - - g++-7 - - g++-9 - - clang-7 - - clang-10 - - libopenblas-base - - rpm2cpio - - cpio - - clinfo - - opencl-headers - - ocl-icd-opencl-dev - -before_install: - - if [ ${TRAVIS_OS_NAME} == "linux" ]; then .ci/install-ocl-ubuntu.sh; fi - - .ci/install-clblas.sh - - cmake --version; - - ${CC} --version; - - ${CXX} --version; - -install: - - cd .. - - git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root - - cd boost-root - - git submodule update --init --jobs 8 tools/build - - git submodule update --init --jobs 8 libs/config - - git submodule update --init --jobs 8 tools/boostdep - - mkdir -p libs/numeric/ - - cp -rp $TRAVIS_BUILD_DIR/. libs/numeric/ublas - - python tools/boostdep/depinst/depinst.py -I benchmarks numeric/ublas - - ./bootstrap.sh - - ./b2 -j 8 headers - - export BOOST_ROOT="`pwd`" - -# use script: to execute build steps -script: - - |- - echo "using $TOOLSET : : $COMPILER ;" >> ~/user-config.jam; - echo "using clblas : : ${CLBLAS_PREFIX}/include ${CLBLAS_PREFIX}/lib ;" >> ~/user-config.jam; - cp $TRAVIS_BUILD_DIR/opencl.jam ~/ - cp $TRAVIS_BUILD_DIR/clblas.jam ~/ - - cd libs/numeric/ublas - - $BOOST_ROOT/b2 -j 8 test toolset=$TOOLSET cxxstd=$CXXSTD - -notifications: - email: - on_success: always \ No newline at end of file diff --git a/IDEs/qtcreator/examples/configuration.pri b/IDEs/qtcreator/examples/configuration.pri index 0c0c8650f..dde3f8f8f 100644 --- a/IDEs/qtcreator/examples/configuration.pri +++ b/IDEs/qtcreator/examples/configuration.pri @@ -1,17 +1,24 @@ CONFIG -= qt CONFIG += depend_includepath win*: CONFIG += console +CONFIG += object_parallel_to_source -QMAKE_CXXFLAGS += -std=c++17 -fopenmp -g +QMAKE_CXXFLAGS =-std=c++20 +QMAKE_CXXFLAGS +=-Wall -Wpedantic -Wextra +QMAKE_CXXFLAGS +=-Wno-unknown-pragmas +QMAKE_CXXFLAGS +=-Wno-unused-but-set-variable -# If ublas tests are build with boost source code then, -# then boost headers and boost libraries should be used. +gcc:QMAKE_CXXFLAGS_RELEASE =-O3 -march=native -fopenmp +clang: QMAKE_CXXFLAGS_RELEASE =-O3 -march=native -fopenmp=libiomp5 -BOOST_ROOT=../../../../../.. +gcc:QMAKE_CXXFLAGS_DEBUG += -g +clang: QMAKE_CXXFLAGS_DEBUG +=-g -exists( $$BOOST_ROOT/boost-build.jam ) { - message("Boost installed.") - INCLUDEPATH += $${BOOST_ROOT}/../libs/numeric/ublas/include - LIBS += -L$${BOOST_ROOT}/../stage/lib -lgomp - QMAKE_RPATHDIR += $${BOOST_ROOT}/../stage/lib -} +BOOST_ROOT=../../../../../../../.. +QMAKE_RPATHDIR += $${BOOST_ROOT}/stage/lib +INCLUDEPATH+=$$BOOST_ROOT/libs/numeric/ublas/include +LIBS+=-L$${BOOST_ROOT}/stage/lib + +#message("INCLUDEPATH: $${INCLUDEPATH}") + +INCLUDE_DIR=$${BOOST_ROOT}/libs/numeric/ublas/include diff --git a/IDEs/qtcreator/examples/tensor/example_access_tensor.pro b/IDEs/qtcreator/examples/tensor/example_access_tensor.pro deleted file mode 100644 index c6d761159..000000000 --- a/IDEs/qtcreator/examples/tensor/example_access_tensor.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = access_tensor - -include (../configuration.pri) - -SOURCES += \ - ../../../../examples/tensor/access_tensor.cpp diff --git a/IDEs/qtcreator/examples/tensor/example_instantiate_tensor.pro b/IDEs/qtcreator/examples/tensor/example_instantiate_tensor.pro deleted file mode 100644 index e98706b38..000000000 --- a/IDEs/qtcreator/examples/tensor/example_instantiate_tensor.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = instantiate_tensor - -include (../configuration.pri) - -SOURCES += \ - ../../../../examples/tensor/instantiate_tensor.cpp diff --git a/IDEs/qtcreator/examples/tensor/example_multiply_tensors_einstein_notation.pro b/IDEs/qtcreator/examples/tensor/example_multiply_tensors_einstein_notation.pro deleted file mode 100644 index 1aca61e34..000000000 --- a/IDEs/qtcreator/examples/tensor/example_multiply_tensors_einstein_notation.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = multiply_tensors_einstein_notation - -include (../configuration.pri) - -SOURCES += \ - ../../../../examples/tensor/multiply_tensors_einstein_notation.cpp diff --git a/IDEs/qtcreator/examples/tensor/example_multiply_tensors_product_function.pro b/IDEs/qtcreator/examples/tensor/example_multiply_tensors_product_function.pro deleted file mode 100644 index bf02e0228..000000000 --- a/IDEs/qtcreator/examples/tensor/example_multiply_tensors_product_function.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = multiply_tensors_product_function - -include (../configuration.pri) - -SOURCES += \ - ../../../../examples/tensor/multiply_tensors_product_function.cpp diff --git a/IDEs/qtcreator/examples/tensor/example_simple_expressions.pro b/IDEs/qtcreator/examples/tensor/example_simple_expressions.pro deleted file mode 100644 index 1c65b9cc6..000000000 --- a/IDEs/qtcreator/examples/tensor/example_simple_expressions.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = simple_expressions - -include (../configuration.pri) - -SOURCES += \ - ../../../../examples/tensor/simple_expressions.cpp diff --git a/IDEs/qtcreator/examples/tensor/tensor.pro b/IDEs/qtcreator/examples/tensor/tensor.pro index feb833f62..f928b32bf 100644 --- a/IDEs/qtcreator/examples/tensor/tensor.pro +++ b/IDEs/qtcreator/examples/tensor/tensor.pro @@ -1,21 +1,10 @@ -#TEMPLATE = subdirs -#SUBDIRS = \ -# construction_access \ -# simple_expressions \ -# multiply_tensors_prod \ -# einstein_notation \ -# instantiate_tensor +TEMPLATE = subdirs +SUBDIRS = \ + simple_expressions \ + multiply_tensors_product_function \ + multiply_tensors_einstein_notation \ + instantiate_tensor \ + access_tensor -include ( example_instantiate_tensor.pro ) -include ( example_access_tensor.pro ) -include ( example_simple_expressions.pro ) -include ( example_multiply_tensors_product_function.pro ) -include ( example_multiply_tensors_einstein_notation.pro ) - -#instantiate_tensor.file = example_instantiate_tensor.pro -#construction_access.file = example_construction_access.pro -#simple_expressions.file = example_simple_expressions.pro -#multiply_tensors_prod.file = example_multiply_tensors_prod.pro -#einstein_notation.file = example_einstein_notation.pro diff --git a/IDEs/qtcreator/include/include.pro b/IDEs/qtcreator/include/include.pro index 17d199106..a5aeead8b 100644 --- a/IDEs/qtcreator/include/include.pro +++ b/IDEs/qtcreator/include/include.pro @@ -1,11 +1,9 @@ TEMPLATE = lib TARGET = ublas -CONFIG += \ - staticlib \ - depend_includepath +CONFIG += staticlib depend_includepath CONFIG -= qt -CONFIG += c++17 +CONFIG += c++20 INCLUDE_DIR=../../../include include(detail/detail.pri) diff --git a/IDEs/qtcreator/include/tensor/tensor.pri b/IDEs/qtcreator/include/tensor/tensor.pri index 4cfae5d9f..112376c11 100644 --- a/IDEs/qtcreator/include/tensor/tensor.pri +++ b/IDEs/qtcreator/include/tensor/tensor.pri @@ -1,14 +1,11 @@ HEADERS += \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/algorithms.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/dynamic_extents.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/dynamic_strides.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/expression.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/expression_evaluation.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/extents_functions.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/fixed_rank_extents.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/fixed_rank_strides.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/extents.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/functions.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/index.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/index_functions.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/layout.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/multi_index.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/multi_index_utility.hpp \ @@ -16,24 +13,43 @@ HEADERS += \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/operators_arithmetic.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/operators_comparison.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/ostream.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/static_extents.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/static_strides.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/strides.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tags.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor_core.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor_engine.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/concepts.hpp \ $${INCLUDE_DIR}/boost/numeric/ublas/tensor/type_traits.hpp + +HEADERS += \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/traits/basic_type_traits.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/traits/storage_traits.hpp + +HEADERS += \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/extents/extents_dynamic_size.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/extents/extents_static_size.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/extents/extents_static_functions.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/extents/extents_static.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/extents/extents_base.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/extents/extents_functions.hpp + + +HEADERS += \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor/tensor_core.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor/tensor_engine.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor/tensor_static.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor/tensor_static_rank.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/tensor/tensor_dynamic.hpp + + HEADERS += \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/basic_type_traits.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/storage_traits.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_dynamic_extents.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_dynamic_strides.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_extents.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_extents.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_fixed_rank_strides.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_static_extents.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_static_strides.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_strides.hpp \ - $${INCLUDE_DIR}/boost/numeric/ublas/tensor/detail/type_traits_tensor.hpp + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/inner_prod.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/init.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/outer_prod.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/trans.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/norm.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/imag.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/real.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/conj.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/tensor_times_vector.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/tensor_times_matrix.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/tensor_times_tensor.hpp \ + $${INCLUDE_DIR}/boost/numeric/ublas/tensor/function/reshape.hpp diff --git a/IDEs/qtcreator/test/test_tensor.pro b/IDEs/qtcreator/test/test_tensor.pro index 5966e27d6..8deee2f99 100644 --- a/IDEs/qtcreator/test/test_tensor.pro +++ b/IDEs/qtcreator/test/test_tensor.pro @@ -1,38 +1,46 @@ TEMPLATE = app -TARGET = test +TARGET = test_tensor +CONFIG += staticlib depend_includepath console CONFIG -= qt -CONFIG += depend_includepath debug -win*: CONFIG += console +CONFIG += c++20 #QMAKE_CXXFLAGS += -fno-inline -QMAKE_CXXFLAGS += -std=c++17 -#QMAKE_CXXFLAGS += -Wno-unknown-pragmas -#QMAKE_CXXFLAGS += --coverage +QMAKE_CXXFLAGS =-std=c++20 +QMAKE_CXXFLAGS +=-Wall -Wpedantic -Wextra +QMAKE_CXXFLAGS +=-Wno-unknown-pragmas +QMAKE_CXXFLAGS +=-Wno-unused-but-set-variable + + +gcc:QMAKE_CXXFLAGS_RELEASE =-O3 -march=native -fopenmp +clang: QMAKE_CXXFLAGS_RELEASE =-O3 -march=native -fopenmp=libiomp5 +gcc:QMAKE_CXXFLAGS_DEBUG = -g +clang: QMAKE_CXXFLAGS_DEBUG =-g -DEFINES += BOOST_UBLAS_NO_EXCEPTIONS -win*: DEFINES += _SCL_SECURE_NO_WARNINGS -#Visual age IBM -xlc: DEFINES += BOOST_UBLAS_NO_ELEMENT_PROXIES +#QMAKE_CXXFLAGS += --coverage + +BOOST_ROOT=../../../../../.. -# If ublas tests are build with boost source code then, -# then boost headers and boost libraries should be used. -#exists(../../../../../../boost-build.jam) { -# INCLUDEPATH += ../../../../../.. -# LIBS += -L../../../../../../stage/lib -# QMAKE_RPATHDIR += ../../../../../../stage/lib +#exists( $$BOOST_ROOT/boost-build.jam ) { +# message("Boost installed.") +# INCLUDEPATH += $${BOOST_ROOT}/libs/numeric/ublas/include +# LIBS += -L$${BOOST_ROOT}/stage/lib -lgomp +# QMAKE_RPATHDIR += $${BOOST_ROOT}/stage/lib #} -INCLUDEPATH += /usr/local/include -INCLUDEPATH += ../../../include -LIBS += -L/usr/local/lib -LIBS +=-lboost_unit_test_framework -# -lgcov +QMAKE_RPATHDIR += $${BOOST_ROOT}/stage/lib +INCLUDEPATH+=$$BOOST_ROOT/libs/numeric/ublas/include +LIBS+=-L$${BOOST_ROOT}/stage/lib -lboost_unit_test_framework -lgomp +#message("INCLUDEPATH: $${INCLUDEPATH}") + +INCLUDE_DIR=$${BOOST_ROOT}/libs/numeric/ublas/include TEST_DIR = ../../../test/tensor +include(../include/tensor/tensor.pri) + HEADERS += \ $${TEST_DIR}/utility.hpp @@ -41,7 +49,8 @@ SOURCES += \ $${TEST_DIR}/test_einstein_notation.cpp \ $${TEST_DIR}/test_expression.cpp \ $${TEST_DIR}/test_expression_evaluation.cpp \ - $${TEST_DIR}/test_extents.cpp \ + $${TEST_DIR}/test_extents_dynamic.cpp \ + $${TEST_DIR}/test_extents_dynamic_rank_static.cpp \ $${TEST_DIR}/test_fixed_rank_expression_evaluation.cpp \ $${TEST_DIR}/test_fixed_rank_extents.cpp \ $${TEST_DIR}/test_fixed_rank_functions.cpp \ @@ -66,8 +75,5 @@ SOURCES += \ $${TEST_DIR}/test_static_tensor_matrix_vector.cpp \ $${TEST_DIR}/test_strides.cpp \ $${TEST_DIR}/test_tensor.cpp \ - $${TEST_DIR}/test_tensor_matrix_vector.cpp - - -INCLUDEPATH += \ - ../../../include + $${TEST_DIR}/test_tensor_matrix_vector.cpp \ + $${TEST_DIR}/test_extents_functions.cpp diff --git a/IDEs/qtcreator/tests.pri b/IDEs/qtcreator/tests.pri index 7b55d478c..04e131f59 100644 --- a/IDEs/qtcreator/tests.pri +++ b/IDEs/qtcreator/tests.pri @@ -1,72 +1,72 @@ SUBDIRS += \ - begin_end \ - comp_mat_erase \ - concepts \ - num_columns \ - num_rows \ - placement_new \ - size \ - sparse_view_test \ - test1 \ - test2 \ - test3 \ - test3_coo \ - test3_mvov \ - test4 \ - test5 \ - test6 \ - test7 \ - test_assignment \ - test_banded_storage_layout \ - test_complex_norms \ - test_coordinate_matrix_inplace_merge \ - test_coordinate_matrix_sort \ - test_coordinate_matrix_always_do_full_sort \ - test_coordinate_vector_inplace_merge \ - test_fixed_containers \ - test_inplace_solve_basic \ - test_inplace_solve_sparse \ - test_inplace_solve_mvov \ - test_lu \ - test_matrix_vector \ - test_ticket7296 \ - test_triangular \ - triangular_access \ - triangular_layout \ - test_tensor +# begin_end \ +# comp_mat_erase \ +# concepts \ +# num_columns \ +# num_rows \ +# placement_new \ +# size \ +# sparse_view_test \ +# test1 \ +# test2 \ +# test3 \ +# test3_coo \ +# test3_mvov \ +# test4 \ +# test5 \ +# test6 \ +# test7 \ +# test_assignment \ +# test_banded_storage_layout \ +# test_complex_norms \ +# test_coordinate_matrix_inplace_merge \ +# test_coordinate_matrix_sort \ +# test_coordinate_matrix_always_do_full_sort \ +# test_coordinate_vector_inplace_merge \ +# test_fixed_containers \ +# test_inplace_solve_basic \ +# test_inplace_solve_sparse \ +# test_inplace_solve_mvov \ +# test_lu \ +# test_matrix_vector \ +# test_ticket7296 \ +# test_triangular \ +# triangular_access \ +# triangular_layout \ + # test_tensor -begin_end.file = test/begin_end.pro -comp_mat_erase.file = test/comp_mat_erase.pro -concepts.file = test/concepts.pro -num_columns.file = test/num_columns.pro -num_rows.file = test/num_rows.pro -placement_new.file = test/placement_new.pro -size.file = test/size.pro -sparse_view_test.file = test/sparse_view_test.pro -test1.file = test/test1.pro -test2.file = test/test2.pro -test3.file = test/test3.pro -test3_coo.file = test/test3_coo.pro -test3_mvov.file = test/test3_mvov.pro -test4.file = test/test4.pro -test5.file = test/test5.pro -test6.file = test/test6.pro -test7.file = test/test7.pro -test_assignment.file = test/test_assignment.pro -test_banded_storage_layout.file = test/test_banded_storage_layout.pro -test_complex_norms.file = test/test_complex_norms.pro -test_coordinate_matrix_inplace_merge.file = test/test_coordinate_matrix_inplace_merge.pro -test_coordinate_matrix_sort.file = test/test_coordinate_matrix_sort.pro -test_coordinate_matrix_always_do_full_sort.file = test/test_coordinate_matrix_always_do_full_sort.pro -test_coordinate_vector_inplace_merge.file = test/test_coordinate_vector_inplace_merge.pro -test_fixed_containers.file = test/test_fixed_containers.pro -test_inplace_solve_basic.file = test/test_inplace_solve_basic.pro -test_inplace_solve_sparse.file = test/test_inplace_solve_sparse.pro -test_inplace_solve_mvov.file = test/test_inplace_solve_mvov.pro -test_lu.file = test/test_lu.pro -test_matrix_vector.file = test/test_matrix_vector.pro -test_ticket7296.file = test/test_ticket7296.pro -test_triangular.file = test/test_triangular.pro -triangular_access.file = test/triangular_access.pro -triangular_layout.file = test/triangular_layout.pro -test_tensor.file = test/test_tensor.pro +#begin_end.file = test/begin_end.pro +#comp_mat_erase.file = test/comp_mat_erase.pro +#concepts.file = test/concepts.pro +#num_columns.file = test/num_columns.pro +#num_rows.file = test/num_rows.pro +#placement_new.file = test/placement_new.pro +#size.file = test/size.pro +#sparse_view_test.file = test/sparse_view_test.pro +#test1.file = test/test1.pro +#test2.file = test/test2.pro +#test3.file = test/test3.pro +#test3_coo.file = test/test3_coo.pro +#test3_mvov.file = test/test3_mvov.pro +#test4.file = test/test4.pro +#test5.file = test/test5.pro +#test6.file = test/test6.pro +#test7.file = test/test7.pro +#test_assignment.file = test/test_assignment.pro +#test_banded_storage_layout.file = test/test_banded_storage_layout.pro +#test_complex_norms.file = test/test_complex_norms.pro +#test_coordinate_matrix_inplace_merge.file = test/test_coordinate_matrix_inplace_merge.pro +#test_coordinate_matrix_sort.file = test/test_coordinate_matrix_sort.pro +#test_coordinate_matrix_always_do_full_sort.file = test/test_coordinate_matrix_always_do_full_sort.pro +#test_coordinate_vector_inplace_merge.file = test/test_coordinate_vector_inplace_merge.pro +#test_fixed_containers.file = test/test_fixed_containers.pro +#test_inplace_solve_basic.file = test/test_inplace_solve_basic.pro +#test_inplace_solve_sparse.file = test/test_inplace_solve_sparse.pro +#test_inplace_solve_mvov.file = test/test_inplace_solve_mvov.pro +#test_lu.file = test/test_lu.pro +#test_matrix_vector.file = test/test_matrix_vector.pro +#test_ticket7296.file = test/test_ticket7296.pro +#test_triangular.file = test/test_triangular.pro +#triangular_access.file = test/triangular_access.pro +#triangular_layout.file = test/triangular_layout.pro +#test_tensor.file = test/test_tensor.pro diff --git a/IDEs/qtcreator/ublas_develop.pro b/IDEs/qtcreator/ublas_develop.pro index e509e747e..49fc2d99c 100644 --- a/IDEs/qtcreator/ublas_develop.pro +++ b/IDEs/qtcreator/ublas_develop.pro @@ -4,7 +4,9 @@ SUBDIRS = include # examples # benchmarks OTHER_FILES += ../../changelog.txt -include (tests.pri) +#include (tests.pri) + + diff --git a/README.md b/README.md index 22ae6db18..1e9ec9223 100644 --- a/README.md +++ b/README.md @@ -8,64 +8,53 @@ Boost Linear and Multilinear Algebra Library [![Mailing List](https://img.shields.io/badge/ublas-mailing%20list-4eb899.svg)](https://lists.boost.org/mailman/listinfo.cgi/ublas) [![Gitter](https://img.shields.io/badge/ublas-chat%20on%20gitter-4eb899.svg)](https://gitter.im/boostorg/ublas) -**Boost.uBLAS** is part of the [Boost C++ Libraries](http://github.com/boostorg). It is directed towards scientific computing on the level of basic linear and multilinear algebra operations with tensors, matrices and vectors. +[![Windows](https://github.com/boostorg/ublas/actions/workflows/windows.yml/badge.svg)](https://github.com/boostorg/ublas/actions/workflows/windows.yml) +[![Linux](https://github.com/boostorg/ublas/actions/workflows/linux.yml/badge.svg)](https://github.com/boostorg/ublas/actions/workflows/linux.yml) +[![Apple MacOS](https://github.com/boostorg/ublas/actions/workflows/apple.yml/badge.svg)](https://github.com/boostorg/ublas/actions/workflows/apple.yml) +[![Clang Sanitizer](https://github.com/boostorg/ublas/actions/workflows/sanitizer.yml/badge.svg)](https://github.com/boostorg/ublas/actions/workflows/sanitizer.yml) +[![Clang Tidy](https://github.com/boostorg/ublas/actions/workflows/clangtidy.yml/badge.svg)](https://github.com/boostorg/ublas/actions/workflows/clangtidy.yml) +[![Codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) +**Boost.uBLAS** is part of the [Boost C++ Libraries](http://github.com/boostorg). +It is directed towards scientific computing on the level of basic linear and multilinear algebra operations with tensors, matrices and vectors. + ## Documentation uBLAS is documented at [boost.org](https://www.boost.org/doc/libs/1_69_0/libs/numeric/ublas/doc/index.html). -The tensor extension has also a [wiki page](https://github.com/BoostGSoC18/tensor/wiki). +The tensor extension has also a [wiki page](https://github.com/boostorg/ublas/wiki/Tensor). ## License Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). ## Properties -* Header-only -* Tensor extension requires C++17 compatible compiler +* header-only +* requires C++20 compatible compiler + * gcc version >= 10.x.x + * clang version >= 10.x.x + * msvc version >= 14.28 * Unit-tests require Boost.Test -## Build Status - - -#### Tensor Build & Test - -| Operating System | Compiler | [`master`](https://github.com/boostorg/ublas/tree/master) | [`develop`](https://github.com/boostorg/ublas/tree/develop) | -| :-------------------------: | :-----------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | -| Linux (Ubuntu 20.04 x86_64) | gcc-{7, 8, 9, 10} | [![Linux GCC Debug](https://github.com/boostorg/ublas/workflows/Linux%20GCC%20Debug/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Linux+GCC%22+branch%3Amaster) | [![Linux GCC Debug](https://github.com/boostorg/ublas/workflows/Linux%20GCC%20Debug/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Linux+GCC%22+branch%3Adevelop) | -| Linux (Ubuntu 20.04 x86_64) | clang-{6, 8, 9, 10} | [![Linux Clang Release](https://github.com/boostorg/ublas/workflows/Linux%20Clang%20Release/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Linux+Clang%22+branch%3Amaster) | [![Linux Clang Release](https://github.com/boostorg/ublas/workflows/Linux%20Clang%20Release/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Linux+Clang%22+branch%3Adevelop) | -| Windows 10 (x86_64) | msvc-{14.16, 14.26} | [![Windows MSVC](https://github.com/boostorg/ublas/workflows/Windows%20MSVC/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Windows+MSVC%22+branch%3Amaster) | [![Windows MSVC](https://github.com/boostorg/ublas/workflows/Windows%20MSVC/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Windows+MSVC%22+branch%3Adevelop) | -| MacOS Catalina (x86_64) | clang-11 | [![Apple Clang](https://github.com/boostorg/ublas/workflows/Apple%20Clang/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Apple+Clang%22+branch%3Amaster) | [![Apple Clang](https://github.com/boostorg/ublas/workflows/Apple%20Clang/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Apple+Clang%22+branch%3Adevelop) | - -#### Tensor Additional Checks - -| Checks | [`master`](https://github.com/boostorg/ublas/tree/master) | [`develop`](https://github.com/boostorg/ublas/tree/develop) | -| :-----------: | :----------------------------------------------------------: | :----------------------------------------------------------: | -| UB Sanitizer | [![Undefined Behaviour Sanitizer](https://github.com/boostorg/ublas/workflows/Undefined%20Behaviour%20Sanitizer/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Undefined+Behaviour+Sanitizer%22+branch%3Amaster) | [![Undefined Behaviour Sanitizer](https://github.com/boostorg/ublas/workflows/Undefined%20Behaviour%20Sanitizer/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Undefined+Behaviour+Sanitizer%22+branch%3Adevelop) | -| TH Sanitizer | [![Thread Sanitizer](https://github.com/boostorg/ublas/workflows/Thread%20Sanitizer/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Thread+Sanitizer%22+branch%3Amaster) | [![Thread Sanitizer](https://github.com/boostorg/ublas/workflows/Thread%20Sanitizer/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Thread+Sanitizer%22+branch%3Adevelop) | -| ADD Sanitizer | [![Address Sanitizer](https://github.com/boostorg/ublas/workflows/Address%20Sanitizer/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Address+Sanitizer%22+branch%3Amaster) | [![Address Sanitizer](https://github.com/boostorg/ublas/workflows/Address%20Sanitizer/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Address+Sanitizer%22+branch%3Adevelop) | -| Codecov | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) | [![codecov](https://codecov.io/gh/boostorg/ublas/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/develop) | -| Clang-Format | [![Code Format](https://github.com/boostorg/ublas/workflows/Code%20Format/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Code+Format%22+branch%3Amaster) | [![Code Format](https://github.com/boostorg/ublas/workflows/Code%20Format/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Code+Format%22+branch%3Adevelop) | -| Clang-Tidy | [![Clang tidy checks](https://github.com/boostorg/ublas/workflows/Clang%20tidy%20checks/badge.svg?branch=master)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Clang+tidy+checks%22+branch%3Amaster) | [![Clang tidy checks](https://github.com/boostorg/ublas/workflows/Clang%20tidy%20checks/badge.svg?branch=develop)](https://github.com/boostorg/ublas/actions?query=workflow%3A%22Clang+tidy+checks%22+branch%3Adevelop) | +## Simple Example -#### Tensor Build Information +```cpp +#include +#include -| OS | Toolchain | Compiler Flags | -| :----------------: | :-------------: | :-----------------------------------------------: | -| Linux Ubuntu 20.04 | GCC | `-O0` | -| Linux Ubuntu 20.04 | Clang | `-O3` | -| Windows 10 | MSVC | No Special Flags | -| MacOS Catalina | Clang | No Special Flags | -| UB Sanitizer | GCC and Clang | `"-g -fsanitize=undefined"` | -| TH Sanitizer | GCC and Clang | `"-g -fsanitize=thread -O2"` | -| ADD Sanitizer | GCC and Clang | `"-g -fsanitize=address -fno-omit-frame-pointer"` | -| Clang Tidy | Clang-Tidy-10 | [Configuration File](.clang-tidy) | -| Clang Format | Clang-Format-10 | [Configuration File](.clang-format) | +int main() +{ + using namespace boost::numeric::ublas::index; + using tensor = boost::numeric::ublas::tensor_dynamic; + auto ones = boost::numeric::ublas::ones{}; -#### uBLAS CI + tensor A = ones(3,4,5); + tensor B = ones(4,6,3,2); -Branch | Travis | Appveyor | Regression | Docs -:-----: | ------ | --------- | ----------- | ----- - [`master`](https://github.com/boostorg/ublas/tree/master) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=master)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/master?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/master) | [![ublas](https://img.shields.io/badge/ublas-master-blue.svg)](https://www.boost.org/development/tests/master/developer/numeric-ublas.html) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) - [`develop`](https://github.com/boostorg/ublas/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/ublas.svg?branch=develop)](https://travis-ci.org/boostorg/ublas) | [![Build status](https://ci.appveyor.com/api/projects/status/ctu3wnfowa627ful/branch/develop?svg=true)](https://ci.appveyor.com/project/stefanseefeld/ublas/branch/develop) | [![ublas](https://img.shields.io/badge/ublas-develop-blue.svg)](https://www.boost.org/development/tests/develop/developer/numeric-ublas.html) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/numeric) + tensor C = 2*ones(5,6,2) + A(_i,_j,_k)*B(_j,_l,_i,_m) + 5; + + // Matlab Compatible Formatted Output + std::cout << "C=" << C << ";" << std::endl; +} +``` ## Directories @@ -79,7 +68,7 @@ Branch | Travis | Appveyor | Regression | Docs ## More information -* If you would like to test the library, contribute new feature or a bug fix, see [contribution](https://github.com/boostorg/ublas/wiki/Guidelines-for-Contribution) where the whole development infrastructure and the contributing workflow is explained in details. +* If you would like to test the library, contribute new feature or a bug fix, see [contribution](https://github.com/boostorg/ublas/wiki/Guidelines-for-Contribution). * Ask questions in [stackoverflow](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-ublas) with `boost-ublas` or `ublas` tags. * Report [bugs](https://github.com/boostorg/ublas/issues) and be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well. * Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). diff --git a/examples/tensor/.clang-tidy b/examples/tensor/.clang-tidy deleted file mode 100644 index 50e8131ae..000000000 --- a/examples/tensor/.clang-tidy +++ /dev/null @@ -1,11 +0,0 @@ ---- -Checks: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-bugprone-exception-escape' -WarningsAsErrors: '-*,modernize-*,cppcoreguidelines-*,openmp-*,bugprone-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-uppercase-literal-suffix,-readability-braces-around-statements,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-bugprone-exception-escape' -HeaderFilterRegex: 'boost\/numeric\/ublas\/tensor\/.*' -AnalyzeTemporaryDtors: false -FormatStyle: file -User: ublas-developers -CheckOptions: - - key: modernize-use-nullptr.NullMacros - value: 'NULL' -... diff --git a/examples/tensor/access_tensor.cpp b/examples/tensor/access_tensor.cpp index ebd7b2fc6..97e797fb8 100644 --- a/examples/tensor/access_tensor.cpp +++ b/examples/tensor/access_tensor.cpp @@ -15,89 +15,102 @@ #include +//NOLINTNEXTLINE int main() { - using namespace boost::numeric::ublas; - using namespace boost::multiprecision; - - { - using value_t = float; - using format_t = boost::numeric::ublas::layout::first_order; // storage format - using tensor_t = boost::numeric::ublas::dynamic_tensor; - - // creates a three-dimensional tensor with extents 3,4 and 2 - // tensor A stores single-precision floating-point number according - // to the first-order storage format - - auto A = tensor_t{3,4,2}; - - // initializes the tensor with increasing values along the first-index - // using a single index. - auto vf = 1.0f; - for(auto i = 0u; i < A.size(); ++i, vf += 1.0f) - A[i] = vf; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "A=" << A << ";" << std::endl << std::endl; - } - - - { - using value_t = std::complex; - using format_t = boost::numeric::ublas::layout::last_order; // storage format - using tensor_t = boost::numeric::ublas::dynamic_tensor; - using shape_t = typename tensor_t::extents_type; - - // creates a four-dimensional tensor with extents 5,4,3 and 2 - // tensor A stores complex floating-point extended double precision numbers - // according to the last-order storage format - // and initializes it with the default value. - - auto B = tensor_t(shape_t{5,4,3,2},value_t{}); - - // initializes the tensor with increasing values along the last-index - // using a single-index - auto vc = value_t(0,0); - for(auto i = 0u; i < B.size(); ++i, vc += value_t(1,1)) - B[i] = vc; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "B=" << B << ";" << std::endl << std::endl; - - - auto C = tensor_t(B.extents()); - // computes the complex conjugate of elements of B - // using multi-index notation. - for(auto i = 0u; i < B.size(0); ++i) - for(auto j = 0u; j < B.size(1); ++j) - for(auto k = 0u; k < B.size(2); ++k) - for(auto l = 0u; l < B.size(3); ++l) - C.at(i,j,k,l) = std::conj(B.at(i,j,k,l)); - - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "C=" << C << ";" << std::endl << std::endl; - - - - // computes the complex conjugate of elements of B - // using iterators. - auto D = tensor_t(B.extents()); - std::transform(B.begin(), B.end(), D.begin(), [](auto const& b){ return std::conj(b); }); - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "D=" << D << ";" << std::endl << std::endl; - - // reshaping tensors. - auto new_extents = B.extents().base(); - std::next_permutation( new_extents.begin(), new_extents.end() ); - D.reshape( extents<>(new_extents) ); - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "newD=" << D << ";" << std::endl << std::endl; - } + namespace ublas = boost::numeric::ublas; + + try { + using value = float; + using layout = ublas::layout::first_order; // storage format + using tensor = ublas::tensor_dynamic; +// constexpr auto ones = ublas::ones{}; + constexpr auto zeros = ublas::zeros{}; + + // creates a three-dimensional tensor with extents 3,4 and 2 + // tensor A stores single-precision floating-point number according + // to the first-order storage format + + tensor A = zeros(3,4,2); + + // initializes the tensor with increasing values along the first-index + // using a single index. + auto vf = 1.0f; + for(auto i = 0u; i < A.size(); ++i, vf += 1.0f) + A[i] = vf; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "A=" << A << ";" << std::endl << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of access-tensor." << std::endl; + } + + + try { + using value = std::complex; + using layout = ublas::layout::last_order; // storage format + using tensor = ublas::tensor_dynamic; + using shape = typename tensor::extents_type; + constexpr auto zeros = ublas::zeros{}; + + + // creates a four-dimensional tensor with extents 5,4,3 and 2 + // tensor A stores complex floating-point extended double precision numbers + // according to the last-order storage format + // and initializes it with the default value. + + //NOLINTNEXTLINE + tensor B = zeros(5,4,3,2); + + // initializes the tensor with increasing values along the last-index + // using a single-index + auto vc = value(0,0); + for(auto i = 0u; i < B.size(); ++i, vc += value(1,1)) + B[i] = vc; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "B=" << B << ";" << std::endl << std::endl; + + + auto C = tensor(B.extents()); + // computes the complex conjugate of elements of B + // using multi-index notation. + for(auto i = 0u; i < B.size(0); ++i) + for(auto j = 0u; j < B.size(1); ++j) + for(auto k = 0u; k < B.size(2); ++k) + for(auto l = 0u; l < B.size(3); ++l) + C.at(i,j,k,l) = std::conj(B.at(i,j,k,l)); + + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "C=" << C << ";" << std::endl << std::endl; + + + + // computes the complex conjugate of elements of B + // using iterators. + auto D = tensor(B.extents()); + std::transform(B.begin(), B.end(), D.begin(), [](auto const& b){ return std::conj(b); }); + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "D=" << D << ";" << std::endl << std::endl; + + // reshaping tensors. + auto new_extents = B.extents().base(); + std::next_permutation( new_extents.begin(), new_extents.end() ); + auto E = reshape( D, shape(new_extents) ); + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "E=" << E << ";" << std::endl << std::endl; + + + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of access-tensor." << std::endl; + } } diff --git a/examples/tensor/instantiate_tensor.cpp b/examples/tensor/instantiate_tensor.cpp index bb3d8a11e..851716c8d 100644 --- a/examples/tensor/instantiate_tensor.cpp +++ b/examples/tensor/instantiate_tensor.cpp @@ -15,79 +15,107 @@ #include #include -void instantiate_dynamic_tensor() +void instantiate_tensor_dynamic() { + namespace ublas = boost::numeric::ublas; + using value = float; + using layout = ublas::layout::first_order; // storage format + using tensor = boost::numeric::ublas::tensor_dynamic; + constexpr auto ones = ublas::ones{}; - using value_t = float; - using format_t = boost::numeric::ublas::layout::first_order; // storage format - using tensor_t = boost::numeric::ublas::dynamic_tensor; - using shape_t = typename tensor_t::extents_type; - - // tensor type has dynamic order and dimensions + + try { + // tensor is resizable has dynamic dimensions // elements are stored contiguously in memory using the 1st-format (column-major) - auto t1 = tensor_t{3,4,2}; + tensor t1 = ones(3,4,2); std::cout << "t1 = " << t1 << std::endl; - auto t2 = tensor_t(shape_t{3,4,2},2.0F); + tensor t2 = 2 * ones(3,4,2); std::cout << "t2 = " << t2 << std::endl; - auto t3 = tensor_t(t2); + tensor t3 = 3*t2 + t1; std::cout << "t3 = " << t3 << std::endl; + + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the instantiate_tensor_dynamic function of instantiate-tensor." << std::endl; + throw; + } } -void instantiate_dynamic_tensors_with_static_order() +void instantiate_tensor_dynamics_with_static_order() { + namespace ublas = boost::numeric::ublas; + using value = float; + using layout = boost::numeric::ublas::layout::first_order; // storage format + using tensor = boost::numeric::ublas::tensor_static_rank; + constexpr auto ones = ublas::ones_static_rank{}; - constexpr auto order = 3U; - using value_t = float; - using format_t = boost::numeric::ublas::layout::first_order; // storage format - using tensor_t = boost::numeric::ublas::fixed_rank_tensor; - using shape_t = typename tensor_t::extents_type; + try { + // tensor type has static order and dynamic dimensions + // elements are stored contiguously in memory using the 1st-format (column-major) - // tensor type has static order and dynamic dimensions - // elements are stored contiguously in memory using the 1st-format (column-major) + auto t1 = ones(3,4,2); + std::cout << "t1 = " << t1 << std::endl; - auto t1 = tensor_t{3,4,2}; - std::cout << "t1 = " << t1 << std::endl; + tensor t2 = 2*ones(3,4,2); + std::cout << "t2 = " << t2 << std::endl; - auto t2 = tensor_t(shape_t{3,4,2},2.0F); - std::cout << "t2 = " << t2 << std::endl; + tensor t3 = 3*t2 + t1; + std::cout << "t3 = " << t3 << std::endl; - auto t3 = tensor_t(t2); - std::cout << "t3 = " << t3 << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the instantiate_tensor_dynamic function of instantiate-tensor." << std::endl; + throw; + } } -void instantiate_static_tensor() +void instantiate_tensor_static() { - using value_t = float; - using format_t = boost::numeric::ublas::layout::first_order; // storage format - using shape_t = boost::numeric::ublas::static_extents<3U,4U,2U>; - using tensor_t = boost::numeric::ublas::static_tensor; + namespace ublas = boost::numeric::ublas; + using value = float; + using layout = ublas::layout::first_order; // storage format + using shape = ublas::extents<3,4,2>; + using tensor = ublas::tensor_static; + constexpr auto ones = ublas::ones_static{}; - // tensor type has static order and static dimensions - // elements are stored contiguously in memory using the 1st-format (column-major) + try { + // tensor type has static order and static dimensions + // elements are stored contiguously in memory using the 1st-format (column-major) - auto t1 = tensor_t{}; - std::cout << "t1 = " << t1 << std::endl; + auto t1 = tensor{}; + std::cout << "t1 = " << t1 << std::endl; + + tensor t2 = 2 * ones(shape{}); + std::cout << "t2 = " << t2 << std::endl; - auto t2 = tensor_t(2.0F); - std::cout << "t2 = " << t2 << std::endl; + tensor t3 = 3*t2 + t1; + std::cout << "t3 = " << t3 << std::endl; - auto t3 = tensor_t(t2); - std::cout << "t3 = " << t3 << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the instantiate_tensor_dynamic function of instantiate-tensor." << std::endl; + throw; + } } int main() { - instantiate_dynamic_tensor(); - instantiate_dynamic_tensors_with_static_order(); - instantiate_static_tensor(); + try{ + instantiate_tensor_dynamic(); + instantiate_tensor_dynamics_with_static_order(); + instantiate_tensor_static(); + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of instantiate-tensor." << std::endl; + } } diff --git a/examples/tensor/multiply_tensors_einstein_notation.cpp b/examples/tensor/multiply_tensors_einstein_notation.cpp index 3609feb95..c7ba3c2c6 100644 --- a/examples/tensor/multiply_tensors_einstein_notation.cpp +++ b/examples/tensor/multiply_tensors_einstein_notation.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,131 +18,150 @@ int main() { - using namespace boost::numeric::ublas; - - using value_t = float; - using format_t = boost::numeric::ublas::layout::first_order; // storage format - using tensor_t = boost::numeric::ublas::dynamic_tensor; - using shape_t = typename tensor_t::extents_type; - - //using format_t = column_major; - //using value_t = float; - //using shape_t = dynamic_extents<>; - //using tensor_t = dynamic_tensor; - using matrix_t = matrix; - - - using namespace boost::numeric::ublas::index; - - // Tensor-Vector-Multiplications - Including Transposition - { - - auto n = shape_t{3,4,2}; - auto A = tensor_t(n,1); - auto B1 = matrix_t(n[1],n[2],2); - auto v1 = tensor_t(shape_t{n[0],1},2); - auto v2 = tensor_t(shape_t{n[1],1},2); -// auto v3 = tensor_t(shape{n[2],1},2); - - // C1(j,k) = B1(j,k) + A(i,j,k)*v1(i); - // tensor_t C1 = B1 + prod(A,vector_t(n[0],1),1); - tensor_t C1 = B1 + A(_i,_,_) * v1(_i,_); - - // C2(i,k) = A(i,j,k)*v2(j) + 4; - //tensor_t C2 = prod(A,vector_t(n[1],1),2) + 4; - tensor_t C2 = A(_,_i,_) * v2(_i,_) + 4; - - // not yet implemented! - // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - // tensor_t C3 = prod(prod(prod(A,v1,1),v2,1),v3,1); - // tensor_t C3 = A(_i,_j,_k) * v1(_i,_) * v2(_j,_) * v3(_k,_); - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(j,k) = B1(j,k) + A(i,j,k)*v1(i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,k) = A(i,j,k)*v2(j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - } - - - // Tensor-Matrix-Multiplications - Including Transposition - { - auto n = shape_t{3,4,2}; - auto m = 5u; - auto A = tensor_t(n,2); - auto B = tensor_t(shape_t{n[1],n[2],m},2); - auto B1 = tensor_t(shape_t{m,n[0]},1); - auto B2 = tensor_t(shape_t{m,n[1]},1); - - - // C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i); - // tensor_t C1 = B + prod(A,B1,1); - tensor_t C1 = B + A(_i,_,_) * B1(_,_i); - - // C2(i,l,k) = A(i,j,k)*B2(l,j) + 4; - // tensor_t C2 = prod(A,B2) + 4; - tensor_t C2 = A(_,_j,_) * B2(_,_j) + 4; - - // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); - // not yet implemented. - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i);" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(i,l,k) = A(i,j,k)*B2(l,j) + 4;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - // formatted output -// std::cout << "% --------------------------- " << std::endl; -// std::cout << "% --------------------------- " << std::endl << std::endl; -// std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; -// std::cout << "C3=" << C3 << ";" << std::endl << std::endl; - } - - - // Tensor-Tensor-Multiplications Including Transposition - { - auto na = shape_t{3,4,5}; - auto nb = shape_t{4,6,3,2}; - auto A = tensor_t(na,2); - auto B = tensor_t(nb,3); - auto T1 = tensor_t(shape_t{na[2],na[2]},2); - auto T2 = tensor_t(shape_t{na[2],nb[1],nb[3]},2); - - - // C1(j,l) = T1(j,l) + A(i,j,k)*A(i,j,l) + 5; - // tensor_t C1 = T1 + prod(A,A,perm_t{1,2}) + 5; - tensor_t C1 = T1 + A(_i,_j,_m)*A(_i,_j,_l) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C1(k,l) = T1(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; - std::cout << "C1=" << C1 << ";" << std::endl << std::endl; - - - // C2(k,l,m) = T2(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; - //tensor_t C2 = T2 + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; - tensor_t C2 = T2 + A(_i,_j,_k)*B(_j,_l,_i,_m) + 5; - - // formatted output - std::cout << "% --------------------------- " << std::endl; - std::cout << "% --------------------------- " << std::endl << std::endl; - std::cout << "% C2(k,l,m) = T2(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; - std::cout << "C2=" << C2 << ";" << std::endl << std::endl; - - } + namespace ublas = boost::numeric::ublas; + using value = float; + using layout = ublas::layout::first_order; // storage format + using tensor = ublas::tensor_dynamic; + using shape = typename tensor::extents_type; + using matrix = ublas::matrix; + + constexpr auto ones = ublas::ones{}; + + // NOLINTNEXTLINE(google-build-using-namespace) + using namespace boost::numeric::ublas::index; + + using namespace boost::numeric::ublas::index; + using tensor = boost::numeric::ublas::tensor_dynamic; + auto fones = boost::numeric::ublas::ones{}; + + + tensor X = fones(3,4,5); + tensor Y = fones(4,6,3,2); + + tensor Z = 2*ones(5,6,2) + X(_i,_j,_k)*Y(_j,_l,_i,_m) + 5; + + // Matlab Compatible Formatted Output + std::cout << "C=" << Z << ";" << std::endl; + + + // Tensor-Vector-Multiplications - Including Transposition + try { + + auto n = shape{3,4,2}; + + tensor A = ones(n); + matrix B1 = 2*matrix(n[1],n[2]); + tensor v1 = 2*ones(n[0],1); + tensor v2 = 2*ones(n[1],1); + // auto v3 = tensor(shape{n[2],1},2); + + // C1(j,k) = B1(j,k) + A(i,j,k)*v1(i); + // tensor C1 = B1 + prod(A,vector_t(n[0],1),1); + tensor C1 = B1 + A(_i,_,_) * v1(_i,_); + + // C2(i,k) = A(i,j,k)*v2(j) + 4; + //tensor C2 = prod(A,vector_t(n[1],1),2) + 4; + tensor C2 = A(_,_i,_) * v2(_i,_) + 4; + + // not yet implemented! + // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); + // tensor C3 = prod(prod(prod(A,v1,1),v2,1),v3,1); + // tensor C3 = A(_i,_j,_k) * v1(_i,_) * v2(_j,_) * v3(_k,_); + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(j,k) = B1(j,k) + A(i,j,k)*v1(i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,k) = A(i,j,k)*v2(j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of multiply-tensor-einstein-notation when doing tensor-vector multiplication." << std::endl; + } + + // Tensor-Matrix-Multiplications - Including Transposition + try { + auto n = shape{3,4,2}; + auto m = 5u; + tensor A = 2*ones(n); + tensor B = 2*ones(n[1],n[2],m); + tensor B1 = ones(m,n[0]); + tensor B2 = ones(m,n[1]); + + + // C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i); + // tensor C1 = B + prod(A,B1,1); + tensor C1 = B + A(_i,_,_) * B1(_,_i); + + // C2(i,l,k) = A(i,j,k)*B2(l,j) + 4; + // tensor C2 = prod(A,B2) + 4; + tensor C2 = A(_,_j,_) * B2(_,_j) + 4; + + // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); + // not yet implemented. + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(l,j,k) = B(j,k,l) + A(i,j,k)*B1(l,i);" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(i,l,k) = A(i,j,k)*B2(l,j) + 4;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + // formatted output + // std::cout << "% --------------------------- " << std::endl; + // std::cout << "% --------------------------- " << std::endl << std::endl; + // std::cout << "% C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k);" << std::endl << std::endl; + // std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of multiply-tensor-einstein-notation when doing tensor-matrix multiplication." << std::endl; + } + + + // Tensor-Tensor-Multiplications Including Transposition + try { + auto na = shape{3,4,5}; + auto nb = shape{4,6,3,2}; + tensor A = 2*ones(na); + tensor B = 3*ones(nb); + tensor T1 = 2*ones(na[2],na[2]); + tensor T2 = 2*ones(na[2],nb[1],nb[3]); + + + // C1(j,l) = T1(j,l) + A(i,j,k)*A(i,j,l) + 5; + // tensor C1 = T1 + prod(A,A,perm_t{1,2}) + 5; + tensor C1 = T1 + A(_i,_j,_m)*A(_i,_j,_l) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C1(k,l) = T1(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; + std::cout << "C1=" << C1 << ";" << std::endl << std::endl; + + + // C2(k,l,m) = T2(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; + //tensor C2 = T2 + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + tensor C2 = T2 + A(_i,_j,_k)*B(_j,_l,_i,_m) + 5; + + // formatted output + std::cout << "% --------------------------- " << std::endl; + std::cout << "% --------------------------- " << std::endl << std::endl; + std::cout << "% C2(k,l,m) = T2(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of multiply-tensor-einstein-notation when doing transpose." << std::endl; + } } diff --git a/examples/tensor/multiply_tensors_product_function.cpp b/examples/tensor/multiply_tensors_product_function.cpp index 31a895370..bd2adb34a 100644 --- a/examples/tensor/multiply_tensors_product_function.cpp +++ b/examples/tensor/multiply_tensors_product_function.cpp @@ -10,44 +10,44 @@ // Google and Fraunhofer IOSB, Ettlingen, Germany // - -#include #include +#include #include #include void multiply_tensors_with_dynamic_order() { - using namespace boost::numeric::ublas; + namespace ublas = boost::numeric::ublas; - using format_t = column_major; - using value_t = float; // std::complex; - using tensor_t = dynamic_tensor; - using shape_t = typename tensor_t::extents_type; - using matrix_t = matrix; - using vector_t = vector; + using layout = ublas::layout::first_order; + using value = float; // std::complex; + using tensor = ublas::tensor_dynamic; + using matrix = ublas::matrix; + using vector = ublas::vector; + using shape = typename tensor::extents_type; + constexpr auto ones = ublas::ones{}; // Tensor-Vector-Multiplications - Including Transposition - { + try { - auto n = shape_t{3,4,2}; - auto A = tensor_t(n,2); + auto n = shape{3,4,2}; + auto A = tensor(n,2); auto q = 0u; // contraction mode // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); q = 1u; - tensor_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); + tensor C1 = matrix(n[1],n[2],2) + ublas::prod(A,vector(n[q-1],1),q); // C2(i,k) = A(i,j,k)*T1(j) + 4; q = 2u; - tensor_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; + tensor C2 = ublas::prod(A,vector(n[q-1],1),q) + 4; // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - tensor_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); + tensor C3 = ublas::prod(ublas::prod(ublas::prod(A,vector(n[0],1),1),vector(n[1],1),1),vector(n[2],1),1); // C4(i,j) = A(k,i,j)*T1(k) + 4; q = 1u; - tensor_t C4 = prod(trans(A,{2,3,1}),vector_t(n[2],1),q) + 4; + tensor C4 = ublas::prod(trans(A,{2,3,1}),vector(n[2],1),q) + 4; // formatted output @@ -74,35 +74,39 @@ void multiply_tensors_with_dynamic_order() std::cout << "% C4(i,j) = A(k,i,j)*T1(k) + 4;" << std::endl << std::endl; std::cout << "C4=" << C4 << ";" << std::endl << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of multiply-tensor-product-function." << std::endl; } + // Tensor-Matrix-Multiplications - Including Transposition - { + try { - auto n = shape_t{3,4,2}; - auto A = tensor_t(n,2); + auto n = shape{3,4,2}; + tensor A = 2*ones(n);//tensor auto m = 5u; auto q = 0u; // contraction mode // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); q = 1u; - tensor_t C1 = tensor_t(shape_t{m,n[1],n[2]},2) + prod(A,matrix_t(m,n[q-1],1),q); + tensor C1 = 2*ones(m,n[1],n[2]) + ublas::prod(A,matrix(m,n[q-1],1),q); // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; q = 2u; - tensor_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4; + tensor C2 = ublas::prod(A,matrix(m,n[q-1],1),q) + 4; // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); q = 3u; - tensor_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q); + tensor C3 = ublas::prod(ublas::prod(A,matrix(m+1,n[q-2],1),q-1),matrix(m+2,n[q-1],1),q); // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); - tensor_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1); + tensor C4 = ublas::prod(ublas::prod(A,matrix(m+2,n[q-1],1),q),matrix(m+1,n[q-2],1),q-1); // C5(i,k,l) = A(i,k,j)*T1(l,j) + 4; q = 3u; - tensor_t C5 = prod(trans(A,{1,3,2}),matrix_t(m,n[1],1),q) + 4; + tensor C5 = ublas::prod(trans(A,{1,3,2}),matrix(m,n[1],1),q) + 4; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -135,6 +139,9 @@ void multiply_tensors_with_dynamic_order() std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C5(i,k,l) = A(i,k,j)*T1(l,j) + 4;" << std::endl << std::endl; std::cout << "C5=" << C5 << ";" << std::endl << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the multiply_tensors_with_dynamic_order function of multiply-tensor-product-function." << std::endl; } @@ -142,18 +149,18 @@ void multiply_tensors_with_dynamic_order() // Tensor-Tensor-Multiplications Including Transposition - { + try { using perm_t = std::vector; - auto na = shape_t{3,4,5}; - auto nb = shape_t{4,6,3,2}; - auto A = tensor_t(na,2); - auto B = tensor_t(nb,3); + auto na = shape{3,4,5}; + auto nb = shape{4,6,3,2}; + tensor A = 2*ones(na); //tensor(na,2); + tensor B = 3*ones(nb); //tensor(nb,3); // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; - tensor_t C1 = tensor_t(shape_t{na[2],na[2]},2) + prod(A,A,perm_t{1,2}) + 5.0F; + tensor C1 = 2*ones(na[2],na[2]) + ublas::prod(A,A,perm_t{1,2}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -163,7 +170,7 @@ void multiply_tensors_with_dynamic_order() // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; - tensor_t C2 = tensor_t(shape_t{na[2],nb[1],nb[3]},2) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; + tensor C2 = 2*ones(na[2],nb[1],nb[3]) + ublas::prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -173,7 +180,7 @@ void multiply_tensors_with_dynamic_order() // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; - tensor_t C3 = tensor_t(shape_t{na[2],nb[1],nb[3]},2) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; + tensor C3 = 2*ones(na[2],nb[1],nb[3]) + ublas::prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -181,44 +188,48 @@ void multiply_tensors_with_dynamic_order() std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of multiply-tensor-product-function." << std::endl; } } void multiply_tensors_with_static_order() { - using namespace boost::numeric::ublas; - - using format_t = column_major; - using value_t = float; // std::complex; - using matrix_t = matrix; - using vector_t = vector; - using tensor2_t = fixed_rank_tensor; - using tensor3_t = fixed_rank_tensor; -// using tensor4_t = fixed_rank_tensor; -// using shape_t = typename tensor_t::extents_type; -// using shape2_t = typename tensor2_t::extents_type; - using shape3_t = typename tensor3_t::extents_type; -// using shape4_t = typename tensor4_t::extents_type; + namespace ublas = boost::numeric::ublas; + + using layout = ublas::layout::first_order; + using value = float; // std::complex; + using matrix = ublas::matrix; + using vector = ublas::vector; + using tensor2 = ublas::tensor_static_rank; + using tensor3 = ublas::tensor_static_rank; + using tensor4 = ublas::tensor_static_rank; + using shape2 = typename tensor2::extents_type; + using shape3 = typename tensor3::extents_type; + using shape4 = typename tensor4::extents_type; + + constexpr auto ones = ublas::ones_static_rank{}; // Tensor-Vector-Multiplications - Including Transposition // dynamic_extents with static rank - { + try { - auto n = shape3_t{3,4,2}; - auto A = tensor3_t(n,value_t(2)); + auto n = shape3{3,4,2}; + tensor3 A = 2*ones(n); auto q = 0U; // contraction mode // C1(j,k) = T2(j,k) + A(i,j,k)*T1(i); q = 1U; - tensor2_t C1 = matrix_t(n[1],n[2],2) + prod(A,vector_t(n[q-1],1),q); + tensor2 C1 = matrix(n[1],n[2],2) + ublas::prod(A,vector(n[q-1],1),q); // C2(i,k) = A(i,j,k)*T1(j) + 4; q = 2U; - tensor2_t C2 = prod(A,vector_t(n[q-1],1),q) + 4; + tensor2 C2 = ublas::prod(A,vector(n[q-1],1),q) + 4; // C3() = A(i,j,k)*T1(i)*T2(j)*T2(k); - tensor2_t C3 = prod(prod(prod(A,vector_t(n[0],1),1),vector_t(n[1],1),1),vector_t(n[2],1),1); + tensor2 C3 = ublas::prod(ublas::prod(ublas::prod(A,vector(n[0],1),1),vector(n[1],1),1),vector(n[2],1),1); // formatted output @@ -239,31 +250,34 @@ void multiply_tensors_with_static_order() std::cout << "% C3() = A(i,j,k)*T1(i)*T2(j)*T2(k);" << std::endl << std::endl; std::cout << "C3()=" << C3(0) << ";" << std::endl << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of multiply-tensor-product-function." << std::endl; } // Tensor-Matrix-Multiplications - Including Transposition // dynamic_extents with static rank - { + try { - auto n = shape3_t{3,4,2}; - auto A = tensor3_t(n,value_t(2)); + auto n = shape3{3,4,2}; + tensor3 A = 2*ones(n); auto m = 5U; auto q = 0U; // contraction mode // C1(l,j,k) = T2(l,j,k) + A(i,j,k)*T1(l,i); q = 1U; - tensor3_t C1 = tensor3_t( shape3_t{m,n[1],n[2]},value_t(2) ) + prod(A,matrix_t(m,n[q-1],1),q); + tensor3 C1 = 2*ones(m,n[1],n[2]) + ublas::prod(A,matrix(m,n[q-1],1),q); // C2(i,l,k) = A(i,j,k)*T1(l,j) + 4; q = 2U; - tensor3_t C2 = prod(A,matrix_t(m,n[q-1],1),q) + 4 ; + tensor3 C2 = ublas::prod(A,matrix(m,n[q-1],1),q) + 4 ; // C3(i,l1,l2) = A(i,j,k)*T1(l1,j)*T2(l2,k); q = 3U; - tensor3_t C3 = prod(prod(A,matrix_t(m+1,n[q-2],1),q-1),matrix_t(m+2,n[q-1],1),q) ; + tensor3 C3 = ublas::prod(ublas::prod(A,matrix(m+1,n[q-2],1),q-1),matrix(m+2,n[q-1],1),q) ; // C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j); - tensor3_t C4 = prod(prod(A,matrix_t(m+2,n[q-1],1),q),matrix_t(m+1,n[q-2],1),q-1) ; + tensor3 C4 = ublas::prod(ublas::prod(A,matrix(m+2,n[q-1],1),q),matrix(m+1,n[q-2],1),q-1) ; // formatted output std::cout << "% --------------------------- " << std::endl; @@ -288,57 +302,69 @@ void multiply_tensors_with_static_order() std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C4(i,l1,l2) = A(i,j,k)*T2(l2,k)*T1(l1,j);" << std::endl << std::endl; std::cout << "C4=" << C4 << ";" << std::endl << std::endl; - std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; + //std::cout << "% C3 and C4 should have the same values, true? " << std::boolalpha << (C3 == C4) << "!" << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of multiply-tensor-product-function." << std::endl; } // Tensor-Tensor-Multiplications Including Transposition // dynamic_extents with static rank - { + try { -// using perm_t = std::array; + using perm_t = std::array; -// auto na = shape3_t{3,4,5}; -// auto nb = shape4_t{4,6,3,2}; -// auto nc = shape2_t{5,5}; -// auto A = tensor3_t(na,2.0F); -// auto B = tensor4_t(nb,3.0F); -// auto C = tensor2_t(nc,2.0F); + auto na = shape3{3,4,5}; + auto nb = shape4{4,6,3,2}; + auto nc = shape2{5,5}; + tensor3 A = 2*ones(na); + tensor4 B = 3*ones(nb); + tensor2 C = 2*ones(nc); // C1(j,l) = T(j,l) + A(i,j,k)*A(i,j,l) + 5; // Right now there exist no tensor other than dynamic_extents with // dynamic rank so every tensor times tensor operator automatically // to dynamic tensor -// auto C1 = C + prod(A,A,perm_t{1,2}) + 5.0F; + auto C1 = C + ublas::prod(A,A,perm_t{1,2}) + 5; std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C1(k,l) = T(k,l) + A(i,j,k)*A(i,j,l) + 5;" << std::endl << std::endl; -// std::cout << "C1=" << tensor_t(C1) << ";" << std::endl << std::endl; + std::cout << "C1=" << tensor2(C1) << ";" << std::endl << std::endl; // C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5; // Similar Problem as above -// tensor_t C2 = tensor_t(shape_t{na[2],nb[1],nb[3]},2.0F) + prod(A,B,perm_t{1,2},perm_t{3,1}) + 5.0F; + tensor3 C2 = 2*ones(na[2],nb[1],nb[3]) + ublas::prod(A,B,perm_t{1,2},perm_t{3,1}) + 5; std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C2(k,l,m) = T(k,l,m) + A(i,j,k)*B(j,l,i,m) + 5;" << std::endl << std::endl; - //std::cout << "C2=" << C2 << ";" << std::endl << std::endl; + std::cout << "C2=" << C2 << ";" << std::endl << std::endl; // C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5; // Similar Problem as above -// tensor_t C3 = tensor_t(shape_t{na[2],nb[1],nb[3]},2.0F) + prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5.0F; + tensor3 C3 = 2*ones(na[2],nb[1],nb[3]) + ublas::prod(A,trans(B,{2,3,1,4}),perm_t{1,2}) + 5; std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "% C3(k,l,m) = T(k,l,m) + A(i,j,k)*trans(B(j,l,i,m),{2,3,1,4})+ 5;" << std::endl << std::endl; -// std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + std::cout << "C3=" << C3 << ";" << std::endl << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the multiply_tensors_with_static_order function of multiply-tensor-product-function." << std::endl; + throw; } } int main() { - multiply_tensors_with_dynamic_order(); - multiply_tensors_with_static_order(); + try { + multiply_tensors_with_dynamic_order(); + multiply_tensors_with_static_order(); + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of multiply-tensor-product-function." << std::endl; + } } diff --git a/examples/tensor/simple_expressions.cpp b/examples/tensor/simple_expressions.cpp index 229bfbf5f..81c6e1cf8 100644 --- a/examples/tensor/simple_expressions.cpp +++ b/examples/tensor/simple_expressions.cpp @@ -18,19 +18,23 @@ int main() { - using namespace boost::numeric::ublas; + namespace ublas = boost::numeric::ublas; + using value = float; + using tensor = ublas::tensor_dynamic; + using matrix = ublas::matrix; + using vector = ublas::vector; + using shape = tensor::extents_type; - using tensorf = dynamic_tensor; - using matrixf = matrix; - using vectorf = vector; + try { - auto A = tensorf{3,4,2}; + + auto A = tensor{3,4,2}; auto B = A = 2; // Calling overloaded operators // and using simple tensor expression templates. if( A != (B+1) ){ - A += 2*B - 1; + A += 2*B - 1; } // formatted output @@ -38,14 +42,14 @@ int main() std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "A=" << A << ";" << std::endl << std::endl; - auto n = extents<>{3,4}; - auto D = matrixf(n[0],n[1],1); - auto e = vectorf(n[1],1); - auto f = vectorf(n[0],2); + auto n = shape{3,4}; + auto D = matrix(n[0],n[1],1); + auto e = vector(n[1],1); + auto f = vector(n[0],2); // Calling constructor with // vector expression templates - tensorf C = 2*f; + tensor C = 2*f; // formatted output std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; @@ -54,12 +58,16 @@ int main() // Calling overloaded operators // and mixing simple tensor and matrix expression templates - tensorf F = 3*C + 4*prod(2*D,e); + tensor F = 3*C + 4*prod(2*D,e); // formatted output std::cout << "% --------------------------- " << std::endl; std::cout << "% --------------------------- " << std::endl << std::endl; std::cout << "F=" << F << ";" << std::endl << std::endl; + } catch (const std::exception& e) { + std::cerr << "Cought exception " << e.what(); + std::cerr << "in the main function of simple expression." << std::endl; + } } diff --git a/include/boost/numeric/ublas/tensor.hpp b/include/boost/numeric/ublas/tensor.hpp index b1fa1f428..e076aebac 100644 --- a/include/boost/numeric/ublas/tensor.hpp +++ b/include/boost/numeric/ublas/tensor.hpp @@ -1,5 +1,4 @@ -// Copyright (c) 2018-2019 -// Cem Bassoy +// Copyright (c) 2018 Cem Bassoy // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/numeric/ublas/tensor/algorithms.hpp b/include/boost/numeric/ublas/tensor/algorithms.hpp index 8ca98ba61..66375e1c0 100644 --- a/include/boost/numeric/ublas/tensor/algorithms.hpp +++ b/include/boost/numeric/ublas/tensor/algorithms.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -10,17 +10,14 @@ // -#ifndef _BOOST_UBLAS_TENSOR_ALGORITHMS_HPP -#define _BOOST_UBLAS_TENSOR_ALGORITHMS_HPP +#ifndef BOOST_UBLAS_TENSOR_ALGORITHMS_HPP +#define BOOST_UBLAS_TENSOR_ALGORITHMS_HPP - -#include #include #include +#include -namespace boost { -namespace numeric { -namespace ublas { +namespace boost::numeric::ublas { @@ -38,37 +35,45 @@ namespace ublas { */ template constexpr void copy(const SizeType p, SizeType const*const n, - PointerOut c, SizeType const*const wc, - PointerIn a, SizeType const*const wa) + PointerOut c, SizeType const*const wc, + PointerIn a, SizeType const*const wa) { - static_assert( std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::copy: Argument types for pointers are not pointer types."); - if( p == 0 ) - return; - - if(c == nullptr || a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); - - if(wc == nullptr || wa == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); - - if(n == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); - - - std::function lambda; - - lambda = [&lambda, n, wc, wa](SizeType r, PointerOut c, PointerIn a) - { - if(r > 0) - for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d) - lambda(r-1, c, a ); - else - for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d) - *c = *a; - }; - - lambda( p-1, c, a ); + static_assert( std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::copy: Argument types for pointers are not pointer types."); + if( p == 0 ){ + return; + } + + if(c == nullptr || a == nullptr){ + throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + } + + if(wc == nullptr || wa == nullptr){ + throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + } + + if(n == nullptr){ + throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + } + + + std::function lambda; + + lambda = [&lambda, n, wc, wa](SizeType r, PointerOut c, PointerIn a) + { + if(r > 0){ + for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d){ + lambda(r-1, c, a ); + } + } + else{ + for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d){ + *c = *a; + } + } + }; + + lambda( p-1, c, a ); } @@ -87,40 +92,40 @@ constexpr void copy(const SizeType p, SizeType const*const n, * @param[in] op unary operation */ template -constexpr void transform(const SizeType p, - SizeType const*const n, - PointerOut c, SizeType const*const wc, - PointerIn a, SizeType const*const wa, - UnaryOp op) +constexpr void transform(SizeType const p, + SizeType const*const n, + PointerOut c, SizeType const*const wc, + PointerIn a, SizeType const*const wa, + UnaryOp op) { - static_assert( std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); - if( p == 0 ) - return; + static_assert( std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); + if( p == 0 ) + return; - if(c == nullptr || a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(c == nullptr || a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(wc == nullptr || wa == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(wc == nullptr || wa == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(n == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(n == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - std::function lambda; + std::function lambda; - lambda = [&lambda, n, wc, wa, op](SizeType r, PointerOut c, PointerIn a) - { - if(r > 0) - for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d) - lambda(r-1, c, a); - else - for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d) - *c = op(*a); - }; + lambda = [&lambda, n, wc, wa, op](SizeType r, PointerOut c, PointerIn a) + { + if(r > 0) + for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d) + lambda(r-1, c, a); + else + for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d) + *c = op(*a); + }; - lambda( p-1, c, a ); + lambda( p-1, c, a ); } @@ -138,39 +143,39 @@ constexpr void transform(const SizeType p, template [[nodiscard]] constexpr ValueType accumulate(SizeType const p, SizeType const*const n, - PointerIn a, SizeType const*const w, - ValueType k) + PointerIn a, SizeType const*const w, + ValueType k) { - static_assert(std::is_pointer::value, - "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); + static_assert(std::is_pointer::value, + "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); - if( p == 0 ) - return k; + if( p == 0 ) + return k; - if(a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(w == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(w == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(n == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(n == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - std::function lambda; + std::function lambda; - lambda = [&lambda, n, w](SizeType r, PointerIn a, ValueType k) - { - if(r > 0u) - for(auto d = 0u; d < n[r]; a += w[r], ++d) - k = lambda(r-1, a, k); - else - for(auto d = 0u; d < n[0]; a += w[0], ++d) - k += *a; - return k; - }; + lambda = [&lambda, n, w](SizeType r, PointerIn a, ValueType k) + { + if(r > 0u) + for(auto d = 0u; d < n[r]; a += w[r], ++d) + k = lambda(r-1, a, k); + else + for(auto d = 0u; d < n[0]; a += w[0], ++d) + k += *a; + return k; + }; - return lambda( p-1, a, k ); + return lambda( p-1, a, k ); } /** @brief Performs a reduce operation with all elements of the tensor and an initial value @@ -188,40 +193,40 @@ constexpr ValueType accumulate(SizeType const p, SizeType const*const n, template [[nodiscard]] constexpr ValueType accumulate(SizeType const p, SizeType const*const n, - PointerIn a, SizeType const*const w, - ValueType k, BinaryOp op) + PointerIn a, SizeType const*const w, + ValueType k, BinaryOp op) { - static_assert(std::is_pointer::value, - "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); + static_assert(std::is_pointer::value, + "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); - if( p == 0 ) - return k; + if( p == 0 ) + return k; - if(a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(w == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(w == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - if(n == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + if(n == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - std::function lambda; + std::function lambda; - lambda = [&lambda, n, w, op](SizeType r, PointerIn a, ValueType k) - { - if(r > 0u) - for(auto d = 0u; d < n[r]; a += w[r], ++d) - k = lambda(r-1, a, k); - else - for(auto d = 0u; d < n[0]; a += w[0], ++d) - k = op ( k, *a ); - return k; - }; + lambda = [&lambda, n, w, op](SizeType r, PointerIn a, ValueType k) + { + if(r > 0u) + for(auto d = 0u; d < n[r]; a += w[r], ++d) + k = lambda(r-1, a, k); + else + for(auto d = 0u; d < n[0]; a += w[0], ++d) + k = op ( k, *a ); + return k; + }; - return lambda( p-1, a, k ); + return lambda( p-1, a, k ); } /** @brief Transposes a tensor @@ -241,45 +246,45 @@ constexpr ValueType accumulate(SizeType const p, SizeType const*const n, template constexpr void trans( SizeType const p, SizeType const*const na, SizeType const*const pi, - PointerOut c, SizeType const*const wc, - PointerIn a, SizeType const*const wa) + PointerOut c, SizeType const*const wc, + PointerIn a, SizeType const*const wa) { - static_assert( std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::trans: Argument types for pointers are not pointer types."); + static_assert( std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::trans: Argument types for pointers are not pointer types."); - if( p < 2) - return; + if( p < 2) + return; - if(c == nullptr || a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(c == nullptr || a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - if(na == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null."); + if(na == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null."); - if(wc == nullptr || wa == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(wc == nullptr || wa == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - if(na == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(na == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - if(pi == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + if(pi == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - std::function lambda; + std::function lambda; - lambda = [&lambda, na, wc, wa, pi](SizeType r, PointerOut c, PointerIn a) - { - if(r > 0) - for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) - lambda(r-1, c, a); - else - for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) - *c = *a; - }; + lambda = [&lambda, na, wc, wa, pi](SizeType r, PointerOut c, PointerIn a) + { + if(r > 0) + for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) + lambda(r-1, c, a); + else + for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) + *c = *a; + }; - lambda( p-1, c, a ); + lambda( p-1, c, a ); } @@ -299,49 +304,47 @@ constexpr void trans( SizeType const p, SizeType const*const na, SizeType const */ template -constexpr void trans( SizeType const p, - SizeType const*const na, - SizeType const*const pi, - std::complex* c, SizeType const*const wc, - std::complex* a, SizeType const*const wa) +constexpr void trans(SizeType const p, + SizeType const*const na, + SizeType const*const pi, + std::complex* c, SizeType const*const wc, + std::complex* a, SizeType const*const wa) { - if( p < 2) - return; - - if(c == nullptr || a == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - - if(wc == nullptr || wa == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - - if(na == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - - if(pi == nullptr) - throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - - - std::function* c, std::complex* a)> lambda; - - lambda = [&lambda, na, wc, wa, pi](SizeType r, std::complex* c, std::complex* a) - { - if(r > 0) - for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) - lambda(r-1, c, a); - else - for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) - *c = std::conj(*a); - }; - - lambda( p-1, c, a ); + if( p < 2){ + return; + } + if(c == nullptr || a == nullptr){ + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + } + if(wc == nullptr || wa == nullptr){ + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + } + if(na == nullptr){ + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + } + if(pi == nullptr){ + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + } + + + std::function* c, std::complex* a)> lambda; + + lambda = [&lambda, na, wc, wa, pi](SizeType r, std::complex* c, std::complex* a) + { + if(r > 0) + for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) + lambda(r-1, c, a); + else + for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) + *c = std::conj(*a); + }; + + lambda( p-1, c, a ); } +} // namespace boost::numeric::ublas -} -} -} - #endif diff --git a/include/boost/numeric/ublas/tensor/concepts.hpp b/include/boost/numeric/ublas/tensor/concepts.hpp new file mode 100644 index 000000000..70820484a --- /dev/null +++ b/include/boost/numeric/ublas/tensor/concepts.hpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_CONCEPTS_HPP +#define BOOST_UBLAS_TENSOR_CONCEPTS_HPP + +#include + +namespace boost::numeric::ublas{ + +template +concept integral = std::is_integral_v; + +template +concept signed_integral = integral && std::is_signed_v; + +template +concept unsigned_integral = integral && !signed_integral; + +template +concept floating_point = std::is_floating_point_v; + +} // namespace boost::numeric::ublas + +#endif // BOOST_UBLAS_TENSOR_CONCEPTS_BASIC_HPP diff --git a/include/boost/numeric/ublas/tensor/dynamic_extents.hpp b/include/boost/numeric/ublas/tensor/dynamic_extents.hpp deleted file mode 100644 index b8d2bdeb5..000000000 --- a/include/boost/numeric/ublas/tensor/dynamic_extents.hpp +++ /dev/null @@ -1,241 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#ifndef _BOOST_NUMERIC_UBLAS_TENSOR_DYNAMIC_EXTENTS_HPP_ -#define _BOOST_NUMERIC_UBLAS_TENSOR_DYNAMIC_EXTENTS_HPP_ - -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace numeric { -namespace ublas { - -/** @brief Template class for storing tensor extents with runtime variable size. - * - * Proxy template class of std::vector. - * - */ -template -class basic_extents -{ - static_assert( std::numeric_limits::value_type>::is_integer, "Static error in basic_layout: type must be of type integer."); - static_assert(!std::numeric_limits::value_type>::is_signed, "Static error in basic_layout: type must be of type unsigned integer."); - -public: - using base_type = std::vector; - using value_type = typename base_type::value_type; - using const_reference = typename base_type::const_reference; - using reference = typename base_type::reference; - using size_type = typename base_type::size_type; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - using const_reverse_iterator = typename base_type::const_reverse_iterator; - - - /** @brief Default constructs basic_extents - * - * @code auto ex = basic_extents{}; - */ - constexpr basic_extents() = default; - - /** @brief Copy constructs basic_extents from a one-dimensional container - * - * @code auto ex = basic_extents( std::vector(3u,3u) ); - * - * @note checks if size > 1 and all elements > 0 - * - * @param b one-dimensional container of type std::vector - */ - explicit basic_extents(base_type b) - : _base(std::move(b)) - { - if (!is_valid(*this)){ - throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); - } - } - - /** @brief Constructs basic_extents from an initializer list - * - * @code auto ex = basic_extents{3,2,4}; - * - * @note checks if size > 1 and all elements > 0 - * - * @param l one-dimensional list of type std::initializer - */ - basic_extents(std::initializer_list l) - : basic_extents( base_type(std::move(l)) ) - { - } - - /** @brief Constructs basic_extents from a range specified by two iterators - * - * @code auto ex = basic_extents(a.begin(), a.end()); - * - * @note checks if size > 1 and all elements > 0 - * - * @param first iterator pointing to the first element - * @param last iterator pointing to the next position after the last element - */ - constexpr basic_extents(const_iterator first, const_iterator last) - : basic_extents ( base_type( first,last ) ) - { - } - - /** @brief Copy constructs basic_extents */ - constexpr basic_extents(basic_extents const& l ) - : _base(l._base) - { - } - - /** @brief Move constructs basic_extents */ - constexpr basic_extents(basic_extents && l ) noexcept - : _base(std::move(l._base)) - { - } - - - template - constexpr basic_extents(OtherExtents const& e) - : _base(e.size()) - { - static_assert( is_extents_v, "boost::numeric::ublas::basic_extents(OtherExtents const&) : " - "OtherExtents should be a valid tensor extents" - ); - std::copy(e.begin(),e.end(), _base.begin()); - } - - ~basic_extents() = default; - - constexpr basic_extents& operator=(basic_extents && other) - noexcept(std::is_nothrow_swappable_v) - { - swap (*this, other); - return *this; - } - constexpr basic_extents& operator=(basic_extents const& other) - noexcept(std::is_nothrow_swappable_v) - { - basic_extents temp(other); - swap (*this, temp); - return *this; - } - - friend void swap(basic_extents& lhs, basic_extents& rhs) - noexcept(std::is_nothrow_swappable_v) - { - std::swap(lhs._base , rhs._base ); - } - - [[nodiscard]] inline - constexpr const_pointer data() const noexcept - { - return this->_base.data(); - } - - [[nodiscard]] inline - constexpr const_reference operator[] (size_type p) const - { - return this->_base[p]; - } - - [[nodiscard]] inline - constexpr const_reference at (size_type p) const - { - return this->_base.at(p); - } - - [[nodiscard]] inline - constexpr reference operator[] (size_type p) - { - return this->_base[p]; - } - - [[nodiscard]] inline - constexpr reference at (size_type p) - { - return this->_base.at(p); - } - - [[nodiscard]] inline - constexpr const_reference back () const - { - return this->_base.back(); - } - - - [[nodiscard]] inline - constexpr bool empty() const noexcept - { - return this->_base.empty(); - } - - [[nodiscard]] inline - constexpr size_type size() const noexcept - { - return this->_base.size(); - } - - inline - constexpr void clear() noexcept - { - this->_base.clear(); - } - - [[nodiscard]] inline - constexpr const_iterator - begin() const noexcept - { - return _base.begin(); - } - - [[nodiscard]] inline - constexpr const_iterator - end() const noexcept - { - return _base.end(); - } - - [[nodiscard]] inline - constexpr const_reverse_iterator - rbegin() const noexcept - { - return _base.rbegin(); - } - - [[nodiscard]] inline - constexpr const_reverse_iterator - rend() const noexcept - { - return _base.rend(); - } - - [[nodiscard]] inline - constexpr base_type const& base() const noexcept { return _base; } - -private: - - base_type _base{}; - -}; - -} // namespace ublas -} // namespace numeric -} // namespace boost - - -#endif diff --git a/include/boost/numeric/ublas/tensor/dynamic_strides.hpp b/include/boost/numeric/ublas/tensor/dynamic_strides.hpp deleted file mode 100644 index 3f26eb345..000000000 --- a/include/boost/numeric/ublas/tensor/dynamic_strides.hpp +++ /dev/null @@ -1,219 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// -/// \file strides.hpp Definition for the basic_strides template class - - -#ifndef _BOOST_UBLAS_TENSOR_DYNAMIC_STRIDES_HPP_ -#define _BOOST_UBLAS_TENSOR_DYNAMIC_STRIDES_HPP_ - -#include -#include -#include -#include - -namespace boost { -namespace numeric { -namespace ublas { - -template -class basic_extents; - - -/** @brief Template class for storing tensor strides for iteration with runtime variable size. - * - * Proxy template class of std::vector. - * - */ -template -class basic_strides -{ -public: - - using base_type = std::vector<__int_type>; - - static_assert( std::numeric_limits::is_integer, - "Static error in boost::numeric::ublas::basic_strides: type must be of type integer."); - static_assert(!std::numeric_limits::is_signed, - "Static error in boost::numeric::ublas::basic_strides: type must be of type unsigned integer."); - static_assert(std::is_same<__layout,layout::first_order>::value || std::is_same<__layout,layout::last_order>::value, - "Static error in boost::numeric::ublas::basic_strides: layout type must either first or last order"); - - - using layout_type = __layout; - using value_type = typename base_type::value_type; - using reference = typename base_type::reference; - using const_reference = typename base_type::const_reference; - using size_type = typename base_type::size_type; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - using const_reverse_iterator = typename base_type::const_reverse_iterator; - - - /** @brief Default constructs basic_strides - * - * @code auto ex = basic_strides{}; - */ - constexpr explicit basic_strides() = default; - - /** @brief Constructs basic_strides from basic_extents for the first- and last-order storage formats - * - * @code auto strides = basic_strides( basic_extents{2,3,4} ); - * - */ - template - constexpr basic_strides(ExtentsType const& s) - : _base(s.size(),1) - { - static_assert( is_extents_v, "boost::numeric::ublas::basic_strides(ExtentsType const&) : " - "ExtentsType is not a tensor extents" - ); - if( s.empty() ) - return; - - if( !is_valid(s) ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_strides(ExtentsType const&) : " - "shape is not valid." - ); - - if( is_vector(s) || is_scalar(s) ) - return; - - if( this->size() < 2 ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_strides(ExtentsType const&) : " - "size of strides must be greater or equal to 2." - ); - - - if constexpr (std::is_same::value){ - std::transform(s.begin(), s.end() - 1, _base.begin(), _base.begin() + 1, std::multiplies{}); - }else { - std::transform(s.rbegin(), s.rend() - 1, _base.rbegin(), _base.rbegin() + 1, std::multiplies{}); - } - } - - constexpr basic_strides(basic_strides const& l) - : _base(l._base) - {} - - constexpr basic_strides(basic_strides && l ) noexcept - : _base(std::move(l._base)) - {} - - constexpr basic_strides(base_type const& l ) - : _base(l) - {} - - constexpr basic_strides(base_type && l ) noexcept - : _base(std::move(l)) - {} - - ~basic_strides() = default; - - constexpr basic_strides& operator=(basic_strides&& other) - noexcept(std::is_nothrow_swappable_v) - { - swap (*this, other); - return *this; - } - - constexpr basic_strides& operator=(basic_strides const& other) - noexcept(std::is_nothrow_swappable_v) - { - basic_strides temp(other); - swap (*this, temp); - return *this; - } - - friend void swap(basic_strides& lhs, basic_strides& rhs) - noexcept(std::is_nothrow_swappable_v) - { - std::swap(lhs._base , rhs._base); - } - - [[nodiscard]] inline - constexpr const_reference operator[] (size_type p) const{ - return _base[p]; - } - - [[nodiscard]] inline - constexpr const_pointer data() const{ - return _base.data(); - } - - [[nodiscard]] inline - constexpr const_reference at (size_type p) const{ - return _base.at(p); - } - - [[nodiscard]] inline - constexpr const_reference back () const{ - return _base.back(); - } - - [[nodiscard]] inline - constexpr reference back (){ - return _base.back(); - } - - [[nodiscard]] inline - constexpr bool empty() const noexcept{ - return _base.empty(); - } - - [[nodiscard]] inline - constexpr size_type size() const noexcept{ - return _base.size(); - } - - [[nodiscard]] inline - constexpr const_iterator begin() const noexcept{ - return _base.begin(); - } - - [[nodiscard]] inline - constexpr const_iterator end() const noexcept{ - return _base.end(); - } - - inline - constexpr void clear() noexcept{ - this->_base.clear(); - } - - [[nodiscard]] inline - constexpr base_type const& base() const noexcept{ - return this->_base; - } - - [[nodiscard]] inline - constexpr const_reverse_iterator - rbegin() const noexcept - { - return _base.rbegin(); - } - - [[nodiscard]] inline - constexpr const_reverse_iterator - rend() const noexcept - { - return _base.rend(); - } - -private: - base_type _base{}; -}; - -} -} -} - -#endif diff --git a/include/boost/numeric/ublas/tensor/expression.hpp b/include/boost/numeric/ublas/tensor/expression.hpp index 9b3c44d2c..47d534010 100644 --- a/include/boost/numeric/ublas/tensor/expression.hpp +++ b/include/boost/numeric/ublas/tensor/expression.hpp @@ -14,13 +14,11 @@ #include #include -#include -#include -namespace boost { -namespace numeric { -namespace ublas { -namespace detail { +#include "tags.hpp" + +namespace boost::numeric::ublas::detail +{ /** @\brief base class for tensor expressions * @@ -67,16 +65,16 @@ struct binary_tensor_expression using size_type = typename tensor_type::size_type; - explicit constexpr binary_tensor_expression(expression_type_left const& l, expression_type_right const& r, binary_operation o) - : el(l) , er(r) , op(o) {} + explicit constexpr binary_tensor_expression(expression_type_left const& l, expression_type_right const& r, binary_operation o) : el(l) , er(r) , op(std::move(o)) {} + constexpr binary_tensor_expression(binary_tensor_expression&& l) noexcept = delete; + constexpr binary_tensor_expression& operator=(binary_tensor_expression&& l) noexcept = delete; + ~binary_tensor_expression() = default; + binary_tensor_expression() = delete; binary_tensor_expression(const binary_tensor_expression& l) = delete; - constexpr binary_tensor_expression(binary_tensor_expression&& l) noexcept - : el(l.el), er(l.er), op(std::move(l.op)) {} - constexpr binary_tensor_expression& operator=(binary_tensor_expression&& l) noexcept = default; binary_tensor_expression& operator=(binary_tensor_expression const& l) noexcept = delete; - ~binary_tensor_expression() = default; + [[nodiscard]] inline constexpr decltype(auto) operator()(size_type i) const { return op(el(i), er(i)); } @@ -135,24 +133,22 @@ struct unary_tensor_expression using self_type = unary_tensor_expression; using tensor_type = T; using expression_type = E; - + using unary_operation = OP; using derived_type = tensor_expression >; using size_type = typename tensor_type::size_type; - explicit constexpr unary_tensor_expression(E const& ee, OP o) : e(ee) , op(o) {} - constexpr unary_tensor_expression() = delete; - unary_tensor_expression(const unary_tensor_expression& l) = delete; - constexpr unary_tensor_expression(unary_tensor_expression&& l) noexcept - : e(l.e), op(std::move(l.op)) {} + explicit constexpr unary_tensor_expression(expression_type const& ee, unary_operation o) : e(ee) , op(std::move(o)) {} + constexpr unary_tensor_expression(unary_tensor_expression&& l) noexcept = delete; + constexpr unary_tensor_expression& operator=(unary_tensor_expression&& l) noexcept = delete; - constexpr unary_tensor_expression& operator=(unary_tensor_expression&& l) noexcept = default; - + constexpr unary_tensor_expression() = delete; + unary_tensor_expression(unary_tensor_expression const& l) = delete; unary_tensor_expression& operator=(unary_tensor_expression const& l) noexcept = delete; ~unary_tensor_expression() = default; - [[nodiscard]] inline - constexpr decltype(auto) operator()(size_type i) const { return op(e(i)); } + [[nodiscard]] inline constexpr + decltype(auto) operator()(size_type i) const { return op(e(i)); } E const& e; OP op; @@ -181,8 +177,6 @@ constexpr auto make_unary_tensor_expression( vector_expression const& e, OP o } -} -} -} -} -#endif +} // namespace boost::numeric::ublas::detail + +#endif // BOOST_UBLAS_TENSOR_EXPRESSIONS_HPP diff --git a/include/boost/numeric/ublas/tensor/expression_evaluation.hpp b/include/boost/numeric/ublas/tensor/expression_evaluation.hpp index a169b4e62..d29b6eabe 100644 --- a/include/boost/numeric/ublas/tensor/expression_evaluation.hpp +++ b/include/boost/numeric/ublas/tensor/expression_evaluation.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,20 +13,22 @@ #ifndef BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP #define BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP -#include #include -#include +#include + + + +#include "extents.hpp" +#include "extents/extents_functions.hpp" +#include "type_traits.hpp" namespace boost::numeric::ublas { -template +template class tensor_core; -template -class basic_extents; - -} +} // namespace boost::numeric::ublas namespace boost::numeric::ublas::detail { @@ -39,7 +41,7 @@ struct binary_tensor_expression; template struct unary_tensor_expression; -} +} // namespace boost::numeric::ublas::detail namespace boost::numeric::ublas::detail { @@ -66,11 +68,8 @@ struct has_tensor_types> } // namespace boost::numeric::ublas::detail -namespace boost::numeric::ublas::detail { - - - - +namespace boost::numeric::ublas::detail +{ /** @brief Retrieves extents of the tensor_core * @@ -166,91 +165,83 @@ constexpr auto& retrieve_extents(unary_tensor_expression const& expr) namespace boost::numeric::ublas::detail { -template +template [[nodiscard]] inline -constexpr auto all_extents_equal(tensor_core const& t, Extents const& extents) + constexpr auto all_extents_equal(tensor_core const& t, extents const& e) { - static_assert(is_extents_v, - "Error in boost::numeric::ublas::detail::all_extents_equal: extents passed should be of extents type." - ); - - return extents == t.extents(); + return ::operator==(e,t.extents()); } -template +template [[nodiscard]] -constexpr auto all_extents_equal(tensor_expression const& expr, Extents const& extents) +constexpr auto all_extents_equal(tensor_expression const& expr, extents const& e) { - static_assert(is_extents_v, - "Error in boost::numeric::ublas::detail::all_extents_equal: extents passed should be of extents type." - ); static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); auto const& cast_expr = static_cast(expr); + using ::operator==; + using ::operator!=; if constexpr ( std::is_same::value ) - if( extents != cast_expr.extents() ) + if( e != cast_expr.extents() ) return false; if constexpr ( detail::has_tensor_types::value ) - if ( !all_extents_equal(cast_expr, extents)) + if ( !all_extents_equal(cast_expr, e)) return false; return true; } -template +template [[nodiscard]] -constexpr auto all_extents_equal(binary_tensor_expression const& expr, Extents const& extents) +constexpr auto all_extents_equal(binary_tensor_expression const& expr, extents const& e) { - static_assert(is_extents_v, - "Error in boost::numeric::ublas::detail::all_extents_equal: extents passed should be of extents type." - ); - static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); + using ::operator==; + using ::operator!=; + if constexpr ( std::is_same::value ) - if(extents != expr.el.extents()) + if(e != expr.el.extents()) return false; if constexpr ( std::is_same::value ) - if(extents != expr.er.extents()) + if(e != expr.er.extents()) return false; if constexpr ( detail::has_tensor_types::value ) - if(!all_extents_equal(expr.el, extents)) + if(!all_extents_equal(expr.el, e)) return false; if constexpr ( detail::has_tensor_types::value ) - if(!all_extents_equal(expr.er, extents)) + if(!all_extents_equal(expr.er, e)) return false; return true; } -template +template [[nodiscard]] -constexpr auto all_extents_equal(unary_tensor_expression const& expr, Extents const& extents) +constexpr auto all_extents_equal(unary_tensor_expression const& expr, extents const& e) { - static_assert(is_extents_v, - "Error in boost::numeric::ublas::detail::all_extents_equal: extents passed should be of extents type." - ); - static_assert(detail::has_tensor_types>::value, "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); + using ::operator==; + if constexpr ( std::is_same::value ) - if(extents != expr.e.extents()) + if(e != expr.e.extents()) return false; if constexpr ( detail::has_tensor_types::value ) - if(!all_extents_equal(expr.e, extents)) + if(!all_extents_equal(expr.e, e)) return false; return true; @@ -259,7 +250,8 @@ constexpr auto all_extents_equal(unary_tensor_expression const& expr, Ex } // namespace boost::numeric::ublas::detail -namespace boost::numeric::ublas::detail { +namespace boost::numeric::ublas::detail +{ /** @brief Evaluates expression for a tensor_core @@ -290,10 +282,10 @@ template const& expr) { - static_assert(is_valid_tensor_v && is_valid_tensor_v, - "boost::numeric::ublas::detail::eval(tensor_type&, tensor_expression const&) : " - "tensor_type and tensor_expresssion should be a valid tensor type" - ); +// static_assert(is_valid_tensor_v && is_valid_tensor_v, +// "boost::numeric::ublas::detail::eval(tensor_type&, tensor_expression const&) : " +// "tensor_type and tensor_expresssion should be a valid tensor type" +// ); static_assert(std::is_same_v, "boost::numeric::ublas::detail::eval(tensor_type&, tensor_expression const&) : " @@ -347,5 +339,5 @@ inline void eval(tensor_type& lhs, unary_fn const& fn) } -} +} // namespace boost::numeric::ublas::detail #endif diff --git a/include/boost/numeric/ublas/tensor/extents.hpp b/include/boost/numeric/ublas/tensor/extents.hpp new file mode 100644 index 000000000..74034264e --- /dev/null +++ b/include/boost/numeric/ublas/tensor/extents.hpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// + +#ifndef BOOST_UBLAS_TENSOR_EXTENTS_HPP +#define BOOST_UBLAS_TENSOR_EXTENTS_HPP + +#include "extents/extents_base.hpp" +#include "extents/extents_dynamic_size.hpp" +#include "extents/extents_static_size.hpp" +#include "extents/extents_static.hpp" +#include "extents/extents_functions.hpp" +#include "extents/extents_static_functions.hpp" + + +template +bool operator==( + boost::numeric::ublas::extents const& lhs, + boost::numeric::ublas::extents const& rhs ) +{ + return size(lhs) == size(rhs) && std::equal( begin(lhs), end (lhs), begin(rhs) ); +} + +template +bool operator==( + boost::numeric::ublas::extents const& lhs, + boost::numeric::ublas::extents const& rhs ) +{ + return size(lhs) == size(rhs) && std::equal( begin(lhs), end (lhs), begin(rhs) ); +} + +template +bool operator!=( + boost::numeric::ublas::extents const& lhs, + boost::numeric::ublas::extents const& rhs ) +{ + return !( lhs == rhs) ; +} + +template +bool operator!=( + boost::numeric::ublas::extents const& lhs, + boost::numeric::ublas::extents const& rhs ) +{ + return !( lhs == rhs) ; +} + + +#endif // BOOST_UBLAS_TENSOR_EXTENTS_HPP diff --git a/include/boost/numeric/ublas/tensor/extents/extents_base.hpp b/include/boost/numeric/ublas/tensor/extents/extents_base.hpp new file mode 100644 index 000000000..40fc01846 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/extents/extents_base.hpp @@ -0,0 +1,54 @@ +// +// Copyright (c) 2020, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// + + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_BASE_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_BASE_HPP + +#include +//#include +#include + +#include "../concepts.hpp" + +namespace boost::numeric::ublas { + + +template +struct extents_base +{ + + using derived_type = D; + inline constexpr decltype(auto) operator()() const { return static_cast(*this); } + inline constexpr decltype(auto) operator()() { return static_cast< derived_type&>(*this); } + +}; + +template +class extents_core; + +template +using extents = extents_core; + +template struct is_extents : std::false_type {}; +template struct is_strides : std::false_type {}; +template struct is_dynamic : std::false_type {}; +template struct is_static : std::false_type {}; +template struct is_dynamic_rank : std::false_type {}; +template struct is_static_rank : std::false_type {}; + +template inline static constexpr bool const is_extents_v = is_extents::value; +template inline static constexpr bool const is_strides_v = is_strides::value; +template inline static constexpr bool const is_dynamic_v = is_dynamic::value; +template inline static constexpr bool const is_static_v = is_static ::value; +template inline static constexpr bool const is_dynamic_rank_v = is_dynamic_rank::value; +template inline static constexpr bool const is_static_rank_v = is_static_rank::value; + +} // namespace boost::numeric::ublas + +#endif // _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_BASE_HPP_ diff --git a/include/boost/numeric/ublas/tensor/extents/extents_dynamic_size.hpp b/include/boost/numeric/ublas/tensor/extents/extents_dynamic_size.hpp new file mode 100644 index 000000000..fe3266050 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/extents/extents_dynamic_size.hpp @@ -0,0 +1,154 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_DYNAMIC_SIZE_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_DYNAMIC_SIZE_HPP + +#include +#include +#include +#include +#include + +#include "extents_base.hpp" +#include "extents_functions.hpp" + +#include "../layout.hpp" +#include "../concepts.hpp" + +namespace boost::numeric::ublas { + + + +/** @brief Template class for storing tensor extents with runtime variable size. + * + * Proxy template class of std::vector. + * + */ +template +class extents_core + : public extents_base> +{ + using super_type = extents_base>; + +public: + using base_type = std::vector; + using value_type = typename base_type::value_type; + using const_reference = typename base_type::const_reference; + using reference = typename base_type::reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; + + + extents_core() = default; + + explicit extents_core(base_type b) + : _base(std::move(b)) + { + if (!ublas::is_valid(*this)){ + throw std::invalid_argument("in boost::numeric::ublas::extents<> : " + "could not intanstiate extents<> as provided extents are not valid."); + } + } + + /** @brief Constructs extents from an initializer list + * + * @code auto ex = extents<>{}; @endcode + * @code auto ex = extents<>{3,2,4}; @endcode + * + * @note checks if size > 1 and all elements > 0 + * + * @param l one-dimensional list of type std::initializer + */ + extents_core(std::initializer_list l) + : extents_core( base_type(l) ) + { + if (!ublas::is_valid(*this)){ + throw std::invalid_argument("in boost::numeric::ublas::extents<> : " + "could not intanstiate extents<> as provided extents are not valid."); + } + } + + /** @brief Constructs extents from a range specified by two iterators + * + * @code auto ex = extents<>(a.begin(), a.end()); + * + * @note checks if size > 1 and all elements > 0 + * + * @param first iterator pointing to the first element + * @param last iterator pointing to the next position after the last element + */ + + template + constexpr extents_core(InputIt first, InputIt last) + : extents_core ( base_type( first,last ) ) + { + if (!ublas::is_valid(*this)){ + throw std::invalid_argument("in boost::numeric::ublas::extents<> : " + "could not intanstiate extents<> as provided extents are not valid."); + } + } + + /** @brief Copy constructs extents */ + /*constexpr*/ extents_core(extents_core const& l ) + : _base(l._base) + { + } + + /** @brief Move constructs extents */ + /*constexpr*/ extents_core(extents_core && l ) noexcept + : _base(std::move(l._base)) + { + } + + ~extents_core() = default; + + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + extents_core& operator=(extents_core other) + noexcept(std::is_nothrow_swappable_v) + { + swap (*this, other); + return *this; + } + + + friend void swap(extents_core& lhs, extents_core& rhs) + noexcept(std::is_nothrow_swappable_v) + { + std::swap(lhs._base,rhs._base); + } + + [[nodiscard]] inline /*constexpr*/ const_reference operator[] (size_type p) const { return this->_base[p]; } + [[nodiscard]] inline /*constexpr*/ const_reference at (size_type p) const { return this->_base.at(p); } + + [[nodiscard]] inline /*constexpr*/ auto size() const noexcept { return this->_base.size(); } + [[nodiscard]] inline /*constexpr*/ auto const& base() const noexcept { return this->_base; } + [[nodiscard]] inline /*constexpr*/ const_pointer data() const noexcept { return this->_base.data(); } +private: + base_type _base; +}; + +} // namespace boost::numeric::ublas + + +namespace boost::numeric::ublas{ +template struct is_extents < extents_core > : std::true_type {}; +template struct is_dynamic < extents_core > : std::true_type {}; +template struct is_dynamic_rank < extents_core > : std::true_type {}; + +} // namespace boost::numeric::ublas + + +#endif diff --git a/include/boost/numeric/ublas/tensor/extents/extents_functions.hpp b/include/boost/numeric/ublas/tensor/extents/extents_functions.hpp new file mode 100644 index 000000000..85e64ff8f --- /dev/null +++ b/include/boost/numeric/ublas/tensor/extents/extents_functions.hpp @@ -0,0 +1,247 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP + + +#include +#include +//#include + +#include "../layout.hpp" +#include "../concepts.hpp" + +namespace boost::numeric::ublas +{ +template +class extents_core; + + +template +struct extents_base; + +template [[nodiscard]] constexpr inline auto front (extents_base const& e) noexcept -> typename D::const_reference { return e().base().front(); } +template [[nodiscard]] constexpr inline auto back (extents_base const& e) noexcept -> typename D::const_reference { return e().base().back(); } +template [[nodiscard]] constexpr inline auto begin (extents_base const& e) noexcept -> typename D::const_iterator { return e().base().begin(); } +template [[nodiscard]] constexpr inline auto end (extents_base const& e) noexcept -> typename D::const_iterator { return e().base().end(); } +template [[nodiscard]] constexpr inline auto cbegin(extents_base const& e) noexcept -> typename D::const_iterator { return e().base().cbegin(); } +template [[nodiscard]] constexpr inline auto cend (extents_base const& e) noexcept -> typename D::const_iterator { return e().base().cend(); } +template [[nodiscard]] constexpr inline auto rbegin(extents_base const& e) noexcept -> typename D::const_reverse_iterator { return e().base().rbegin(); } +template [[nodiscard]] constexpr inline auto rend (extents_base const& e) noexcept -> typename D::const_reverse_iterator { return e().base().rend(); } +template [[nodiscard]] constexpr inline auto empty (extents_base const& e) noexcept -> bool { return e().base().empty(); } +template [[nodiscard]] constexpr inline auto size (extents_base const& e) noexcept -> typename D::size_type { return e().base().size(); } + +} //namespace boost::numeric::ublas + + +namespace boost::numeric::ublas +{ + +/** @brief Returns true if extents equals ([m,n,...,l]) with m>0,n>0,...,l>0 */ +template +[[nodiscard]] inline constexpr bool is_valid(extents_base const& e) +{ + return std::all_of(begin(e),end(e), [](auto a){ return a>0UL; } ); +} + +/** @brief Returns true if extents equals (m,[n,...,l]) with m=1,n=1,...,l=1 */ +template +[[nodiscard]] inline constexpr bool is_scalar(extents_base const& e) +{ + return (size(e)>0) && std::all_of (cbegin(e),cend(e),[](auto a){return a==1ul;}); +} + +/** @brief Returns true if extents equals (m,[n,1,...,1]) with m>=1||n>=1 && m==1||n==1*/ +template +[[nodiscard]] inline constexpr bool is_vector(extents_base const& e) +{ + if (empty(e) ) {return false;} + if (size (e) == 1) {return front(e)>=1ul;} + + return + std::any_of(cbegin(e) ,cbegin(e)+2ul, [](auto a){return a>=1ul;}) && + std::any_of(cbegin(e) ,cbegin(e)+2ul, [](auto a){return a==1ul;}) && + std::all_of(cbegin(e)+2ul,cend (e) , [](auto a){return a==1ul;}); + +// std::any_of(cbegin(e) ,cbegin(e)+2, [](auto a){return a>=1UL;}) && // a>1UL +// std::any_of(cbegin(e) ,cbegin(e)+2, [](auto a){return a==1UL;}) && +// std::all_of(cbegin(e)+2,cend(e) , [](auto a){return a==1UL;}); +} + +/** @brief Returns true if (m,[n,1,...,1]) with m>=1 or n>=1 */ +template +[[nodiscard]] inline constexpr bool is_matrix(extents_base const& e) +{ + if (empty(e) ) {return false;} + if (size (e) == 1) {return front(e)>=1ul;} + + return std::any_of (cbegin(e) ,cbegin(e)+2, [](auto a){return a>=1ul;}) && // all_of > 1UL + std::all_of (cbegin(e)+2,cend(e) , [](auto a){return a==1ul;}); +} + +/** @brief Returns true if shape is has a tensor shape + * + * @returns true if is_valid & not (is_scalar&is_vector&is_matrix) + */ +template +[[nodiscard]] inline constexpr bool is_tensor(extents_base const& e) +{ + return size(e) > 2 && + std::all_of (cbegin(e) ,cbegin(e)+2, [](auto a){return a>=1ul;}) && // all_of > 1UL + std::any_of (cbegin(e)+2,cend(e) , [](auto a){return a> 1ul;}); +} + + + + + +/** @brief Computes the number of elements */ +template +[[nodiscard]] inline constexpr auto product( extents_base const& e ) +{ + if( empty(e) ){ + return std::size_t{0UL}; + } + + return std::accumulate(begin(e), end(e), std::size_t{1UL}, std::multiplies<>{}); +} + + +//template // std::inserter(out,out.begin()) +//inline constexpr +// void squeeze( +// extents_base const& in, +// extents_base const& out) +//{ +// if(e().size() < 2){ return; } + +// if(is_vector(e) || is_scalar(e)) { +// std::copy (in, in+2, out ); +// } +// else{ +// std::copy_if(in, in_end, out, [](auto a){return a!=1u;}); +// } +//} + +//template +//[[nodiscard]] inline bool operator==( +// extents_base const& lhs, +// extents_base const& rhs ) +//{ +// return size(lhs) == size(rhs) && std::equal( begin(lhs), end (lhs), begin(rhs) ); +//} + +//template +//[[nodiscard]] inline bool operator!=( +// extents_base const& lhs, +// extents_base const& rhs ) +//{ +// return !( lhs == rhs) ; +//} + +template +[[nodiscard]] inline auto to_strides(extents_core const& e, L /*unused*/) +{ + auto s = typename extents_core::base_type(e.size(),1ul); + + if(empty(e) || is_vector(e) || is_scalar(e)){ + return s; + } + if constexpr(std::is_same_v){ + std::transform(begin (e), end (e) - 1, s.begin (), s.begin ()+1, std::multiplies<>{}); + } else { + std::transform(rbegin(e), rend(e) - 1, s.rbegin(), s.rbegin()+1, std::multiplies<>{}); + } + return s; +} + +template +[[nodiscard]] inline auto to_strides(extents_core const& e, L /*unused*/) +{ + auto s = typename extents_core::base_type{}; + std::fill(s.begin(),s.end(),1ul); + + if(empty(e) || is_vector(e) || is_scalar(e)){ + return s; + } + if constexpr(std::is_same_v){ + std::transform(begin (e), end (e) - 1, s.begin (), s.begin ()+1, std::multiplies<>{}); + } else { + std::transform(rbegin(e), rend(e) - 1, s.rbegin(), s.rbegin()+1, std::multiplies<>{}); + } + return s; +} + + + +} // namespace boost::numeric::ublas + + +template +[[nodiscard]] inline constexpr bool operator==( + boost::numeric::ublas::extents_core const& lhs, + boost::numeric::ublas::extents_core const& rhs ) +{ + if constexpr(m != n) + return false; + return std::equal( begin(lhs), end (lhs), begin(rhs) ); +} + +template +[[nodiscard]] inline constexpr bool operator!=( + boost::numeric::ublas::extents_core const& lhs, + boost::numeric::ublas::extents_core const& rhs ) +{ + if constexpr(m == n) + return false; + return !(lhs == rhs) ; +} + +template +[[nodiscard]] inline constexpr bool operator==( + boost::numeric::ublas::extents_base const& lhs, + boost::numeric::ublas::extents_base const& rhs ) +{ + return size(lhs) == size(rhs) && std::equal( begin(lhs), end (lhs), begin(rhs) ); +} + +template +[[nodiscard]] inline constexpr bool operator!=( + boost::numeric::ublas::extents_base const& lhs, + boost::numeric::ublas::extents_base const& rhs ) +{ + return !( lhs == rhs) ; +} + + +namespace std +{ + +template +struct tuple_size< boost::numeric::ublas::extents_core > + : integral_constant::base_type>> +{}; + +template +[[nodiscard]] constexpr inline + auto get(boost::numeric::ublas::extents_core const& e) noexcept +{ + return std::get(e.base()); +} + +} // namespace std + + +#endif // _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP_ + + diff --git a/include/boost/numeric/ublas/tensor/extents/extents_static.hpp b/include/boost/numeric/ublas/tensor/extents/extents_static.hpp new file mode 100644 index 000000000..3f375b50d --- /dev/null +++ b/include/boost/numeric/ublas/tensor/extents/extents_static.hpp @@ -0,0 +1,78 @@ +// +// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_STATIC_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_STATIC_HPP + +#include +#include +#include +#include + +#include "extents_functions.hpp" +#include "extents_base.hpp" +#include "../concepts.hpp" + + +namespace boost::numeric::ublas { + + +/** @brief Template class for storing tensor extents for compile time. + * + * @code extents<1,2,3,4> t @endcode + * + * @tparam e parameter pack of extents + * + */ +template +class extents_core + : public extents_base> +{ + static constexpr auto size = sizeof...(e)+2u; +public: + + using base_type = std::array; + using value_type = typename base_type::value_type; + using size_type = typename base_type::size_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; + + constexpr extents_core() = default; + constexpr extents_core(extents_core const&) noexcept = default; + constexpr extents_core(extents_core &&) noexcept = default; + constexpr extents_core& operator=(extents_core const&) noexcept = default; + constexpr extents_core& operator=(extents_core &&) noexcept = default; + ~extents_core() = default; + + [[nodiscard]] inline constexpr const_reference at (size_type k) const{ return m_data.at(k); } + [[nodiscard]] inline constexpr const_reference operator[](size_type k) const{ return m_data[k]; } + [[nodiscard]] inline constexpr base_type const& base() const noexcept{ return m_data; } + [[nodiscard]] inline constexpr const_pointer data () const noexcept{ return m_data.data(); } + +private: + static constexpr base_type const m_data{e1,e2,e...}; + +}; + +template struct is_extents < extents_core > : std::true_type {}; +template struct is_static < extents_core > : std::true_type {}; +template struct is_static_rank < extents_core > : std::true_type {}; + +} // namespace boost::numeric::ublas + + + + +#endif diff --git a/include/boost/numeric/ublas/tensor/extents/extents_static_functions.hpp b/include/boost/numeric/ublas/tensor/extents/extents_static_functions.hpp new file mode 100644 index 000000000..08b930d6f --- /dev/null +++ b/include/boost/numeric/ublas/tensor/extents/extents_static_functions.hpp @@ -0,0 +1,637 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_STATIC_FUNCTIONS_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_STATIC_FUNCTIONS_HPP + + +#include +#include +#include + +#include "extents_base.hpp" +#include "../layout.hpp" + + + +namespace boost::numeric::ublas +{ + + + +//////////////// SIZE /////////////// + +namespace detail { +template +struct size_impl_t; +template +struct size_impl_t> +{ static constexpr auto value = sizeof ...(es); }; +template +struct size_impl_t> +{ static constexpr auto value = sizeof ...(es); }; +} // namespace detail + +/** @brief Returns the size of a pure static extents type + * + * @code constexpr auto n = size_v>; + * @note corresponds to std::tuple_size_v + * +*/ +template +constexpr inline auto size_v = detail::size_impl_t>::value; + +//////////////// EMPTY /////////////// + +namespace detail { +template +struct empty_impl_t; + +template +struct empty_impl_t> +{ static constexpr bool value = size_v> == 0ul; }; +} // namespace detail + +/** @brief Returns if a pure static extents type is empty + * + * @code constexpr bool empty = empty_v>; // -> false + * +*/ +template +constexpr inline bool empty_v = detail::empty_impl_t>::value; + + +//////////////// GET ///////////////////// + +namespace detail { +template +struct get_impl_t; + +template +struct get_impl_t> +{ + static constexpr auto value = 0; +}; + +template +struct get_impl_t> +{ + static_assert ( j < n && k < n ); + static constexpr auto value = e1; +}; + +template +struct get_impl_t> +{ + static_assert ( k < n && j < n ); + static constexpr auto value = (j==k) ? e1 : get_impl_t>::value; +}; +} // namespace detail + +/** @brief Returns the j-th element of a pure static extents type with 0 <= j < size_v + * + * @code constexpr auto e_j = get_v,2>; + * +*/ +template +constexpr inline auto get_v = detail::get_impl_t,std::decay_t>::value; + + +//////////////// CAT ///////////////////// +namespace detail { +template +struct cat_impl_t +{ + template + struct inner; + template + struct inner < std::index_sequence, std::index_sequence > + { + using type = extents < get_v..., get_v... >; + }; + using type = typename inner < + std::make_index_sequence>, + std::make_index_sequence> >::type; +}; +} // namespace detail + +/** @brief Concatenates two static extents type + * + * @code using extents_t = cat,extents<7,6>>; // -> extents<4,3,2,7,6> + * + * @tparam EL left extents<...> + * @tparam ER right extents<...> +*/ +template +using cat_t = typename detail::cat_impl_t,std::decay_t>::type; + +//////////////// FOR_EACH //////////////// + +namespace detail { + +template class> +struct for_each_impl_t; + +template class UnaryOp, typename std::size_t ... es> +struct for_each_impl_t, UnaryOp > +{ using type = extents< ( UnaryOp::value )... >; }; + +template class UnaryOp, typename std::size_t ... is> +struct for_each_impl_t, UnaryOp > +{ using type = std::index_sequence< ( UnaryOp::value )... >; }; + +} // namespace detail + +/** @brief Applies a unary operation for each element of a given static extents type + * + * @code template struct add5 { static constexpr auto value = e+5; }; + * @code using extents_t = for_each,add5>; // -> extents<9,8,7> + * + * @tparam E extents<...> +*/ +template typename UnaryOp> +using for_each_t = typename detail::for_each_impl_t, UnaryOp>::type; + +//////////////// TEST //////////////// + +namespace detail { + +template class> +struct for_each_test_impl_t; + +template class UnaryPred, typename std::size_t ... es> +struct for_each_test_impl_t, UnaryPred > +{ using type = std::integer_sequence::value )... >; }; + +template class UnaryPred, typename std::size_t ... is> +struct for_each_test_impl_t, UnaryPred > +{ using type = std::integer_sequence::value )... >; }; + +} // namespace detail + +/** @brief Returns true if for each element of a given static extents type the unary predicate holds + * + * @code template struct equal5 { static constexpr bool value = e==5; }; + * @code using sequence_t = for_each,equal5>; // -> std::integer_sequence + * + * @tparam E extents<...> +*/ +template typename UnaryPred> +using for_each_test_t = typename detail::for_each_test_impl_t, UnaryPred>::type; + + +//////////////// SELECT INDEX SEQUENCE ///////////////// + +namespace detail { +template +struct select_impl_t +{ + static_assert( size_v >= I::size() ); + template struct inner; + template + struct inner > { using type = extents ... >; }; + using type = typename inner::type; +}; +} // namespace detail + +/** @brief Returns a static extents type selected from a static extents type using std::index_sequence + * + * @code using extents_t = select,std::index_sequence<0,2>>; // -> extents<4,2> + * + * @tparam E extents<...> + * @tparam S std::index_sequence<...> +*/ +template +using select_t = typename detail::select_impl_t, S>::type; + + +//////////////// BINARY PLUS OP ///////////////// + +template +struct plus_t { static constexpr auto value = i+j; }; + +template +constexpr inline auto plus_v = plus_t::value; + +template +struct multiply_t { static constexpr auto value = i*j;}; + + + +//////////////// SET ///////////////////// + +namespace detail { +template +struct set_impl_t; + +template +struct set_impl_t> +{ + static constexpr inline auto n = size_v>; + template using plus_j1 = plus_t; + + using head_indices = std::make_index_sequence; + using tail_indices = for_each_t,plus_j1>; + + using head = select_t,head_indices>; + using tail = select_t,tail_indices>; + using type = cat_t>,tail>; +}; +} // namespace detail + +/** @brief Sets the j-th element of a pure static extents type with 0 <= j < size_v + * + * @code using extents_t = set_t<2,5,extents<4,3,2>>; // extents<4,3,5> + * + * @tparam j j-th position in extents with 0 <= j < size_v + * @tparam e value to replace the j-th element + * @tparam E extents +*/ +template +using set_t = typename detail::set_impl_t>::type; + + + +//////////////// REVERSE ////////////////// + +namespace detail { +template +struct reverse_impl_t; + +template +struct reverse_impl_t> +{ + using type = extents < ( get_v-js-1>) ... >; +}; +} // namespace detail + +/** @brief Reverses static extents of a static extents type + * + * @code using extents_t = reverse_t>; // -> extents<2,3,4> + * + * @tparam E extents<...> +*/ +template +using reverse_t = typename detail::reverse_impl_t, std::make_index_sequence>>::type; + + +//////////////// REMOVE ////////////////// + +namespace detail{ +template +struct remove_element_impl_t +{ + static constexpr auto n = E::size(); + using head = select_t >; + + template + struct tail_indices; + template + struct tail_indices> + { + using type = extents< (is+k+1) ... >; + }; + using tail = select_t>::type>; + using type = cat_t< head, tail>; +}; +} // namespace detail + +/** @brief Removes a static extent of a static extents type + * + * @code using extents_t = remove<1,extents<4,3,2>>; // -> extents<4,2> + * @note it is a special case of the select function + * + * @tparam k zero-based index + * @tparam E extents<...> +*/ +template +using remove_element_t = typename detail::remove_element_impl_t>::type; + + + +//////////////// ACCUMULATE ///////////////////// + +namespace detail { + +template class> +struct accumulate_impl_t; + +template class op, std::size_t i> +struct accumulate_impl_t, i, op> +{ static constexpr auto value = i; }; + +template class op, std::size_t i, std::size_t e> +struct accumulate_impl_t, i, op> +{ static constexpr auto value = op::value; }; + +template class op, std::size_t i, std::size_t e, std::size_t ... es> +struct accumulate_impl_t, i, op> +{ + using next = accumulate_impl_t,i,op>; + static constexpr auto value = op::value; + +}; +} // namespace detail + +template class BinaryOp> +constexpr inline auto accumulate_v = detail::accumulate_impl_t>,I,BinaryOp>::value; + + +//////////////// Product ///////////////////// + +namespace detail { + +template +struct product_impl_t +{ + static constexpr auto value = empty_v ? 0UL : accumulate_v; +}; + +} // namespace detail +template +constexpr inline auto product_v = detail::product_impl_t>::value; + + +//////////////// ALL_OF ///////////////////// + + +namespace detail { + +template +struct all_of_impl_t; +template<> +struct all_of_impl_t> +{ static constexpr bool value = true; }; +template +struct all_of_impl_t> +{ static constexpr bool value = ( e && ... && es ); }; + +} // namespace detail + +/** @brief Returns true if all elements of Extents satisfy UnaryOp + * + * @code constexpr auto e_j = all_of_v>; +*/ +template class UnaryPred> +constexpr inline bool all_of_v = detail::all_of_impl_t,UnaryPred>>::value; + + +//////////////// ALL_OF ///////////////////// + +namespace detail { +template +struct any_of_impl_t; +template<> +struct any_of_impl_t> +{ static constexpr bool value = true;}; + +template +struct any_of_impl_t> +{ static constexpr bool value = ( e || ... || es ); }; + +} // namespace detail + +template class UnaryOp> +constexpr inline bool any_of_v = detail::any_of_impl_t,UnaryOp>>::value; + + +//////////////// IS_VALID ///////////////////// + +namespace detail { + +template +struct is_valid_impl_t { static constexpr bool value = false; }; +template<> +struct is_valid_impl_t> { static constexpr bool value = true ; }; + +template +struct is_valid_impl_t> +{ + template + struct greater_than_zero { static constexpr auto value = (n>0ul); }; + + static constexpr bool value = all_of_v,greater_than_zero >; +}; +} // namespace detail + +/** @brief Returns true if extents equals ([m,n,...,l]) with m>0,n>0,...,l>0 */ +template +constexpr inline bool is_valid_v = detail::is_valid_impl_t>::value; + + + +//////////////// IS_SCALAR ///////////////////// + +namespace detail { +template +struct is_scalar_impl_t +{ + template + struct equal_to_one { static constexpr auto value = (n == 1ul); }; + + static constexpr bool value = is_valid_v && + !empty_v && + all_of_v; +}; +} // namespace detail + +/** @brief Returns true if extents equals (m,[n,...,l]) with m=1,n=1,...,l=1 */ +template +constexpr inline bool is_scalar_v = detail::is_scalar_impl_t>::value; + + +//////////////// IS_VECTOR ///////////////////// + +namespace detail { + +template +struct is_vector_impl_t { static constexpr bool value = false; }; +template<> +struct is_vector_impl_t> { static constexpr bool value = false; }; + +template +struct is_vector_impl_t> { static constexpr bool value = (e>=1); }; + +template +struct is_vector_impl_t> +{ + template struct equal_to_one { static constexpr auto value = (n == 1ul); }; + template struct greater_than_zero { static constexpr auto value = (n > 0ul); }; + + static constexpr bool value = + is_valid_v > && + any_of_v ,greater_than_zero> && + any_of_v ,equal_to_one > && + all_of_v ,equal_to_one >; +}; + + +} // namespace detail + +/** @brief Returns true if extents equals (m,[n,1,...,1]) with m>=1||n>=1 && m==1||n==1*/ +template +constexpr inline bool is_vector_v = detail::is_vector_impl_t>::value; + + + +//////////////// IS_MATRIX ///////////////////// + +namespace detail { + +template +struct is_matrix; + +template<> +struct is_matrix> { static constexpr bool value = false; }; + +template +struct is_matrix> { static constexpr bool value = true; }; + +template +struct is_matrix> +{ + template struct equal_to_one { static constexpr auto value = (n == 1ul); }; + template struct greater_than_zero { static constexpr auto value = (n > 0ul); }; + + static constexpr bool value = + is_valid_v > && + all_of_v ,greater_than_zero > && + all_of_v ,equal_to_one >; +}; + + +} // namespace detail + +/** @brief Returns true if (m,n,[1,...,1]) with m>=1 or n>=1 */ +template +constexpr inline bool is_matrix_v = detail::is_matrix>::value; + + +//////////////// IS_TENSOR ///////////////////// + +namespace detail { + +template +struct is_tensor; + +template<> +struct is_tensor> { static constexpr bool value = false; }; + +template +struct is_tensor> { static constexpr bool value = false; }; + +template +struct is_tensor> +{ + template + struct greater_than_one { static constexpr auto value = (n > 1ul); }; + + static constexpr bool value = + is_valid_v > && + size_v > > 2ul && + any_of_v ,greater_than_one >; +}; + + +} // namespace detail + +/** @brief Returns true if extents is equal to (m,n,[1,...,1],k,[1,...,1]) with k > 1 */ +template +constexpr inline bool is_tensor_v = detail::is_tensor>::value; + + +//////////////// ARRAY_CONVERSION ///////////////////// + +namespace detail { +template +struct to_array_impl_t; + +template +struct to_array_impl_t> +{ static constexpr auto value = std::array{is... }; }; + +template +struct to_array_impl_t> +{ static constexpr auto value = std::array{is... }; }; + +} // namespace detail + +template +constexpr inline auto to_array_v = detail::to_array_impl_t>::value; + + + + +namespace detail { + +template +struct to_strides_impl_t; + +template +struct to_strides_impl_t > +{ + static_assert (is_valid_v); + + static constexpr bool is_first_order = std::is_same_v; + using adjusted_extents = std::conditional_t>; + + template + static constexpr std::size_t selected_product = product_v>>; + + using pre_type = extents <1,( selected_product ) ... >; + using type = std::conditional_t>; +}; + +} // namespace detail + +template +using to_strides_impl_t = typename detail::to_strides_impl_t-1>>::type; + +template +constexpr inline auto to_strides_v = to_array_v,L>>; + +} //namespace boost::numeric::ublas + + +template < + std::size_t l1, + std::size_t l2, + std::size_t r1, + std::size_t r2, + std::size_t ... l, + std::size_t ... r> +[[nodiscard]] inline constexpr bool operator==( + boost::numeric::ublas::extents /*unused*/, + boost::numeric::ublas::extents /*unused*/) +{ + return std::is_same_v< + boost::numeric::ublas::extents, + boost::numeric::ublas::extents>; +} + +template < + std::size_t l1, + std::size_t l2, + std::size_t r1, + std::size_t r2, + std::size_t ... l, + std::size_t ... r> +[[nodiscard]] inline constexpr bool operator!=( + boost::numeric::ublas::extents el, + boost::numeric::ublas::extents er) +{ + return !(el == er); +} + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_STATIC_FUNCTIONS_HPP + + diff --git a/include/boost/numeric/ublas/tensor/extents/extents_static_size.hpp b/include/boost/numeric/ublas/tensor/extents/extents_static_size.hpp new file mode 100644 index 000000000..f274dfafc --- /dev/null +++ b/include/boost/numeric/ublas/tensor/extents/extents_static_size.hpp @@ -0,0 +1,148 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_STATIC_SIZE_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_STATIC_SIZE_HPP + +#include +#include +#include +#include +#include + + +#include "extents_functions.hpp" +#include "extents_base.hpp" + +#include "../layout.hpp" +#include "../concepts.hpp" + + +namespace boost::numeric::ublas +{ + +/** @brief Class template for storing static-number of extents + * + * @code auto e = extents<3>{3,2,4}; @endcode + * + * @tparam N number of extents + * + */ +template +class extents_core : public extents_base> +{ +public: + using base_type = std::array; + using value_type = typename base_type::value_type; + using size_type = typename base_type::size_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; + + constexpr extents_core() = default; + + constexpr explicit extents_core(base_type data) + : _base(std::move(data)) + { + if ( !ublas::is_valid(*this) ){ + throw std::invalid_argument("in boost::numeric::ublas::extents : " + "could not intanstiate extents as provided extents are not valid."); + } + } + + + constexpr extents_core(std::initializer_list const& li) + : _base() + { + if( li.size() != ublas::size(*this) ){ + throw std::length_error("in boost::numeric::ublas::extents : " + "could not intanstiate extents as number of indices exceed N."); + } + + std::copy(li.begin(), li.end(), _base.begin()); + + if ( !ublas::is_valid(*this) ){ + throw std::invalid_argument("in boost::numeric::ublas::extents : " + "could not intanstiate extents as provided extents are not valid."); + } + } + + constexpr extents_core(const_iterator begin, const_iterator end) + { + if( std::distance(begin,end) < 0 || static_cast(std::distance(begin,end)) > this->base().size()){ + throw std::out_of_range("in boost::numeric::ublas::extents : " + "initializer list size is greater than the rank"); + } + + std::copy(begin, end, _base.begin()); + + if ( !ublas::is_valid(*this) ) { + throw std::invalid_argument("in boost::numeric::ublas::extents::ctor: " + "could not intanstiate extents as provided extents are not valid."); + } + } + constexpr extents_core(extents_core const& other) + : _base(other._base) + { + assert(ublas::is_valid(*this)); + } + + constexpr extents_core(extents_core && other) noexcept + : _base( std::move(other._base) ) + { + } + + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + constexpr extents_core& operator=(extents_core other) + noexcept(std::is_nothrow_swappable_v) + { + swap(*this,other); + return *this; + } + + ~extents_core() = default; + + + friend void swap(extents_core& lhs, extents_core& rhs) + noexcept(std::is_nothrow_swappable_v) + { + std::swap(lhs._base, rhs._base); + } + + [[nodiscard]] inline constexpr const_reference at (size_type k) const { return this->_base.at(k); } + [[nodiscard]] inline constexpr const_reference operator[](size_type k) const { return this->_base[k]; } + [[nodiscard]] inline constexpr auto const& base () const noexcept { return this->_base; } + [[nodiscard]] inline constexpr const_pointer data () const noexcept { return this->_base.data(); } + + +private: + base_type _base{}; +}; + +} // namespace boost::numeric::ublas + + + + +namespace boost::numeric::ublas{ +template struct is_extents < extents_core > : std::true_type {}; +template struct is_dynamic < extents_core > : std::true_type {}; +template struct is_static_rank < extents_core > : std::true_type {}; +} // namespace boost::numeric::ublas + + + + +#endif diff --git a/include/boost/numeric/ublas/tensor/extents_functions.hpp b/include/boost/numeric/ublas/tensor/extents_functions.hpp deleted file mode 100644 index 46f15f93a..000000000 --- a/include/boost/numeric/ublas/tensor/extents_functions.hpp +++ /dev/null @@ -1,449 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP_ -#define _BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_FUNCTIONS_HPP_ - -#include -#include -#include -#include -#include -#include - -namespace boost::numeric::ublas::detail{ - - template - constexpr auto push_back(basic_static_extents) -> basic_static_extents; - - template - constexpr auto push_front(basic_static_extents) -> basic_static_extents; - - template - constexpr auto pop_front(basic_static_extents) -> basic_static_extents; - - template - constexpr auto any_extents_greater_than_one([[maybe_unused]] basic_static_extents const& e) noexcept{ - constexpr auto sz = sizeof...(Es); - return sz && ( ( Es > T(1) ) || ... ); - } - - template - constexpr auto squeeze_impl_remove_one( - [[maybe_unused]] basic_static_extents e, - basic_static_extents num = basic_static_extents{} - ){ - // executed when basic_static_extents is size of 1 - // @code basic_static_extents @endcode - if constexpr( sizeof...(E) == 0ul ){ - // if element E0 is 1 we return number list but we do not append - // it to the list - if constexpr( E0 == T(1) ){ - return num; - }else{ - // if element E0 is 1 we return number list but we append - // it to the list - return decltype(push_back(num)){}; - } - }else{ - if constexpr( E0 == T(1) ){ - // if element E0 is 1 we return number list but we do not append - // it to the list - return squeeze_impl_remove_one(basic_static_extents{}, num); - }else{ - // if element E0 is 1 we return number list but we append - // it to the list - auto n_num_list = decltype(push_back(num)){}; - return squeeze_impl_remove_one(basic_static_extents{}, n_num_list); - } - } - } - - template - constexpr auto squeeze_impl( basic_static_extents const& e ){ - - using extents_type = basic_static_extents; - - if constexpr( extents_type::_size <= typename extents_type::size_type(2) ){ - return e; - } - - using value_type = typename extents_type::value_type; - using size_type = typename extents_type::size_type; - - auto one_free_static_extents = squeeze_impl_remove_one(e); - - // check after removing 1s from the list are they same - // if same that means 1s does not exist and no need to - // squeeze - if constexpr( decltype(one_free_static_extents)::_size != extents_type::_size ){ - - // after squeezing, all the extents are 1s we need to - // return extents of (1, 1) - if constexpr( decltype(one_free_static_extents)::_size == size_type(0) ){ - - return basic_static_extents{}; - - }else if constexpr( decltype(one_free_static_extents)::_size == (1) ){ - // to comply with GNU Octave this check is made - // if position 2 contains 1 we push at back - // else we push at front - if constexpr( extents_type::at(1) == value_type(1) ){ - return decltype( push_back(one_free_static_extents) ){}; - }else{ - return decltype( push_front(one_free_static_extents) ){}; - } - - }else{ - return one_free_static_extents; - } - - }else{ - return e; - } - - } - - template - inline - constexpr auto squeeze_impl( basic_extents const& e ){ - using extents_type = basic_extents; - using base_type = typename extents_type::base_type; - using value_type = typename extents_type::value_type; - using size_type = typename extents_type::size_type; - - if( e.size() <= size_type(2) ){ - return e; - } - - auto not_one = [](auto const& el){ - return el != value_type(1); - }; - - // count non one values - size_type size = std::count_if(e.begin(), e.end(), not_one); - - // reserve space - base_type n_extents( std::max(size, size_type(2)), 1 ); - - // copying non 1s to the new extents - std::copy_if(e.begin(), e.end(), n_extents.begin(), not_one); - - // checking if extents size goes blow 2 - // if size of extents goes to 1 - // complying with GNU Octave - // if position 2 contains 1 we - // swap the pos - if( size < size_type(2) && e[1] != value_type(1) ){ - std::swap(n_extents[0], n_extents[1]); - } - - return extents_type(n_extents); - } - - template - inline - auto squeeze_impl( basic_fixed_rank_extents const& e ){ - if constexpr( N <= 2 ){ - return e; - }else{ - return squeeze_impl(basic_extents(e)); - } - } - - - -} // namespace boost::numeric::ublas::detail - -namespace boost::numeric::ublas { - -/** @brief Returns true if size > 1 and all elements > 0 or size == 1 && e[0] == 1 */ -template -[[nodiscard]] inline -constexpr bool is_valid(ExtentsType const &e) { - - static_assert(is_extents_v, "boost::numeric::ublas::is_valid() : invalid type, type should be an extents"); - - auto greater_than_zero = [](auto const& a){ return a > 0u; }; - - if( e.size() == 1u ) return e[0] == 1u; - return !e.empty() && std::all_of(e.begin(), e.end(), greater_than_zero ); -} - -/** @brief Returns true if size > 1 and all elements > 0 or size == 1 && e[0] == 1 */ -template -[[nodiscard]] inline -constexpr bool is_valid( [[maybe_unused]] basic_static_extents const &e) noexcept { - constexpr auto sz = sizeof...(Es); - /// if number of extents is 1 then extents at 0th pos should be 1 - /// else if number of extents is greater than 1 then all the extents - /// should be greater than 0 - /// else return false - return ( ( sz == 1ul ) && ( ( T(1) == Es ) && ... ) ) || - ( ( sz > 1ul ) && ( ( T(0) < Es ) && ... ) ); -} - -/** - * @code static_extents<4,1,2,3,4> s; - * std::cout< -[[nodiscard]] inline -std::string to_string(T const &e) { - - using value_type = typename T::value_type; - - static_assert(is_extents_v ||is_strides_v, - "boost::numeric::ublas::to_string() : invalid type, type should be an extents or a strides"); - - if ( e.empty() ) return "[]"; - - std::stringstream ss; - - ss << "[ "; - - std::copy( e.begin(), e.end() - 1, std::ostream_iterator(ss,", ") ); - - ss << e.back() << " ]"; - - return ss.str(); -} - -/** @brief Returns true if this has a scalar shape - * - * @returns true if (1,1,[1,...,1]) - */ -template -[[nodiscard]] inline -constexpr bool is_scalar(ExtentsType const &e) { - - static_assert(is_extents_v, "boost::numeric::ublas::is_scalar() : invalid type, type should be an extents"); - - auto equal_one = [](auto const &a) { return a == 1u; }; - - return !e.empty() && std::all_of(e.begin(), e.end(), equal_one); -} - -/** @brief Returns true if this has a scalar shape - * - * @returns true if (1,1,[1,...,1]) - */ -template -[[nodiscard]] inline -constexpr bool is_scalar( [[maybe_unused]] basic_static_extents const &e) noexcept { - constexpr auto sz = sizeof...(Es); - /// if number of extents is greater than 1 then all the extents should be 1 - /// else return false; - return sz && ( ( T(1) == Es ) && ... ); -} - -/** @brief Returns true if this has a vector shape - * - * @returns true if (1,n,[1,...,1]) or (n,1,[1,...,1]) with n > 1 - */ -template -[[nodiscard]] inline -constexpr bool is_vector(ExtentsType const &e) { - - static_assert(is_extents_v, "boost::numeric::ublas::is_vector() : invalid type, type should be an extents"); - - auto greater_one = [](auto const &a) { return a > 1u; }; - auto equal_one = [](auto const &a) { return a == 1u; }; - - if (e.empty()) return false; - if (e.size() == 1u) return e[0] > 1u; - return std::any_of(e.begin(), e.begin() + 2, greater_one) && - std::any_of(e.begin(), e.begin() + 2, equal_one) && - std::all_of(e.begin() + 2, e.end(), equal_one); - -} - -/** @brief Returns true if this has a vector shape - * - * @returns true if (1,n,[1,...,1]) or (n,1,[1,...,1]) with n > 1 - */ -template -[[nodiscard]] inline -constexpr bool is_vector( [[maybe_unused]] basic_static_extents const &e) noexcept { - using extents_type = basic_static_extents; - - if constexpr (sizeof... (Es) == 1ul) return extents_type::at(0) > T(1); - else if constexpr (sizeof... (Es) >= 2ul){ - /// first two elements of the extents cannot be greater than 1 at the - /// same time which xor operation keeps in check - /// example: 0 xor 1 => 1, 1 xor 1 => 0, 1 xor 0 => 1, and 0 xor 0 => 0 - constexpr bool first_two_extents = ( extents_type::at(0) > T(1) ) ^ ( extents_type::at(1) > T(1) ); - - /// poping first two elements from the extents and checking is_scalar - /// basic_static_extents after poping two times becomes - /// basic_static_extents - using extents_after_removing_the_first_element = decltype( detail::pop_front( e ) ); - using extents_after_removing_the_second_element = decltype( detail::pop_front( extents_after_removing_the_first_element{} ) ); - return first_two_extents && - ( extents_after_removing_the_second_element::_size == 0ul || - is_scalar(extents_after_removing_the_second_element{}) - ); - } else return false; -} - -/** @brief Returns true if this has a matrix shape - * - * @returns true if (m,n,[1,...,1]) with m > 1 and n > 1 - */ -template -[[nodiscard]] inline -constexpr bool is_matrix(ExtentsType const &e) { - - static_assert(is_extents_v, "boost::numeric::ublas::is_matrix() : invalid type, type should be an extents"); - - auto greater_one = [](auto const &a) { return a > 1u; }; - auto equal_one = [](auto const &a) { return a == 1u; }; - - return ( e.size() >= 2u ) && std::all_of(e.begin(), e.begin() + 2, greater_one) && - std::all_of(e.begin() + 2, e.end(), equal_one); -} - -/** @brief Returns true if this has a matrix shape - * - * @returns true if (m,n,[1,...,1]) with m > 1 and n > 1 - */ -template -[[nodiscard]] inline -constexpr bool is_matrix( [[maybe_unused]] basic_static_extents const &e) noexcept { - using extents_type = basic_static_extents; - - if constexpr (sizeof... (Es) >= 2ul){ - /// first two elements of the extents should be greater than 1 at the - /// same time and remaing range should be scalar or empty - constexpr bool first_two_extents = ( extents_type::at(0) > T(1) ) && ( extents_type::at(1) > T(1) ); - - /// poping first two elements from the extents and checking is_scalar - /// basic_static_extents after poping two times becomes - /// basic_static_extents - using extents_after_removing_the_first_element = decltype( detail::pop_front( e ) ); - using extents_after_removing_the_second_element = decltype( detail::pop_front( extents_after_removing_the_first_element{} ) ); - return first_two_extents && - ( extents_after_removing_the_second_element::_size == 0ul || - is_scalar(extents_after_removing_the_second_element{}) - ); - } else return false; -} - -/** @brief Returns true if this is has a tensor shape - * - * @returns true if !empty() && !is_scalar() && !is_vector() && !is_matrix() - */ -template -[[nodiscard]] inline -constexpr bool is_tensor(ExtentsType const &e) { - - static_assert(is_extents_v, "boost::numeric::ublas::is_tensor() : invalid type, type should be an extents"); - - auto greater_one = [](auto const &a) { return a > 1u;}; - - return ( e.size() >= 3u ) && std::any_of(e.begin() + 2, e.end(), greater_one); -} - -/** @brief Returns true if this is has a tensor shape - * - * @returns true if !empty() && !is_scalar() && !is_vector() && !is_matrix() - */ -template -[[nodiscard]] inline -constexpr bool is_tensor( [[maybe_unused]] basic_static_extents const &e) noexcept { - if constexpr( sizeof...(Es) >= 3ul ){ - /// poping first two elements from the extents and checking the remaining - /// extent, if any extent is greater than 1 - /// basic_static_extents after poping two times becomes - /// basic_static_extents - using extents_after_removing_the_first_element = decltype( detail::pop_front( e ) ); - using extents_after_removing_the_second_element = decltype( detail::pop_front( extents_after_removing_the_first_element{} ) ); - return detail::any_extents_greater_than_one(extents_after_removing_the_second_element{}); - - } else return false; -} - -/** @brief Eliminates singleton dimensions when size > 2 - * - * squeeze { 1,1} -> { 1,1} - * squeeze { 2,1} -> { 2,1} - * squeeze { 1,2} -> { 1,2} - * - * squeeze {1,2,3} -> { 2,3} - * squeeze {2,1,3} -> { 2,3} - * squeeze {1,3,1} -> { 1,3} - * - * @returns basic_extents with squeezed extents - */ -template -[[nodiscard]] inline -auto squeeze(ExtentsType const &e) { - - static_assert(is_extents_v, "boost::numeric::ublas::squeeze() : invalid type, type should be an extents"); - - return detail::squeeze_impl(e); -} - -/** @brief Returns the product of extents */ -template -[[nodiscard]] inline -constexpr auto product(ExtentsType const &e) { - - static_assert(is_extents_v, "boost::numeric::ublas::product() : invalid type, type should be an extents"); - - if ( e.empty() ) return 0u; - return std::accumulate(e.begin(), e.end(), 1u, std::multiplies<>()) ; -} - -/** @brief Returns the product of static extents at compile-time */ -template -[[nodiscard]] inline -constexpr auto product( [[maybe_unused]] basic_static_extents const &e) noexcept { - if constexpr( sizeof...(Es) == 0 ) return T(0); - else return T( (Es * ...) ); -} - - -template && is_extents_v - , int> = 0 -> -[[nodiscard]] inline -constexpr bool operator==(LExtents const& lhs, RExtents const& rhs) noexcept{ - - static_assert( std::is_same_v, - "boost::numeric::ublas::operator==(LExtents, RExtents) : LHS value type should be same as RHS value type"); - - return ( lhs.size() == rhs.size() ) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); -} - -template && is_extents_v - , int> = 0 -> -[[nodiscard]] inline -constexpr bool operator!=(LExtents const& lhs, RExtents const& rhs) noexcept{ - - static_assert( std::is_same_v, - "boost::numeric::ublas::operator!=(LExtents, RExtents) : LHS value type should be same as RHS value type"); - - return !( lhs == rhs ); -} - -} // namespace boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp b/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp deleted file mode 100644 index a3aa3603d..000000000 --- a/include/boost/numeric/ublas/tensor/fixed_rank_extents.hpp +++ /dev/null @@ -1,248 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#ifndef _BOOST_NUMERIC_UBLAS_TENSOR_FIXED_RANK_EXTENTS_HPP_ -#define _BOOST_NUMERIC_UBLAS_TENSOR_FIXED_RANK_EXTENTS_HPP_ - -#include -#include -#include -#include -#include -#include - -namespace boost::numeric::ublas { - -/** @brief Template class for storing tensor extents for compile time. - * - * @code basic_static_extents<1,2,3,4> t @endcode - * @tparam E parameter pack of extents - * - */ -template -class basic_fixed_rank_extents -{ - -public: - - static constexpr std::size_t const _size = N; - - using base_type = std::array; - using value_type = typename base_type::value_type; - using size_type = typename base_type::size_type; - using reference = typename base_type::reference; - using const_reference = typename base_type::const_reference; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - using const_reverse_iterator = typename base_type::const_reverse_iterator; - - static_assert( std::numeric_limits::is_integer, "Static error in basic_fixed_rank_extents: type must be of type integer."); - static_assert(!std::numeric_limits::is_signed, "Static error in basic_fixed_rank_extents: type must be of type unsigned integer."); - - //@returns the rank of basic_static_extents - [[nodiscard]] - static constexpr size_type size() noexcept { return _size; } - - [[nodiscard]] inline - constexpr const_reference at(size_type k) const{ - return _base.at(k); - } - - [[nodiscard]] inline - constexpr reference at(size_type k){ - return _base.at(k); - } - - [[nodiscard]] inline - constexpr const_reference operator[](size_type k) const noexcept{ - return _base[k]; - } - - [[nodiscard]] inline - constexpr reference operator[](size_type k) noexcept{ - return _base[k]; - } - - constexpr basic_fixed_rank_extents() = default; - - constexpr basic_fixed_rank_extents(basic_fixed_rank_extents const& other) - : _base(other._base) - {} - - constexpr basic_fixed_rank_extents(basic_fixed_rank_extents && other) noexcept - : _base( std::move(other._base) ) - {} - - constexpr basic_fixed_rank_extents& operator=(basic_fixed_rank_extents const& other) - noexcept(std::is_nothrow_swappable_v) - { - basic_fixed_rank_extents temp(other); - swap(*this,temp); - return *this; - } - - constexpr basic_fixed_rank_extents& operator=(basic_fixed_rank_extents && other) - noexcept(std::is_nothrow_swappable_v) - { - swap(*this,other); - return *this; - } - - ~basic_fixed_rank_extents() = default; - - constexpr basic_fixed_rank_extents(std::initializer_list li){ - if( li.size() > _size ){ - throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(std::initializer_list): " - "number of elements in std::initializer_list is greater than the size" - ); - } - - std::copy(li.begin(), li.end(), _base.begin()); - - if ( !is_valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents() : " - "shape tuple is not a valid permutation: has zero elements." - ); - } - } - - constexpr basic_fixed_rank_extents(const_iterator begin, const_iterator end){ - if( std::distance(begin,end) < 0 || static_cast(std::distance(begin,end)) > _size){ - throw std::out_of_range("boost::numeric::ublas::basic_fixed_rank_extents(): initializer list size is greater than the rank"); - } - - std::copy(begin, end, _base.begin()); - - if ( !is_valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents(const_iterator,const_iterator) : " - "shape tuple is not a valid permutation: has zero elements." - ); - } - } - - inline - constexpr void fill( value_type value ){ - _base.fill(value); - } - - template - constexpr basic_fixed_rank_extents(OtherExtents const& e){ - static_assert( is_extents_v, "boost::numeric::ublas::basic_fixed_rank_extents(OtherExtents const&) : " - "OtherExtents should be a valid tensor extents" - ); - - if constexpr( is_static_rank_v< OtherExtents > ){ - static_assert( OtherExtents::_size == _size, - "basic_fixed_rank_extents::basic_fixed_rank_extents(OtherExtents const&) : " - "unequal rank found, rank should be equal" - ); - }else{ - if( e.size() != size() ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents(OtherExtents const&) : " - "unequal rank found, rank should be equal" - ); - } - } - - std::copy_n(e.begin(),_size, _base.begin()); - } - - constexpr basic_fixed_rank_extents(base_type const& data) - : _base(data) - { - if ( !is_valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents(base_type const&) : " - "shape tuple is not a valid permutation: has zero elements." - ); - } - } - - constexpr basic_fixed_rank_extents(base_type&& data) - : _base(std::move(data)) - { - if ( !is_valid(*this) ){ - throw std::length_error("Error in basic_fixed_rank_extents::basic_fixed_rank_extents(base_type &&) : " - "shape tuple is not a valid permutation: has zero elements." - ); - } - } - - /** @brief Returns the std::vector containing extents */ - [[nodiscard]] inline - constexpr base_type const& base() const noexcept{ - return _base; - } - - /** @brief Checks if extents is empty or not - * - * @returns true if rank is 0 else false - * - */ - [[nodiscard]] inline - constexpr bool empty() const noexcept { return _size == size_type{0}; } - - friend void swap(basic_fixed_rank_extents& lhs, basic_fixed_rank_extents& rhs) - noexcept(std::is_nothrow_swappable_v) - { - std::swap(lhs._base , rhs._base ); - } - - [[nodiscard]] inline - constexpr const_pointer data() const noexcept - { - return _base.data(); - } - - [[nodiscard]] inline - constexpr const_iterator - begin() const noexcept - { - return _base.begin(); - } - - [[nodiscard]] inline - constexpr const_iterator - end() const noexcept - { - return _base.end(); - } - - [[nodiscard]] inline - constexpr const_reference back () const - { - return _base.back(); - } - - [[nodiscard]] inline - constexpr const_reverse_iterator - rbegin() const noexcept - { - return _base.rbegin(); - } - - [[nodiscard]] inline - constexpr const_reverse_iterator - rend() const noexcept - { - return _base.rend(); - } - -private: - base_type _base{}; -}; - -} // namespace boost::numeric::ublass - - - -#endif diff --git a/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp b/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp index 952f6e29e..011a4c64c 100644 --- a/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp +++ b/include/boost/numeric/ublas/tensor/fixed_rank_strides.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,11 +12,17 @@ /// \file strides.hpp Definition for the basic_strides template class -#ifndef _BOOST_UBLAS_TENSOR_FIXED_RANK_STRIDES_HPP_ -#define _BOOST_UBLAS_TENSOR_FIXED_RANK_STRIDES_HPP_ -#include -#include +#ifndef BOOST_UBLAS_TENSOR_FIXED_RANK_STRIDES_HPP +#define BOOST_UBLAS_TENSOR_FIXED_RANK_STRIDES_HPP + +#if 0 + +#include "detail/strides_functions.hpp" +#include "extents/extents_static_size.hpp" +#include "layout.hpp" +#include "strides_base.hpp" + namespace boost::numeric::ublas { @@ -25,126 +31,63 @@ namespace boost::numeric::ublas { * Proxy template class of std::array. * */ -template -class basic_fixed_rank_strides +template +class strides,L> : public strides_base,L>> { public: - static constexpr std::size_t const _size = N; - - using layout_type = L; - using base_type = std::array; - using value_type = typename base_type::value_type; - using reference = typename base_type::reference; - using const_reference = typename base_type::const_reference; - using size_type = typename base_type::size_type; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - using const_reverse_iterator = typename base_type::const_reverse_iterator; - - static_assert( std::numeric_limits::is_integer, - "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type integer."); - static_assert(!std::numeric_limits::is_signed, - "Static error in boost::numeric::ublas::basic_fixed_rank_strides: type must be of type unsigned integer."); - static_assert(std::is_same::value || std::is_same::value, - "Static error in boost::numeric::ublas::basic_fixed_rank_strides: layout type must either first or last order"); - - /** @brief Default constructs basic_fixed_rank_strides + using extents_type = extents; + using layout_type = L; + using base_type = typename extents_type::base_type; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; + + + static_assert(std::is_same::value || + std::is_same::value); + /** @brief Default constructs strides with static size * - * @code auto ex = basic_fixed_rank_strides{}; + * @code auto s = strides>{}; */ - constexpr basic_fixed_rank_strides() noexcept = default; + constexpr strides() noexcept = default; - /** @brief Constructs basic_fixed_rank_strides from basic_extents for the first- and last-order storage formats + /** @brief Constructs strides from extents with static size for the first- and last-order storage formats * - * @code auto strides = basic_fixed_rank_strides( basic_extents{2,3,4} ); + * @code auto s = strides>({2,3,4},layout::first_order{}); * */ - template - constexpr basic_fixed_rank_strides(ExtentsType const& s) + constexpr explicit strides(extents_type const& e) + : _base(compute_strides(e)) { - static_assert( is_extents_v, "boost::numeric::ublas::basic_fixed_rank_strides(ExtentsType const&) : " - "ExtentsType is not a tensor extents" - ); - - if constexpr( is_static_rank_v< ExtentsType > ){ - static_assert( ExtentsType::_size == _size, - "boost::numeric::ublas::basic_fixed_rank_strides(ExtentsType const&) : " - "ExentsType size should be equal to the size of basic_fixed_rank_strides" - ); - }else{ - if ( s.size() != size() ){ - throw std::length_error( - "boost::numeric::ublas::basic_fixed_rank_strides(ExtentsType const&) : " - "ExentsType size should be equal to the size of basic_fixed_rank_strides" - ); - } - } - - _base.fill(value_type(1)); - - if( s.empty() ) - return; - - if( !is_valid(s) ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides(ExtentsType const&) : " - "shape is not valid." - ); - - if( is_vector(s) || is_scalar(s) ) - return; - - if( this->size() < 2 ) - throw std::runtime_error("Error in boost::numeric::ublas::basic_fixed_rank_strides(ExtentsType const&) : " - "size of strides must be greater or equal 2." - ); - - - if constexpr (std::is_same::value){ - std::transform(s.begin(), s.end() - 1, _base.begin(), _base.begin() + 1, std::multiplies{}); - }else { - std::transform(s.rbegin(), s.rend() - 1, _base.rbegin(), _base.rbegin() + 1, std::multiplies{}); - } - } - - constexpr basic_fixed_rank_strides(basic_fixed_rank_strides const& l) + } + + constexpr strides(strides const& l) : _base(l._base) {} - constexpr basic_fixed_rank_strides(basic_fixed_rank_strides && l ) noexcept + constexpr strides(strides && l ) noexcept : _base(std::move(l._base)) {} - constexpr basic_fixed_rank_strides(base_type const& l ) - : _base(l) - {} + ~strides() = default; - constexpr basic_fixed_rank_strides(base_type && l ) - : _base(std::move(l)) - {} - - ~basic_fixed_rank_strides() = default; - - - basic_fixed_rank_strides& operator=(basic_fixed_rank_strides const& other) - noexcept(std::is_nothrow_swappable_v) - { - basic_fixed_rank_strides temp(other); - swap (*this, temp); - return *this; - } - basic_fixed_rank_strides& operator=(basic_fixed_rank_strides && other) + strides& operator=(strides other) noexcept(std::is_nothrow_swappable_v) { swap (*this, other); return *this; } - friend void swap(basic_fixed_rank_strides& lhs, basic_fixed_rank_strides& rhs) + friend void swap(strides& lhs, strides& rhs) noexcept(std::is_nothrow_swappable_v) { - std::swap(lhs._base , rhs._base); + std::swap(lhs._base,rhs._base); } [[nodiscard]] inline @@ -191,7 +134,7 @@ class basic_fixed_rank_strides constexpr const_iterator end() const noexcept{ return _base.end(); } - + [[nodiscard]] inline constexpr base_type const& base() const noexcept{ return this->_base; @@ -212,10 +155,41 @@ class basic_fixed_rank_strides } private: - base_type _base; + base_type _base; + static constexpr std::size_t const _size = N; + + + [[nodiscard]] inline auto compute_strides( extents_type const& e) + { + using base_type = typename extents_type::base_type; + namespace ub = boost::numeric::ublas; + auto init = [](std::index_sequence){ return base_type{is...}; }; + + auto s = init(std::make_index_sequence{}); + + if (std::tuple_size_v == 0UL) + return s; + if (ub::is_vector(e) || ub::is_scalar(e)) + return s; + + if constexpr(std::is_same_v){ + std::transform(ub::begin(e), ub::end(e) - 1, s.begin(), s.begin() + 1, std::multiplies<>{}); + } + else { + std::transform(ub::rbegin(e), ub::rbegin(e) - 1, s.rbegin(), s.rbegin() + 1, std::multiplies<>{}); + } + + return s; + } }; -} // namespace boost::numeric::ublass +template struct is_strides ,L>> : std::true_type {}; +template struct is_dynamic ,L>> : std::true_type {}; +template struct is_static_rank ,L>> : std::true_type {}; + +} // namespace boost::numeric::ublas + +#endif #endif diff --git a/include/boost/numeric/ublas/tensor/function/conj.hpp b/include/boost/numeric/ublas/tensor/function/conj.hpp new file mode 100644 index 000000000..d30d08385 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/conj.hpp @@ -0,0 +1,81 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2020, Amit Singh, amitsingh19975@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_CONJ_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_CONJ_HPP + +#include +#include +#include + + +#include "../extents/extents_functions.hpp" +#include "../traits/basic_type_traits.hpp" +#include "../expression.hpp" +#include "../expression_evaluation.hpp" + +namespace boost::numeric::ublas +{ +template +class tensor_core; + +template +struct tensor_engine; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas +{ +/** @brief Computes the complex conjugate component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ +template::value_type>, int > = 0 + > +auto conj(detail::tensor_expression< tensor_core, D > const& expr) +{ + return detail::make_unary_tensor_expression< tensor_core > (expr(), [] (auto const& l) { return std::conj( l ); } ); +} + +/** @brief Computes the complex conjugate component of tensor elements within a tensor expression + * + * @param[in] expr tensor expression + * @returns complex tensor + */ +template +auto conj(detail::tensor_expression const& expr) +{ + using tensor_type = T; + using value_type = typename tensor_type::value_type; + using complex_type = std::complex; + using layout_type = typename tensor_type::layout_type; + using container_type = typename tensor_type::container_type; + using extents_type = typename tensor_type::extents_type; + using return_container_type = typename container_traits::template rebind; + using return_tensor_type = tensor_core>; + + if( ublas::empty( detail::retrieve_extents( expr ) ) ){ + throw std::runtime_error("error in boost::numeric::ublas::conj: tensors should not be empty."); + } + + auto a = tensor_type( expr ); + auto c = return_tensor_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::conj(l) ; } ); + + return c; +} + + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_PROD_DYNAMIC_HPP diff --git a/include/boost/numeric/ublas/tensor/function/imag.hpp b/include/boost/numeric/ublas/tensor/function/imag.hpp new file mode 100644 index 000000000..0058cb188 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/imag.hpp @@ -0,0 +1,82 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2020, Amit Singh, amitsingh19975@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_IMAG_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_IMAG_HPP + +#include +#include +#include + + +#include "../extents/extents_functions.hpp" +#include "../traits/basic_type_traits.hpp" +#include "../expression.hpp" +#include "../expression_evaluation.hpp" + +namespace boost::numeric::ublas +{ +template +class tensor_core; + +template +struct tensor_engine; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas +{ + +/** @brief Extract the imaginary component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ +template +auto imag(detail::tensor_expression const& lhs) { + return detail::make_unary_tensor_expression (lhs(), [] (auto const& l) { return std::imag( l ); } ); +} + + +/** @brief Extract the imag component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ +template::value_type>, int > = 0 + > +auto imag(detail::tensor_expression< tensor_core< TE > ,D> const& expr) +{ + using tensor_type = tensor_core< TE >; + using complex_type = typename tensor_type::value_type; + using value_type = typename complex_type::value_type; + using layout_type = typename tensor_type::layout_type; + using container_type = typename tensor_type::container_type; + using extents_type = typename tensor_type::extents_type; + using return_container_type = typename container_traits::template rebind; + + using return_tensor_type = tensor_core>; + + if( ublas::empty( detail::retrieve_extents( expr ) ) ){ + throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); + } + + auto a = tensor_type( expr ); + auto c = return_tensor_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::imag(l) ; } ); + + return c; +} + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_PROD_DYNAMIC_HPP diff --git a/include/boost/numeric/ublas/tensor/function/init.hpp b/include/boost/numeric/ublas/tensor/function/init.hpp new file mode 100644 index 000000000..3a19c3507 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/init.hpp @@ -0,0 +1,120 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_FUNCTIONS_INIT_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_FUNCTIONS_INIT_HPP + +#include "../extents.hpp" +#include "../tensor.hpp" +#include "../concepts.hpp" + +//#include + + +namespace boost::numeric::ublas +{ + +template +struct init +{ + using container = std::vector; + using tensor = tensor_core, L, container>>; + + inline auto operator()(extents<> const& e) const + { + auto p = ublas::product(e); + return tensor(e,container(p,V{n})); + } + + + template + inline auto operator()(Ns ... ns) const + { + auto p = ( std::size_t(1) * ... * std::size_t(ns) ); + return tensor(extents<>{std::size_t(ns)...},container(p,V{n})); + } +}; + +template +using ones = init; + +template +using zeros = init; + + + +template +struct init_static_rank +{ + using container = std::vector; + + template + inline auto operator()(extents const& e) const + { + auto p = ublas::product(e); + using tensor = tensor_core, L, container>>; + + return tensor(e, container(p,V{k})); + } + + + template + inline auto operator()(Ns ... ns) const + { + constexpr auto n = sizeof...(ns); + auto p = ( std::size_t(1) * ... * std::size_t(ns) ); + using tensor = tensor_core, L, container>>; + + return tensor(extents{std::size_t(ns)...}, container(p,V{k})); + } +}; + +template +using ones_static_rank = init_static_rank; + +template +using zeros_static_rank = init_static_rank; + + +template +struct init_static +{ + template + struct inner; + + template + struct inner> + { + static constexpr auto n = sizeof...(is); + // NOLINTNEXTLINE(bugprone-integer-division) + static constexpr auto value = std::array{ V(k*(is+1)/(is+1)) ... }; + }; + + template + constexpr inline auto operator()(extents const& /**/) const + { + using extents_type = extents; + constexpr auto p = product_v; + constexpr auto c = inner>::value; + using tensor = tensor_core>>; + return tensor(c); + } +}; + + +template +using ones_static = init_static; + +template +using zeros_static = init_static; + + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_FUNCTIONS_ONES_HPP diff --git a/include/boost/numeric/ublas/tensor/function/inner_prod.hpp b/include/boost/numeric/ublas/tensor/function/inner_prod.hpp new file mode 100644 index 000000000..e82e2d10d --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/inner_prod.hpp @@ -0,0 +1,68 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2020, Amit Singh, amitsingh19975@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_INNER_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_INNER_HPP + +#include +#include + +#include "../extents.hpp" +#include "../multiplication.hpp" + + +namespace boost::numeric::ublas +{ +template +class tensor_core; +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas +{ + +/** @brief Computes the inner product of two tensors * + * Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,jp]) + * + * @note calls inner function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns a value type. + */ +template +inline decltype(auto) inner_prod(tensor_core< TE1 > const &a, tensor_core< TE2 > const &b) +{ + using value_type = typename tensor_core< TE1 >::value_type; + + static_assert( + std::is_same_v::value_type>, + "error in boost::numeric::ublas::inner_prod(tensor_core< TE1 > const&, tensor_core< TensorEngine2 > const&): " + "Both the tensor should have the same value_type" + ); + + if (a.rank() != b.rank()) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Rank of both the tensors must be the same."); + + if (a.empty() || b.empty()) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensors should not be empty."); + + //if (a.extents() != b.extents()) + if (::operator!=(a.extents(),b.extents())) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensor extents should be the same."); + + return inner(a.rank(), a.extents().data(), + a.data(), a.strides().data(), + b.data(), b.strides().data(), value_type{0}); +} + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_PROD_DYNAMIC_HPP diff --git a/include/boost/numeric/ublas/tensor/function/norm.hpp b/include/boost/numeric/ublas/tensor/function/norm.hpp new file mode 100644 index 000000000..7f4922f49 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/norm.hpp @@ -0,0 +1,60 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2020, Amit Singh, amitsingh19975@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_NORM_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_NORM_HPP + +#include +#include +#include + + +#include "../traits/basic_type_traits.hpp" + +namespace boost::numeric::ublas +{ +template +class tensor_core; +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas +{ + +/** + * + * @brief Computes the frobenius nor of a tensor + * + * @note Calls accumulate on the tensor. + * + * implements + * k = sqrt( sum_(i1,...,ip) A(i1,...,ip)^2 ) + * + * @tparam V the data type of tensor + * @tparam F the format of tensor storage + * @tparam A the array_type of tensor + * @param a the tensor whose norm is expected of rank p. + * @return the frobenius norm of a tensor. + */ +template +inline auto norm(tensor_core< TE > const &a) +{ + using value_type = typename tensor_core< TE >::value_type; + + if (a.empty()) { + throw std::runtime_error("Error in boost::numeric::ublas::norm: tensors should not be empty."); + } + + return std::sqrt(accumulate(a.order(), a.extents().data(), a.data(), a.strides().data(), value_type{}, + [](auto const &l, auto const &r) { return l + r * r; })); +} + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_NORM_HPP diff --git a/include/boost/numeric/ublas/tensor/function/outer_prod.hpp b/include/boost/numeric/ublas/tensor/function/outer_prod.hpp new file mode 100644 index 000000000..2adb6fef7 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/outer_prod.hpp @@ -0,0 +1,283 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2020, Amit Singh, amitsingh19975@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_OUTER_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_OUTER_HPP + +#include +#include + +#include "../extents.hpp" +#include "../multiplication.hpp" +#include "../type_traits.hpp" +#include "../tags.hpp" + + +namespace boost::numeric::ublas +{ + +template +struct tensor_engine; + +template +class tensor_core; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas +{ + + +namespace detail{ +/** Enables if E1 or E1 is dynamic extents with static rank + * + * extents< > & extents + * extents & extents< > + * extents< > & extents< > + * + */ +template< + class TEA, + class TEB, + class EA = typename tensor_core::extents_type, + class EB = typename tensor_core::extents_type + > +using enable_outer_if_one_extents_has_dynamic_rank = std::enable_if_t< + ( is_dynamic_rank_v || is_dynamic_rank_v) && + (!is_static_v || !is_static_v ) , bool >; + +} // namespace detail + +/** @brief Computes the outer product of two tensors + * + * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] + * + * @note calls outer function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns tensor object C with the same storage format F and allocator type A1 + */ +template = true > +inline auto outer_prod( tensor_core< TEA > const &a, tensor_core< TEB > const &b) +{ + using tensorA = tensor_core< TEA >; + using tensorB = tensor_core< TEB >; + using valueA = typename tensorA::value_type; + using extentsA = typename tensorA::extents_type; + + using valueB = typename tensorB::value_type; + using extentsB = typename tensorB::extents_type; + + using tensorC = std::conditional_t < is_dynamic_rank_v, tensorA, tensorB>; +// using valueC = typename tensorC::value_type; + using extentsC = typename tensorC::extents_type; + + static_assert( std::is_same_v ); + static_assert( is_dynamic_rank_v || is_dynamic_rank_v); + + if (a.empty() || b.empty()){ + throw std::runtime_error("Error in boost::numeric::ublas::outer_prod: tensors should not be empty."); + } + + auto const& na = a.extents(); + auto const& nb = b.extents(); + + auto nc_base = typename extentsC::base_type(ublas::size(na)+ublas::size(nb)); + auto nci = std::copy(ublas::begin(na),ublas::end(na), std::begin(nc_base)); + std::copy(ublas::begin(nb),ublas::end(nb), nci); + auto nc = extentsC(nc_base); + + auto c = tensorC( nc, valueA{} ); + + outer(c.data(), c.rank(), nc.data(), c.strides().data(), + a.data(), a.rank(), na.data(), a.strides().data(), + b.data(), b.rank(), nb.data(), b.strides().data()); + + return c; +} + + +namespace detail{ +/** Enables if extents E1, E1 + * + * both are dynamic extents with static rank + * + * extents & extents + * + */ +template< + class TEA, + class TEB, + class E1 = typename tensor_core::extents_type, + class E2 = typename tensor_core::extents_type + > +using enable_outer_if_both_extents_have_static_rank = std::enable_if_t< + ( is_static_rank_v && is_dynamic_v) && + ( is_static_rank_v && is_dynamic_v) , bool >; +} // namespace detail + +/** @brief Computes the outer product of two tensors + * + * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] + * + * @note calls outer function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns tensor object C with the same storage format F and allocator type A1 + */ +template = true > +inline auto outer_prod(tensor_core const &a, tensor_core const &b) +{ + using tensorA = tensor_core; + using valueA = typename tensorA::value_type; + using layoutA = typename tensorA::layout_type; + using extentsA = typename tensorA::extents_type; + using containerA = typename tensorA::container_type; + using resizableA_tag = typename tensorA::resizable_tag; + + using tensorB = tensor_core; + using valueB = typename tensorB::value_type; +// using layoutB = typename tensorB::layout_type; + using extentsB = typename tensorB::extents_type; + using resizableB_tag = typename tensorB::resizable_tag; + + static_assert(std::is_same_v); + static_assert(is_static_rank_v || is_static_rank_v); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + + if (a.empty() || b.empty()) + throw std::runtime_error("error in boost::numeric::ublas::outer_prod: tensors should not be empty."); + + auto const& na = a.extents(); + auto const& nb = b.extents(); + + constexpr auto sizeA = std::tuple_size_v; + constexpr auto sizeB = std::tuple_size_v; + + using extentsC = extents; + using tensorC = tensor_core>; + + auto nc_base = typename extentsC::base_type{}; + auto nci = std::copy(ublas::begin(na), ublas::end(na), std::begin(nc_base)); + std::copy(ublas::begin(nb),ublas::end(nb), nci); + auto nc = extentsC( nc_base ); + + auto c = tensorC( nc ); + + outer(c.data(), c.rank(), nc.data(), c.strides().data(), + a.data(), a.rank(), na.data(), a.strides().data(), + b.data(), b.rank(), nb.data(), b.strides().data()); + + return c; +} + + +namespace detail { + +// concat two static_stride_list togather +// @code using type = typename concat< static_stride_list, static_stride_list >::type @endcode +template +struct concat; + +template +struct concat< basic_static_extents, basic_static_extents > { + using type = basic_static_extents; +}; + +template +using concat_t = typename concat::type; + +} // namespace detail + +namespace detail { +/** Enables if extents E1, E1 + * + * both are dynamic extents with static rank + * + * extents & extents + * + */ +template< + class TEA, + class TEB, + class E1 = typename tensor_core::extents_type, + class E2 = typename tensor_core::extents_type + > +using enable_outer_if_both_extents_are_static = std::enable_if_t< + ( is_static_v && is_static_v) , bool>; + +} // namespace detail +/** @brief Computes the outer product of two tensors + * + * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] + * + * @note calls outer function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns tensor object C with the same storage format F and allocator type A1 + */ +template = true > +inline decltype(auto) outer_prod(tensor_core const &a, tensor_core const &b) +{ + using tensorA = tensor_core; + using valueA = typename tensorA::value_type; + using layoutA = typename tensorA::layout_type; + using extentsA = typename tensorA::extents_type; + using arrayA = typename tensorA::array_type; +// using resizableA_tag = typename tensorA::resizable_tag; + + using tensorB = tensor_core; + using valueB = typename tensorB::value_type; +// using layoutB = typename tensorB::layout_type; + using extentsB = typename tensorB::extents_type; +// using resizableB_tag = typename tensorB::resizable_tag; + + using extentsC = ublas::cat_t;// detail::concat_t; + using layoutC = layoutA; + using valueC = valueA; + using storageC = rebind_storage_size_t; + using tensorC = tensor_core>; + + static_assert(std::is_same_v); + static_assert(is_static_v || is_static_v); + + constexpr auto extentsA_size = std::tuple_size_v; + constexpr auto extentsB_size = std::tuple_size_v; + + + if (a.empty() || b.empty()) + throw std::runtime_error("error in boost::numeric::ublas::outer_prod: tensors should not be empty."); + + auto nc = extentsC{}; + + auto const& na = a.extents(); + auto const& nb = b.extents(); + + auto c = tensorC(valueC{}); + + outer(c.data(), c.rank(), data(nc), c.getStrides().data(), + a.data(), a.rank(), data(na), a.getStrides().data(), + b.data(), b.rank(), data(nb), b.getStrides().data()); + + return c; +} + + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_PROD_DYNAMIC_HPP diff --git a/include/boost/numeric/ublas/tensor/function/real.hpp b/include/boost/numeric/ublas/tensor/function/real.hpp new file mode 100644 index 000000000..302637776 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/real.hpp @@ -0,0 +1,80 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_REAL_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_REAL_HPP + +#include +#include +#include + + +#include "../extents/extents_functions.hpp" +#include "../traits/basic_type_traits.hpp" +#include "../expression.hpp" +#include "../expression_evaluation.hpp" + +namespace boost::numeric::ublas +{ +template +class tensor_core; + +template +struct tensor_engine; +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas +{ + +/** @brief Extract the real component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ +template +auto real(detail::tensor_expression const& expr) { + return detail::make_unary_tensor_expression (expr(), [] (auto const& l) { return std::real( l ); } ); +} + +/** @brief Extract the real component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression + */ +template::value_type>, int > = 0 + > +auto real(detail::tensor_expression< tensor_core< TE > ,D > const& expr) +{ + + using tensor_type = tensor_core< TE >; + using complex_type = typename tensor_type::value_type; + using value_type = typename complex_type::value_type; + using layout_type = typename tensor_type::layout_type; + using container_type = typename tensor_type::container_type; + using extents_type = typename tensor_type::extents_type; + using storage_type = typename container_traits::template rebind; + using return_tensor_engine = tensor_engine; + using return_tensor_type = tensor_core; + + if( ublas::empty ( detail::retrieve_extents( expr ) ) ) + throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); + + auto a = tensor_type( expr ); + auto c = return_tensor_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::real(l) ; } ); + + return c; +} + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_PROD_DYNAMIC_HPP diff --git a/include/boost/numeric/ublas/tensor/function/reshape.hpp b/include/boost/numeric/ublas/tensor/function/reshape.hpp new file mode 100644 index 000000000..d27e59446 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/reshape.hpp @@ -0,0 +1,87 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_RESHAPE_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_RESHAPE_HPP + +#include "../extents.hpp" +#include "../tensor.hpp" + +namespace boost::numeric::ublas{ + +/** Enables prod(ttt) if E1 or E1 is dynamic extents with static rank + * + * extents< > & extents + * extents & extents< > + * extents< > & extents< > + * + */ +template< + class TE, + class E = typename tensor_core< TE >::extents_type + > +using enable_reshape_if_shape_is_dynamic = std::enable_if_t< is_dynamic_v , bool >; + +/** @brief Reshapes the basic_tensor + * + * + * (1) @code auto b = a.reshape(extents{m,n,o}); @endcode or + * (2) @code auto b = a.reshape(extents{m,n,o},4); @endcode + * + * If the size of this smaller than the specified extents than + * default constructed (1) or specified (2) value is appended. + * + * @note rank of the basic_tensor might also change. + * + * @param e extents with which the basic_tensor is reshaped. + * @param v value which is appended if the basic_tensor is enlarged. + */ +template< class E, class D, + enable_reshape_if_shape_is_dynamic = true> +[[nodiscard]] constexpr auto reshape (tensor_core const& t, extents_base const& e, [[maybe_unused]] typename tensor_core::value_type v = {}) +{ + using from_engine_type = E; + using from_tensor_type = tensor_core; +// using from_extents_type = typename from_tensor_type::extents_type; + using from_container_type = typename from_tensor_type::container_type; + using from_layout_type = typename from_tensor_type::layout_type; + + using to_extents_type = D; + using to_engine_type = tensor_engine; + using to_tensor_type = tensor_core; + + auto const& efrom = t.extents(); + auto const& eto = e(); + + if( ::operator==(efrom,eto) ) + return t; + + auto const to_size = product(eto); + auto const from_size = product(efrom); + + + auto r = to_tensor_type(eto); + const auto m = std::min(to_size,from_size); + std::copy(t.begin() , t.begin()+m ,r.begin() ); + + if(m < to_size){ + const auto n = to_size - m; + std::fill_n(r.begin()+m,n,v); + } + + return r; +} + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_PROD_COMMON_HPP diff --git a/include/boost/numeric/ublas/tensor/function/tensor_times_matrix.hpp b/include/boost/numeric/ublas/tensor/function/tensor_times_matrix.hpp new file mode 100644 index 000000000..9e5c9acff --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/tensor_times_matrix.hpp @@ -0,0 +1,256 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_TTM_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_TTM_HPP + +#include +#include +#include + +#include "../extents.hpp" +#include "../type_traits.hpp" +#include "../tags.hpp" +#include "../tensor.hpp" + + +/** @brief Computes the m-mode tensor-times-matrix product + * + * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] + * + * @note calls ublas::ttm + * + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * @param[in] m contraction dimension with 1 <= m <= p + * + * @returns tensor object C with order p, the same storage format and allocator type as A + */ + +//namespace boost::numeric::ublas +//{ + +//template +//struct tensor_engine; + +//template +//class tensor_core; + +//template +//class matrix; + +//} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas +{ + +namespace detail { +template< class TE, class E = typename tensor_core::extents_type > +using enable_ttm_if_extent_is_modifiable = std::enable_if_t, bool>; +} // namespace detail + +template ::value_type, + typename L = typename tensor_core::layout_type, + detail::enable_ttm_if_extent_is_modifiable = true > +inline decltype(auto) prod( tensor_core< TE > const &a, matrix const &b, const std::size_t m) +{ + using tensor_type = tensor_core< TE >; + using extents_type = typename tensor_type::extents_type; + using layout_type = typename tensor_type::layout_type; + using resizeable_tag = typename tensor_type::resizable_tag; + + static_assert(std::is_same_v ); + static_assert(is_dynamic_v); + + auto const p = a.rank(); + auto const& na = a.extents(); + auto nb = extents<2>{std::size_t(b.size1()), std::size_t(b.size2())}; + + assert( p != 0 ); + assert( p == ublas::size(na)); + + if( m == 0 ) throw std::length_error("Error in boost::numeric::ublas::ttm: contraction mode must be greater than zero."); + if( p < m ) throw std::length_error("Error in boost::numeric::ublas::ttm: tensor order must be greater than or equal to the specified mode."); + if(na[m-1]!=nb[1]) throw std::invalid_argument("Error in boost::numeric::ublas::ttm: 2nd extent of B and m-th extent of A must be equal."); + + + auto nc_base = na.base(); + auto wb = ublas::to_strides(nb,layout_type{}); + nc_base[m-1] = nb[0]; + auto nc = extents_type(nc_base); + auto c = tensor_type(nc); + + assert( std::equal(begin(na) , begin(na)+m-1, begin(nc) ) ); + assert( std::equal(begin(na)+m, end (na), begin(nc)+m) ); + assert( nc[m-1] == nb[0] ); + + auto const* bb = &(b(0, 0)); + ttm(m, p, + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + bb, nb.data(), wb.data()); + + return c; +} + + +/** @brief Computes the m-mode tensor-times-matrix product + * + * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] + * + * @note calls ublas::ttm + * + * @tparam M contraction dimension with 1 <= M <= p + * @tparam N is a non contracting dimension + * @tparam TE TensorEngine is used for the tensor + * + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p, the same storage format and allocator type as A + */ + +namespace detail { +template< class TE, class E = typename tensor_core< TE >::extents_type > +using enable_ttm_if_extent_is_not_resizable = + std::enable_if_t && is_dynamic_v, bool>; +} // namespace detail + +template ::value_type, + typename L = typename tensor_core< TE >::layout_type, + detail::enable_ttm_if_extent_is_not_resizable> +inline decltype(auto) prod(tensor_core const &a, matrix const &b) +{ + using tensor_type = tensor_core; + using extents_type = typename tensor_type::extents_type; + using layout_type = typename tensor_type::layout_type; + using resizeable_tag = typename tensor_type::resizable_tag; + + static_assert(std::is_same_v ); + static_assert(is_dynamic_v); + + constexpr auto p = std::tuple_size_v; + + auto const& na = a.extents(); + auto nb = extents<2>{std::size_t(b.size1()), std::size_t(b.size2())}; + + static_assert( p != 0 ); + static_assert( p == a.rank()); + static_assert( m != 0); + static_assert( p < m); + + if(na[m-1]!=nb[1]) throw std::invalid_argument("Error in boost::numeric::ublas::ttm: 2nd extent of B and m-th extent of A must be equal."); + + auto nc_base = na.base(); + auto wb = ublas::to_strides(nb,layout_type{}); + + std::get(nc_base) = std::get<0>(nb.base()); + + auto nc = extents_type(nc_base); + auto c = tensor_type(nc); + + assert(std::equal(begin(na) , begin(na)+m-1, begin(nc) )); + assert(std::equal(begin(na)+m, end (na), begin(nc)+m)); + assert(nc[m-1] == nb[0]); + + auto bbdata = &(b(0, 0)); + + auto const& wa = a.strides(); + auto const& wc = c.strides(); + + ttm(m, p, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + bbdata , nb.data(), wb.data()); + + return c; +} + + +//namespace detail { +//template< +// class TEL, +// class TER, +// class EL = typename TEL::extents_type, +// class ER = typename TER::extents_type +// > +//using enable_ttm_if_extent_is_static = +// std::enable_if_t && is_static_v, bool>; +//} // namespace detail + +//template +//inline decltype(auto) prod( tensor_core const& a, tensor_core const &b) +//{ +// using tensorA = tensor_core; +// using extentsA = typename tensorA::extents_type; +// using layout = typename tensorA::layout_type; +// using resizeable_tag = typename tensorA::resizable_tag; + +// static_assert(std::is_same_v ); +// static_assert(is_static_v); + +// constexpr auto p = size_v; + + +// auto const& na = a.extents(); +// auto const& nb = b.extents(); + +// static_assert( p != 0 ); +// static_assert( p == a.rank()); +// static_assert( m != 0); +// static_assert( p < m); + +// static_assert(get_v != get_v); + +// if(na[m-1]!=nb[1]) throw std::invalid_argument("Error in boost::numeric::ublas::ttm: 2nd extent of B and m-th extent of A must be equal."); + +// auto nc_base = na.base(); +// auto wb = ublas::to_strides(nb,layout{}); + +// std::get(nc_base) = std::get<0>(nb.base()); + +// auto nc = extents_type(nc_base); +// auto c = tensor_type(nc); + +// assert(std::equal(na.begin() , na.begin()+m-1, nc.begin())); +// assert(std::equal(na.begin()+m, na.end, nc.begin())); +// assert(nc[m-1] == nb[0]); + +// auto bbdata = &(b(0, 0)); + +// auto const& wa = a.strides(); +// auto const& wc = c.strides(); + +// ttm(m, p, +// c.data(), nc.data(), wc.data(), +// a.data(), na.data(), wa.data(), +// bbdata , nb.data(), wb.data()); + +// return c; +//} + + + +//using value_type = typename tensor_type::value_type; +//using container_type = typename tensor_type::container_type; +//using return_extents_type = std::decay_t; +//using return_container_type = rebind_storage_size_t; +//using return_tensor_type = tensor_core>; + +//auto c = return_tensor_type(value_type{}); + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_NORM_HPP diff --git a/include/boost/numeric/ublas/tensor/function/tensor_times_tensor.hpp b/include/boost/numeric/ublas/tensor/function/tensor_times_tensor.hpp new file mode 100644 index 000000000..aed107711 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/tensor_times_tensor.hpp @@ -0,0 +1,337 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_TTT_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_TTT_HPP + +#include +#include +#include + +#include "../extents.hpp" +#include "../tags.hpp" +#include "../tensor.hpp" +#include "../type_traits.hpp" + + +namespace boost::numeric::ublas +{ + +template +struct tensor_engine; + +template +class tensor_core; + +template +class matrix; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas +{ + +namespace detail +{ +/** Enables prod(ttt) if E1 or E1 is dynamic extents with static rank + * + * extents< > & extents + * extents & extents< > + * extents< > & extents< > + * + */ +template< + class TEA, + class TEB, + class EA = typename tensor_core< TEA >::extents_type, + class EB = typename tensor_core< TEB >::extents_type + > +using enable_ttt_if_one_extents_has_dynamic_rank = std::enable_if_t< + ( is_dynamic_rank_v || is_dynamic_rank_v) && + (!is_static_v || !is_static_v ) , bool >; +} // namespace detail +/** @brief Computes the q-mode tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls ublas::ttt + * + * na[phia[x]] = nb[phib[x]] for 1 <= x <= q + * + * @param[in] a left-hand side tensor with order r+q + * @param[in] b right-hand side tensor with order s+q + * @param[in] phia one-based permutation tuple of length q for the first input tensor a can be of type std::vector or std::array + * @param[in] phib one-based permutation tuple of length q for the second input tensor b can be of type std::vector or std::array + * @result tensor with order r+s + */ +template = true > +inline decltype(auto) prod(tensor_core< TEA > const &a, + tensor_core< TEB > const &b, + std::vector const &phia, + std::vector const &phib) +{ + using tensorA_type = tensor_core< TEA >; + using tensorB_type = tensor_core< TEB >; + using extentsA_type = typename tensorA_type::extents_type; + using extentsB_type = typename tensorB_type::extents_type; + using layoutA_type = typename tensorA_type::layout_type; + using container_type = typename tensorA_type::container_type; + using resizableA_tag = typename tensorA_type::resizable_tag; + using resizableB_tag = typename tensorB_type::resizable_tag; + using valueA_type = typename tensorA_type::value_type; + using valueB_type = typename tensorB_type::value_type; + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + + static_assert(is_dynamic_rank_v || is_dynamic_rank_v); + + + auto const pa = a.rank(); + auto const pb = b.rank(); + + auto const q = std::size_t{phia.size()}; + + if (pa == 0ul) throw std::runtime_error("error in ublas::prod(ttt): order of left-hand side tensor must be greater than 0."); + if (pb == 0ul) throw std::runtime_error("error in ublas::prod(ttt): order of right-hand side tensor must be greater than 0."); + if (pa < q) throw std::runtime_error("error in ublas::prod(ttt): number of contraction dimensions cannot be greater than the order of the left-hand side tensor."); + if (pb < q) throw std::runtime_error("error in ublas::prod(ttt): number of contraction dimensions cannot be greater than the order of the right-hand side tensor."); + if (q != phib.size()) throw std::runtime_error("error in ublas::prod(ttt): permutation tuples must have the same length."); + if (pa < phia.size()) throw std::runtime_error("error in ublas::prod(ttt): permutation tuple for the left-hand side tensor cannot be greater than the corresponding order."); + if (pb < phib.size()) throw std::runtime_error("error in ublas::prod(ttt): permutation tuple for the right-hand side tensor cannot be greater than the corresponding order."); + + auto const &na = a.extents(); + auto const &nb = b.extents(); + + for (auto i = 0ul; i < q; ++i) + if (na.at(phia.at(i) - 1) != nb.at(phib.at(i) - 1)) + throw std::runtime_error("error in ublas::prod: permutations of the extents are not correct."); + + auto const r = pa - q; + auto const s = pb - q; + + auto phia1 = std::vector(pa); + auto phib1 = std::vector(pb); + std::iota(phia1.begin(), phia1.end(), std::size_t(1)); + std::iota(phib1.begin(), phib1.end(), std::size_t(1)); + + using dynamic_extents = std::conditional_t, extentsA_type, extentsB_type>; + using extents_base = typename dynamic_extents::base_type; + auto const size = std::size_t(pa+pb-2*q); + auto nc_base = extents_base (std::max(size,std::size_t{2}),std::size_t{1}); + + //for (auto i = 0ul; i < phia.size(); ++i) + for (auto p : phia) + *std::remove(phia1.begin(), phia1.end(), p) = p; + //phia1.erase( std::remove(phia1.begin(), phia1.end(), phia.at(i)), phia1.end() ) ; + + for (auto i = 0ul; i < r; ++i) + nc_base[i] = na[phia1[i] - 1]; + + //for (auto i = 0ul; i < phib.size(); ++i) + for (auto p : phib) + *std::remove(phib1.begin(), phib1.end(), p) = p; + //phib1.erase( std::remove(phib1.begin(), phib1.end(), phia.at(i)), phib1.end() ) ; + + for (auto i = 0ul; i < s; ++i) + nc_base[r + i] = nb[phib1[i] - 1]; + + assert(phia1.size() == pa); + assert(phib1.size() == pb); + + auto nc = dynamic_extents(nc_base); + + using return_tensor_type = tensor_core>; + auto c = return_tensor_type( nc, valueA_type{} ); + + ttt(pa, pb, q, + phia1.data(), phib1.data(), + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + b.data(), b.extents().data(), b.strides().data()); + + return c; +} + + + +/** @brief Computes the q-mode tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls ublas::ttt + * + * na[phi[x]] = nb[phi[x]] for 1 <= x <= q + * + * @param[in] a left-hand side tensor with order r+q + * @param[in] b right-hand side tensor with order s+q + * @param[in] phi one-based permutation tuple of length q for both input + * tensors can be of type std::vector or std::array + * @result tensor with order r+s + */ +template = true > +inline decltype(auto) prod(tensor_core const &a, + tensor_core const &b, + std::vector const &phi) +{ + return prod(a, b, phi, phi); +} + + + +namespace detail +{ + +/** Enables if extents E1, E1 are dynamic extents with static rank + * + * extents & extents + * + */ +template< + class TE1, + class TE2, + class E1 = typename tensor_core< TE1 >::extents_type, + class E2 = typename tensor_core< TE2 >::extents_type + > +using enable_ttt_if_extents_have_static_rank = std::enable_if_t< + (is_static_rank_v && is_dynamic_v) && + (is_static_rank_v && is_dynamic_v) , bool>; + +} // namespace detail + +/** @brief Computes the q-mode tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls ublas::ttt + * + * na[phia[x]] = nb[phib[x]] for 1 <= x <= q + * + * @param[in] a left-hand side tensor with order r+q + * @param[in] b right-hand side tensor with order s+q + * @param[in] phia one-based permutation tuple of length q for the first input tensor a + * @param[in] phib one-based permutation tuple of length q for the second input tensor b + * @result tensor with order r+s + */ +template = true > +inline auto prod(tensor_core const &a, + tensor_core const &b, + std::array const &phia, + std::array const &phib) +{ + using tensorA_type = tensor_core; + using tensorB_type = tensor_core; + using extentsA_type = typename tensorA_type::extents_type; + using extentsB_type = typename tensorB_type::extents_type; + using valueA_type = typename tensorA_type::value_type; + using valueB_type = typename tensorB_type::value_type; + using layout_type = typename tensorA_type::layout_type; + using container_type = typename tensorA_type::container_type; + using resizeableA_tag = typename tensorA_type::resizable_tag; + using resizeableB_tag = typename tensorB_type::resizable_tag; + + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + + constexpr auto q = Q; + constexpr auto pa = std::tuple_size_v; + constexpr auto pb = std::tuple_size_v; + + static_assert(pa != 0); + static_assert(pb != 0); + static_assert(pa >= q); + static_assert(pb >= q); + +// if (pa < phia.size()) throw std::runtime_error("error in ublas::prod: permutation tuple for the left-hand side tensor cannot be greater than the corresponding order."); +// if (pb < phib.size()) throw std::runtime_error("error in ublas::prod: permutation tuple for the right-hand side tensor cannot be greater than the corresponding order."); + + auto const &na = a.extents(); + auto const &nb = b.extents(); + + for (auto i = 0ul; i < q; ++i) + if (na.at(phia.at(i) - 1) != nb.at(phib.at(i) - 1)) + throw std::runtime_error("error in ublas::prod: permutations of the extents are not correct."); + + constexpr auto r = pa - q; + constexpr auto s = pb - q; + + auto phia1 = std::array{}; + auto phib1 = std::array{}; + std::iota(phia1.begin(), phia1.end(),std::size_t(1)); + std::iota(phib1.begin(), phib1.end(),std::size_t(1)); + + constexpr auto const msz = std::max(std::size_t(r+s), std::size_t(2)); + using return_extents_type = extents; + auto nc_base = std::array{}; + + for (auto i = 0ul; i < phia.size(); ++i) + *std::remove(phia1.begin(), phia1.end(), phia.at(i)) = phia.at(i); + //phia1.erase( std::remove(phia1.begin(), phia1.end(), phia.at(i)), phia1.end() ) ; + + for (auto i = 0ul; i < phib.size(); ++i) + *std::remove(phib1.begin(), phib1.end(), phib.at(i)) = phib.at(i); + //phib1.erase( std::remove(phib1.begin(), phib1.end(), phia.at(i)), phib1.end() ) ; + + for (auto i = 0ul; i < r; ++i) + nc_base[i] = na[phia1[i] - 1]; + + for (auto i = 0ul; i < s; ++i) + nc_base[r+i] = nb[phib1[i] - 1]; + + auto nc = return_extents_type(nc_base); + + using return_tensor_type = tensor_core>; + + auto c = return_tensor_type( nc ); + + ttt(pa, pb, q, + phia1.data(), phib1.data(), + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + b.data(), b.extents().data(), b.strides().data()); + + return c; +} + + +/** @brief Computes the q-mode tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls ublas::ttt + * + * na[phi[x]] = nb[phi[x]] for 1 <= x <= q + * + * @param[in] a left-hand side tensor with order r+q + * @param[in] b right-hand side tensor with order s+q + * @param[in] phi one-based permutation tuple of length q for both input + * tensors can be of type std::vector or std::array + * @result tensor with order r+s + */ +template * = nullptr > +inline decltype(auto) prod(tensor_core const &a, + tensor_core const &b, + std::array const &phi) +{ + return prod(a, b, phi, phi); +} + + + + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_NORM_HPP diff --git a/include/boost/numeric/ublas/tensor/function/tensor_times_vector.hpp b/include/boost/numeric/ublas/tensor/function/tensor_times_vector.hpp new file mode 100644 index 000000000..82c9b3c41 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/tensor_times_vector.hpp @@ -0,0 +1,240 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_TTV_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_TTV_HPP + +#include +#include +#include + +#include "../extents.hpp" +#include "../type_traits.hpp" +#include "../tags.hpp" + +namespace boost::numeric::ublas +{ + + +template +struct tensor_engine; + +template +class tensor_core; + +//template +//class vector; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas +{ + +namespace detail { + +/** Enables if extent E is dynamic with dynamic rank: extents< > */ +template< + class TE, + class E = typename tensor_core::extents_type + > +using enable_ttv_if_extent_has_dynamic_rank = std::enable_if_t, bool>; + +} // namespace detail + + +/** @brief Computes the m-mode tensor-times-vector product + * + * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] + * + * @note calls ublas::ttv + * + * @param[in] m contraction dimension with 1 <= m <= p + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p-1, the same storage format and allocator type as A + */ +template ::value, + detail::enable_ttv_if_extent_has_dynamic_rank = true > +inline decltype(auto) prod( tensor_core< TE > const &a, vector const &b, const std::size_t m) +{ + + using tensor = tensor_core< TE >; + using shape = typename tensor::extents_type; + using value = typename tensor::value_type; + using layout = typename tensor::layout_type; + using resize_tag = typename tensor::resizable_tag; + + auto const p = a.rank(); + + static_assert(std::is_same_v); + static_assert(is_dynamic_v); + + if (m == 0ul) throw std::length_error("error in boost::numeric::ublas::prod(ttv): contraction mode must be greater than zero."); + if (p < m) throw std::length_error("error in boost::numeric::ublas::prod(ttv): rank of tensor must be greater than or equal to the contraction mode."); + if (a.empty()) throw std::length_error("error in boost::numeric::ublas::prod(ttv): first argument tensor should not be empty."); + if (b.empty()) throw std::length_error("error in boost::numeric::ublas::prod(ttv): second argument vector should not be empty."); + + auto const& na = a.extents(); + auto nb = extents<2>{std::size_t(b.size()),std::size_t(1ul)}; + auto wb = ublas::to_strides(nb,layout{} ); + + auto const sz = std::max( std::size_t(ublas::size(na)-1u), std::size_t(2) ); + auto nc_base = typename shape::base_type(sz,1); + + for (auto i = 0ul, j = 0ul; i < p; ++i) + if (i != m - 1) + nc_base[j++] = na.at(i); + + auto nc = shape(nc_base); + + + auto c = tensor( nc, value{} ); + auto const* bb = &(b(0)); + ttv(m, p, + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + bb, nb.data(), wb.data()); + return c; +} + + +namespace detail { +/** Enables if extent E is dynamic with static rank: extents */ +template< + class TE, + class E = typename tensor_core< TE >::extents_type + > +using enable_ttv_if_extent_is_dynamic_with_static_rank = + std::enable_if_t< is_static_rank_v< E > && is_dynamic_v< E >, bool>; + +} // namespace detail + + +/** @brief Computes the m-mode tensor-times-vector product + * + * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] + * + * @note calls ublas::ttv + * + * @param[in] m contraction dimension with 1 <= m <= p + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p-1, the same storage format and allocator type as A + */ +template ::value, + detail::enable_ttv_if_extent_is_dynamic_with_static_rank = true + > +inline auto prod( tensor_core< TE > const &a, vector const &b, const std::size_t m) +{ + using tensor = tensor_core< TE >; + using shape = typename tensor::extents_type; + using container = typename tensor::container_type; + using layout = typename tensor::layout_type; + using resizeable_tag = typename tensor::resizable_tag; + + constexpr auto p = std::tuple_size_v; + constexpr auto sz = std::max(std::size_t(std::tuple_size_v-1U),std::size_t(2)); + + using shape_b = ublas::extents<2>; + using shape_c = ublas::extents; + using tensor_c = tensor_core>; + + static_assert(std::is_same_v); + + if (m == 0ul) throw std::length_error("error in boost::numeric::ublas::prod(ttv): contraction mode must be greater than zero."); + if (p < m) throw std::length_error("error in boost::numeric::ublas::prod(ttv): rank of tensor must be greater than or equal to the modus."); + if (a.empty()) throw std::length_error("error in boost::numeric::ublas::prod(ttv): first argument tensor should not be empty."); + if (b.empty()) throw std::length_error("error in boost::numeric::ublas::prod(ttv): second argument vector should not be empty."); + + auto const& na = a.extents(); + + auto nc_base = typename shape_c::base_type{}; + std::fill(nc_base.begin(), nc_base.end(),std::size_t(1)); + for (auto i = 0ul, j = 0ul; i < p; ++i) + if (i != m - 1) + nc_base[j++] = na.at(i); + + auto nc = shape_c(std::move(nc_base)); + auto nb = shape_b{b.size(),1UL}; + auto wb = ublas::to_strides(nb,layout{}); + auto c = tensor_c( std::move(nc) ); + auto const* bb = &(b(0)); + + ttv(m, p, + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + bb, nb.data(), wb.data() ); + return c; +} + + + +/** @brief Computes the m-mode tensor-times-vector product + * + * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] + * + * @note calls ublas::ttv + * + * @tparam M contraction dimension with 1 <= m <= p + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p-1, the same storage format and allocator type as A + */ + +template ::value> +inline auto prod( tensor_core< TE > const &a, vector const &b) +{ + using tensor = tensor_core< TE >; + using container = typename tensor::container; + using shape = typename tensor::extents; + using layout = typename tensor::layout; + using shape_b = extents<2>; + using shape_c = remove_element_t; + using container_c = rebind_storage_size_t; + using tensor_c = tensor_core>; + + static_assert( m != 0ul ); + static_assert(std::tuple_size_v != 0 ); + static_assert(std::tuple_size_v >= m ); + + constexpr auto p = std::tuple_size_v; + + if (a.empty()) throw std::length_error("error in boost::numeric::ublas::prod(ttv): first argument tensor should not be empty."); + if (b.empty()) throw std::length_error("error in boost::numeric::ublas::prod(ttv): second argument vector should not be empty."); + + auto const& na = a.extents(); + + auto nc = shape_c{}; + auto nb = shape_b{std::size_t(b.size()),std::size_t(1)}; + + auto c = tensor_c{}; + auto const* bb = &(b(0)); + + auto const& wa = a.strides(); + auto const& wc = c.strides(); + auto wb = ublas::to_strides(nb,layout{}); + + ttv(m, p, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + bb, nb.data(), wb.data()); + + return c; +} + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_NORM_HPP diff --git a/include/boost/numeric/ublas/tensor/function/trans.hpp b/include/boost/numeric/ublas/tensor/function/trans.hpp new file mode 100644 index 000000000..e328b4327 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/function/trans.hpp @@ -0,0 +1,78 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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) +// +// + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_TRANS_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_TRANS_HPP + +#include +#include +#include + +#include "../extents.hpp" +#include "../traits/basic_type_traits.hpp" +#include "../multiplication.hpp" + + +namespace boost::numeric::ublas +{ +template +class tensor_core; +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas +{ + +/** @brief Transposes a tensor according to a permutation tuple + * + * Implements C[tau[i1],tau[i2]...,tau[ip]] = A[i1,i2,...,ip] + * + * @note calls trans function + * + * @param[in] a tensor object of rank p + * @param[in] tau one-based permutation tuple of length p + * @returns a transposed tensor object with the same storage format F and allocator type A + */ +template > +inline decltype(auto) trans(tensor_core< TensorEngine > const &a, PermuType const &tau) +{ + + using tensor_type = tensor_core< TensorEngine >; + using extents_type = typename tensor_type::extents_type; + + static_assert( is_dynamic_v< extents_type > ); + + auto const p = a.rank(); + auto const &na = a.extents(); + typename extents_type::base_type nc; + + if constexpr( is_dynamic_rank_v ){ + nc.resize(p); + } + + for (auto i = 0u; i < p; ++i){ + nc.at(tau.at(i) - 1) = na.at(i); + } + + auto c = tensor_type( extents_type( std::move(nc) ) ); + + if (a.empty()){ + return c; + } + + trans(a.rank(), a.extents().data(), tau.data(), + c.data(), c.strides().data(), + a.data(), a.strides().data()); + + return c; +} + +} // namespace boost::numeric::ublas + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_PROD_DYNAMIC_HPP diff --git a/include/boost/numeric/ublas/tensor/functions.hpp b/include/boost/numeric/ublas/tensor/functions.hpp index d77b6a9a4..8029d59a1 100644 --- a/include/boost/numeric/ublas/tensor/functions.hpp +++ b/include/boost/numeric/ublas/tensor/functions.hpp @@ -1,1101 +1,27 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2020, Amit Singh, amitsingh19975@gmail.com // // 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#ifndef _BOOST_UBLAS_TENSOR_FUNCTIONS_HPP_ -#define _BOOST_UBLAS_TENSOR_FUNCTIONS_HPP_ - -#include -#include - -namespace boost::numeric::ublas{ - - template class tensor_core; - -} // namespace boost::numeric::ublas - - -namespace boost::numeric::ublas -{ - namespace detail{ - - template - struct is_complex : std::false_type{}; - - template - struct is_complex< std::complex > : std::true_type{}; - - template - inline static constexpr bool is_complex_v = is_complex::value; - - /// To check if the type is the std::array or not. - /// Can be extented by providing specialization. - /// Point to Remember: C-Style arrays are not supported. - template - struct is_bounded_array : std::false_type{}; - - template - inline static constexpr bool is_bounded_array_v = is_bounded_array::value; - - template - struct is_bounded_array> : std::true_type{}; - - /// Gives the extent of rank one std::array. - /// Similar to is_bounded_array, it can also be - /// extented using specialization. - /// Custom Type should have similar APIs to - /// std::array. - /// Point to Remember: C-Style arrays are not supported. - template - struct extent_of_rank_one_array; - - template - struct extent_of_rank_one_array> - : std::integral_constant - {}; - - template - inline static constexpr bool extent_of_rank_one_array_v = extent_of_rank_one_array::value; - - } // namespace detail - - /** @brief Computes the m-mode tensor-times-vector product - * - * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] - * - * @note calls ublas::ttv - * - * @param[in] m contraction dimension with 1 <= m <= p - * @param[in] a tensor object A with order p - * @param[in] b vector object B - * - * @returns tensor object C with order p-1, the same storage format and allocator type as A - */ - template - inline decltype(auto) prod( tensor_core< TensorEngine > const &a, - vector::value_type, A> const &b, - const std::size_t m) - { - using tensor_type = tensor_core< TensorEngine >; - using extents_type = typename tensor_type::extents_type; - using value_type = typename tensor_type::value_type; - using array_type = typename tensor_type::array_type; - using size_type = typename extents_type::size_type; - using layout_type = typename tensor_type::layout_type; - - auto const p = a.rank(); - - static_assert( - std::is_same_v< - typename tensor_core::resizable_tag, - storage_resizable_container_tag - >, - "error in boost::numeric::ublas::prod(tensor_core const&, vector const& ): " - "tensor container should be resizable" - ); - - static_assert( - is_dynamic_v, - "error in boost::numeric::ublas::prod(tensor_core const&, vector const& ): " - "extents type should be dynamic" - ); - - if (m == 0ul) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttv): " - "contraction mode must be greater than zero."); - - if (p < m) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttv): rank of tensor must be " - "greater than or equal to the modus."); - - if (a.empty()) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttv): first " - "argument tensor should not be empty."); - - if (b.empty()) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttv): second " - "argument vector should not be empty."); - - using extents_value_type = typename extents_type::value_type; - - auto a_extents = a.extents(); - - auto extents_result = [&a_extents](){ - using size_type = typename extents_type::size_type; - if constexpr( is_static_rank_v ){ - // To disable the warning for unused variable; - (void)a_extents; - constexpr size_type esz = extents_type::_size - 1u; - constexpr auto sz = std::max( esz, size_type(2) ); - auto ret = extents< sz >(); - ret.fill(1u); - return ret; - }else{ - using extents_base_type = typename extents_type::base_type; - auto const sz = std::max( a_extents.size() - 1, size_type(2) ); - auto arr = extents_base_type(sz,1); - return extents_type{ std::move(arr) } ; - } - }; - - auto nc = extents_result(); - auto nb = std::vector{b.size(), extents_value_type(1)}; - - for (auto i = size_type(0), j = size_type(0); i < p; ++i) - if (i != m - 1) - nc[j++] = a_extents.at(i); - - using c_extents_type = std::decay_t< decltype(nc) >; - - using t_engine = tensor_engine< - c_extents_type, - layout_type, - strides, - array_type - >; - - auto c = tensor_core( nc, value_type{} ); - auto bb = &(b(0)); - ttv(m, p, - c.data(), c.extents().data(), c.strides().data(), - a.data(), a.extents().data(), a.strides().data(), - bb, nb.data(), nb.data()); - return c; - } - - /** @brief Computes the m-mode tensor-times-matrix product - * - * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] - * - * @note calls ublas::ttm - * - * @param[in] a tensor object A with order p - * @param[in] b vector object B - * @param[in] m contraction dimension with 1 <= m <= p - * - * @returns tensor object C with order p, the same storage format and allocator type as A - */ - template - inline decltype(auto) prod( tensor_core< TensorEngine > const &a, - matrix::value_type, typename tensor_core< TensorEngine >::layout_type , A> const &b, - const std::size_t m) - { - - using tensor_type = tensor_core< TensorEngine >; - using extents_type = typename tensor_type::extents_type; - using value_type = typename tensor_type::value_type; - using layout_type = typename tensor_type::layout_type; - using array_type = typename tensor_type::array_type; - using dynamic_strides_type = basic_strides; - - - static_assert( - std::is_same_v< - typename tensor_core::resizable_tag, - storage_resizable_container_tag - >, - "error in boost::numeric::ublas::prod(tensor_core const&, matrix const& ): " - "tensor container should be resizable" - ); - - static_assert( - is_dynamic_v, - "error in boost::numeric::ublas::prod(tensor_core const&, matrix const& ): " - "extents type should be dynamic" - ); - - auto const p = a.rank(); - - if (m == 0ul) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttm): " - "contraction mode must be greater than zero."); - - if (p < m || m > a.extents().size()) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttm): rank " - "of the tensor must be greater equal the modus."); - - if (a.empty()) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttm): first " - "argument tensor should not be empty."); - - if (b.size1() * b.size2() == 0ul) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttm): second " - "argument matrix should not be empty."); - - auto nc = a.extents(); - auto nb = extents<>{b.size1(), b.size2()}; - - auto wb = dynamic_strides_type(nb); - - nc[m - 1] = nb[0]; - - using c_extents_type = std::decay_t< decltype(nc) >; - - using t_engine = tensor_engine< - c_extents_type, - layout_type, - strides, - array_type - >; - - auto c = tensor_core(nc, value_type{}); - - auto bb = &(b(0, 0)); - ttm(m, p, - c.data(), c.extents().data(), c.strides().data(), - a.data(), a.extents().data(), a.strides().data(), - bb, nb.data(), wb.data()); - - return c; - } - - /** @brief Computes the q-mode tensor-times-tensor product - * - * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) - * - * @note calls ublas::ttt - * - * na[phia[x]] = nb[phib[x]] for 1 <= x <= q - * - * @param[in] a left-hand side tensor with order r+q - * @param[in] b right-hand side tensor with order s+q - * @param[in] phia one-based permutation tuple of length q for the first - * input tensor a can be of type std::vector or std::array - * @param[in] phib one-based permutation tuple of length q for the second - * input tensor b can be of type std::vector or std::array - * @result tensor with order r+s - */ - template , - std::enable_if_t< - !( is_static_v::extents_type> || - is_static_v::extents_type> ) - ,int> = 0 - > - inline decltype(auto) prod(tensor_core< TensorEngine1 > const &a, tensor_core< TensorEngine2 > const &b, - PermuType const &phia, PermuType const &phib) - { - using tensor_type = tensor_core< TensorEngine1 >; - using extents_type = typename tensor_type::extents_type; - using value_type = typename tensor_type::value_type; - using layout_type = typename tensor_type::layout_type; - using extents_size_type = typename extents_type::size_type; - using array_type = typename tensor_type::array_type; - - static_assert( - std::is_same_v< - typename tensor_core::resizable_tag, - typename tensor_core::resizable_tag - > && - std::is_same_v< - typename tensor_core::resizable_tag, - storage_resizable_container_tag - >, - "error in boost::numeric::ublas::prod(tensor_core const&, tensor_core const&, " - "PermuType const&, PermuType const& ): " - "Both the tensor storage should have the same type of storage and both should be resizable" - ); - - static_assert( - std::is_same_v::value_type>, - "error in boost::numeric::ublas::prod(tensor_core< TensorEngine1 > const&, tensor_core< TensorEngine2 > const&, " - "PermuType const&, PermuType const&): " - "Both the tensor should have the same value_type" - ); - - auto const pa = a.rank(); - auto const pb = b.rank(); - - auto const q = static_cast(phia.size()); - - if (pa == 0ul) - throw std::runtime_error("error in ublas::prod: order of left-hand side tensor must be greater than 0."); - if (pb == 0ul) - throw std::runtime_error("error in ublas::prod: order of right-hand side tensor must be greater than 0."); - if (pa < q) - throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the left-hand side tensor."); - if (pb < q) - throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the right-hand side tensor."); - - if (q != phib.size()) - throw std::runtime_error("error in ublas::prod: permutation tuples must have the same length."); - - if (pa < phia.size()) - throw std::runtime_error("error in ublas::prod: permutation tuple for the left-hand side tensor cannot be greater than the corresponding order."); - if (pb < phib.size()) - throw std::runtime_error("error in ublas::prod: permutation tuple for the right-hand side tensor cannot be greater than the corresponding order."); - - auto const &na = a.extents(); - auto const &nb = b.extents(); - - for (auto i = 0ul; i < q; ++i) - if (na.at(phia.at(i) - 1) != nb.at(phib.at(i) - 1)) - throw std::runtime_error("error in ublas::prod: permutations of the extents are not correct."); - - std::size_t const r = pa - q; - std::size_t const s = pb - q; - - std::vector phia1(pa); - std::vector phib1(pb); - std::iota(phia1.begin(), phia1.end(), 1ul); - std::iota(phib1.begin(), phib1.end(), 1ul); - - auto extents_result = [&e1 = na, &e2 = nb, &a1 = phia, &a2 = phib](){ - using lextents_type = std::decay_t< decltype(e1) >; - using rextents_type = std::decay_t< decltype(e2) >; - using array_type = std::decay_t< decltype(a1) >; - if constexpr( - detail::is_bounded_array_v && - is_static_rank_v && - is_static_rank_v - ){ - constexpr auto const N = detail::extent_of_rank_one_array_v; - constexpr auto const sz = lextents_type::_size + rextents_type::_size - 2 * N; - auto res = extents(); - res.fill(1u); - return res; - }else{ - extents_size_type const size = ( e1.size() + e2.size() ) - ( a1.size() + a2.size() ); - using extents_base_type = typename extents<>::base_type; - auto arr = extents_base_type( std::max(size, extents_size_type(2)), 1u ); - return extents<>(std::move(arr)); - } - }; - - auto nc = extents_result(); - - for (auto i = 0ul; i < phia.size(); ++i) - *std::remove(phia1.begin(), phia1.end(), phia.at(i)) = phia.at(i); - - //phia1.erase( std::remove(phia1.begin(), phia1.end(), phia.at(i)), phia1.end() ) ; - - for (auto i = 0ul; i < r; ++i) - nc[i] = na[phia1[i] - 1]; - - for (auto i = 0ul; i < phib.size(); ++i) - *std::remove(phib1.begin(), phib1.end(), phib.at(i)) = phib.at(i); - //phib1.erase( std::remove(phib1.begin(), phib1.end(), phia.at(i)), phib1.end() ) ; - - for (auto i = 0ul; i < s; ++i) - nc[r + i] = nb[phib1[i] - 1]; - - // std::copy( phib.begin(), phib.end(), phib1.end() ); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(phia1.size() == pa); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(phib1.size() == pb); - - using c_extents_type = std::decay_t< decltype(nc) >; - - using t_engine = tensor_engine< - c_extents_type, - layout_type, - strides, - array_type - >; - - auto c = tensor_core( nc, value_type{} ); - - ttt(pa, pb, q, - phia1.data(), phib1.data(), - c.data(), c.extents().data(), c.strides().data(), - a.data(), a.extents().data(), a.strides().data(), - b.data(), b.extents().data(), b.strides().data()); - - return c; - } - - // template - // auto operator*( tensor_index const& lhs, tensor_index - // const& rhs) - - /** @brief Computes the q-mode tensor-times-tensor product - * - * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) - * - * @note calls ublas::ttt - * - * na[phi[x]] = nb[phi[x]] for 1 <= x <= q - * - * @param[in] a left-hand side tensor with order r+q - * @param[in] b right-hand side tensor with order s+q - * @param[in] phi one-based permutation tuple of length q for bot input - * tensors can be of type std::vector or std::array - * @result tensor with order r+s - */ - template > - inline decltype(auto) prod( - tensor_core< TensorEngine1 > const &a, - tensor_core< TensorEngine2 > const &b, - PermuType const &phi) - { - return prod(a, b, phi, phi); - } - - /** @brief Computes the inner product of two tensors * - * Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,jp]) - * - * @note calls inner function - * - * @param[in] a tensor object A - * @param[in] b tensor object B - * - * @returns a value type. - */ - template - inline decltype(auto) inner_prod(tensor_core< TensorEngine1 > const &a, tensor_core< TensorEngine2 > const &b) - { - - - using value_type = typename tensor_core< TensorEngine1 >::value_type; - - static_assert( - std::is_same_v::value_type>, - "error in boost::numeric::ublas::inner_prod(tensor_core< TensorEngine1 > const&, tensor_core< TensorEngine2 > const&): " - "Both the tensor should have the same value_type" - ); - - if (a.rank() != b.rank()) - throw std::length_error("error in boost::numeric::ublas::inner_prod: Rank of both the tensors must be the same."); - - if (a.empty() || b.empty()) - throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensors should not be empty."); - - if (a.extents() != b.extents()) - throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensor extents should be the same."); - - return inner(a.rank(), a.extents().data(), - a.data(), a.strides().data(), - b.data(), b.strides().data(), value_type{0}); - } - - /** @brief Computes the outer product of two tensors - * - * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] - * - * @note calls outer function - * - * @param[in] a tensor object A - * @param[in] b tensor object B - * - * @returns tensor object C with the same storage format F and allocator type A1 - */ - template ::extents_type> || - is_static_v::extents_type> ) - ,int> = 0 - > - inline decltype(auto) outer_prod(tensor_core< TensorEngine1 > const &a, tensor_core< TensorEngine2 > const &b) - { - using tensor_type = tensor_core< TensorEngine1 >; - using value_type = typename tensor_type::value_type; - using layout_type = typename tensor_type::layout_type; - using array_type = typename tensor_type::array_type; - - static_assert( - std::is_same_v< - typename tensor_core::resizable_tag, - typename tensor_core::resizable_tag - > && - std::is_same_v< - typename tensor_core::resizable_tag, - storage_resizable_container_tag - >, - "error in boost::numeric::ublas::outer_prod(tensor_core const&, tensor_core const&): " - "Both the tensor storage should have the same type of storage and both should be resizable" - ); - - static_assert( - std::is_same_v::value_type>, - "error in boost::numeric::ublas::outer_prod(tensor_core< TensorEngine1 > const&, tensor_core< TensorEngine2 > const&): " - "Both the tensor should have the same value_type" - ); - - if (a.empty() || b.empty()) - throw std::runtime_error( - "error in boost::numeric::ublas::outer_prod: " - "tensors should not be empty."); - - auto extents_result = [&e1 = a.extents(), &e2 = b.extents()](){ - using lextents_type = std::decay_t< decltype(e1) >; - using rextents_type = std::decay_t< decltype(e2) >; - - if constexpr( is_static_rank_v && is_static_rank_v ){ - return extents< lextents_type::_size + rextents_type::_size >{}; - }else { - using extents_base_type = typename extents<>::base_type; - auto arr = extents_base_type( e1.size() + e2.size(), 1 ); - return extents<>{std::move(arr)}; - } - }; - - auto nc = extents_result(); - - auto a_extents = a.extents(); - auto b_extents = b.extents(); - - for(auto i = 0u; i < a.rank(); ++i) - nc.at(i) = a_extents.at(i); - - for(auto i = 0u; i < b.rank(); ++i) - nc.at(a.rank()+i) = b_extents.at(i); - - using c_extents_type = std::decay_t< decltype(nc) >; - - using t_engine = tensor_engine< - c_extents_type, - layout_type, - strides, - array_type - >; - - auto c = tensor_core( nc, value_type{} ); - - outer(c.data(), c.rank(), c.extents().data(), c.strides().data(), - a.data(), a.rank(), a_extents.data(), a.strides().data(), - b.data(), b.rank(), b_extents.data(), b.strides().data()); - - return c; - } - - /** @brief Transposes a tensor according to a permutation tuple - * - * Implements C[tau[i1],tau[i2]...,tau[ip]] = A[i1,i2,...,ip] - * - * @note calls trans function - * - * @param[in] a tensor object of rank p - * @param[in] tau one-based permutation tuple of length p - * @returns a transposed tensor object with the same storage format F and allocator type A - */ - template > - inline decltype(auto) trans(tensor_core< TensorEngine > const &a, PermuType const &tau) - { - - using tensor_type = tensor_core< TensorEngine >; - using layout_type = typename tensor_type::layout_type; - using array_type = typename tensor_type::array_type; - using extents_type = typename tensor_type::extents_type; - - static_assert( - is_dynamic_v< extents_type > , - "error in boost::numeric::ublas::trans(tensor_core< TensorEngine > const &a, " - "PermuType const &tau): " - "Tensor should have dynamic extents" - ); - - using t_engine = tensor_engine< - extents_type, - layout_type, - strides, - array_type - >; - - auto const p = a.rank(); - auto const &na = a.extents(); - typename extents_type::base_type nc; - - if constexpr( is_dynamic_rank_v ){ - nc.resize(p); - } - - for (auto i = 0u; i < p; ++i) - nc.at(tau.at(i) - 1) = na.at(i); - - auto c = tensor_core( extents_type( std::move(nc) ) ); - - if (a.empty()) - return c; - - trans(a.rank(), a.extents().data(), tau.data(), - c.data(), c.strides().data(), - a.data(), a.strides().data()); - - return c; - } - /** - * - * @brief Computes the frobenius nor of a tensor - * - * @note Calls accumulate on the tensor. - * - * implements - * k = sqrt( sum_(i1,...,ip) A(i1,...,ip)^2 ) - * - * @tparam V the data type of tensor - * @tparam F the format of tensor storage - * @tparam A the array_type of tensor - * @param a the tensor whose norm is expected of rank p. - * @return the frobenius norm of a tensor. - */ - template - inline decltype(auto) norm(tensor_core< TensorEngine > const &a) - { - using tensor_type = tensor_core< TensorEngine >; - using value_type = typename tensor_type::value_type; - - static_assert(std::is_default_constructible::value, - "Value type of tensor must be default construct able in order " - "to call boost::numeric::ublas::norm"); - - if (a.empty()) - { - throw std::runtime_error( - "error in boost::numeric::ublas::norm: tensors should not be empty."); - } - return std::sqrt(accumulate(a.order(), a.extents().data(), a.data(), a.strides().data(), value_type{}, - [](auto const &l, auto const &r) { return l + r * r; })); - } - - - /** @brief Computes the complex conjugate component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression - */ - template::value_type>, int > = 0 - > - auto conj(detail::tensor_expression< tensor_core, D > const& expr) - { - return detail::make_unary_tensor_expression< tensor_core > (expr(), [] (auto const& l) { return std::conj( l ); } ); - } - - /** @brief Computes the complex conjugate component of tensor elements within a tensor expression - * - * @param[in] expr tensor expression - * @returns complex tensor - */ - template - auto conj(detail::tensor_expression const& expr) - { - using old_tensor_type = T; - using value_type = typename old_tensor_type::value_type; - using layout_type = typename old_tensor_type::layout_type; - using array_type = typename old_tensor_type::array_type; - using extents_type = typename old_tensor_type::extents_type; - - using complex_type = std::complex; - using storage_traits_t = storage_traits; - - using t_engine = tensor_engine< - extents_type, - layout_type, - strides, - typename storage_traits_t::template rebind - >; - - using tensor_type = tensor_core; - - if( detail::retrieve_extents( expr ).empty() ) - throw std::runtime_error("error in boost::numeric::ublas::conj: tensors should not be empty."); - - auto a = old_tensor_type( expr ); - auto c = tensor_type( a.extents() ); - - std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::conj(l) ; } ); - - return c; - } - - /** @brief Extract the real component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression - */ - template - auto real(detail::tensor_expression const& expr) { - return detail::make_unary_tensor_expression (expr(), [] (auto const& l) { return std::real( l ); } ); - } - - /** @brief Extract the real component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression - */ - template::value_type>, int > = 0 - > - auto real(detail::tensor_expression< tensor_core< TensorEngine > ,D > const& expr) - { - - using old_tensor_type = tensor_core< TensorEngine >; - using complex_type = typename old_tensor_type::value_type; - using value_type = typename complex_type::value_type; - using layout_type = typename old_tensor_type::layout_type; - using array_type = typename old_tensor_type::array_type; - using extents_type = typename old_tensor_type::extents_type; - using storage_traits_t = storage_traits; - - using t_engine = tensor_engine< - extents_type, - layout_type, - strides, - typename storage_traits_t::template rebind - >; - - using tensor_type = tensor_core; - - if( detail::retrieve_extents( expr ).empty() ) - throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); - - auto a = old_tensor_type( expr ); - auto c = tensor_type( a.extents() ); - - std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::real(l) ; } ); - - return c; - } - - - /** @brief Extract the imaginary component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression - */ - template - auto imag(detail::tensor_expression const& lhs) { - return detail::make_unary_tensor_expression (lhs(), [] (auto const& l) { return std::imag( l ); } ); - } - - - /** @brief Extract the imag component of tensor elements within a tensor expression - * - * @param[in] lhs tensor expression - * @returns unary tensor expression - */ - template::value_type>, int > = 0 - > - auto imag(detail::tensor_expression< tensor_core< TensorEngine > ,D> const& expr) - { - using old_tensor_type = tensor_core< TensorEngine >; - using complex_type = typename old_tensor_type::value_type; - using value_type = typename complex_type::value_type; - using layout_type = typename old_tensor_type::layout_type; - using array_type = typename old_tensor_type::array_type; - using extents_type = typename old_tensor_type::extents_type; - using storage_traits_t = storage_traits; - - using t_engine = tensor_engine< - extents_type, - layout_type, - strides, - typename storage_traits_t::template rebind - >; - - using tensor_type = tensor_core; - - if( detail::retrieve_extents( expr ).empty() ) - throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); - - auto a = old_tensor_type( expr ); - auto c = tensor_type( a.extents() ); - - std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::imag(l) ; } ); - - return c; - } - -} - -// static functions -namespace boost::numeric::ublas -{ - - namespace detail{ - - template - inline - constexpr auto extents_result_tensor_times_vector( - [[maybe_unused]] basic_static_extents e, - [[maybe_unused]] basic_static_extents te1, - [[maybe_unused]] basic_static_extents te2) - { - return basic_static_extents{}; - } - - template - inline - constexpr auto extents_result_tensor_times_vector( - [[maybe_unused]] basic_static_extents e1, - [[maybe_unused]] basic_static_extents e2, - [[maybe_unused]] basic_static_extents e3 = basic_static_extents{}) - { - if constexpr(I != M - 1){ - return extents_result_tensor_times_vector - ( basic_static_extents{}, basic_static_extents{}, basic_static_extents{} ); - }else{ - return extents_result_tensor_times_vector - ( basic_static_extents{}, basic_static_extents{}, basic_static_extents{} ); - } - } - - - template - inline - constexpr auto extents_result_tensor_times_vector(basic_static_extents const& e) - { - using size_type = typename basic_static_extents::size_type; - auto ones = typename impl::make_sequence_of_ones_t< T, std::max( size_type(2), sizeof...(E) ) >::extents_type{}; - return extents_result_tensor_times_vector(e, ones); - } - - template - inline - constexpr auto static_extents_set_at( - [[maybe_unused]] basic_static_extents const& e1, - [[maybe_unused]] basic_static_extents e2 = basic_static_extents{} - ){ - static_assert( I < sizeof...(E) + 1, "boost::numeric::ublas::detail::static_extents_set_at(): out of bound"); - if constexpr( sizeof...(E) == 0 ){ - if constexpr( I == 0 ){ - return basic_static_extents{}; - }else{ - return basic_static_extents{}; - } - }else{ - if constexpr(I == 0){ - return basic_static_extents{}; - }else{ - return static_extents_set_at( basic_static_extents{}, basic_static_extents{} ); - } - } - } - - } // namespace detail - - /** @brief Computes the m-mode tensor-times-vector product - * - * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] - * - * @note calls ublas::ttv - * - * @tparam M contraction dimension with 1 <= m <= p - * @param[in] a tensor object A with order p - * @param[in] b vector object B - * - * @returns tensor object C with order p-1, the same storage format and allocator type as A - */ - template - inline decltype(auto) prod(tensor_core< TensorType > const &a - , vector::value_type, A> const &b) - { - using tensor_type = tensor_core< TensorType >; - using array_type = typename tensor_type::array_type; - using extents_type = typename tensor_type::extents_type; - using value_type = typename tensor_type::value_type; - using layout_type = typename tensor_type::layout_type; - - auto const p = std::size_t(a.rank()); - - static_assert( M != 0ul, - "error in boost::numeric::ublas::prod(ttv): " - "contraction mode must be greater than zero."); - - static_assert( extents_type::_size >= M, - "error in boost::numeric::ublas::prod(ttv): rank of tensor must be " - "greater than or equal to the modus."); - - static_assert(extents_type::_size != 0, - "error in boost::numeric::ublas::prod(ttv): first " - "argument tensor should not be empty."); - - if (b.size() == 0ul) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttv): second " - "argument vector should not be empty."); - - using extents_value_type = typename extents_type::value_type; - - auto nc = detail::extents_result_tensor_times_vector(a.extents()); - auto nb = std::vector{b.size(), extents_value_type(1)}; - using c_extents_type = std::decay_t; - - using t_engine = tensor_engine< - c_extents_type, - layout_type, - strides, - rebind_storage_size_t - >; - - auto c = t_engine(value_type{}); - auto bb = &(b(0)); - - auto& a_static_extents = a.extents().base(); - auto& c_static_extents = c.extents().base(); - - auto& a_static_strides = a.strides().base(); - auto& c_static_strides = c.strides().base(); - - ttv(M, p, - c.data(), c_static_extents.data(), c_static_strides.data(), - a.data(), a_static_extents.data(), a_static_strides.data(), - bb, nb.data(), nb.data()); - - return c; - } - - /** @brief Computes the m-mode tensor-times-matrix product - * - * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] - * - * @note calls ublas::ttm - * - * @tparam M contraction dimension with 1 <= M <= p - * @tparam MatrixDimension is a non contracting dimension - * @param[in] a tensor object A with order p - * @param[in] b vector object B - * - * @returns tensor object C with order p, the same storage format and allocator type as A - */ - template - inline decltype(auto) prod(tensor_core< TensorType > const &a, - matrix::value_type, typename tensor_core< TensorType >::layout_type, A> const &b) - { - using tensor_type = tensor_core< TensorType >; - using extents_type = typename tensor_type::extents_type; - using layout_type = typename tensor_type::layout_type; - using value_type = typename tensor_type::value_type; - using array_type = typename tensor_type::array_type; - using dynamic_strides_type = strides_t, layout_type>; - - auto const p = a.rank(); - - static_assert(M != 0ul, - "error in boost::numeric::ublas::prod(ttm): " - "contraction mode must be greater than zero."); - - static_assert( extents_type::_size >= M , - "error in boost::numeric::ublas::prod(ttm): rank " - "of the tensor must be greater equal the modus."); - - static_assert( extents_type::_size, - "error in boost::numeric::ublas::prod(ttm): first " - "argument tensor should not be empty."); - - if (b.size1() * b.size2() == 0ul) - throw std::length_error( - "error in boost::numeric::ublas::prod(ttm): second " - "argument matrix should not be empty."); - - auto nc = detail::static_extents_set_at< M - 1, MatrixDimension >( a.extents() ); - auto nb = extents<>{b.size1(), b.size2()}; - - auto wb = dynamic_strides_type(nb); - - using c_extents_type = std::decay_t; - - using t_engine = tensor_engine< - c_extents_type, - layout_type, - strides, - rebind_storage_size_t - >; - auto c = t_engine(value_type{}); - - auto bb = &(b(0, 0)); - - auto& a_static_extents = a.extents().base(); - auto& c_static_extents = c.extents().base(); - - auto& a_static_strides = a.strides().base(); - auto& c_static_strides = c.strides().base(); - ttm(M, p, - c.data(), c_static_extents.data(), c_static_strides.data(), - a.data(), a_static_extents.data(), a_static_strides.data(), - bb, nb.data(), wb.data()); - - return c; - } - - /** @brief Computes the outer product of two tensors - * - * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] - * - * @note calls outer function - * - * @param[in] a tensor object A - * @param[in] b tensor object B - * - * @returns tensor object C with the same storage format F and allocator type A1 - */ - template ::extents_type > && - is_static_v< typename tensor_core< TensorEngine2 >::extents_type > - ,int> = 0 - > - inline decltype(auto) outer_prod(tensor_core< TensorEngine1 > const &a, tensor_core< TensorEngine2 > const &b) - { - if (a.empty() || b.empty()) - throw std::runtime_error( - "error in boost::numeric::ublas::outer_prod: " - "tensors should not be empty."); - - using extents_type1 = std::decay_t< decltype(a.extents()) >; - using extents_type2 = std::decay_t< decltype(b.extents()) >; - using array_type = typename tensor_core< TensorEngine1 >::array_type; - using value_type = typename tensor_core< TensorEngine1 >::value_type; - using layout_type = typename tensor_core< TensorEngine1 >::layout_type; - - static_assert( - std::is_same_v::value_type>, - "error in boost::numeric::ublas::outer_prod(tensor_core< TensorEngine1 > const&, tensor_core< TensorEngine2 > const&): " - "Both the tensor should have the same value_type" - ); - - auto nc = detail::impl::concat_t{}; - - auto a_extents = a.extents(); - auto b_extents = b.extents(); - - - using c_extents_type = std::decay_t; - - using t_engine = tensor_engine< - c_extents_type, - layout_type, - strides, - rebind_storage_size_t - >; - - auto c = t_engine(value_type{}); - - auto& a_static_extents = a_extents.base(); - auto& a_static_strides = a.strides().base(); - - auto& b_static_extents = b_extents.base(); - auto& b_static_strides = b.strides().base(); - - auto c_static_extents = c.extents().base(); - auto c_static_strides = c.strides().base(); - - outer(c.data(), c.rank(), c_static_extents.data(), c_static_strides.data(), - a.data(), a.rank(), a_static_extents.data(), a_static_strides.data(), - b.data(), b.rank(), b_static_extents.data(), b_static_strides.data()); - - return c; - } -} +#ifndef BOOST_UBLAS_TENSOR_FUNCTIONS_HPP +#define BOOST_UBLAS_TENSOR_FUNCTIONS_HPP + +#include "function/reshape.hpp" +#include "function/inner_prod.hpp" +#include "function/outer_prod.hpp" +#include "function/norm.hpp" +#include "function/imag.hpp" +#include "function/real.hpp" +#include "function/conj.hpp" +#include "function/trans.hpp" +#include "function/tensor_times_vector.hpp" +#include "function/tensor_times_matrix.hpp" +#include "function/tensor_times_tensor.hpp" +#include "function/init.hpp" #endif diff --git a/include/boost/numeric/ublas/tensor/index.hpp b/include/boost/numeric/ublas/tensor/index.hpp index 7de9e52e7..f13872ceb 100644 --- a/include/boost/numeric/ublas/tensor/index.hpp +++ b/include/boost/numeric/ublas/tensor/index.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,14 +13,11 @@ #define BOOST_UBLAS_TENSOR_INDEX_HPP -#include #include +#include #include -namespace boost { -namespace numeric { -namespace ublas { -namespace index { +namespace boost::numeric::ublas::index { /** @brief Proxy template class for the einstein summation notation * @@ -80,10 +77,7 @@ static constexpr index_type<24> _x; static constexpr index_type<25> _y; static constexpr index_type<26> _z; -} // namespace indices +} // namespace boost::numeric::ublas::index -} -} -} #endif // _BOOST_UBLAS_TENSOR_INDEX_HPP_ diff --git a/include/boost/numeric/ublas/tensor/index_functions.hpp b/include/boost/numeric/ublas/tensor/index_functions.hpp new file mode 100644 index 000000000..bc3d54ac0 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/index_functions.hpp @@ -0,0 +1,64 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_INDEX_FUNCTIONS_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_INDEX_FUNCTIONS_HPP + +#include +#include +#include +#include "concepts.hpp" + + +namespace boost::numeric::ublas::detail +{ + +/** @brief Returns relative memory index with respect to a multi-index + * + * @code auto j = to_index({3,4,5}, to_strides({4,2,3},first_order{})); @endcode + * + * @param[in] i multi-index of length p + * @param[in] w stride vector of length p + * @returns relative memory location depending on \c i and \c w + */ +template +[[nodiscard]] inline constexpr auto to_index(std::vector const& w, std::vector const& i) +{ + return std::inner_product(i.begin(), i.end(), w.begin(), T{}); +} + +template +[[nodiscard]] inline constexpr auto to_index(std::array const& w, std::array const& i) +{ + return std::inner_product(i.begin(), i.end(), w.begin(), T{}); +} + +template +[[nodiscard]] inline constexpr auto to_index(std::array const& w, Is ... is) +{ + static_assert(N != sizeof...(is)+2); + auto ai = std::array{I(is)...}; + return std::inner_product(ai.begin(), ai.end(), w.begin(), I{}); +} + +template +[[nodiscard]] inline auto to_index(std::vector const& w, Is ... is) +{ + constexpr auto N = sizeof...(is); + auto ai = std::array{I(is)...}; + return std::inner_product(ai.begin(), ai.end(), w.begin(), std::size_t{}); +} + + +} // namespace boost::numeric::ublas::detail + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_INDEX_FUNCTIONS_HPP diff --git a/include/boost/numeric/ublas/tensor/multi_index.hpp b/include/boost/numeric/ublas/tensor/multi_index.hpp index 5b4638944..adb5f8707 100644 --- a/include/boost/numeric/ublas/tensor/multi_index.hpp +++ b/include/boost/numeric/ublas/tensor/multi_index.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,30 +13,16 @@ #define BOOST_UBLAS_TENSOR_MULTI_INDEX_HPP -#include + #include +#include #include -#include "multi_index_utility.hpp" #include "index.hpp" - -namespace boost { -namespace numeric { -namespace ublas { -namespace index { - -template -struct index_type; - -} // namespace indices -} -} -} +#include "multi_index_utility.hpp" -namespace boost { -namespace numeric { -namespace ublas { +namespace boost::numeric::ublas { /** @brief Proxy class for the einstein summation notation * @@ -49,7 +35,8 @@ class multi_index multi_index() = delete; template - constexpr multi_index(index::index_type const& i, indexes ... is ) + constexpr explicit inline + multi_index(index::index_type const& i, indexes ... is ) : _base{i(), is()... } { static_assert( sizeof...(is)+1 == N, @@ -59,30 +46,34 @@ class multi_index "Static assert in boost::numeric::ublas::multi_index: indexes occur twice in multi-index." ); } - multi_index(multi_index const& other) - : _base(other._base) + multi_index(multi_index const& other) = default; + multi_index(multi_index&& other) noexcept = default ; + + multi_index& operator=(multi_index other) { + std::swap(this->_base,other._base); + return *this; } - multi_index& operator=(multi_index const& other) + multi_index& operator=(multi_index&& other) noexcept { - this->_base = other._base; - return *this; + this->_base = std::move(other._base); + return *this; } ~multi_index() = default; - auto const& base() const { return _base; } - constexpr auto size() const { return _base.size(); } - constexpr auto at(std::size_t i) const { return _base.at(i); } - constexpr auto operator[](std::size_t i) const { return _base.at(i); } + [[nodiscard]] inline auto const& base() const { return _base; } + [[nodiscard]] inline constexpr auto size() const { return _base.size(); } + [[nodiscard]] inline constexpr auto at(std::size_t i) const { return _base.at(i); } + [[nodiscard]] inline constexpr auto operator[](std::size_t i) const { return _base.at(i); } private: std::array _base; }; template -constexpr auto get(multi_index const& m) { return std::get(m.base()); } +inline constexpr auto get(multi_index const& m) { return std::get(m.base()); } template auto array_to_vector(multi_index const& lhs, multi_index const& rhs) @@ -91,22 +82,17 @@ auto array_to_vector(multi_index const& lhs, multi_index const& rhs) auto pair_of_vector = std::make_pair( vtype {}, vtype{} ); - for(auto i = 0u; i < N; ++i) - for(auto j = 0u; j < M; ++j) + for(auto i = 0ul; i < N; ++i){ + for(auto j = 0ul; j < M; ++j){ if ( lhs.at(i) == rhs.at(j) && lhs.at(i) != boost::numeric::ublas::index::_()){ pair_of_vector.first .push_back( i+1 ); pair_of_vector.second.push_back( j+1 ); } - + } + } return pair_of_vector; } - - - - -} // namespace ublas -} // namespace numeric -} // namespace boost +} // namespace boost::numeric::ublas #endif // MULTI_INDEX_HPP diff --git a/include/boost/numeric/ublas/tensor/multi_index_utility.hpp b/include/boost/numeric/ublas/tensor/multi_index_utility.hpp index f4593e1fd..aa98fa4b0 100644 --- a/include/boost/numeric/ublas/tensor/multi_index_utility.hpp +++ b/include/boost/numeric/ublas/tensor/multi_index_utility.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,15 +13,12 @@ #define BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP +#include #include #include -namespace boost { -namespace numeric { -namespace ublas { -namespace detail { - +namespace boost::numeric::ublas::detail { template struct has_index_impl; @@ -50,9 +47,12 @@ struct has_index_impl > using next_type = has_index_impl>; static constexpr bool value = has_index_impl::value || next_type::value; }; -} // namespace detail +} // namespace boost::numeric::ublas::detail + +namespace boost::numeric::ublas +{ /** @brief has_index is true if index occurs once or more in a multi-index * @@ -69,17 +69,12 @@ struct has_index static constexpr bool value = detail::has_index_impl,std::decay_t>::value; }; -} // namespace ublas -} // namespace numeric -} // namespace boost +} // namespace boost::numeric::ublas //////////////////////////////////////////////// //////////////////////////////////////////////// -namespace boost { -namespace numeric { -namespace ublas { -namespace detail { +namespace boost::numeric::ublas::detail { template @@ -108,7 +103,10 @@ struct valid_multi_index_impl> static constexpr bool has_index_value = has_index_type::value && !is_index_zero; static constexpr bool value = !has_index_value && valid_multi_index_impl::value; }; -} // namespace detail +} // namespace boost::numeric::ublas::detail + +namespace boost::numeric::ublas +{ /** @brief valid_multi_index is true if indexes occur only once in a multi-index * @@ -125,17 +123,13 @@ struct valid_multi_index static constexpr bool value = detail::valid_multi_index_impl>::value; }; -} // namespace ublas -} // namespace numeric -} // namespace boost +} // namespace boost::numeric::ublas //////////////////////////////////////////////// //////////////////////////////////////////////// -namespace boost { -namespace numeric { -namespace ublas { -namespace detail { +namespace boost::numeric::ublas::detail +{ template struct number_equal_indexes_impl; @@ -159,9 +153,11 @@ struct number_equal_indexes_impl < std::tuple, std::tuple< static constexpr unsigned v = has_index_value ? 1 : 0; static constexpr unsigned value = v + next_type::value; }; -} // namespace detail +} // namespace boost::numeric::ublas::detail +namespace boost::numeric::ublas { + /** @brief number_equal_indexes contains the number of equal indexes of two multi-indexes * * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type @@ -182,18 +178,14 @@ struct number_equal_indexes detail::number_equal_indexes_impl< std::decay_t, std::decay_t>::value; }; -} // namespace ublas -} // namespace numeric -} // namespace boost +} // namespace boost::numeric::ublas //////////////////////////////////////////////// //////////////////////////////////////////////// -namespace boost { -namespace numeric { -namespace ublas { -namespace detail { +namespace boost::numeric::ublas::detail +{ template @@ -211,10 +203,11 @@ struct index_position_impl < m, m, itype, ttype> static constexpr auto value = std::tuple_size::value; }; -} // namespace detail - +} // namespace boost::numeric::ublas::detail +namespace boost::numeric::ublas +{ /** @brief index_position contains the zero-based index position of an index type within a multi-index * * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type @@ -235,18 +228,14 @@ struct index_position static constexpr auto value = detail::index_position_impl<0ul,std::tuple_size::value,std::decay_t,std::decay_t>::value; }; -} // namespace ublas -} // namespace numeric -} // namespace boost +} // namespace boost::numeric::ublas //////////////////////////////////////////////// //////////////////////////////////////////////// -namespace boost { -namespace numeric { -namespace ublas { -namespace detail { +namespace boost::numeric::ublas::detail +{ template struct index_position_pairs_impl @@ -295,9 +284,10 @@ struct index_position_pairs_impl }; -} // namespace detail - +} // namespace boost::numeric::ublas::detail +namespace boost::numeric::ublas +{ /** @brief index_position_pairs returns zero-based index positions of matching indexes of two multi-indexes * * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type @@ -321,9 +311,7 @@ auto index_position_pairs(tuple_left const& lhs, tuple_right const& rhs) return array; } -} // namespace ublas -} // namespace numeric -} // namespace boost +} // namespace boost::numeric::ublas //////////////////////////// //////////////////////////// @@ -331,42 +319,40 @@ auto index_position_pairs(tuple_left const& lhs, tuple_right const& rhs) //////////////////////////// -namespace boost { -namespace numeric { -namespace ublas { -namespace detail { +//namespace boost::numeric::ublas::detail +//{ -template -constexpr auto array_to_vector_impl( array_type const& array, [[maybe_unused]] std::index_sequence sq) -{ - return std::make_pair( - std::vector{std::get<0>( std::get(array) )+1 ...} , - std::vector{std::get<1>( std::get(array) )+1 ...} ); -} +//template +//constexpr auto array_to_vector_impl( array_type const& array, std::index_sequence /*unused*/) +//{ +// return std::make_pair( +// std::vector{std::get(array).first +1 ...} , +// std::vector{std::get(array).second +1 ...} ); +//} -} // namespace detail +//} // namespace boost::numeric::ublas::detail -/** @brief array_to_vector converts a std::array of zero-based index position pairs into two std::vector of one-based index positions - * - * @code auto two_vectors = array_to_vector(std::make_array ( std::make_pair(1,2), std::make_pair(3,4) ) ) ; - * @endcode - * - * @returns two std::vector of one-based index positions - * - * @param array std::array of zero-based index position pairs -*/ -template -constexpr auto array_to_vector( std::array const& array) -{ - constexpr auto sequence = std::make_index_sequence{}; - return detail::array_to_vector_impl( array, sequence ); -} +//namespace boost::numeric::ublas +//{ +///** @brief array_to_vector converts a std::array of zero-based index position pairs into two std::vector of one-based index positions +// * +// * @code auto two_vectors = array_to_vector(std::make_array ( std::make_pair(1,2), std::make_pair(3,4) ) ) ; +// * @endcode +// * +// * @returns two std::vector of one-based index positions +// * +// * @param array std::array of zero-based index position pairs +//*/ +//template +//constexpr auto array_to_vector( std::array const& array) +//{ +// constexpr auto sequence = std::make_index_sequence{}; +// return detail::array_to_vector_impl( array, sequence ); +//} -} // namespace ublas -} // namespace numeric -} // namespace boost +//} // namespace boost::numeric::ublas -#endif // _BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP_ +#endif // BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP diff --git a/include/boost/numeric/ublas/tensor/multiplication.hpp b/include/boost/numeric/ublas/tensor/multiplication.hpp index 934dd2d17..6a9c0613b 100644 --- a/include/boost/numeric/ublas/tensor/multiplication.hpp +++ b/include/boost/numeric/ublas/tensor/multiplication.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -15,11 +15,8 @@ #include -namespace boost { -namespace numeric { -namespace ublas { -namespace detail { -namespace recursive { +namespace boost::numeric::ublas { +namespace detail::recursive { /** @brief Computes the tensor-times-tensor product for q contraction modes @@ -57,34 +54,30 @@ void ttt(SizeType const k, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(k < r) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(nc[k] == na[phia[k]-1]); - for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) - ttt(k+1, r, s, q, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(k < r+s) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(nc[k] == nb[phib[k-r]-1]); - for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) - ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(k < r+s+q-1) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); - for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) - ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); - } - else - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); - for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) - *c += *a * *b; + if(k < r) { + assert(nc[k] == na[phia[k]-1]); + for(SizeType ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) { + ttt(k+1, r, s, q, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); } + } + else if(k < r+s) { + assert(nc[k] == nb[phib[k-r]-1]); + for(SizeType ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) { + ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); + } + } + else if(k < r+s+q-1) { + assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); + for(SizeType ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) { + ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); + } + } + else { + assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); + for(SizeType ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) { + *c += *a * *b; + } + } } @@ -124,34 +117,30 @@ void ttt(SizeType const k, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(k < r) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(nc[k] == na[k]); - for(size_t ic = 0u; ic < nc[k]; a += wa[k], c += wc[k], ++ic) - ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(k < r+s) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(nc[k] == nb[k-r]); - for(size_t ic = 0u; ic < nc[k]; b += wb[k-r], c += wc[k], ++ic) - ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(k < r+s+q-1) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(na[k-s] == nb[k-r]); - for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) - ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); - } - else - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(na[k-s] == nb[k-r]); - for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) - *c += *a * *b; + if(k < r) { + assert(nc[k] == na[k]); + for(auto ic = 0ul; ic < nc[k]; a += wa[k], c += wc[k], ++ic) { + ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); + } + } + else if(k < r+s) { + assert(nc[k] == nb[k-r]); + for(auto ic = 0ul; ic < nc[k]; b += wb[k-r], c += wc[k], ++ic) { + ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); + } + } + else if(k < r+s+q-1) { + assert(na[k-s] == nb[k-r]); + for(auto ia = 0ul; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) { + ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); + } + } + else { + assert(na[k-s] == nb[k-r]); + for(auto ia = 0ul; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) { + *c += *a * *b; } + } } @@ -181,26 +170,28 @@ void ttm(SizeType const m, SizeType const r, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(r == m) { - ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(r == 0){ - for(auto i0 = 0ul; i0 < nc[0]; c += wc[0], a += wa[0], ++i0) { - auto cm = c; - auto b0 = b; - for(auto i1 = 0ul; i1 < nc[m]; cm += wc[m], b0 += wb[0], ++i1){ - auto am = a; - auto b1 = b0; - for(auto i2 = 0ul; i2 < nb[1]; am += wa[m], b1 += wb[1], ++i2) - *cm += *am * *b1; - } + if(r == m) { + ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(r == 0){ + for(auto i0 = 0ul; i0 < nc[0]; c += wc[0], a += wa[0], ++i0) { + auto cm = c; + auto b0 = b; + for(auto i1 = 0ul; i1 < nc[m]; cm += wc[m], b0 += wb[0], ++i1){ + auto am = a; + auto b1 = b0; + for(auto i2 = 0ul; i2 < nb[1]; am += wa[m], b1 += wb[1], ++i2){ + *cm += *am * *b1; } + } } + } - else{ - for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i) - ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb); + else{ + for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i){ + ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb); } + } } /** @brief Computes the tensor-times-matrix product for the contraction mode m = 0 @@ -223,31 +214,31 @@ void ttm(SizeType const m, SizeType const r, */ template void ttm0( SizeType const r, - PointerOut c, SizeType const*const nc, SizeType const*const wc, - PointerIn1 a, SizeType const*const na, SizeType const*const wa, - PointerIn2 b, SizeType const*const nb, SizeType const*const wb) + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(r > 1){ - for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i) - ttm0(r-1, c, nc, wc, a, na, wa, b, nb, wb); + if(r > 1){ + for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i){ + ttm0(r-1, c, nc, wc, a, na, wa, b, nb, wb); } - else{ - for(auto i1 = 0ul; i1 < nc[1]; c += wc[1], a += wa[1], ++i1) { - auto cm = c; - auto b0 = b; - // r == m == 0 - for(auto i0 = 0ul; i0 < nc[0]; cm += wc[0], b0 += wb[0], ++i0){ - - auto am = a; - auto b1 = b0; - for(auto i2 = 0u; i2 < nb[1]; am += wa[0], b1 += wb[1], ++i2){ - - *cm += *am * *b1; - } - } + } + else{ + for(auto i1 = 0ul; i1 < nc[1]; c += wc[1], a += wa[1], ++i1) { + auto cm = c; + auto b0 = b; + // r == m == 0 + for(auto i0 = 0ul; i0 < nc[0]; cm += wc[0], b0 += wb[0], ++i0){ + + auto am = a; + auto b1 = b0; + for(auto i2 = 0u; i2 < nb[1]; am += wa[0], b1 += wb[1], ++i2){ + *cm += *am * *b1; } + } } + } } @@ -277,25 +268,29 @@ void ttm0( SizeType const r, template void ttv( SizeType const m, SizeType const r, SizeType const q, - PointerOut c, SizeType const*const nc, SizeType const*const wc, - PointerIn1 a, SizeType const*const na, SizeType const*const wa, - PointerIn2 b) + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b) { - if(r == m) { - ttv(m, r-1, q, c, nc, wc, a, na, wa, b); + if(r == m) { + ttv(m, r-1, q, c, nc, wc, a, na, wa, b); + } + else if(r == 0){ + for(auto i0 = 0u; i0 < na[0]; c += wc[0], a += wa[0], ++i0) { + auto c1 = c; + auto a1 = a; + auto b1 = b; + for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im){ + *c1 += *a1 * *b1; + } } - else if(r == 0){ - for(auto i0 = 0u; i0 < na[0]; c += wc[0], a += wa[0], ++i0) { - auto c1 = c; auto a1 = a; auto b1 = b; - for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im) - *c1 += *a1 * *b1; - } - } - else{ - for(auto i = 0u; i < na[r]; c += wc[q], a += wa[r], ++i) - ttv(m, r-1, q-1, c, nc, wc, a, na, wa, b); + } + else{ + for(auto i = 0u; i < na[r]; c += wc[q], a += wa[r], ++i){ + ttv(m, r-1, q-1, c, nc, wc, a, na, wa, b); } + } } @@ -322,18 +317,21 @@ void ttv0(SizeType const r, PointerIn2 b) { - if(r > 1){ - for(auto i = 0u; i < na[r]; c += wc[r-1], a += wa[r], ++i) - ttv0(r-1, c, nc, wc, a, na, wa, b); + if(r > 1){ + for(auto i = 0u; i < na[r]; c += wc[r-1], a += wa[r], ++i) { + ttv0(r-1, c, nc, wc, a, na, wa, b); } - else{ - for(auto i1 = 0u; i1 < na[1]; c += wc[0], a += wa[1], ++i1) - { - auto c1 = c; auto a1 = a; auto b1 = b; - for(auto i0 = 0u; i0 < na[0]; a1 += wa[0], ++b1, ++i0) - *c1 += *a1 * *b1; - } + } + else{ + for(auto i1 = 0u; i1 < na[1]; c += wc[0], a += wa[1], ++i1) { + auto c1 = c; + auto a1 = a; + auto b1 = b; + for(auto i0 = 0u; i0 < na[0]; a1 += wa[0], ++b1, ++i0){ + *c1 += *a1 * *b1; + } } + } } @@ -354,18 +352,21 @@ void ttv0(SizeType const r, */ template void mtv(SizeType const m, - PointerOut c, [[maybe_unused]] SizeType const*const nc, SizeType const*const wc, - PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerOut c, SizeType const*const /*unsed*/, SizeType const*const wc, + PointerIn1 a, SizeType const*const na , SizeType const*const wa, PointerIn2 b) { - // decides whether matrix multiplied with vector or vector multiplied with matrix - const auto o = (m == 0) ? 1 : 0; - - for(auto io = 0u; io < na[o]; c += wc[o], a += wa[o], ++io) { - auto c1 = c; auto a1 = a; auto b1 = b; - for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im) - *c1 += *a1 * *b1; + // decides whether matrix multiplied with vector or vector multiplied with matrix + const auto o = (m == 0) ? 1 : 0; + + for(auto io = 0u; io < na[o]; c += wc[o], a += wa[o], ++io) { + auto c1 = c; + auto a1 = a; + auto b1 = b; + for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im) { + *c1 += *a1 * *b1; } + } } @@ -391,28 +392,23 @@ void mtm(PointerOut c, SizeType const*const nc, SizeType const*const wc, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - // C(i,j) = A(i,k) * B(k,j) - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(nc[0] == na[0]); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(nc[1] == nb[1]); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(na[1] == nb[0]); - - auto cj = c; auto bj = b; - for(auto j = 0u; j < nc[1]; cj += wc[1], bj += wb[1], ++j) { - - auto bk = bj; auto ak = a; - for(auto k = 0u; k < na[1]; ak += wa[1], bk += wb[0], ++k) { - - auto ci = cj; auto ai = ak; - for(auto i = 0u; i < na[0]; ai += wa[0], ci += wc[0], ++i){ - *ci += *ai * *bk; - } - - } - + // C(i,j) = A(i,k) * B(k,j) + assert(nc[0] == na[0]); + assert(nc[1] == nb[1]); + assert(na[1] == nb[0]); + + auto cj = c; auto bj = b; + for(auto j = 0u; j < nc[1]; cj += wc[1], bj += wb[1], ++j) { + auto bk = bj; + auto ak = a; + for(auto k = 0u; k < na[1]; ak += wa[1], bk += wb[0], ++k) { + auto ci = cj; + auto ai = ak; + for(auto i = 0u; i < na[0]; ai += wa[0], ci += wc[0], ++i){ + *ci += *ai * *bk; + } } + } } @@ -438,13 +434,17 @@ value_t inner(SizeType const r, SizeType const*const n, PointerIn2 b, SizeType const*const wb, value_t v) { - if(r == 0) - for(auto i0 = 0u; i0 < n[0]; a += wa[0], b += wb[0], ++i0) - v += *a * *b; - else - for(auto ir = 0u; ir < n[r]; a += wa[r], b += wb[r], ++ir) - v = inner(r-1, n, a, wa, b, wb, v); - return v; + if(r == 0){ + for(auto i0 = 0u; i0 < n[0]; a += wa[0], b += wb[0], ++i0){ + v += *a * *b; + } + } + else{ + for(auto ir = 0u; ir < n[r]; a += wa[r], b += wb[r], ++ir){ + v = inner(r-1, n, a, wa, b, wb, v); + } + } + return v; } @@ -454,25 +454,26 @@ void outer_2x2(SizeType const pa, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - // assert(rc == 3); - // assert(ra == 1); - // assert(rb == 1); - - for(auto ib1 = 0u; ib1 < nb[1]; b += wb[1], c += wc[pa+1], ++ib1) { - auto c2 = c; - auto b0 = b; - for(auto ib0 = 0u; ib0 < nb[0]; b0 += wb[0], c2 += wc[pa], ++ib0) { - const auto new_b = *b0; - auto c1 = c2; - auto a1 = a; - for(auto ia1 = 0u; ia1 < na[1]; a1 += wa[1], c1 += wc[1], ++ia1) { - auto a0 = a1; - auto c0 = c1; - for(SizeType ia0 = 0u; ia0 < na[0]; a0 += wa[0], c0 += wc[0], ++ia0) - *c0 = *a0 * new_b; - } + // assert(rc == 3); + // assert(ra == 1); + // assert(rb == 1); + + for(auto ib1 = 0u; ib1 < nb[1]; b += wb[1], c += wc[pa+1], ++ib1) { + auto c2 = c; + auto b0 = b; + for(auto ib0 = 0u; ib0 < nb[0]; b0 += wb[0], c2 += wc[pa], ++ib0) { + const auto new_b = *b0; + auto c1 = c2; + auto a1 = a; + for(auto ia1 = 0u; ia1 < na[1]; a1 += wa[1], c1 += wc[1], ++ia1) { + auto a0 = a1; + auto c0 = c1; + for(SizeType ia0 = 0u; ia0 < na[0]; a0 += wa[0], c0 += wc[0], ++ia0){ + *c0 = *a0 * new_b; } + } } + } } /** @brief Computes the outer product of two tensors @@ -505,14 +506,19 @@ void outer(SizeType const pa, SizeType const ra, PointerIn1 a, SizeType const*const na, SizeType const*const wa, SizeType const rb, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(rb > 1) - for(auto ib = 0u; ib < nb[rb]; b += wb[rb], c += wc[rc], ++ib) - outer(pa, rc-1, c, nc, wc, ra, a, na, wa, rb-1, b, nb, wb); - else if(ra > 1) - for(auto ia = 0u; ia < na[ra]; a += wa[ra], c += wc[ra], ++ia) - outer(pa, rc-1, c, nc, wc, ra-1, a, na, wa, rb, b, nb, wb); - else - outer_2x2(pa, c, nc, wc, a, na, wa, b, nb, wb); //assert(ra==1 && rb==1 && rc==3); + if(rb > 1){ + for(auto ib = 0u; ib < nb[rb]; b += wb[rb], c += wc[rc], ++ib){ + outer(pa, rc-1, c, nc, wc, ra, a, na, wa, rb-1, b, nb, wb); + } + } + else if(ra > 1){ + for(auto ia = 0u; ia < na[ra]; a += wa[ra], c += wc[ra], ++ia){ + outer(pa, rc-1, c, nc, wc, ra-1, a, na, wa, rb, b, nb, wb); + } + } + else{ + outer_2x2(pa, c, nc, wc, a, na, wa, b, nb, wb); //assert(ra==1 && rb==1 && rc==3); + } } @@ -551,38 +557,29 @@ void outer(SizeType const k, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - if(k < r) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(nc[k] == na[phia[k]-1]); - for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) - outer(k+1, r, s, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); - } - else if(k < r+s-1) - { - - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(nc[k] == nb[phib[k-r]-1]); - for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) - outer(k+1, r, s, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); - } - else - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - assert(nc[k] == nb[phib[k-r]-1]); - for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) - *c = *a * *b; + if(k < r) { + assert(nc[k] == na[phia[k]-1]); + for(auto ic = 0ul; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic){ + outer(k+1, r, s, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); + } + } + else if(k < r+s-1) { + assert(nc[k] == nb[phib[k-r]-1]); + for(auto ic = 0ul; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic){ + outer(k+1, r, s, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); + } + } + else { + assert(nc[k] == nb[phib[k-r]-1]); + for(auto ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic){ + *c = *a * *b; } + } } -} // namespace recursive -} // namespace detail -} // namespace ublas -} // namespace numeric -} // namespace boost - - +} // namespace detail::recursive +} // namespace boost::numeric::ublas ////////////////////////////////////////////////////////////////////////////////////////// @@ -598,9 +595,7 @@ void outer(SizeType const k, #include -namespace boost { -namespace numeric { -namespace ublas { +namespace boost::numeric::ublas { /** @brief Computes the tensor-times-vector product * @@ -628,44 +623,53 @@ void ttv(SizeType const m, SizeType const p, const PointerIn1 a, SizeType const*const na, SizeType const*const wa, const PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::ttv: Argument types for pointers are not pointer types."); - - if( m == 0) - throw std::length_error("Error in boost::numeric::ublas::ttv: Contraction mode must be greater than zero."); - - if( p < m ) - throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater equal the modus."); - - if( p == 0) - throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater than zero."); - - if(c == nullptr || a == nullptr || b == nullptr) - throw std::length_error("Error in boost::numeric::ublas::ttv: Pointers shall not be null pointers."); - - for(auto i = 0u; i < m-1; ++i) - if(na[i] != nc[i]) - throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal."); - - for(auto i = m; i < p; ++i) - if(na[i] != nc[i-1]) - throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal."); - - const auto max = std::max(nb[0], nb[1]); - if( na[m-1] != max) - throw std::length_error("Error in boost::numeric::ublas::ttv: Extent of dimension mode of A and b must be equal."); - + static_assert( std::is_pointer::value && std::is_pointer::value & std::is_pointer::value, + "Static error in boost::numeric::ublas::ttv: Argument types for pointers are not pointer types."); + + if( m == 0){ + throw std::length_error("Error in boost::numeric::ublas::ttv: Contraction mode must be greater than zero."); + } + + if( p < m ){ + throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater equal the modus."); + } + if( p == 0){ + throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater than zero."); + } + if(c == nullptr || a == nullptr || b == nullptr){ + throw std::length_error("Error in boost::numeric::ublas::ttv: Pointers shall not be null pointers."); + } + for(auto i = 0u; i < m-1; ++i){ + if(na[i] != nc[i]){ + throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal."); + } + } - if((m != 1) && (p > 2)) - detail::recursive::ttv(m-1, p-1, p-2, c, nc, wc, a, na, wa, b); - else if ((m == 1) && (p > 2)) - detail::recursive::ttv0(p-1, c, nc, wc, a, na, wa, b); - else if( p == 2 ) - detail::recursive::mtv(m-1, c, nc, wc, a, na, wa, b); - else /*if( p == 1 )*/{ - auto v = std::remove_pointer_t>{}; - *c = detail::recursive::inner(SizeType(0), na, a, wa, b, wb, v); + for(auto i = m; i < p; ++i){ + if(na[i] != nc[i-1]){ + throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal."); } + } + + const auto max = std::max(nb[0], nb[1]); + if( na[m-1] != max){ + throw std::length_error("Error in boost::numeric::ublas::ttv: Extent of dimension mode of A and b must be equal."); + } + + + if((m != 1) && (p > 2)){ + detail::recursive::ttv(m-1, p-1, p-2, c, nc, wc, a, na, wa, b); + } + else if ((m == 1) && (p > 2)){ + detail::recursive::ttv0(p-1, c, nc, wc, a, na, wa, b); + } + else if( p == 2 ){ + detail::recursive::mtv(m-1, c, nc, wc, a, na, wa, b); + } + else /*if( p == 1 )*/{ + auto v = std::remove_pointer_t>{}; + *c = detail::recursive::inner(SizeType(0), na, a, wa, b, wb, v); + } } @@ -699,40 +703,47 @@ void ttm(SizeType const m, SizeType const p, const PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); - - if( m == 0 ) - throw std::length_error("Error in boost::numeric::ublas::ttm: Contraction mode must be greater than zero."); - - if( p < m ) - throw std::length_error("Error in boost::numeric::ublas::ttm: Rank must be greater equal than the specified mode."); - - if( p == 0) - throw std::length_error("Error in boost::numeric::ublas::ttm:Rank must be greater than zero."); - - if(c == nullptr || a == nullptr || b == nullptr) - throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); - - for(auto i = 0u; i < m-1; ++i) - if(na[i] != nc[i]) - throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal."); - - for(auto i = m; i < p; ++i) - if(na[i] != nc[i]) - throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal."); - - if(na[m-1] != nb[1]) - throw std::length_error("Error in boost::numeric::ublas::ttm: 2nd Extent of B and M-th Extent of A must be the equal."); - - if(nc[m-1] != nb[0]) - throw std::length_error("Error in boost::numeric::ublas::ttm: 1nd Extent of B and M-th Extent of C must be the equal."); - - if ( m != 1 ) - detail::recursive::ttm (m-1, p-1, c, nc, wc, a, na, wa, b, nb, wb); - else /*if (m == 1 && p > 2)*/ - detail::recursive::ttm0( p-1, c, nc, wc, a, na, wa, b, nb, wb); - + static_assert( + std::is_pointer::value && + std::is_pointer::value && + std::is_pointer::value); + + if( m == 0 ){ + throw std::length_error("Error in boost::numeric::ublas::ttm: Contraction mode must be greater than zero."); + } + if( p < m ){ + throw std::length_error("Error in boost::numeric::ublas::ttm: Rank must be greater equal than the specified mode."); + } + if( p == 0 ){ + throw std::length_error("Error in boost::numeric::ublas::ttm:Rank must be greater than zero."); + } + if(c == nullptr || a == nullptr || b == nullptr){ + throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); + } + for(auto i = 0u; i < m-1; ++i){ + if(na[i] != nc[i]){ + throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal."); + } + } + for(auto i = m; i < p; ++i){ + if(na[i] != nc[i]){ + throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal."); + } + } + if(na[m-1] != nb[1]){ + throw std::length_error("Error in boost::numeric::ublas::ttm: 2nd Extent of B and M-th Extent of A must be the equal."); + } + if(nc[m-1] != nb[0]){ + throw std::length_error("Error in boost::numeric::ublas::ttm: 1nd Extent of B and M-th Extent of C must be the equal."); + } + + + if ( m != 1 ){ + detail::recursive::ttm (m-1, p-1, c, nc, wc, a, na, wa, b, nb, wb); + } + else{ /*if (m == 1 && p > 2)*/ + detail::recursive::ttm0( p-1, c, nc, wc, a, na, wa, b, nb, wb); + } } @@ -769,39 +780,44 @@ void ttt(SizeType const pa, SizeType const pb, SizeType const q, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); - - if( pa == 0 || pb == 0) - throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero."); - - if( q > pa && q > pb) - throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order."); - - - SizeType const r = pa - q; - SizeType const s = pb - q; - - if(c == nullptr || a == nullptr || b == nullptr) - throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); - - for(auto i = 0ul; i < r; ++i) - if( na[phia[i]-1] != nc[i] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct."); - - for(auto i = 0ul; i < s; ++i) - if( nb[phib[i]-1] != nc[r+i] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct."); - - for(auto i = 0ul; i < q; ++i) - if( nb[phib[s+i]-1] != na[phia[r+i]-1] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct."); - - - if(q == 0ul) - detail::recursive::outer(SizeType{0},r,s, phia,phib, c,nc,wc, a,na,wa, b,nb,wb); - else - detail::recursive::ttt(SizeType{0},r,s,q, phia,phib, c,nc,wc, a,na,wa, b,nb,wb); + static_assert( std::is_pointer::value && std::is_pointer::value && std::is_pointer::value, + "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); + + if( pa == 0 || pb == 0){ + throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero."); + } + + if( q > pa && q > pb) { + throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order."); + } + + SizeType const r = pa - q; + SizeType const s = pb - q; + + if(c == nullptr || a == nullptr || b == nullptr){ + throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); + } + for(auto i = 0ul; i < r; ++i){ + if( na[phia[i]-1] != nc[i] ){ + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct."); + } + } + for(auto i = 0ul; i < s; ++i){ + if( nb[phib[i]-1] != nc[r+i] ){ + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct."); + } + } + for(auto i = 0ul; i < q; ++i){ + if( nb[phib[s+i]-1] != na[phia[r+i]-1] ){ + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct."); + } + } + if(q == 0ul){ + detail::recursive::outer(SizeType{0},r,s, phia,phib, c,nc,wc, a,na,wa, b,nb,wb); + } + else{ + detail::recursive::ttt(SizeType{0},r,s,q, phia,phib, c,nc,wc, a,na,wa, b,nb,wb); + } } @@ -836,45 +852,51 @@ void ttt(SizeType const pa, SizeType const pb, SizeType const q, PointerIn1 a, SizeType const*const na, SizeType const*const wa, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) { - static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); - - if( pa == 0 || pb == 0) - throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero."); - - if( q > pa && q > pb) - throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order."); - - - SizeType const r = pa - q; - SizeType const s = pb - q; - SizeType const pc = r+s; - - if(c == nullptr || a == nullptr || b == nullptr) - throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); - - for(auto i = 0ul; i < r; ++i) - if( na[i] != nc[i] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct."); - - for(auto i = 0ul; i < s; ++i) - if( nb[i] != nc[r+i] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct."); - - for(auto i = 0ul; i < q; ++i) - if( nb[s+i] != na[r+i] ) - throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct."); - - using value_type = std::decay_t; + static_assert( std::is_pointer::value && std::is_pointer::value && std::is_pointer::value, + "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); + + if( pa == 0 || pb == 0){ + throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero."); + } + if( q > pa && q > pb){ + throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order."); + } + + SizeType const r = pa - q; + SizeType const s = pb - q; + SizeType const pc = r+s; + + if(c == nullptr || a == nullptr || b == nullptr){ + throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); + } + for(auto i = 0ul; i < r; ++i){ + if( na[i] != nc[i] ){ + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct."); + } + } + for(auto i = 0ul; i < s; ++i){ + if( nb[i] != nc[r+i] ){ + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct."); + } + } + for(auto i = 0ul; i < q; ++i){ + if( nb[s+i] != na[r+i] ){ + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct."); + } + } + using value_type = std::decay_t; - if(q == 0ul) - detail::recursive::outer(pa, pc-1, c,nc,wc, pa-1, a,na,wa, pb-1, b,nb,wb); - else if(r == 0ul && s == 0ul) - *c = detail::recursive::inner(q-1, na, a,wa, b,wb, value_type(0) ); - else - detail::recursive::ttt(SizeType{0},r,s,q, c,nc,wc, a,na,wa, b,nb,wb); + if(q == 0ul){ + detail::recursive::outer(pa, pc-1, c,nc,wc, pa-1, a,na,wa, pb-1, b,nb,wb); + } + else if(r == 0ul && s == 0ul){ + *c = detail::recursive::inner(q-1, na, a,wa, b,wb, value_type(0) ); + } + else{ + detail::recursive::ttt(SizeType{0},r,s,q, c,nc,wc, a,na,wa, b,nb,wb); + } } @@ -900,14 +922,16 @@ auto inner(const SizeType p, SizeType const*const n, const PointerIn2 b, SizeType const*const wb, value_t v) { - static_assert( std::is_pointer::value && std::is_pointer::value, - "Static error in boost::numeric::ublas::inner: Argument types for pointers must be pointer types."); - if(p<2) - throw std::length_error("Error in boost::numeric::ublas::inner: Rank must be greater than zero."); - if(a == nullptr || b == nullptr) - throw std::length_error("Error in boost::numeric::ublas::inner: Pointers shall not be null pointers."); + static_assert( std::is_pointer::value && std::is_pointer::value, + "Static error in boost::numeric::ublas::inner: Argument types for pointers must be pointer types."); + if(p<2){ + throw std::length_error("Error in boost::numeric::ublas::inner: Rank must be greater than zero."); + } + if(a == nullptr || b == nullptr){ + throw std::length_error("Error in boost::numeric::ublas::inner: Pointers shall not be null pointers."); + } - return detail::recursive::inner(p-1, n, a, wa, b, wb, v); + return detail::recursive::inner(p-1, n, a, wa, b, wb, v); } @@ -936,24 +960,25 @@ void outer(PointerOut c, SizeType const pc, SizeType const*const nc, SizeT const PointerIn1 a, SizeType const pa, SizeType const*const na, SizeType const*const wa, const PointerIn2 b, SizeType const pb, SizeType const*const nb, SizeType const*const wb) { - static_assert( std::is_pointer::value & std::is_pointer::value & std::is_pointer::value, - "Static error in boost::numeric::ublas::outer: argument types for pointers must be pointer types."); - if(pa < 2u || pb < 2u) - throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs and rhs tensor must be equal or greater than two."); - if((pa + pb) != pc) - throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs plus rhs tensor must be equal to the number of extents of C."); - if(a == nullptr || b == nullptr || c == nullptr) - throw std::length_error("Error in boost::numeric::ublas::outer: pointers shall not be null pointers."); - - detail::recursive::outer(pa, pc-1, c, nc, wc, pa-1, a, na, wa, pb-1, b, nb, wb); + static_assert( std::is_pointer::value && std::is_pointer::value && std::is_pointer::value, + "Static error in boost::numeric::ublas::outer: argument types for pointers must be pointer types."); + if(pa < 2u || pb < 2u){ + throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs and rhs tensor must be equal or greater than two."); + } + if((pa + pb) != pc){ + throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs plus rhs tensor must be equal to the number of extents of C."); + } + if(a == nullptr || b == nullptr || c == nullptr){ + throw std::length_error("Error in boost::numeric::ublas::outer: pointers shall not be null pointers."); + } + + detail::recursive::outer(pa, pc-1, c, nc, wc, pa-1, a, na, wa, pb-1, b, nb, wb); } -} -} -} +} // namespace boost::numeric::ublas #endif diff --git a/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp b/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp index c6679a3d7..fa89d431f 100644 --- a/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp +++ b/include/boost/numeric/ublas/tensor/operators_arithmetic.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -16,16 +16,14 @@ #include "expression_evaluation.hpp" #include "multi_index_utility.hpp" #include "functions.hpp" -#include +#include "type_traits.hpp" #include #include #include -namespace boost{ -namespace numeric{ -namespace ublas { - +namespace boost::numeric::ublas +{ template class tensor_core; @@ -37,15 +35,14 @@ class matrix_expression; template class vector_expression; -} -} -} +} // namespace boost::numeric::ublas + template inline -constexpr auto operator*( - boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, - boost ::numeric ::ublas ::vector_expression const& rhs) noexcept + constexpr auto operator*( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::vector_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::multiplies<>{}); @@ -53,9 +50,9 @@ constexpr auto operator*( template inline -constexpr auto operator+( - boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, - boost ::numeric ::ublas ::vector_expression const& rhs) noexcept + constexpr auto operator+( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::vector_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::plus<>{}); @@ -63,9 +60,9 @@ constexpr auto operator+( template inline -constexpr auto operator-( - boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, - boost ::numeric ::ublas ::vector_expression const& rhs) noexcept + constexpr auto operator-( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::vector_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::minus<>{}); @@ -73,9 +70,9 @@ constexpr auto operator-( template inline -constexpr auto operator/( - boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, - boost ::numeric ::ublas ::vector_expression const& rhs) noexcept + constexpr auto operator/( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::vector_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::divides<>{}); @@ -84,9 +81,9 @@ constexpr auto operator/( template inline -constexpr auto operator*( - boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, - boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept + constexpr auto operator*( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::multiplies<>{}); @@ -94,9 +91,9 @@ constexpr auto operator*( template inline -constexpr auto operator+( - boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, - boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept + constexpr auto operator+( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::plus<>{}); @@ -104,9 +101,9 @@ constexpr auto operator+( template inline -constexpr auto operator-( - boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, - boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept + constexpr auto operator-( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::minus<>{}); @@ -114,9 +111,9 @@ constexpr auto operator-( template inline -constexpr auto operator/( - boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, - boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept + constexpr auto operator/( + boost ::numeric ::ublas ::detail ::tensor_expression const& lhs, + boost ::numeric ::ublas ::matrix_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::divides<>{}); @@ -125,9 +122,9 @@ constexpr auto operator/( template inline -constexpr auto operator*( - boost ::numeric ::ublas ::vector_expression const& lhs, - boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept + constexpr auto operator*( + boost ::numeric ::ublas ::vector_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::multiplies<>{}); @@ -135,9 +132,9 @@ constexpr auto operator*( template inline -constexpr auto operator+( - boost ::numeric ::ublas ::vector_expression const& lhs, - boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept + constexpr auto operator+( + boost ::numeric ::ublas ::vector_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::plus<>{}); @@ -145,9 +142,9 @@ constexpr auto operator+( template inline -constexpr auto operator-( - boost ::numeric ::ublas ::vector_expression const& lhs, - boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept + constexpr auto operator-( + boost ::numeric ::ublas ::vector_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::minus<>{}); @@ -155,9 +152,9 @@ constexpr auto operator-( template inline -constexpr auto operator/( - boost ::numeric ::ublas ::vector_expression const& lhs, - boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept + constexpr auto operator/( + boost ::numeric ::ublas ::vector_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::divides<>{}); @@ -166,9 +163,9 @@ constexpr auto operator/( template inline -constexpr auto operator*( - boost ::numeric ::ublas ::matrix_expression const& lhs, - boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept + constexpr auto operator*( + boost ::numeric ::ublas ::matrix_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::multiplies<>{}); @@ -176,9 +173,9 @@ constexpr auto operator*( template inline -constexpr auto operator+( - boost ::numeric ::ublas ::matrix_expression const& lhs, - boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept + constexpr auto operator+( + boost ::numeric ::ublas ::matrix_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::plus<>{}); @@ -186,9 +183,9 @@ constexpr auto operator+( template inline -constexpr auto operator-( - boost ::numeric ::ublas ::matrix_expression const& lhs, - boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept + constexpr auto operator-( + boost ::numeric ::ublas ::matrix_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::minus<>{}); @@ -196,9 +193,9 @@ constexpr auto operator-( template inline -constexpr auto operator/( - boost ::numeric ::ublas ::matrix_expression const& lhs, - boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept + constexpr auto operator/( + boost ::numeric ::ublas ::matrix_expression const& lhs, + boost ::numeric ::ublas ::detail ::tensor_expression const& rhs) noexcept { return boost ::numeric ::ublas ::detail ::make_binary_tensor_expression( lhs(), rhs(), std::divides<>{}); @@ -207,191 +204,191 @@ constexpr auto operator/( template inline -constexpr auto operator+( boost::numeric::ublas::detail::tensor_expression const& lhs, + constexpr auto operator+( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - - static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, - "operator+() : LHS tensor and RHS tensor should have the same value type" - ); - - if constexpr( !std::is_same_v ){ - auto const& e = boost::numeric::ublas::detail::retrieve_extents(rhs); - - if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ - throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); - } + + static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, + "operator+() : LHS tensor and RHS tensor should have the same value type" + ); + + if constexpr( !std::is_same_v ){ + auto const& e = boost::numeric::ublas::detail::retrieve_extents(rhs); + + if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ + throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); } + } - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l + r; }); + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l + r; }); } template inline -constexpr auto operator-( boost::numeric::ublas::detail::tensor_expression const& lhs, + constexpr auto operator-( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - - static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, - "operator-() : LHS tensor and RHS tensor should have the same value type" - ); - if constexpr( !std::is_same_v ){ - auto e = boost::numeric::ublas::detail::retrieve_extents(rhs); + static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, + "operator-() : LHS tensor and RHS tensor should have the same value type" + ); + + if constexpr( !std::is_same_v ){ + auto e = boost::numeric::ublas::detail::retrieve_extents(rhs); - if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ - throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); - } + if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ + throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); } + } - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l - r; }); -// return boost::numeric::ublas::detail::make_lambda([&lhs,&rhs](std::size_t i){ return lhs(i) - rhs(i);}); + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l - r; }); + // return boost::numeric::ublas::detail::make_lambda([&lhs,&rhs](std::size_t i){ return lhs(i) - rhs(i);}); } template inline -constexpr auto operator*( boost::numeric::ublas::detail::tensor_expression const& lhs, + constexpr auto operator*( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - - static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, - "operator*() : LHS tensor and RHS tensor should have the same value type" - ); - if constexpr( !std::is_same_v ){ - auto const& e = boost::numeric::ublas::detail::retrieve_extents(rhs); + static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, + "operator*() : LHS tensor and RHS tensor should have the same value type" + ); - if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ - throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); - } + if constexpr( !std::is_same_v ){ + auto const& e = boost::numeric::ublas::detail::retrieve_extents(rhs); + + if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ + throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); } + } - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l * r; }); + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), [](auto const& l, auto const& r){ return l * r; }); } template inline -constexpr auto operator/( boost::numeric::ublas::detail::tensor_expression const& lhs, + constexpr auto operator/( boost::numeric::ublas::detail::tensor_expression const& lhs, boost::numeric::ublas::detail::tensor_expression const& rhs) { - - static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, - "operator/() : LHS tensor and RHS tensor should have the same value type" - ); - if constexpr( !std::is_same_v ){ - auto e = boost::numeric::ublas::detail::retrieve_extents(rhs); + static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, + "operator/() : LHS tensor and RHS tensor should have the same value type" + ); + + if constexpr( !std::is_same_v ){ + auto e = boost::numeric::ublas::detail::retrieve_extents(rhs); - if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ - throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); - } + if( !boost::numeric::ublas::detail::all_extents_equal(lhs,e) ){ + throw std::runtime_error("operator+() : LHS tensor and RHS tensor should have equal extents"); } + } - return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), std::divides<>{}); + return boost::numeric::ublas::detail::make_binary_tensor_expression (lhs(), rhs(), std::divides<>{}); } // Overloaded Arithmetic Operators with Scalars template inline -constexpr auto operator+(typename boost::numeric::ublas::tensor_core::const_reference lhs, + constexpr auto operator+(typename boost::numeric::ublas::tensor_core::const_reference lhs, boost::numeric::ublas::detail::tensor_expression,R> const& rhs) noexcept { - using tensor_core_type = boost::numeric::ublas::tensor_core; - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs + r; }); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs + r; }); } template inline -constexpr auto operator-(typename boost::numeric::ublas::tensor_core::const_reference lhs, + constexpr auto operator-(typename boost::numeric::ublas::tensor_core::const_reference lhs, boost::numeric::ublas::detail::tensor_expression,R> const& rhs) noexcept { - using tensor_core_type = boost::numeric::ublas::tensor_core; - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs - r; }); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs - r; }); } template inline -constexpr auto operator*(typename boost::numeric::ublas::tensor_core::const_reference lhs, + constexpr auto operator*(typename boost::numeric::ublas::tensor_core::const_reference lhs, boost::numeric::ublas::detail::tensor_expression,R> const& rhs) noexcept { - using tensor_core_type = boost::numeric::ublas::tensor_core; - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs * r; }); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs * r; }); } template inline -constexpr auto operator/(typename boost::numeric::ublas::tensor_core::const_reference lhs, + constexpr auto operator/(typename boost::numeric::ublas::tensor_core::const_reference lhs, boost::numeric::ublas::detail::tensor_expression,R> const& rhs) noexcept { - using tensor_core_type = boost::numeric::ublas::tensor_core; - return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs / r; }); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (rhs(), [lhs](auto const& r){ return lhs / r; }); } template inline -constexpr auto operator+(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + constexpr auto operator+(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, typename boost::numeric::ublas::tensor_core::const_reference rhs) noexcept { - using tensor_core_type = boost::numeric::ublas::tensor_core; - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l + rhs; } ); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l + rhs; } ); } template inline -constexpr auto operator-(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + constexpr auto operator-(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, typename boost::numeric::ublas::tensor_core::const_reference rhs) noexcept { - using tensor_core_type = boost::numeric::ublas::tensor_core; - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l - rhs; } ); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l - rhs; } ); } template inline -constexpr auto operator*(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + constexpr auto operator*(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, typename boost::numeric::ublas::tensor_core::const_reference rhs) noexcept { - using tensor_core_type = boost::numeric::ublas::tensor_core; - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l * rhs; } ); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l * rhs; } ); } template inline -constexpr auto operator/(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, + constexpr auto operator/(boost::numeric::ublas::detail::tensor_expression,L> const& lhs, typename boost::numeric::ublas::tensor_core::const_reference rhs) noexcept { - using tensor_core_type = boost::numeric::ublas::tensor_core; - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l / rhs; } ); + using tensor_core_type = boost::numeric::ublas::tensor_core; + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), [rhs] (auto const& l) { return l / rhs; } ); } template inline -constexpr auto& operator += (boost::numeric::ublas::tensor_core& lhs, + constexpr auto& operator += (boost::numeric::ublas::tensor_core& lhs, const boost::numeric::ublas::detail::tensor_expression,D> &expr) { - boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l+=r; } ); - return lhs; + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l+=r; } ); + return lhs; } template inline -constexpr auto& operator -= (boost::numeric::ublas::tensor_core& lhs, + constexpr auto& operator -= (boost::numeric::ublas::tensor_core& lhs, const boost::numeric::ublas::detail::tensor_expression,D> &expr) { - boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l-=r; } ); - return lhs; + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l-=r; } ); + return lhs; } template inline -constexpr auto& operator *= (boost::numeric::ublas::tensor_core& lhs, + constexpr auto& operator *= (boost::numeric::ublas::tensor_core& lhs, const boost::numeric::ublas::detail::tensor_expression,D> &expr) { - boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l*=r; } ); - return lhs; + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l*=r; } ); + return lhs; } template inline -constexpr auto& operator /= (boost::numeric::ublas::tensor_core& lhs, + constexpr auto& operator /= (boost::numeric::ublas::tensor_core& lhs, const boost::numeric::ublas::detail::tensor_expression,D> &expr) { - boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l/=r; } ); - return lhs; + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l/=r; } ); + return lhs; } @@ -399,36 +396,36 @@ constexpr auto& operator /= (boost::numeric::ublas::tensor_core& lhs, template inline -constexpr auto& operator += (boost::numeric::ublas::tensor_core& lhs, + constexpr auto& operator += (boost::numeric::ublas::tensor_core& lhs, typename boost::numeric::ublas::tensor_core::const_reference r) { - boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l+=r; } ); - return lhs; + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l+=r; } ); + return lhs; } template inline -constexpr auto& operator -= (boost::numeric::ublas::tensor_core& lhs, + constexpr auto& operator -= (boost::numeric::ublas::tensor_core& lhs, typename boost::numeric::ublas::tensor_core::const_reference r) { - boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l-=r; } ); - return lhs; + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l-=r; } ); + return lhs; } template inline -constexpr auto& operator *= (boost::numeric::ublas::tensor_core& lhs, + constexpr auto& operator *= (boost::numeric::ublas::tensor_core& lhs, typename boost::numeric::ublas::tensor_core::const_reference r) { - boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l*=r; } ); - return lhs; + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l*=r; } ); + return lhs; } template constexpr auto& operator /= (boost::numeric::ublas::tensor_core& lhs, typename boost::numeric::ublas::tensor_core::const_reference r) { - boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l/=r; } ); + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l/=r; } ); return lhs; } @@ -438,15 +435,15 @@ constexpr auto& operator /= (boost::numeric::ublas::tensor_core& l template -inline -constexpr auto const& operator +(const boost::numeric::ublas::detail::tensor_expression& lhs) noexcept{ - return lhs; +inline constexpr + auto const& operator +(const boost::numeric::ublas::detail::tensor_expression& lhs) noexcept{ + return lhs; } template -inline -constexpr auto operator -(boost::numeric::ublas::detail::tensor_expression const& lhs) { - return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), std::negate<>{} ); +inline constexpr + auto operator -(boost::numeric::ublas::detail::tensor_expression const& lhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression (lhs(), std::negate<>{} ); } @@ -459,33 +456,53 @@ constexpr auto operator -(boost::numeric::ublas::detail::tensor_expression template auto operator*( - std::pair< tensor_type_left const&, tuple_type_left > lhs, - std::pair< tensor_type_right const&, tuple_type_right > rhs) + std::pair< tensor_type_left const&, tuple_type_left > lhs, + std::pair< tensor_type_right const&, tuple_type_right > rhs) { - using namespace boost::numeric::ublas; + namespace ublas = boost::numeric::ublas; - auto const& tensor_left = lhs.first; - auto const& tensor_right = rhs.first; + auto const& tensor_left = lhs.first; + auto const& tensor_right = rhs.first; - auto multi_index_left = lhs.second; - auto multi_index_right = rhs.second; + auto multi_index_left = lhs.second; + auto multi_index_right = rhs.second; - static constexpr auto num_equal_ind = number_equal_indexes::value; + static constexpr auto num_equal_ind = ublas::number_equal_indexes::value; - if constexpr ( num_equal_ind == 0 ){ - return tensor_left * tensor_right; - } - else if constexpr ( num_equal_ind==std::tuple_size::value && std::is_same::value ){ + if constexpr ( num_equal_ind == 0 ){ + return tensor_left * tensor_right; + } + else if constexpr ( num_equal_ind==std::tuple_size::value && std::is_same::value ){ - return boost::numeric::ublas::inner_prod( tensor_left, tensor_right ); - } - else { - auto array_index_pairs = index_position_pairs(multi_index_left,multi_index_right); - auto index_pairs = array_to_vector( array_index_pairs ); - return boost::numeric::ublas::prod( tensor_left, tensor_right, index_pairs.first, index_pairs.second ); + return ublas::inner_prod( tensor_left, tensor_right ); + } + else { + auto index_pairs = ublas::index_position_pairs(multi_index_left,multi_index_right); + constexpr auto size = std::tuple_size_v; + + using extents_left_type = typename tensor_type_left ::extents_type; + using extents_right_type = typename tensor_type_right::extents_type; + + constexpr bool has_dynamic_extents = ublas::is_dynamic_rank_v || ublas::is_dynamic_rank_v; + + using index_tuple = std::conditional_t, std::array>; + + auto phi_left = index_tuple{}; + auto phi_right = index_tuple{}; + + if constexpr(has_dynamic_extents) { + phi_left .resize(size); + phi_right.resize(size); } + std::transform(index_pairs.begin(), index_pairs.end(), phi_left .begin(), [](auto a){ return a.first +1ul; } ); + std::transform(index_pairs.begin(), index_pairs.end(), phi_right.begin(), [](auto b){ return b.second +1ul; } ); + +// auto index_pairs = ublas::array_to_vector( array_index_pairs ); + return ublas::prod( tensor_left, tensor_right, phi_left, phi_right ); + } + } #endif diff --git a/include/boost/numeric/ublas/tensor/operators_comparison.hpp b/include/boost/numeric/ublas/tensor/operators_comparison.hpp index 7516c1731..efc6c7323 100644 --- a/include/boost/numeric/ublas/tensor/operators_comparison.hpp +++ b/include/boost/numeric/ublas/tensor/operators_comparison.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,20 +12,23 @@ #ifndef BOOST_UBLAS_TENSOR_OPERATORS_COMPARISON_HPP #define BOOST_UBLAS_TENSOR_OPERATORS_COMPARISON_HPP -#include -#include -#include #include #include #include #include +#include "extents.hpp" +#include "expression.hpp" +#include "type_traits.hpp" +#include "expression_evaluation.hpp" + namespace boost::numeric::ublas { template class tensor_core; -} +} // namespace boost::numeric::ublas -namespace boost::numeric::ublas::detail { +namespace boost::numeric::ublas::detail +{ template [[nodiscard]] inline @@ -36,7 +39,7 @@ constexpr bool compare(tensor_core const& lhs, tensor_core const& rhs, B "LHS and RHS both should have the same value type" ); - if(lhs.extents() != rhs.extents()){ + if(::operator!=(lhs.extents(),rhs.extents())){ if constexpr(!std::is_same>::value && !std::is_same>::value) throw std::runtime_error( "boost::numeric::ublas::detail::compare(tensor_core const&, tensor_core const&, BinaryPred) : " @@ -95,43 +98,49 @@ constexpr bool compare(tensor_expression const& expr, UnaryPred pred) return compare(T( expr ), pred); } -} +} // namespace boost::numeric::ublas::detail template -[[nodiscard]] inline -constexpr bool operator==( boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { +[[nodiscard]] inline +constexpr bool operator==( + boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { return boost::numeric::ublas::detail::compare( lhs, rhs, std::equal_to<>{} ); } template [[nodiscard]] inline -constexpr auto operator!=(boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { +constexpr auto operator!=( + boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { return boost::numeric::ublas::detail::compare( lhs, rhs, std::not_equal_to<>{} ); } template [[nodiscard]] inline -constexpr auto operator< ( boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { +constexpr auto operator< ( + boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { return boost::numeric::ublas::detail::compare( lhs, rhs, std::less<>{} ); } template [[nodiscard]] inline -constexpr auto operator<=( boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { +constexpr auto operator<=( + boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { return boost::numeric::ublas::detail::compare( lhs, rhs, std::less_equal<>{} ); } template [[nodiscard]] inline -constexpr auto operator> ( boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { +constexpr auto operator> ( + boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { return boost::numeric::ublas::detail::compare( lhs, rhs, std::greater<>{} ); } template [[nodiscard]] inline -constexpr auto operator>=( boost::numeric::ublas::detail::tensor_expression const& lhs, - boost::numeric::ublas::detail::tensor_expression const& rhs) { +constexpr auto operator>=( + boost::numeric::ublas::detail::tensor_expression const& lhs, + boost::numeric::ublas::detail::tensor_expression const& rhs) { return boost::numeric::ublas::detail::compare( lhs, rhs, std::greater_equal<>{} ); } diff --git a/include/boost/numeric/ublas/tensor/ostream.hpp b/include/boost/numeric/ublas/tensor/ostream.hpp index 1940546a3..2ce7940cc 100644 --- a/include/boost/numeric/ublas/tensor/ostream.hpp +++ b/include/boost/numeric/ublas/tensor/ostream.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,25 +12,28 @@ #ifndef BOOST_UBLAS_TENSOR_OSTREAM_HPP #define BOOST_UBLAS_TENSOR_OSTREAM_HPP -#include + +#include "extents/extents_functions.hpp" + + #include -#include +#include + -namespace boost { -namespace numeric { -namespace ublas { -namespace detail { + +namespace boost::numeric::ublas::detail +{ template void print(std::ostream& out, value_type const& p) { - out << p << " "; + out << p << " "; } template void print(std::ostream& out, const std::complex& p) { - out << std::real(p) << "+" << std::imag(p) << "i "; + out << std::real(p) << "+" << std::imag(p) << "i "; } @@ -38,95 +41,80 @@ template void print(std::ostream& out, size_type r, const value_type* p, const size_type* w, const size_type* n) { - if(r < 2) + if(r < 2) + { + out << "[ ... " << std::endl; + + for(auto row = 0u; row < n[0]; p += w[0], ++row) // iterate over one column { - out << "[ ... " << std::endl; - - for(auto row = 0u; row < n[0]; p += w[0], ++row) // iterate over one column - { - auto const* p1 = p; - for(auto col = 0u; col < n[1]; p1 += w[1], ++col) // iterate over first row - { - print(out,*p1); - } - if(row < n[0]-1) - out << "; " << std::endl; - } - out << "]"; + auto const* p1 = p; + for(auto col = 0u; col < n[1]; p1 += w[1], ++col) // iterate over first row + { + print(out,*p1); + } + if(row < n[0]-1){ + out << "; " << std::endl; + } } - else - { - out << "cat("<< r+1 <<",..." << std::endl; - for(auto d = 0u; d < n[r]-1; p += w[r], ++d){ - print(out, r-1, p, w, n); - out << ",..." << std::endl; - } - print(out, r-1, p, w, n); + out << "]"; + } + else + { + out << "cat("<< r+1 <<",..." << std::endl; + for(auto d = 0u; d < n[r]-1; p += w[r], ++d){ + print(out, r-1, p, w, n); + out << ",..." << std::endl; } - if(r>1) - out << ")"; + print(out, r-1, p, w, n); + } + if(r>1){ + out << ")"; + } } //////////////////////////// -} -} -} -} +} // namespace boost::numeric::ublas::detail -namespace boost { -namespace numeric { -namespace ublas { +namespace boost::numeric::ublas +{ template class tensor_core; -template -class matrix; - -template -class vector; - -} -} -} +} //namespace boost::numeric::ublas template -std::ostream& operator << (std::ostream& out, boost::numeric::ublas::tensor_core const& t) +std::ostream& operator << (std::ostream& out, class boost::numeric::ublas::tensor_core const& t) { - if(is_scalar(t.extents())){ - out << '['; - boost::numeric::ublas::detail::print(out,t[0]); - out << ']'; - } - else if(is_vector(t.extents())) { - const auto& cat = t.extents().at(0) > t.extents().at(1) ? ';' : ','; - out << '['; - for(auto i = 0u; i < t.size()-1; ++i){ - boost::numeric::ublas::detail::print(out,t[i]); - out << cat << ' '; - } - boost::numeric::ublas::detail::print(out,t[t.size()-1]); - out << ']'; + namespace ublas = boost::numeric::ublas; + + auto const& n = t.extents(); + auto const& w = t.strides(); + + if(is_scalar(n)){ + out << '['; + ublas::detail::print(out,t[0]); + out << ']'; + } + else if(is_vector(n)) { + const auto& cat = n.at(0) > n.at(1) ? ';' : ','; + out << '['; + for(auto i = 0u; i < t.size()-1; ++i){ + ublas::detail::print(out,t[i]); + out << cat << ' '; } - else{ - boost::numeric::ublas::detail::print(out, t.rank()-1, t.data(), t.strides().data(), t.extents().data()); - } - return out; -} - -template - || boost::numeric::ublas::is_extents_v - , int> = 0 -> -std::ostream& operator<<(std::ostream& os, T const& e){ - return os< -#include -#include - -namespace boost::numeric::ublas { - -template class basic_static_extents; - -/** @brief Template class for storing tensor extents for compile time. - * - * @code basic_static_extents<1,2,3,4> t @endcode - * @tparam E parameter pack of extents - * - */ -template -class basic_static_extents{ - -public: - - static constexpr auto _size = sizeof...(E); - - using base_type = std::array; - using value_type = typename base_type::value_type; - using size_type = typename base_type::size_type; - using reference = typename base_type::reference; - using const_reference = typename base_type::const_reference; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - using const_reverse_iterator = typename base_type::const_reverse_iterator; - - static_assert( std::numeric_limits::is_integer, "Static error in basic_static_extents: type must be of type integer."); - static_assert(!std::numeric_limits::is_signed, "Static error in basic_static_extents: type must be of type unsigned integer."); - - //@returns the rank of basic_static_extents - [[nodiscard]] inline - constexpr size_type size() const noexcept { return _size; } - - /** - * @param k pos of extent - * @returns the element at given pos - */ - [[nodiscard]] inline - static constexpr const_reference at(size_type k){ - return m_data.at(k); - } - - [[nodiscard]] inline - constexpr const_reference operator[](size_type k) const{ - return m_data[k]; - } - - constexpr basic_static_extents() = default; - - constexpr basic_static_extents(basic_static_extents const&) noexcept = default; - constexpr basic_static_extents(basic_static_extents &&) noexcept = default; - - constexpr basic_static_extents& operator=(basic_static_extents const&) noexcept = default; - constexpr basic_static_extents& operator=(basic_static_extents &&) noexcept = default; - - ~basic_static_extents() = default; - - /** @brief Returns ref to the std::array containing extents */ - [[nodiscard]] inline - constexpr base_type const& base() const noexcept{ - return m_data; - } - - /** @brief Returns pointer to the std::array containing extents */ - [[nodiscard]] inline - constexpr const_pointer data() const noexcept{ - return m_data.data(); - } - - /** @brief Checks if extents is empty or not - * - * @returns true if rank is 0 else false - * - */ - [[nodiscard]] inline - constexpr bool empty() const noexcept { return m_data.empty(); } - - [[nodiscard]] inline - constexpr const_reference back() const{ - return m_data.back(); - } - - [[nodiscard]] inline - constexpr const_iterator begin() const noexcept{ - return m_data.begin(); - } - - [[nodiscard]] inline - constexpr const_iterator end() const noexcept{ - return m_data.end(); - } - - [[nodiscard]] inline - constexpr const_reverse_iterator - rbegin() const noexcept - { - return m_data.rbegin(); - } - - [[nodiscard]] inline - constexpr const_reverse_iterator - rend() const noexcept - { - return m_data.rend(); - } - - /// msvc 14.27 does not consider 'at' function constexpr. - /// To make msvc happy get function is declared - /// and it will be removed when we start using boost.mp11 - template - static constexpr auto get() noexcept{ - static_assert(I < _size, - "boost::numeric::ublas::basic_static_extents::get() : " - "out of bound access" - ); - using element_at = std::tuple_element_t; - return element_at{}; - } - -private: - static constexpr base_type const m_data{E...}; - /// will be removed when we start using boost.mp11 - using tuple_type = std::tuple< std::integral_constant... >; -}; - - -template -using static_extents = basic_static_extents; - -} // namespace boost::numeric::ublas -#endif diff --git a/include/boost/numeric/ublas/tensor/static_strides.hpp b/include/boost/numeric/ublas/tensor/static_strides.hpp deleted file mode 100644 index f43101b8c..000000000 --- a/include/boost/numeric/ublas/tensor/static_strides.hpp +++ /dev/null @@ -1,267 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// -/// \file strides.hpp Definition for the basic_strides template class - -#ifndef BOOST_UBLAS_TENSOR_STATIC_STRIDES_HPP -#define BOOST_UBLAS_TENSOR_STATIC_STRIDES_HPP - -#include -#include -#include - -namespace boost::numeric::ublas{ - - template class basic_static_strides; - -} // boost::numeric::ublas - -namespace boost::numeric::ublas::detail{ - - namespace impl{ - - // concat two static_stride_list togather - // @code using type = typename concat< static_stride_list, static_stride_list >::type @endcode - template - struct concat; - - template - struct concat< basic_static_extents, basic_static_extents > { - using type = basic_static_extents; - }; - - template - using concat_t = typename concat::type; - - // generates static_stride_list containing ones with specific size - template - struct make_sequence_of_ones; - - template - using make_sequence_of_ones_t = typename make_sequence_of_ones::type; - - template - struct make_sequence_of_ones { - using type = concat_t, make_sequence_of_ones_t>; - }; - - template - struct make_sequence_of_ones { - using type = basic_static_extents; - }; - template - struct make_sequence_of_ones{ - using type = basic_static_extents; - }; - - template - struct extents_to_array; - - template - inline static constexpr auto extents_to_array_v = extents_to_array::value; - - template - struct extents_to_array< basic_static_extents > - { - static constexpr std::array const value = {Es...}; - }; - - } // impl - - - template - using make_sequence_of_ones_t = impl::make_sequence_of_ones_t; - - template - constexpr auto make_static_strides_first_order( [[maybe_unused]] E const& e, [[maybe_unused]] basic_static_extents const& res ){ - if constexpr( I >= E::_size - 1ul ){ - return impl::extents_to_array_v< basic_static_extents >; - }else{ - using res_type = basic_static_extents; - - constexpr auto prod = E::template get().value * res_type::template get().value; - using nextents = basic_static_extents; - return make_static_strides_first_order(e, nextents{}); - } - } - - template - constexpr auto make_static_strides_last_order( [[maybe_unused]] E const& e, [[maybe_unused]] basic_static_extents const& res ){ - if constexpr( I >= E::_size - 1ul ){ - return impl::extents_to_array_v< basic_static_extents >; - }else{ - using res_type = basic_static_extents; - - constexpr auto J = E::_size - I - 1ul; - constexpr auto K = res_type::_size - I - 1ul; - constexpr auto prod = E::template get().value * res_type::template get().value; - using nextents = basic_static_extents; - return make_static_strides_last_order(e, nextents{}); - } - } - - template - constexpr auto make_static_strides( [[maybe_unused]] E const& e ){ - using value_type = typename E::value_type; - if constexpr( E::_size == 0 ){ - return impl::extents_to_array_v; - }else if constexpr( is_scalar(E{}) || is_vector(E{}) ){ - using extents_with_ones = make_sequence_of_ones_t; - return impl::extents_to_array_v; - }else{ - if constexpr( std::is_same_v ){ - return make_static_strides_first_order(e, basic_static_extents{}); - }else{ - return make_static_strides_last_order(e, basic_static_extents{}); - } - } - } - - // It is use for first order to - // get std::array containing strides - template - inline static constexpr auto strides_helper_v = make_static_strides(ExtentsType{}); - -} // namespace boost::numeric::ublas::detail - -namespace boost::numeric::ublas -{ -/** @brief Partial Specialization for layout::first_order or column_major - * - * @code basic_static_strides, layout::first_order> s @endcode - * - * @tparam R rank of basic_static_extents - * @tparam Extents paramerter pack of extents - * - */ -template -class basic_static_strides, Layout> -{ - -public: - - static constexpr std::size_t const _size = sizeof...(Extents); - - using layout_type = Layout; - using extents_type = basic_static_extents; - using base_type = std::array; - using value_type = typename base_type::value_type; - using reference = typename base_type::reference; - using const_reference = typename base_type::const_reference; - using size_type = typename base_type::size_type; - using const_pointer = typename base_type::const_pointer; - using const_iterator = typename base_type::const_iterator; - using const_reverse_iterator = typename base_type::const_reverse_iterator; - - /** - * @param k pos of extent - * @returns the element at given pos - */ - [[nodiscard]] inline - constexpr const_reference at(size_type k) const - { - return m_data.at(k); - } - - [[nodiscard]] inline - constexpr const_reference operator[](size_type k) const { return m_data[k]; } - - //@returns the rank of basic_static_extents - [[nodiscard]] inline - constexpr size_type size() const noexcept { return static_cast(_size); } - - [[nodiscard]] inline - constexpr const_reference back () const{ - return m_data.back(); - } - - // default constructor - constexpr basic_static_strides() noexcept{ - static_assert( - _size == 0 || - ( is_valid(extents_type{}) && - ( is_vector(extents_type{}) || - is_scalar(extents_type{}) || - _size >= 2 - ) - ) - , - "Error in boost::numeric::ublas::basic_static_strides() : " - "Size cannot be 0 or Shape should be valid and shape can be vector or shape can be scalar or size should be greater than" - " or equal to 2" - ); - - - } - - constexpr basic_static_strides(extents_type const& e) noexcept{ (void)e; }; - - // default copy constructor - constexpr basic_static_strides(basic_static_strides const &other) noexcept = default; - constexpr basic_static_strides(basic_static_strides &&other) noexcept = default; - - // default assign constructor - constexpr basic_static_strides & - operator=(basic_static_strides const &other) noexcept = default; - - constexpr basic_static_strides & - operator=(basic_static_strides &&other) noexcept = default; - - ~basic_static_strides() = default; - - /** @brief Returns ref to the std::array containing extents */ - [[nodiscard]] inline - constexpr auto const& base() const noexcept{ - return m_data; - } - - /** @brief Returns pointer to the std::array containing extents */ - [[nodiscard]] inline - constexpr const_pointer data() const noexcept{ - return m_data.data(); - } - - [[nodiscard]] inline - constexpr const_iterator begin() const noexcept{ - return m_data.begin(); - } - - [[nodiscard]] inline - constexpr const_iterator end() const noexcept{ - return m_data.end(); - } - - [[nodiscard]] inline - constexpr bool empty() const noexcept{ - return m_data.empty(); - } - - [[nodiscard]] inline - constexpr const_reverse_iterator - rbegin() const noexcept - { - return m_data.rbegin(); - } - - [[nodiscard]] inline - constexpr const_reverse_iterator - rend() const noexcept - { - return m_data.rend(); - } - -private: - static constexpr base_type const m_data{ detail::strides_helper_v }; -}; - -} // namespace boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/strides.hpp b/include/boost/numeric/ublas/tensor/strides.hpp deleted file mode 100644 index eb78c24da..000000000 --- a/include/boost/numeric/ublas/tensor/strides.hpp +++ /dev/null @@ -1,99 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// -/// \file strides.hpp Definition for the basic_strides template class - -#ifndef _BOOST_UBLAS_TENSOR_STRIDES_HPP_ -#define _BOOST_UBLAS_TENSOR_STRIDES_HPP_ - -#include -#include -#include - -namespace boost::numeric::ublas{ - - template && is_strides_v - , int> = 0 - > - [[nodiscard]] inline - constexpr bool operator==(LStrides const& lhs, RStrides const& rhs) noexcept{ - static_assert( std::is_same_v, - "boost::numeric::ublas::operator==(LStrides,RStrides) : LHS value type should be the same as the RHS value type"); - - return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); - } - - template && is_strides_v - , int> = 0 - > - [[nodiscard]] inline - constexpr bool operator!=(LStrides const& lhs, RStrides const& rhs) noexcept{ - static_assert( std::is_same_v, - "boost::numeric::ublas::operator!=(LStrides,RStrides) : LHS value type should be the same as the RHS value type"); - return !( lhs == rhs ); - } - -} // namespace boost::numeric::ublas - - -namespace boost::numeric::ublas::detail { - - /** @brief Returns relative memory index with respect to a multi-index - * - * @code auto j = access(std::vector{3,4,5}, strides{shape{4,2,3},first_order}); @endcode - * - * @param[in] i multi-index of length p - * @param[in] w stride vector of length p - * @returns relative memory location depending on \c i and \c w - */ - template - [[nodiscard]] inline - constexpr auto access(std::vector const& i, Stride const& w) - { - static_assert( is_strides_v, - "boost::numeric::ublas::detail::access() : invalid type, the type should be a strides"); - - using value_type = typename Stride::value_type; - return std::inner_product(i.begin(), i.end(), w.begin(), value_type{}); - } - - /** @brief Returns relative memory index with respect to a multi-index - * - * @code auto j = access(strides{shape{4,2,3},first_order}, 2,3,4); @endcode - * - * @param[in] is the elements of the partial multi-index - * @param[in] sum the current relative memory index - * @returns relative memory location depending on \c i and \c w - */ - template - [[nodiscard]] inline - constexpr auto access(Stride const& w, Indices ... is) - { - static_assert( is_strides_v, - "boost::numeric::ublas::detail::access() : invalid type, the type should be a strides"); - - if constexpr( is_static_rank_v ){ - static_assert( Stride::_size >= sizeof...(is), - "boost::numeric::ublas::detail::access() : number of indices exceeds the size of the stride"); - } - - using value_type = typename Stride::value_type; - std::array i = {is...}; - return std::inner_product(i.begin(), i.end(), w.begin(), value_type{}); - } - -} // namespace boost::numeric::ublas::detail - -#endif diff --git a/include/boost/numeric/ublas/tensor/tags.hpp b/include/boost/numeric/ublas/tensor/tags.hpp index 079c2e783..7774f9ccb 100644 --- a/include/boost/numeric/ublas/tensor/tags.hpp +++ b/include/boost/numeric/ublas/tensor/tags.hpp @@ -1,17 +1,15 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2020, Amit Singh, amitsingh19975@gmail.com // // 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany // -#ifndef BOOST_UBLAS_TENSOR_TAGS_IMPL_HPP -#define BOOST_UBLAS_TENSOR_TAGS_IMPL_HPP +#ifndef BOOST_UBLAS_TENSOR_TAGS_HPP +#define BOOST_UBLAS_TENSOR_TAGS_HPP namespace boost::numeric::ublas{ @@ -25,7 +23,7 @@ namespace boost::numeric::ublas{ struct storage_non_seq_container_tag{}; -} // namespace boost::numeric::ublas::tag +} // namespace boost::numeric::ublas -#endif +#endif // BOOST_UBLAS_TENSOR_TAGS_HPP diff --git a/include/boost/numeric/ublas/tensor/tensor.hpp b/include/boost/numeric/ublas/tensor/tensor.hpp index f635f4fbe..02ceaa53a 100644 --- a/include/boost/numeric/ublas/tensor/tensor.hpp +++ b/include/boost/numeric/ublas/tensor/tensor.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -10,46 +10,13 @@ // Google and Fraunhofer IOSB, Ettlingen, Germany // -#ifndef BOOST_UBLAS_TENSOR_IMPL_HPP -#define BOOST_UBLAS_TENSOR_IMPL_HPP +#ifndef BOOST_UBLAS_TENSOR_TENSOR_HPP +#define BOOST_UBLAS_TENSOR_TENSOR_HPP -#include -#include +#include "tensor/tensor_core.hpp" +#include "tensor/tensor_dynamic.hpp" +#include "tensor/tensor_engine.hpp" +#include "tensor/tensor_static_rank.hpp" +#include "tensor/tensor_static.hpp" -namespace boost::numeric::ublas{ - - template - using dynamic_tensor = tensor_core< - tensor_engine< - extents<>, - Layout, - strides< extents<> >, - std::vector< ValueType, std::allocator > - > - >; - - - template - using static_tensor = tensor_core< - tensor_engine< - ExtentsType, - Layout, - strides, - std::array< ValueType, product(ExtentsType{}) > - > - >; - - template - using fixed_rank_tensor = tensor_core< - tensor_engine< - extents, - Layout, - strides< extents >, - std::vector< ValueType, std::allocator > - > - >; - -} // namespace boost::numeric::ublas - - -#endif +#endif // BOOST_UBLAS_TENSOR_TENSOR_HPP diff --git a/include/boost/numeric/ublas/tensor/tensor/tensor_core.hpp b/include/boost/numeric/ublas/tensor/tensor/tensor_core.hpp new file mode 100644 index 000000000..43591af63 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/tensor/tensor_core.hpp @@ -0,0 +1,27 @@ +// +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2020, Cem Bassoy, cem.bassoy@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +/// \file tensor_core.hpp Definition for the tensor template class + +#ifndef BOOST_UBLAS_TENSOR_CORE_HPP +#define BOOST_UBLAS_TENSOR_CORE_HPP + + +namespace boost::numeric::ublas { + +template +class tensor_core; + +} // namespace boost::numeric::ublas + +#endif // BOOST_UBLAS_TENSOR_CORE_HPP diff --git a/include/boost/numeric/ublas/tensor/tensor/tensor_dynamic.hpp b/include/boost/numeric/ublas/tensor/tensor/tensor_dynamic.hpp new file mode 100644 index 000000000..ec27296a6 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/tensor/tensor_dynamic.hpp @@ -0,0 +1,466 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +/// \file tensor_core.hpp Definition for the tensor template class + +#ifndef BOOST_UBLAS_TENSOR_DYNAMIC_HPP +#define BOOST_UBLAS_TENSOR_DYNAMIC_HPP + +#include + +#include "../algorithms.hpp" +#include "../expression.hpp" +#include "../expression_evaluation.hpp" +#include "../extents.hpp" +#include "../index.hpp" +#include "../index_functions.hpp" +#include "../layout.hpp" +#include "../type_traits.hpp" +#include "../tags.hpp" +#include "../concepts.hpp" + +#include "tensor_engine.hpp" + + +namespace boost::numeric::ublas { + +template +using engine_tensor_dynamic = tensor_engine, L, std::vector>; + +template + class tensor_core> + : public detail::tensor_expression< + tensor_core>, + tensor_core>> +{ +public: + using engine_type = engine_tensor_dynamic; + using self_type = tensor_core; + + template + using tensor_expression_type = detail::tensor_expression; + template + using matrix_expression_type = matrix_expression; + template + using vector_expression_type = vector_expression; + + using super_type = tensor_expression_type; + + using container_type = typename engine_type::container_type; + using layout_type = typename engine_type::layout_type; + using extents_type = typename engine_type::extents_type; + using strides_type = typename extents_type::base_type; + + using container_traits_type = container_traits; + + using size_type = typename container_traits_type::size_type; + using difference_type = typename container_traits_type::difference_type; + using value_type = typename container_traits_type::value_type; + + using reference = typename container_traits_type::reference; + using const_reference = typename container_traits_type::const_reference; + + using pointer = typename container_traits_type::pointer; + using const_pointer = typename container_traits_type::const_pointer; + + using iterator = typename container_traits_type::iterator; + using const_iterator = typename container_traits_type::const_iterator; + + using reverse_iterator = typename container_traits_type::reverse_iterator; + using const_reverse_iterator = typename container_traits_type::const_reverse_iterator; + + using container_tag = typename container_traits_type::container_tag; + using resizable_tag = typename container_traits_type::resizable_tag; + + using matrix_type = matrix >; + using vector_type = vector >; + + explicit tensor_core () = default; + + /** @brief Constructs a tensor_core with a \c shape + * + * @code auto t = tensor{3,4,2}; @endcode + * + */ + template + explicit inline tensor_core (Is ... is) + : tensor_expression_type{} + , _extents{size_type(is)...} + , _strides(ublas::to_strides(_extents,layout_type{})) + , _container(ublas::product(_extents)) + { + } + + + /** @brief Constructs a tensor_core with a \c shape + * + * @code auto t = tensor(extents{3,4,2}); @endcode + * + */ + explicit inline tensor_core (extents_type e) + : tensor_expression_type{} + , _extents(std::move(e)) + , _strides(ublas::to_strides(_extents,layout_type{})) + , _container(ublas::product(_extents)) + { + } + + /** @brief Constructs a tensor_core with a \c shape and initial value + * + * @code auto t = tensor(extents<>{4,3,2},5); @endcode + * + * @param i initial tensor_core with this value + */ + inline tensor_core (extents_type e, value_type i) + : tensor_expression_type{} + , _extents(std::move(e)) + , _strides(to_strides(_extents,layout_type{})) + , _container(product(_extents),i) + { + } + + /** @brief Constructs a tensor_core with a \c shape and initiates it with one-dimensional data + * + * @code auto t = tensor(extents<>{3,4,2},std::vector(3*4*2,1.f)); @endcode + * + * @param e instance of \c extents<> specifying the dimensions of tensor + * @param a instance of \c std::vector to be copied + */ + inline tensor_core (extents_type e, container_type a) + : tensor_expression_type{} + , _extents(std::move(e)) + , _strides(ublas::to_strides(_extents,layout_type{})) + , _container(std::move(a)) + { + if(std::size(_container) != ublas::product(_extents)){ + throw std::invalid_argument("boost::numeric::ublas::tensor_core: " + "Cannot construct tensor with specified std::vector instance. " + "Number of extents and std::vector size do not match."); + } + } + + + /** @brief Constructs a tensor_core with another tensor_core with a different layout + * + * @param other tensor_core with a different layout to be copied. + */ + template + explicit inline tensor_core (const tensor_core &other) + : tensor_expression_type{} + , _extents (ublas::begin(other.extents ()), ublas::end (other.extents ())) + , _strides (ublas::begin(other.extents ()), ublas::end (other.extents ())) + , _container( std::begin(other.container()), std::end (other.container())) + { + } + + + /** @brief Constructs a tensor_core with an tensor_core expression + * + * @code tensor_core A = B + 3 * C; @endcode + * + * @note type must be specified of tensor_core must be specified. + * @note dimension extents are extracted from tensors within the expression. + * + * @param expr tensor_core expression + * @param size tensor_core expression + */ + template + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline tensor_core (detail::tensor_expression const& expr) + : tensor_expression_type{} + , _extents (ublas::detail::retrieve_extents(expr)) + , _strides (ublas::to_strides(_extents,layout_type{})) + , _container(ublas::product(_extents)) + { + detail::eval(*this, expr); + } + + // NOLINTNEXTLINE(hicpp-explicit-conversions) + explicit tensor_core( matrix_type const& m ) + : tensor_expression_type{} + , _extents {m.size1(),m.size2()} + , _strides (ublas::to_strides(_extents,layout_type{})) + , _container(m.data().begin(), m.data().end()) + { + } + + // NOLINTNEXTLINE(hicpp-explicit-conversions) + explicit tensor_core (vector_type const& v) + : tensor_expression_type{} + , _extents {v.size(),1} + , _strides (ublas::to_strides(_extents,layout_type{})) + , _container(v.data().begin(), v.data().end()) + { + } + + /** @brief Constructs a tensor_core with a matrix expression + * + * @code tensor_core A = B + 3 * C; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr matrix expression + */ + template + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline tensor_core (const matrix_expression_type &expr) + : tensor_core(matrix_type(expr)) + { + } + + /** @brief Constructs a tensor_core with a vector expression + * + * @code tensor_core A = b + 3 * b; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr vector expression + */ + template + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline tensor_core (const vector_expression_type &expr) + : tensor_core( vector_type ( expr ) ) + { + } + + + /** @brief Constructs a tensor_core from another tensor_core + * + * @param t tensor_core to be copied. + */ + inline tensor_core (const tensor_core &t) + : tensor_expression_type{} + , _extents (t._extents ) + , _strides (t._strides ) + , _container(t._container) + {} + + + + /** @brief Constructs a tensor_core from another tensor_core + * + * @param t tensor_core to be moved. + */ + inline tensor_core (tensor_core &&t) noexcept + : tensor_expression_type{} + , _extents (std::move(t._extents )) + , _strides (std::move(t._strides )) + , _container(std::move(t._container)) + {} + + /// @brief Default destructor + ~tensor_core() = default; + + /** @brief Evaluates the tensor_expression and assigns the results to the tensor_core + * + * @code A = B + C * 2; @endcode + * + * @note rank and dimension extents of the tensors in the expressions must conform with this tensor_core. + * + * @param expr expression that is evaluated. + */ + template + tensor_core &operator = (const tensor_expression_type &expr) + { + detail::eval(*this, expr); + return *this; + } + + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + tensor_core& operator=(tensor_core other) noexcept + { + swap (*this, other); + return *this; + } + + tensor_core& operator=(const_reference v) + { + std::fill_n(_container.begin(), _container.size(), v); + return *this; + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A.at(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline const_reference at (I1 i1, I2 i2, Is ... is) const + { + if(sizeof...(is)+2 != this->order()){ + throw std::invalid_argument("boost::numeric::ublas::tensor_core::at : " + "Cannot access tensor with multi-index. " + "Number of provided indices does not match with tensor order."); + } + const auto idx = ublas::detail::to_index(_strides,i1,i2,is...); + return _container.at(idx); + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A.at(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline reference at (I1 i1, I2 i2, Is ... is) + { + if(sizeof...(is)+2 != this->order()){ + throw std::invalid_argument("boost::numeric::ublas::tensor_core::at : " + "Cannot access tensor with multi-index." + "Number of provided indices does not match with tensor order."); + } + const auto idx = ublas::detail::to_index(_strides,i1,i2,is...); + return _container.at(idx); + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline const_reference operator()(Is ... is) const + { + return this->at(is...); + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline reference operator()(Is ... is) + { + return this->at(is...); + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + [[nodiscard]] inline const_reference operator [] (size_type i) const { + return this->_container[i]; + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + [[nodiscard]] inline reference operator [] (size_type i) { + return this->_container[i]; + } + + /** @brief Element access using a single-index with bound checking which can throw an exception. + * + * @code auto a = A.at(i); @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + template + [[nodiscard]] inline const_reference at (size_type i) const { + return this->_container.at(i); + } + + /** @brief Read tensor element of a tensor \c t with a single-index \c i + * + * @code auto a = t.at(i); @endcode + * + * @param i zero-based index where 0 <= i < t.size() + */ + [[nodiscard]] inline reference at (size_type i) { + return this->_container.at(i); + } + + /** @brief Generates a tensor_core index for tensor_core contraction + * + * + * @code auto Ai = A(_i,_j,k); @endcode + * + * @param i placeholder + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline decltype(auto) operator() (index::index_type p, index_types ... ps) const + { + constexpr auto size = sizeof...(ps)+1; + if(size != this->order()){ + throw std::invalid_argument("boost::numeric::ublas::tensor_core : " + "Cannot multiply using Einstein notation. " + "Number of provided indices does not match with tensor order."); + } + return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward(ps)... ) ); + } + + friend void swap(tensor_core& lhs, tensor_core& rhs) + { + std::swap(lhs._extents , rhs._extents); + std::swap(lhs._strides , rhs._strides); + std::swap(lhs._container , rhs._container); + } + + + [[nodiscard]] inline auto begin () const noexcept -> const_iterator { return _container.begin (); } + [[nodiscard]] inline auto end () const noexcept -> const_iterator { return _container.end (); } + [[nodiscard]] inline auto begin () noexcept -> iterator { return _container.begin (); } + [[nodiscard]] inline auto end () noexcept -> iterator { return _container.end (); } + [[nodiscard]] inline auto cbegin () const noexcept -> const_iterator { return _container.cbegin (); } + [[nodiscard]] inline auto cend () const noexcept -> const_iterator { return _container.cend (); } + [[nodiscard]] inline auto crbegin() const noexcept -> const_reverse_iterator { return _container.crbegin(); } + [[nodiscard]] inline auto crend () const noexcept -> const_reverse_iterator { return _container.crend (); } + [[nodiscard]] inline auto rbegin () const noexcept -> const_reverse_iterator { return _container.rbegin (); } + [[nodiscard]] inline auto rend () const noexcept -> const_reverse_iterator { return _container.rend (); } + [[nodiscard]] inline auto rbegin () noexcept -> reverse_iterator { return _container.rbegin (); } + [[nodiscard]] inline auto rend () noexcept -> reverse_iterator { return _container.rend (); } + + [[nodiscard]] inline auto empty () const noexcept { return _container.empty(); } + [[nodiscard]] inline auto size () const noexcept { return _container.size(); } + [[nodiscard]] inline auto size (size_type r) const { return _extents.at(r); } + [[nodiscard]] inline auto rank () const { return _extents.size(); } + [[nodiscard]] inline auto order () const { return this->rank(); } + + [[nodiscard]] inline auto const& strides () const noexcept { return _strides; } + [[nodiscard]] inline auto const& extents () const noexcept { return _extents; } + [[nodiscard]] inline auto data () const noexcept -> const_pointer { return _container.data();} + [[nodiscard]] inline auto data () noexcept -> pointer { return _container.data();} + [[nodiscard]] inline auto const& base () const noexcept { return _container; } + +private: + extents_type _extents; + strides_type _strides; + container_type _container; +}; + +} // namespace boost::numeric::ublas + +namespace boost::numeric::ublas{ +template +using tensor_dynamic = tensor_core, L, std::vector>>; +} // namespace boost::numeric::ublas + + +#endif + diff --git a/include/boost/numeric/ublas/tensor/tensor/tensor_engine.hpp b/include/boost/numeric/ublas/tensor/tensor/tensor_engine.hpp new file mode 100644 index 000000000..dc6cbd790 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/tensor/tensor_engine.hpp @@ -0,0 +1,29 @@ +// +// Copyright (c) 2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_ENGINE_HPP +#define BOOST_UBLAS_TENSOR_ENGINE_HPP + +namespace boost::numeric::ublas{ + +template +struct tensor_engine +{ + using extents_type = E; + using layout_type = L; + using container_type = C; +}; + +} // namespace boost::numeric::ublas + + +#endif diff --git a/include/boost/numeric/ublas/tensor/tensor/tensor_static.hpp b/include/boost/numeric/ublas/tensor/tensor/tensor_static.hpp new file mode 100644 index 000000000..644ed9c51 --- /dev/null +++ b/include/boost/numeric/ublas/tensor/tensor/tensor_static.hpp @@ -0,0 +1,456 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +/// \file tensor_core.hpp Definition for the tensor template class + +#ifndef BOOST_UBLAS_TENSOR_STATIC_HPP +#define BOOST_UBLAS_TENSOR_STATIC_HPP + +#include + +#include "../algorithms.hpp" +#include "../expression.hpp" +#include "../expression_evaluation.hpp" +#include "../extents.hpp" +#include "../index.hpp" +#include "../index_functions.hpp" +#include "../layout.hpp" +#include "../type_traits.hpp" +#include "../tags.hpp" +#include "../concepts.hpp" + +#include "tensor_engine.hpp" + + + + +namespace boost::numeric::ublas::detail +{ +template +using engine_tensor_static = tensor_engine< + extents, L, std::array>> >; +} // namespace boost::numeric::ublas::detail + +namespace boost::numeric::ublas { +template +class tensor_core> + : public detail::tensor_expression< + tensor_core>, + tensor_core>> +{ +public: + using engine_type = detail::engine_tensor_static; + using self_type = tensor_core; + + template + using tensor_expression_type = detail::tensor_expression; + template + using matrix_expression_type = matrix_expression; + template + using vector_expression_type = vector_expression; + + using super_type = tensor_expression_type; + + using container_type = typename engine_type::container_type; + using layout_type = typename engine_type::layout_type; + using extents_type = typename engine_type::extents_type; + using strides_type = typename extents_type::base_type; + + using container_traits_type = container_traits; + + using size_type = typename container_traits_type::size_type; + using difference_type = typename container_traits_type::difference_type; + using value_type = typename container_traits_type::value_type; + + using reference = typename container_traits_type::reference; + using const_reference = typename container_traits_type::const_reference; + + using pointer = typename container_traits_type::pointer; + using const_pointer = typename container_traits_type::const_pointer; + + using iterator = typename container_traits_type::iterator; + using const_iterator = typename container_traits_type::const_iterator; + + using reverse_iterator = typename container_traits_type::reverse_iterator; + using const_reverse_iterator = typename container_traits_type::const_reverse_iterator; + + using container_tag = typename container_traits_type::container_tag; + using resizable_tag = typename container_traits_type::resizable_tag; + + using matrix_type = matrix >; + using vector_type = vector >; + + static_assert(std::tuple_size_v == ublas::product_v); + static_assert(0ul != ublas::product_v); + + /** @brief Constructs a tensor_core. + * + */ + constexpr inline tensor_core () noexcept = default; + + /** @brief Constructs a tensor_core with a \c shape + * + * + * @code tensor> A(4); @endcode + * + * @param v value with which tensor_core is initialized + */ + constexpr explicit inline tensor_core (value_type v) + : tensor_core() + { + std::fill_n(begin(),this->size(),v); + } + + /** @brief Constructs a tensor_core with a \c shape and initiates it with one-dimensional data + * + * @code auto a = tensor>(array); @endcode + * + * @param s initial tensor_core dimension extents + * @param a container of \c array_type that is copied according to the storage layout + */ + constexpr explicit inline tensor_core (container_type a) noexcept + : tensor_expression_type{} + , _container{std::move(a)} + { + } + + + /** @brief Constructs a tensor_core with another tensor_core with a different layout + * + * @param other tensor_core with a different layout to be copied. + */ + template + explicit inline tensor_core (const tensor_core &other) + : tensor_expression_type{} + , _container{} + { + if(_extents != other.extents()){ + throw std::invalid_argument("error in boost::numeric::ublas::tensor_core: extents do not match."); + } + + ublas::copy(this->rank(), this->extents().data(), + this->data(), this->strides().data(), + other.data(), other.strides().data()); + + } + + + /** @brief Constructs a tensor_core with an tensor_core expression + * + * @code tensor_core A = B + 3 * C; @endcode + * + * @note type must be specified of tensor_core must be specified. + * @note dimension extents are extracted from tensors within the expression. + * + * @param expr tensor_core expression + * @param size tensor_core expression + */ + template + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline tensor_core (const detail::tensor_expression &expr) + : tensor_expression_type{} + , _container{} + { + detail::eval(*this, expr); + } + + // NOLINTNEXTLINE(hicpp-explicit-conversions) + explicit tensor_core( matrix_type const& m ) + { + static_assert(is_matrix_v); + if(m.size1() != std::get<0>(_extents) || m.size2() != std::get<1>(_extents) ){ + throw std::invalid_argument("error in boost::numeric::ublas::tensor_core: matrix and tensor dimensions do not match."); + } + std::copy(m.data().begin(), m.data().end(), this->begin()); + } + + // NOLINTNEXTLINE(hicpp-explicit-conversions) + constexpr explicit tensor_core (vector_type const& v) + { + static_assert(is_vector_v); + + if(v.size() != std::get<0>(_extents) && v.size() != std::get<1>(_extents) ){ + throw std::invalid_argument("error in boost::numeric::ublas::tensor_core: matrix and tensor dimensions do not match."); + } + std::copy(v.data().begin(), v.data().end(), this->begin()); + } + + /** @brief Constructs a tensor_core with a matrix expression + * + * @code tensor_core A = B + 3 * C; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr matrix expression + */ + template + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline tensor_core (const matrix_expression_type &expr) + : tensor_core(matrix_type(expr)) + { + } + + /** @brief Constructs a tensor_core with a vector expression + * + * @code tensor_core A = b + 3 * b; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr vector expression + */ + template + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline tensor_core (const vector_expression_type &expr) + : tensor_core( vector_type ( expr ) ) + { + } + + + /** @brief Constructs a tensor_core from another tensor_core + * + * @param t tensor_core to be copied. + */ + constexpr inline tensor_core (const tensor_core &t) noexcept + : tensor_expression_type{} + , _container{t._container} + {} + + + + /** @brief Constructs a tensor_core from another tensor_core + * + * @param t tensor_core to be moved. + */ + constexpr inline tensor_core (tensor_core &&t) noexcept + : tensor_expression_type{} + , _container (std::move(t._container)) + {} + + /// @brief Default destructor + ~tensor_core() = default; + + /** @brief Evaluates the tensor_expression and assigns the results to the tensor_core + * + * @code A = B + C * 2; @endcode + * + * @note rank and dimension extents of the tensors in the expressions must conform with this tensor_core. + * + * @param expr expression that is evaluated. + */ + template + tensor_core &operator = (const tensor_expression_type &expr) + { + detail::eval(*this, expr); + return *this; + } + + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + constexpr tensor_core& operator=(tensor_core other) noexcept + { + swap (*this, other); + return *this; + } + + constexpr tensor_core& operator=(const_reference v) noexcept + { + std::fill_n(this->_container.begin(), this->_container.size(), v); + return *this; + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A.at(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline const_reference at (I1 i1, I2 i2, Is ... is) const + { + static_assert (sizeof...(is)+2 == ublas::size_v); + const auto idx = ublas::detail::to_index(_strides,i1,i2,is... ); + return _container[idx]; + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A.at(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline reference at (I1 i1, I2 i2, Is ... is) + { + static_assert (sizeof...(is)+2 == ublas::size_v); + const auto idx = ublas::detail::to_index(_strides,i1,i2,is... ); + return _container[idx]; + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline constexpr const_reference operator()(Is ... is) const + { + return this->at(is...); + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline constexpr reference operator()(Is ... is) + { + return this->at(is...); + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + [[nodiscard]] inline constexpr const_reference operator [] (size_type i) const { + return this->_container[i]; + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + [[nodiscard]] inline constexpr reference operator [] (size_type i) { + return this->_container[i]; + } + + /** @brief Element access using a single-index with bound checking which can throw an exception. + * + * @code auto a = A.at(i); @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + [[nodiscard]] inline constexpr const_reference at (size_type i) const { + return this->_container.at(i); + } + + /** @brief Read tensor element of a tensor \c t with a single-index \c i + * + * @code auto a = t.at(i); @endcode + * + * @param i zero-based index where 0 <= i < t.size() + */ + [[nodiscard]] inline constexpr reference at (size_type i) { + return this->_container.at(i); + } + + /** @brief Generates a tensor_core index for tensor_core contraction + * + * + * @code auto Ai = A(_i,_j,k); @endcode + * + * @param i placeholder + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline constexpr decltype(auto) operator() (index::index_type p, index_types ... ps) const + { + constexpr auto size = sizeof...(ps)+1; + static_assert(size == ublas::size_v); + return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward(ps)... ) ); + } + + friend void swap(tensor_core& lhs, tensor_core& rhs) + { + std::swap(lhs._container, rhs._container); + } + + + [[nodiscard]] inline constexpr auto begin () const noexcept -> const_iterator { return _container.begin (); } + [[nodiscard]] inline constexpr auto end () const noexcept -> const_iterator { return _container.end (); } + [[nodiscard]] inline constexpr auto begin () noexcept -> iterator { return _container.begin (); } + [[nodiscard]] inline constexpr auto end () noexcept -> iterator { return _container.end (); } + [[nodiscard]] inline constexpr auto cbegin () const noexcept -> const_iterator { return _container.cbegin (); } + [[nodiscard]] inline constexpr auto cend () const noexcept -> const_iterator { return _container.cend (); } + [[nodiscard]] inline constexpr auto crbegin() const noexcept -> const_reverse_iterator { return _container.crbegin(); } + [[nodiscard]] inline constexpr auto crend () const noexcept -> const_reverse_iterator { return _container.crend (); } + [[nodiscard]] inline constexpr auto rbegin () const noexcept -> const_reverse_iterator { return _container.rbegin (); } + [[nodiscard]] inline constexpr auto rend () const noexcept -> const_reverse_iterator { return _container.rend (); } + [[nodiscard]] inline constexpr auto rbegin () noexcept -> reverse_iterator { return _container.rbegin (); } + [[nodiscard]] inline constexpr auto rend () noexcept -> reverse_iterator { return _container.rend (); } + + + [[nodiscard]] inline constexpr auto empty () const noexcept { return _container.empty(); } + [[nodiscard]] inline constexpr auto size () const noexcept { return _container.size(); } + [[nodiscard]] inline constexpr auto size (size_type r) const { return _extents.at(r); } + [[nodiscard]] inline constexpr auto rank () const noexcept { return ublas::size_v; } + [[nodiscard]] inline constexpr auto order () const noexcept { return this->rank(); } + + [[nodiscard]] constexpr inline auto const& strides () const noexcept{ return _strides; } + [[nodiscard]] inline constexpr auto const& extents () const noexcept{ return _extents; } + [[nodiscard]] inline constexpr const_pointer data () const noexcept{ return _container.data();} + [[nodiscard]] inline constexpr pointer data () noexcept{ return _container.data();} + [[nodiscard]] inline constexpr auto const& base () const noexcept{ return _container; } + + + + +private: + static constexpr extents_type _extents = extents_type{}; + static constexpr strides_type _strides = to_strides_v; + container_type _container; +}; + + + +//template +//static constexpr inline auto make_tensor( +// typename tensor_static::base_type && a, +// typename tensor_static::extents_type && /*unused*/, +// typename tensor_static::layout_type && /*unused*/) +//{ +// return tensor_static( a ); +//} + + +} // namespace boost::numeric::ublas + + +namespace boost::numeric::ublas{ + +template +using tensor_static = tensor_core>>>; + +} + +namespace boost::numeric::ublas::experimental +{ +template +using matrix_static = tensor_static, L>; + +template +using vector_static = tensor_static, L>; +} // namespace boost::numeric::ublas::experimental + +#endif + diff --git a/include/boost/numeric/ublas/tensor/tensor/tensor_static_rank.hpp b/include/boost/numeric/ublas/tensor/tensor/tensor_static_rank.hpp new file mode 100644 index 000000000..fbb5074db --- /dev/null +++ b/include/boost/numeric/ublas/tensor/tensor/tensor_static_rank.hpp @@ -0,0 +1,473 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +/// \file tensor_core.hpp Definition for the tensor template class + +#ifndef BOOST_UBLAS_TENSOR_STATIC_RANK_HPP +#define BOOST_UBLAS_TENSOR_STATIC_RANK_HPP + +#include + +#include "../algorithms.hpp" +#include "../expression.hpp" +#include "../expression_evaluation.hpp" +#include "../extents.hpp" +#include "../index.hpp" +#include "../index_functions.hpp" +#include "../layout.hpp" +#include "../type_traits.hpp" +#include "../tags.hpp" +#include "../concepts.hpp" + +#include "tensor_engine.hpp" + + + +namespace boost::numeric::ublas { + +template +using engine_tensor_static_rank = tensor_engine, L, std::vector>; + +template + class tensor_core> + : public detail::tensor_expression< + tensor_core>, + tensor_core>> +{ +public: + using engine_type = engine_tensor_static_rank; + using self_type = tensor_core; + + template + using tensor_expression_type = detail::tensor_expression; + template + using matrix_expression_type = matrix_expression; + template + using vector_expression_type = vector_expression; + + using super_type = tensor_expression_type; + + using container_type = typename engine_type::container_type; + using layout_type = typename engine_type::layout_type; + using extents_type = typename engine_type::extents_type; + using strides_type = typename extents_type::base_type; + + using container_traits_type = container_traits; + + using size_type = typename container_traits_type::size_type; + using difference_type = typename container_traits_type::difference_type; + using value_type = typename container_traits_type::value_type; + + using reference = typename container_traits_type::reference; + using const_reference = typename container_traits_type::const_reference; + + using pointer = typename container_traits_type::pointer; + using const_pointer = typename container_traits_type::const_pointer; + + using iterator = typename container_traits_type::iterator; + using const_iterator = typename container_traits_type::const_iterator; + + using reverse_iterator = typename container_traits_type::reverse_iterator; + using const_reverse_iterator = typename container_traits_type::const_reverse_iterator; + + using container_tag = typename container_traits_type::container_tag; + using resizable_tag = typename container_traits_type::resizable_tag; + + using matrix_type = matrix >; + using vector_type = vector >; + + tensor_core () = default; + + /** @brief Constructs a tensor_core with a \c shape + * + * @code auto t = tensor(extents<3>{3,4,2}); @endcode + * + */ + explicit inline tensor_core (extents_type e) + : tensor_expression_type{} + , _extents(std::move(e)) + , _strides(ublas::to_strides(_extents,layout_type{})) + , _container(ublas::product(_extents)) + { + } + + /** @brief Constructs a tensor_core with a \c shape + * + * @code auto t = tensor{3,4,2}; @endcode + * + */ + template + explicit inline tensor_core (Is ... is) + : tensor_core(extents_type{size_type(is)...}) + { + } + + /** @brief Constructs a tensor_core with a \c shape and initiates it with one-dimensional data + * + * @code auto t = tensor(extents<>{3,4,2},std::vector(3*4*2,1.f)); @endcode + * + * @param e instance of \c extents<> specifying the dimensions of tensor + * @param a instance of \c std::vector to be copied + */ + inline tensor_core (extents_type e, container_type a) + : tensor_expression_type{} + , _extents(std::move(e)) + , _strides(ublas::to_strides(_extents,layout_type{})) + , _container(std::move(a)) + { + if(std::size(_container) != ublas::product(_extents)){ + throw std::length_error("boost::numeric::ublas::tensor_static_rank : " + "Cannot construct tensor with specified container and extents. " + "Number of container elements do not match with the specified extents."); + } + } + + /** @brief Constructs a tensor_core with another tensor_core with a different layout + * + * @param other tensor_core with a different layout to be copied. + */ + template + explicit inline tensor_core (const tensor_core &other) + : tensor_expression_type{} + , _extents (ublas::begin(other.extents()),ublas::end (other.extents ())) + , _strides (ublas::to_strides(_extents)) + , _container(std::begin(other.container()),std::end (other.container())) + { + } + + + /** @brief Constructs a tensor_core with an tensor_core expression + * + * @code tensor_core A = B + 3 * C; @endcode + * + * @note type must be specified of tensor_core must be specified. + * @note dimension extents are extracted from tensors within the expression. + * + * @param expr tensor_core expression + * @param size tensor_core expression + */ + template + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline tensor_core (detail::tensor_expression const& expr) + : tensor_expression_type{} + , _extents (ublas::detail::retrieve_extents(expr)) + , _strides (ublas::to_strides(_extents,layout_type{})) + , _container(ublas::product(_extents)) + { + detail::eval(*this, expr); + } + + // NOLINTNEXTLINE(hicpp-explicit-conversions) + explicit tensor_core( matrix_type const& m ) + : tensor_expression_type{} + , _extents {m.size1(),m.size2()} + , _strides (ublas::to_strides(_extents,layout_type{})) + , _container(m.data().begin(), m.data().end()) + { + } + + // NOLINTNEXTLINE(hicpp-explicit-conversions) + explicit tensor_core (vector_type const& v) + : tensor_expression_type{} + , _extents {v.size(),1} + , _strides (ublas::to_strides(_extents,layout_type{})) + , _container(v.data().begin(), v.data().end()) + { + } + + /** @brief Constructs a tensor_core with a matrix expression + * + * @code tensor_core A = B + 3 * C; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr matrix expression + */ + template + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline tensor_core (const matrix_expression_type &expr) + : tensor_core(matrix_type(expr)) + { + } + + /** @brief Constructs a tensor_core with a vector expression + * + * @code tensor_core A = b + 3 * b; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr vector expression + */ + template + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline tensor_core (const vector_expression_type &expr) + : tensor_core( vector_type ( expr ) ) + { + } + + + /** @brief Constructs a tensor_core from another tensor_core + * + * @param t tensor_core to be copied. + */ + inline tensor_core (const tensor_core &t) noexcept + : tensor_expression_type{} + , _extents (t._extents ) + , _strides (t._strides ) + , _container(t._container) + {} + + + + /** @brief Constructs a tensor_core from another tensor_core + * + * @param t tensor_core to be moved. + */ + inline tensor_core (tensor_core &&t) noexcept + : tensor_expression_type{} + , _extents (std::move(t._extents )) + , _strides (std::move(t._strides )) + , _container(std::move(t._container)) + {} + + /// @brief Default destructor + ~tensor_core() = default; + + /** @brief Evaluates the tensor_expression and assigns the results to the tensor_core + * + * @code A = B + C * 2; @endcode + * + * @note rank and dimension extents of the tensors in the expressions must conform with this tensor_core. + * + * @param expr expression that is evaluated. + */ + template + tensor_core &operator = (const tensor_expression_type &expr) + { + detail::eval(*this, expr); + return *this; + } + + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + tensor_core& operator=(tensor_core other) noexcept + { + swap (*this, other); + return *this; + } + + tensor_core& operator=(container_type c) + { + if( c.size() != this->size()){ + throw std::length_error("boost::numeric::ublas::tensor_core: " + "Cannot assign provided container to tensor." + "Number of elements do not match."); + } + _container = std::move(c); + return *this; + } + + tensor_core& operator=(const_reference v) + { + std::fill_n(_container.begin(), _container.size(), v); + return *this; + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A.at(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline const_reference at (I1 i1, I2 i2, Is ... is) const + { + static_assert (sizeof...(is)+2 == std::tuple_size_v); + const auto idx = ublas::detail::to_index(_strides,i1,i2,is...); + return _container.at(idx); + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A.at(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline reference at (I1 i1, I2 i2, Is ... is) + { + static_assert (sizeof...(Is)+2 == std::tuple_size_v); + const auto idx = ublas::detail::to_index(_strides,i1,i2,is...); + return _container.at(idx); + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline const_reference operator()(Is ... is) const + { + return this->at(is...); + } + + /** @brief Element access using a multi-index with bound checking which can throw an exception. + * + * @code auto a = A(i,j,k); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline reference operator()(Is ... is) + { + return this->at(is...); + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + [[nodiscard]] inline const_reference operator [] (size_type i) const { + return this->_container[i]; + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + [[nodiscard]] inline reference operator [] (size_type i) { + return this->_container[i]; + } + + /** @brief Element access using a single-index with bound checking which can throw an exception. + * + * @code auto a = A.at(i); @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + [[nodiscard]] inline const_reference at (size_type i) const { + return this->_container.at(i); + } + + /** @brief Read tensor element of a tensor \c t with a single-index \c i + * + * @code auto a = t.at(i); @endcode + * + * @param i zero-based index where 0 <= i < t.size() + */ + [[nodiscard]] inline reference at (size_type i) { + return this->_container.at(i); + } + + /** @brief Generates a tensor_core index for tensor_core contraction + * + * + * @code auto Ai = A(_i,_j,k); @endcode + * + * @param i placeholder + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template + [[nodiscard]] inline constexpr decltype(auto) operator() (index::index_type p, index_types ... ps) const + { + constexpr auto size = sizeof...(index_types)+1; + static_assert(size == std::tuple_size_v); + return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward(ps)... ) ); + } + + friend void swap(tensor_core& lhs, tensor_core& rhs) + { + std::swap(lhs._extents , rhs._extents ); + std::swap(lhs._strides , rhs._strides ); + std::swap(lhs._container , rhs._container); + } + + + [[nodiscard]] inline auto begin () const noexcept -> const_iterator { return _container.begin (); } + [[nodiscard]] inline auto end () const noexcept -> const_iterator { return _container.end (); } + [[nodiscard]] inline auto begin () noexcept -> iterator { return _container.begin (); } + [[nodiscard]] inline auto end () noexcept -> iterator { return _container.end (); } + [[nodiscard]] inline auto cbegin () const noexcept -> const_iterator { return _container.cbegin (); } + [[nodiscard]] inline auto cend () const noexcept -> const_iterator { return _container.cend (); } + + [[nodiscard]] inline auto crbegin() const noexcept -> const_reverse_iterator { return _container.crbegin(); } + [[nodiscard]] inline auto crend () const noexcept -> const_reverse_iterator { return _container.crend (); } + [[nodiscard]] inline auto rbegin () const noexcept -> const_reverse_iterator { return _container.rbegin (); } + [[nodiscard]] inline auto rend () const noexcept -> const_reverse_iterator { return _container.rend (); } + [[nodiscard]] inline auto rbegin () noexcept -> reverse_iterator { return _container.rbegin (); } + [[nodiscard]] inline auto rend () noexcept -> reverse_iterator { return _container.rend (); } + + [[nodiscard]] inline auto empty () const noexcept { return _container.empty(); } + [[nodiscard]] inline auto size () const noexcept { return _container.size(); } + [[nodiscard]] inline auto size (size_type r) const { return _extents.at(r); } + [[nodiscard]] inline constexpr auto rank () const noexcept { return std::tuple_size_v; } + [[nodiscard]] inline constexpr auto order () const noexcept { return this->rank(); } + + [[nodiscard]] inline auto const& strides () const noexcept { return _strides; } + [[nodiscard]] inline auto const& extents () const noexcept { return _extents; } + [[nodiscard]] inline auto data () const noexcept -> const_pointer { return _container.data();} + [[nodiscard]] inline auto data () noexcept -> pointer { return _container.data();} + [[nodiscard]] inline auto const& base () const noexcept { return _container; } + + +private: + extents_type _extents; + strides_type _strides; + container_type _container; +}; + +/** @brief Type for create a dynamic tensor instance with dynamic non-resizable extents + * + * @code + * // defines a 4-dimensional tensor type + * // tensor_core,layout::first_order,std::vector>> + * + * using ftensor = tensor_mixed; + * + * // instantiates a 4-dimension + * auto t = ftensor{{5,6,4,3}}; + * + * @endcode + * + * */ + +template +using tensor_static_rank = tensor_core>; + +} // namespace boost::numeric::ublas + + +namespace boost::numeric::ublas::experimental +{ + +template +using matrix = tensor_core>; + +template +using vector = tensor_core>; + +} // namespace boost::numeric::ublas::experimental + + +#endif // BOOST_UBLAS_TENSOR_STATIC_RANK_HPP + diff --git a/include/boost/numeric/ublas/tensor/tensor_core.hpp b/include/boost/numeric/ublas/tensor/tensor_core.hpp deleted file mode 100644 index 609c9e15e..000000000 --- a/include/boost/numeric/ublas/tensor/tensor_core.hpp +++ /dev/null @@ -1,886 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -/// \file tensor_core.hpp Definition for the tensor template class - -#ifndef BOOST_UBLAS_TENSOR_CORE_IMPL_HPP -#define BOOST_UBLAS_TENSOR_CORE_IMPL_HPP - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost::numeric::ublas { - -template< class T > -class tensor_core: - public detail::tensor_expression< tensor_core,tensor_core > -{ - - using self_type = tensor_core; - -public: - using tensor_traits = T; - - template - using tensor_expression_type = detail::tensor_expression; - - template - using matrix_expression_type = matrix_expression; - - template - using vector_expression_type = vector_expression; - - using super_type = tensor_expression_type; - using storage_traits_type = typename tensor_traits::storage_traits_type; - - using array_type = typename storage_traits_type::array_type; - using layout_type = typename tensor_traits::layout_type; - - - using size_type = typename storage_traits_type::size_type; - using difference_type = typename storage_traits_type::difference_type; - using value_type = typename storage_traits_type::value_type; - - using reference = typename storage_traits_type::reference; - using const_reference = typename storage_traits_type::const_reference; - - using pointer = typename storage_traits_type::pointer; - using const_pointer = typename storage_traits_type::const_pointer; - - using iterator = typename storage_traits_type::iterator; - using const_iterator = typename storage_traits_type::const_iterator; - - using reverse_iterator = typename storage_traits_type::reverse_iterator; - using const_reverse_iterator = typename storage_traits_type::const_reverse_iterator; - - using tensor_temporary_type = self_type; - using storage_category = dense_tag; - using container_tag = typename storage_traits_type::container_tag; - using resizable_tag = typename storage_traits_type::resizable_tag; - - using extents_type = typename tensor_traits::extents_type; - using strides_type = typename tensor_traits::strides_type; - - using matrix_type = matrix >; - using vector_type = vector >; - - /** @brief Constructs a tensor_core. - * - * @note the tensor_core is empty. - * @note the tensor_core needs to reshaped for further use. - * - */ - inline - constexpr tensor_core () - { - if constexpr( is_static_v ){ - auto temp = tensor_core(extents_type{},resizable_tag{}); - swap(*this,temp); - } - } - - constexpr tensor_core( extents_type e, [[maybe_unused]] storage_resizable_container_tag t ) - : tensor_expression_type() - , extents_(std::move(e)) - , strides_(extents_) - , data_( product(extents_) ) - {} - - constexpr tensor_core( extents_type e, [[maybe_unused]] storage_static_container_tag t ) - : tensor_expression_type() - , extents_(std::move(e)) - , strides_(extents_) - { - if ( data_.size() < product(extents_) ){ - throw std::length_error("boost::numeric::ublas::tensor_core(extents_type const&, storage_static_container_tag): " - "size of requested storage exceeds the current container size" - ); - } - } - - /** @brief Constructs a tensor_core with an initializer list for dynamic_extents - * - * By default, its elements are initialized to 0. - * - * @code tensor_core A{4,2,3}; @endcode - * - * @param l initializer list for setting the dimension extents of the tensor_core - */ - template> - > - explicit inline - tensor_core (std::initializer_list l) - : tensor_core( std::move( extents_type( std::move(l) ) ), resizable_tag{} ) - {} - - /** @brief Constructs a tensor_core with a \c shape - * - * By default, its elements are initialized to 0. - * - * @code tensor_core A{extents{4,2,3}}; @endcode - * - * @param s initial tensor_core dimension extents - */ - template> - > - explicit inline - tensor_core (extents_type s) - : tensor_core( std::move(s), resizable_tag{} ) - {} - - /** @brief Constructs a tensor_core with a \c shape - * - * By default, its elements are initialized to 0. - * - * @code tensor_core A{extents{4,2,3}}; @endcode - * - * @param s initial tensor_core dimension extents - * @param i initial tensor_core with this value - */ - template> - > - explicit inline - tensor_core (extents_type s, value_type const& i) - : tensor_core( std::move(s), resizable_tag{} ) - { - std::fill(begin(),end(),i); - } - - /** @brief Constructs a tensor_core with a \c shape - * - * By default, its elements are initialized to 0. - * - * @code tensor_core A{}; @endcode - * - * @param i initial tensor_core with this value - */ - template> - > - explicit inline - tensor_core (value_type const& i) - : tensor_core() - { - std::fill(begin(),end(),i); - } - - /** @brief Constructs a tensor_core with a \c shape and initiates it with one-dimensional data - * - * @code tensor_core A{extents{4,2,3}, array }; @endcode - * - * - * @param s initial tensor_core dimension extents - * @param a container of \c array_type that is copied according to the storage layout - */ - template> - > - inline - tensor_core (extents_type s, const array_type &a) - : tensor_core( std::move(s), resizable_tag{} ) - { - if( size() != a.size() ){ - throw std::runtime_error("boost::numeric::ublas::tensor_core(extents_type,array_type): " - "array size mismatch with extents" - ); - } - std::copy(a.begin(),a.end(),begin()); - } - - /** @brief Constructs a tensor_core with a \c shape and initiates it with one-dimensional data - * - * @code tensor_core A{ array }; @endcode - * - * @param a container of \c array_type that is copied according to the storage layout - */ - template> - > - inline - tensor_core (const array_type &a) - : tensor_core() - { - if( size() != a.size() ){ - throw std::runtime_error("boost::numeric::ublas::tensor_core(extents_type,array_type): " - "array size mismatch with extents" - ); - } - std::copy(a.begin(),a.end(),begin()); - } - - - /** @brief Constructs a tensor_core with another tensor_core with a different layout - * - * @param other tensor_core with a different layout to be copied. - */ - template - tensor_core (const tensor_core &other) - : tensor_core( other.extents(), resizable_tag{} ) - { - copy(this->rank(), this->extents().data(), - this->data(), this->strides().data(), - other.data(), other.strides().data()); - - } - - - /** @brief Constructs a tensor_core with an tensor_core expression - * - * @code tensor_core A = B + 3 * C; @endcode - * - * @note type must be specified of tensor_core must be specified. - * @note dimension extents are extracted from tensors within the expression. - * - * @param expr tensor_core expression - * @param size tensor_core expression - */ - template - tensor_core (const detail::tensor_expression &expr) - : tensor_core( detail::retrieve_extents(expr), resizable_tag{} ) - { - static_assert(is_valid_tensor_v, - "boost::numeric::ublas::tensor_core(tensor_expression const&) : " - "other_tensor should be a valid tensor type" - ); - - static_assert(std::is_same_v, - "boost::numeric::ublas::tensor_core(tensor_expression const&) : " - "LHS and RHS should have the same value type" - ); - - detail::eval( *this, expr ); - } - - constexpr tensor_core( matrix_type const& v ) - : tensor_core() - { - if constexpr( is_dynamic_v< extents_type > ){ - auto temp = tensor_core(extents_type{v.size1(), v.size2()}); - swap(*this,temp); - } - - if constexpr( is_static_rank_v ){ - static_assert( extents_type::_size == 2ul, - "boost::numeric::ublas::tensor_core(const matrix &v)" - " : the rank of extents is not correct, it should be of the rank 2" - ); - }else{ - if( extents_.size() != 2ul ){ - throw std::runtime_error( - "boost::numeric::ublas::tensor_core(const matrix &v)" - " : the rank of extents is not correct, it should be of the rank 2" - ); - } - } - - - if( extents_[0] != v.size1() || extents_[1] != v.size2() ){ - throw std::runtime_error( - "boost::numeric::ublas::tensor_core(const matrix &v)" - " : please set the extents properly, the extents should contain the row and col of the matrix" - ); - } - - std::copy(v.data().begin(), v.data().end(), data_.begin()); - } - - constexpr tensor_core( matrix_type && v ) - : tensor_core() - { - if constexpr( is_dynamic_v< extents_type > ){ - auto temp = tensor_core(extents_type{v.size1(), v.size2()}); - swap(*this,temp); - } - - if constexpr( is_static_rank_v ){ - static_assert( extents_type::_size == 2ul, - "boost::numeric::ublas::tensor_core(matrix &&v)" - " : the rank of extents is not correct, it should be of the rank 2" - ); - }else{ - if( extents_.size() != 2ul ){ - throw std::runtime_error( - "boost::numeric::ublas::tensor_core(matrix &&v)" - " : the rank of extents is not correct, it should be of the rank 2" - ); - } - } - - if( extents_[0] != v.size1() || extents_[1] != v.size2() ){ - throw std::runtime_error( - "boost::numeric::ublas::tensor_core(matrix &&v)" - " : please set the extents properly, the extents should contain the row and col of the matrix" - ); - } - - std::move(v.data().begin(), v.data().end(),data_.begin()); - } - - constexpr tensor_core (const vector_type &v) - : tensor_core() - { - if constexpr( is_dynamic_v< extents_type > ){ - auto temp = tensor_core(extents_type{ v.size(), typename extents_type::value_type{1} }); - swap(*this,temp); - } - - if constexpr( is_static_rank_v ){ - static_assert( extents_type::_size == 2ul, - "boost::numeric::ublas::tensor_core(const vector_type &v)" - " : the rank of extents is not correct, it should be of the rank 2" - ); - }else{ - if( extents_.size() != 2ul ){ - throw std::runtime_error( - "boost::numeric::ublas::tensor_core(const vector_type &v)" - " : the rank of extents is not correct, it should be of the rank 2" - ); - } - } - - if( extents_[0] != v.size() || extents_[1] != 1ul ){ - throw std::runtime_error( - "boost::numeric::ublas::tensor_core(const vector_type &v)" - " : please set the extents properly, the first extent should be the size of the vector and 1 for the second extent" - ); - } - - std::copy(v.data().begin(), v.data().end(), data_.begin()); - - } - - constexpr tensor_core (vector_type &&v) - : tensor_core() - { - if constexpr( is_dynamic_v< extents_type > ){ - auto temp = tensor_core(extents_type{ v.size(), typename extents_type::value_type{1} }); - swap(*this,temp); - } - - if constexpr( is_static_rank_v ){ - static_assert( extents_type::_size == 2ul, - "boost::numeric::ublas::tensor_core(vector_type &&v)" - " : the rank of extents is not correct, it should be of the rank 2" - ); - }else{ - if( extents_.size() != 2ul ){ - throw std::runtime_error( - "boost::numeric::ublas::tensor_core(vector_type &&v)" - " : the rank of extents is not correct, it should be of the rank 2" - ); - } - } - - if( extents_[0] != v.size() || extents_[1] != 1ul ){ - throw std::runtime_error( - "boost::numeric::ublas::tensor_core(vector_type &&v)" - " : please set the extents properly, the first extent should be the size of the vector and 1 for the second extent" - ); - } - - std::move(v.data().begin(), v.data().end(),data_.begin()); - - } - - /** @brief Constructs a tensor_core with a matrix expression - * - * @code tensor_core A = B + 3 * C; @endcode - * - * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. - * @note extents are automatically extracted from the temporary matrix - * - * @param expr matrix expression - */ - template - tensor_core (const matrix_expression_type &expr) - : tensor_core( matrix_type ( expr ) ) - { - } - - /** @brief Constructs a tensor_core with a vector expression - * - * @code tensor_core A = b + 3 * b; @endcode - * - * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. - * @note extents are automatically extracted from the temporary matrix - * - * @param expr vector expression - */ - template - tensor_core (const vector_expression_type &expr) - : tensor_core( vector_type ( expr ) ) - { - } - - - /** @brief Constructs a tensor_core from another tensor_core - * - * @param v tensor_core to be copied. - */ - inline - tensor_core (const tensor_core &v) - : tensor_expression_type() - , extents_ (v.extents_) - , strides_ (v.strides_) - , data_ (v.data_ ) - {} - - - - /** @brief Constructs a tensor_core from another tensor_core - * - * @param v tensor_core to be moved. - */ - inline - tensor_core (tensor_core &&v) noexcept - : tensor_expression_type() //tensor_container () - , extents_ (std::move(v.extents_)) - , strides_ (std::move(v.strides_)) - , data_ (std::move(v.data_ )) - {} - - - /** @brief Move assignsment operator - * - * @param v tensor_core to be moved. - */ - inline - tensor_core& operator=(tensor_core &&v) noexcept - { - swap(*this,v); - return *this; - } - - /// @brief Default destructor - ~tensor_core() = default; - - /** @brief Evaluates the tensor_expression and assigns the results to the tensor_core - * - * @code A = B + C * 2; @endcode - * - * @note rank and dimension extents of the tensors in the expressions must conform with this tensor_core. - * - * @param expr expression that is evaluated. - */ - template - tensor_core &operator = (const tensor_expression_type &expr) - { - detail::eval(*this, expr); - return *this; - } - - tensor_core& operator=(tensor_core const& other) - { - tensor_core temp(other); - swap (*this, temp); - return *this; - } - - constexpr tensor_core& operator=(const_reference v) - { - std::fill_n(this->begin(), this->size(), v); - return *this; - } - - /** @brief Returns true if the tensor_core is empty (\c size==0) */ - [[nodiscard]] inline - constexpr bool empty () const noexcept{ - return this->data_.empty(); - } - - /** @brief Returns the upper bound or max size of the tensor_core */ - [[nodiscard]] inline - constexpr size_type size() const noexcept{ - return this->data_.size(); - } - - /** @brief Returns the size of the tensor_core */ - [[nodiscard]] inline - constexpr size_type size (size_type r) const { - return this->extents_.at(r); - } - - /** @brief Returns the number of dimensions/modes of the tensor_core */ - [[nodiscard]] inline - constexpr size_type rank () const noexcept{ - return this->extents_.size(); - } - - /** @brief Returns the number of dimensions/modes of the tensor_core */ - [[nodiscard]] inline - constexpr size_type order () const noexcept{ - return this->extents_.size(); - } - - /** @brief Returns the strides of the tensor_core */ - [[nodiscard]] inline - constexpr strides_type const& strides () const noexcept{ - return this->strides_; - } - - /** @brief Returns the extents of the tensor_core */ - [[nodiscard]] inline - constexpr extents_type const& extents () const noexcept{ - return this->extents_; - } - - /** @brief Returns the strides of the tensor_core */ - [[nodiscard]] inline - constexpr strides_type& strides () noexcept{ - return this->strides_; - } - - /** @brief Returns the extents of the tensor_core */ - [[nodiscard]] inline - constexpr extents_type& extents () noexcept{ - return this->extents_; - } - - /** @brief Returns a \c const reference to the container. */ - [[nodiscard]] inline - constexpr const_pointer data () const noexcept{ - return this->data_.data(); - } - - /** @brief Returns a \c const reference to the container. */ - [[nodiscard]] inline - constexpr pointer data () noexcept{ - return this->data_.data(); - } - - /** @brief Returns a \c const reference to the underlying container. */ - [[nodiscard]] inline - constexpr array_type const& base () const noexcept{ - return data_; - } - - /** @brief Returns a reference to the underlying container. */ - [[nodiscard]] inline - constexpr array_type& base () noexcept{ - return data_; - } - - /** @brief Element access using a single index. - * - * @code auto a = A[i]; @endcode - * - * @param i zero-based index where 0 <= i < this->size() - */ - [[nodiscard]] inline - constexpr const_reference operator [] (size_type i) const { - return this->data_[i]; - } - - /** @brief Element access using a single index. - * - * @code auto a = A[i]; @endcode - * - * @param i zero-based index where 0 <= i < this->size() - */ - [[nodiscard]] inline - constexpr reference operator [] (size_type i) { - return this->data_[i]; - } - - /** @brief Element access using a multi-index or single-index with bound checking - * and it throws the exception. - * - * @code auto a = A.at(i,j,k); @endcode or - * @code auto a = A.at(i); @endcode - * - * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - [[nodiscard]] inline - constexpr const_reference at (size_type i, Indices ... is) const { - if constexpr( sizeof...(is) == 0ul ){ - return this->data_.at(i); - }else{ - if( sizeof...(is) + 1 > strides_.size() ){ - throw std::runtime_error("Error in boost::numeric::ublas::at(size_type, Indices...): " - "number of variadic argument exceeds the strides size." - ); - } - static_assert( - std::conjunction_v< std::is_convertible... >, - "boost::numeric::ublas::tensor_core::at(size_type,Indices...) : " - "provided variadic argument is not convertible to tensor size_type" - ); - using strides_value_type = typename strides_type::value_type; - auto const idx = detail::access(this->strides_, - static_cast(i), - static_cast(is)... - ); - return this->data_.at(idx); - } - } - - /** @brief Element access using a multi-index or single-index with bound checking - * and it throws the exception. - * - * - * @code A.at(i,j,k) = a; @endcode or - * @code A.at(i) = a; @endcode - * - * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - [[nodiscard]] inline - constexpr reference at (size_type i, Indices ... is) { - if constexpr( sizeof...(is) == 0ul ){ - return this->data_.at(i); - }else{ - if( sizeof...(is) + 1 > strides_.size() ){ - throw std::runtime_error("Error in boost::numeric::ublas::at(size_type, Indices...): " - "number of variadic argument exceeds the strides size." - ); - } - static_assert( - std::conjunction_v< std::is_convertible... >, - "boost::numeric::ublas::tensor_core::at(size_type,Indices...) : " - "provided variadic argument is not convertible to tensor size_type" - ); - using strides_value_type = typename strides_type::value_type; - auto const idx = detail::access(this->strides_, - static_cast(i), - static_cast(is)... - ); - return this->data_.at(idx); - } - } - - /** @brief Element access using a multi-index or single-index with no bound checking - * and it does not throw. - * - * - * @code auto a = A(i,j,k); @endcode or - * @code auto a = A(i); @endcode - * - * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - [[nodiscard]] inline - constexpr const_reference operator() (size_type i, Indices ... is) const { - if constexpr( sizeof...(is) == 0ul ){ - return this->data_[i]; - }else{ - static_assert( - std::conjunction_v< std::is_convertible... >, - "boost::numeric::ublas::tensor_core::operator()(size_type,Indices...) : " - "provided variadic argument is not convertible to tensor size_type" - ); - using strides_value_type = typename strides_type::value_type; - auto const idx = detail::access(this->strides_, - static_cast(i), - static_cast(is)... - ); - return this->data_[idx]; - } - } - - /** @brief Element access using a multi-index or single-index with no bound checking - * and it does not throw. - * - * - * @code A(i,j,k) = a; @endcode or - * @code A(i) = a; @endcode - * - * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - [[nodiscard]] inline - constexpr reference operator() (size_type i, Indices ... is) { - if constexpr( sizeof...(is) == 0ul ){ - return this->data_[i]; - }else{ - static_assert( - std::conjunction_v< std::is_convertible... >, - "boost::numeric::ublas::tensor_core::operator()(size_type,Indices...) : " - "provided variadic argument is not convertible to tensor size_type" - ); - using strides_value_type = typename strides_type::value_type; - auto const idx = detail::access(this->strides_, - static_cast(i), - static_cast(is)... - ); - return this->data_[idx]; - } - } - - /** @brief Generates a tensor_core index for tensor_core contraction - * - * - * @code auto Ai = A(_i,_j,k); @endcode - * - * @param i placeholder - * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() - */ - template - [[nodiscard]] inline - constexpr decltype(auto) operator() (index::index_type p, index_types ... ps) const - { - constexpr auto N = sizeof...(ps)+1; - if( N != this->rank() ) - throw std::runtime_error("Error in boost::numeric::ublas::operator(index::index_type,index_types&&): " - "size of provided index_types does not match with the rank." - ); - - return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward(ps)... ) ); - } - - - /** @brief Reshapes the basic_tensor - * - * - * (1) @code A.reshape(extents{m,n,o}); @endcode or - * (2) @code A.reshape(extents{m,n,o},4); @endcode - * - * If the size of this smaller than the specified extents than - * default constructed (1) or specified (2) value is appended. - * - * @note rank of the basic_tensor might also change. - * - * @param e extents with which the basic_tensor is reshaped. - * @param v value which is appended if the basic_tensor is enlarged. - */ - inline - void reshape (extents_type const& e, value_type v = value_type{}) - { - static_assert(is_dynamic_v && is_dynamic_v, - "Error in boost::numeric::ublas::basic_tensor::reshape(extents_type const&,value_type) : " - "static extents or static strides cannot used inside reshape function" - ); - - this->extents_ = e; - this->strides_ = strides_type(this->extents_); - - auto p = product(extents_); - if constexpr( !std::is_same_v< resizable_tag, storage_resizable_container_tag > ){ - if( p != this->size() ){ - throw std::runtime_error( - "boost::numeric::ublas::basic_tensor::reshape(extents_type const&,value_type) : " - "cannot resize the non-resizable container, change the extents such a way that the product does not change" - ); - } - }else{ - if(p != this->size()) - this->data_.resize (p, v); - } - } - - friend void swap(tensor_core& lhs, tensor_core& rhs){ - std::swap(lhs.data_ , rhs.data_ ); - std::swap(lhs.extents_, rhs.extents_); - std::swap(lhs.strides_, rhs.strides_); - } - - - /// \brief return an iterator on the first element of the tensor_core - [[nodiscard]] inline - constexpr const_iterator begin () const noexcept{ - return data_.begin (); - } - - /// \brief return an iterator on the first element of the tensor_core - [[nodiscard]] inline - constexpr const_iterator cbegin () const noexcept{ - return data_.cbegin (); - } - - /// \brief return an iterator after the last element of the tensor_core - [[nodiscard]] inline - constexpr const_iterator end () const noexcept{ - return data_.end(); - } - - /// \brief return an iterator after the last element of the tensor_core - [[nodiscard]] inline - constexpr const_iterator cend () const noexcept{ - return data_.cend (); - } - - /// \brief Return an iterator on the first element of the tensor_core - [[nodiscard]] inline - constexpr iterator begin () noexcept{ - return data_.begin(); - } - - /// \brief Return an iterator at the end of the tensor_core - [[nodiscard]] inline - constexpr iterator end () noexcept{ - return data_.end(); - } - - /// \brief Return a const reverse iterator before the first element of the reversed tensor_core (i.e. end() of normal tensor_core) - [[nodiscard]] inline - constexpr const_reverse_iterator rbegin () const noexcept{ - return data_.rbegin(); - } - - /// \brief Return a const reverse iterator before the first element of the reversed tensor_core (i.e. end() of normal tensor_core) - [[nodiscard]] inline - constexpr const_reverse_iterator crbegin () const noexcept{ - return data_.crbegin(); - } - - /// \brief Return a const reverse iterator on the end of the reverse tensor_core (i.e. first element of the normal tensor_core) - [[nodiscard]] inline - constexpr const_reverse_iterator rend () const noexcept{ - return data_.rend(); - } - - /// \brief Return a const reverse iterator on the end of the reverse tensor_core (i.e. first element of the normal tensor_core) - [[nodiscard]] inline - constexpr const_reverse_iterator crend () const noexcept{ - return data_.crend(); - } - - /// \brief Return a const reverse iterator before the first element of the reversed tensor_core (i.e. end() of normal tensor_core) - [[nodiscard]] inline - constexpr reverse_iterator rbegin () noexcept{ - return data_.rbegin(); - } - - /// \brief Return a const reverse iterator on the end of the reverse tensor_core (i.e. first element of the normal tensor_core) - [[nodiscard]] inline - constexpr reverse_iterator rend () noexcept{ - return data_.rend(); - } - -private: - - extents_type extents_; - strides_type strides_; - array_type data_; -}; - -} // namespaces - -#endif diff --git a/include/boost/numeric/ublas/tensor/tensor_engine.hpp b/include/boost/numeric/ublas/tensor/tensor_engine.hpp deleted file mode 100644 index 8f9293e05..000000000 --- a/include/boost/numeric/ublas/tensor/tensor_engine.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef BOOST_UBLAS_TENSOR_ENGINE_IMPL_HPP -#define BOOST_UBLAS_TENSOR_ENGINE_IMPL_HPP - -#include - -namespace boost::numeric::ublas{ - - template - struct tensor_engine; - - template - struct tensor_engine{ - using extents_type = ExtentsType; - - static_assert(is_extents_v, - "boost::numeric::ublas::tensor_engine : please provide valid tensor extents type" - ); - - using layout_type = LayoutType; - using strides_type = typename StrideType::template type; - - static_assert(is_strides_v, - "boost::numeric::ublas::tensor_engine : please provide valid tensor layout type" - ); - - using storage_traits_type = storage_traits; - - }; - - template - struct tensor_engine - : tensor_engine< ExtentsType, LayoutType, strides, StorageType > - {}; - -} // namespace boost::numeric::ublas - - -#endif diff --git a/include/boost/numeric/ublas/tensor/traits/basic_type_traits.hpp b/include/boost/numeric/ublas/tensor/traits/basic_type_traits.hpp index 7d75800ba..ba6510194 100644 --- a/include/boost/numeric/ublas/tensor/traits/basic_type_traits.hpp +++ b/include/boost/numeric/ublas/tensor/traits/basic_type_traits.hpp @@ -1,64 +1,31 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com // // 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// #ifndef BOOST_UBLAS_TENSOR_BASIC_TYPE_TRAITS_HPP #define BOOST_UBLAS_TENSOR_BASIC_TYPE_TRAITS_HPP #include #include +#include +#include namespace boost::numeric::ublas { - -/** @brief Checks if the extents or strides is dynamic - * - * @tparam E of type basic_extents or basic_static_extents - * - */ -template struct is_dynamic : std::false_type {}; - -template -inline static constexpr bool const is_dynamic_v = is_dynamic::value; - -/** @brief Checks if the extents or strides is static - * - * @tparam E of type basic_extents or basic_static_extents - * - */ -template struct is_static : std::false_type {}; - -template -inline static constexpr bool const is_static_v = is_static::value; -/** @brief Checks if the extents or strides has dynamic rank - * - * @tparam E of type basic_extents or basic_static_extents - * - */ -template -struct is_dynamic_rank : std::false_type {}; -template -inline static constexpr bool const is_dynamic_rank_v = is_dynamic_rank::value; +template +struct is_complex : std::false_type{}; -/** @brief Checks if the extents or strides has static rank - * - * @tparam E of type basic_extents or basic_static_extents - * - */ -template -struct is_static_rank : std::false_type {}; +template +struct is_complex< std::complex > : std::true_type{}; -template -inline static constexpr bool const is_static_rank_v = is_static_rank::value; +template +inline static constexpr bool is_complex_v = is_complex::value; } // namespace boost::numeric::ublas diff --git a/include/boost/numeric/ublas/tensor/traits/storage_traits.hpp b/include/boost/numeric/ublas/tensor/traits/storage_traits.hpp index 4e5619966..e7bef80ae 100644 --- a/include/boost/numeric/ublas/tensor/traits/storage_traits.hpp +++ b/include/boost/numeric/ublas/tensor/traits/storage_traits.hpp @@ -1,52 +1,51 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com + // // 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany +// The authors gratefully acknowledge the support of Google // #ifndef BOOST_UBLAS_TRAITS_STORAGE_HPP #define BOOST_UBLAS_TRAITS_STORAGE_HPP -#include #include -#include +#include -namespace boost { -namespace numeric { -namespace ublas { +#include "../tags.hpp" +namespace boost::numeric::ublas +{ -template -struct storage_traits; +template +struct container_traits; template -struct storage_traits> +struct container_traits> { - using array_type = std::vector; + using container_type = std::vector; - using size_type = typename array_type::size_type; - using difference_type = typename array_type::difference_type; - using value_type = typename array_type::value_type; + using size_type = typename container_type::size_type; + using difference_type = typename container_type::difference_type; + using value_type = typename container_type::value_type; - using reference = typename array_type::reference; - using const_reference = typename array_type::const_reference; + using reference = typename container_type::reference; + using const_reference = typename container_type::const_reference; - using pointer = typename array_type::pointer; - using const_pointer = typename array_type::const_pointer; + using pointer = typename container_type::pointer; + using const_pointer = typename container_type::const_pointer; - using iterator = typename array_type::iterator; - using const_iterator = typename array_type::const_iterator; + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; - using reverse_iterator = typename array_type::reverse_iterator; - using const_reverse_iterator = typename array_type::const_reverse_iterator; + using reverse_iterator = typename container_type::reverse_iterator; + using const_reverse_iterator = typename container_type::const_reverse_iterator; using container_tag = storage_seq_container_tag; using resizable_tag = storage_resizable_container_tag; @@ -57,25 +56,25 @@ struct storage_traits> template -struct storage_traits> +struct container_traits> { - using array_type = std::array; + using container_type = std::array; - using size_type = typename array_type::size_type; - using difference_type = typename array_type::difference_type; - using value_type = typename array_type::value_type; + using size_type = typename container_type::size_type; + using difference_type = typename container_type::difference_type; + using value_type = typename container_type::value_type; - using reference = typename array_type::reference; - using const_reference = typename array_type::const_reference; + using reference = typename container_type::reference; + using const_reference = typename container_type::const_reference; - using pointer = typename array_type::pointer; - using const_pointer = typename array_type::const_pointer; + using pointer = typename container_type::pointer; + using const_pointer = typename container_type::const_pointer; - using iterator = typename array_type::iterator; - using const_iterator = typename array_type::const_iterator; + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; - using reverse_iterator = typename array_type::reverse_iterator; - using const_reverse_iterator = typename array_type::const_reverse_iterator; + using reverse_iterator = typename container_type::reverse_iterator; + using const_reverse_iterator = typename container_type::const_reverse_iterator; using container_tag = storage_seq_container_tag; using resizable_tag = storage_static_container_tag; @@ -87,38 +86,40 @@ struct storage_traits> using rebind_size = std::array; }; -} // ublas -} // numeric -} // boost +} // namespace boost::numeric::ublas namespace boost::numeric::ublas { + +template +class basic_static_extents; + namespace detail{ template struct rebind_storage_size_helper{ using type = A; }; - template - struct rebind_storage_size_helper, A, storage_static_container_tag>{ - using type = typename storage_traits::template rebind_size< E0 * (Es * ...) >; + template + struct rebind_storage_size_helper, C, storage_static_container_tag>{ + using type = typename container_traits::template rebind_size< E0 * (Es * ...) >; }; - template - struct rebind_storage_size_helper, A, storage_static_container_tag>{ - using type = typename storage_traits::template rebind_size< 0 >; + template + struct rebind_storage_size_helper, C, storage_static_container_tag>{ + using type = typename container_traits::template rebind_size< 0 >; }; - } + } //namespace detail - template + template struct rebind_storage_size - : detail::rebind_storage_size_helper::resizable_tag + : detail::rebind_storage_size_helper::resizable_tag > {}; - template - using rebind_storage_size_t = typename rebind_storage_size::type; + template + using rebind_storage_size_t = typename rebind_storage_size::type; } // namespace boost::numeric::ublas diff --git a/include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_extents.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_extents.hpp deleted file mode 100644 index 54a11a471..000000000 --- a/include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_extents.hpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_EXTENTS_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_EXTENTS_HPP - -#include - -namespace boost::numeric::ublas{ - -template class basic_extents; - -} // namespace boost::numeric::ublas - -namespace boost::numeric::ublas{ - - template - struct is_extents< basic_extents > : std::true_type {}; - - template - struct is_dynamic< basic_extents > : std::true_type {}; - - template - struct is_dynamic_rank< basic_extents > : std::true_type {}; - - - namespace detail{ - - template <> struct dynamic_extents_impl<> { - using type = basic_extents; - }; - - } // namespace detail - -} // namespace boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_strides.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_strides.hpp deleted file mode 100644 index 0eaf8ff9e..000000000 --- a/include/boost/numeric/ublas/tensor/traits/type_traits_dynamic_strides.hpp +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_STRIDES_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_DYNAMIC_STRIDES_HPP - -#include - -namespace boost::numeric::ublas{ - -template class basic_extents; - -template -class basic_strides; - -} // namespace boost::numeric::ublas - -namespace boost::numeric::ublas{ - - template - struct is_strides> : std::true_type {}; - - template - struct is_dynamic< basic_strides > : std::true_type {}; - - template - struct is_dynamic_rank< basic_strides > : std::true_type {}; - - template - struct strides> - { - template - using type = basic_strides; - }; - -} // namespace boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/traits/type_traits_extents.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_extents.hpp deleted file mode 100644 index 14ed34870..000000000 --- a/include/boost/numeric/ublas/tensor/traits/type_traits_extents.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_EXTENTS_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_EXTENTS_HPP - -namespace boost::numeric::ublas { - -/// @brief checks if the type is tensor extents or not -template -struct is_extents : std::false_type {}; - -template -inline static constexpr bool const is_extents_v = is_extents::value; - -namespace detail{ - - template - struct dynamic_extents_impl; - -} // detail - -template -using extents = typename detail::dynamic_extents_impl::type; - -} // namespace boost::numeric::ublas - -#include -#include -#include - -#endif diff --git a/include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_extents.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_extents.hpp deleted file mode 100644 index f1cbfba38..000000000 --- a/include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_extents.hpp +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_EXTENTS_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_EXTENTS_HPP - -#include - -namespace boost::numeric::ublas{ - -template class basic_fixed_rank_extents; - -} // namespace boost::numeric::ublas - -namespace boost::numeric::ublas{ - - template - struct is_extents< basic_fixed_rank_extents > : std::true_type {}; - - template - struct is_dynamic< basic_fixed_rank_extents > : std::true_type {}; - - template - struct is_static_rank< basic_fixed_rank_extents > : std::true_type {}; - - namespace detail{ - - template struct dynamic_extents_impl { - using type = basic_fixed_rank_extents; - }; - - } // namespace detail - -} // namespace boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_strides.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_strides.hpp deleted file mode 100644 index 2e378a269..000000000 --- a/include/boost/numeric/ublas/tensor/traits/type_traits_fixed_rank_strides.hpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_STRIDES_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_FIXED_RANK_STRIDES_HPP - -#include - -namespace boost::numeric::ublas{ - -template class basic_fixed_rank_extents; - -template class basic_fixed_rank_strides; - -} // namespace boost::numeric::ublas - -namespace boost::numeric::ublas{ - - template - struct is_strides< basic_fixed_rank_strides< T, R, L> > : std::true_type {}; - - template - struct is_dynamic< basic_fixed_rank_strides > : std::true_type {}; - - template - struct is_static_rank< basic_fixed_rank_strides > : std::true_type {}; - - template - struct strides> - { - template - using type = basic_fixed_rank_strides; - }; - -} // namespace boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/traits/type_traits_static_extents.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_static_extents.hpp deleted file mode 100644 index 19662f0ae..000000000 --- a/include/boost/numeric/ublas/tensor/traits/type_traits_static_extents.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_EXTENTS_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_EXTENTS_HPP - -#include - -namespace boost::numeric::ublas{ - -template class basic_static_extents; - -} // namespace boost::numeric::ublas - -namespace boost::numeric::ublas{ - -template -struct is_extents< basic_static_extents > : std::true_type {}; - -template -struct is_static< basic_static_extents > : std::true_type {}; - -template -struct is_static_rank< basic_static_extents > : std::true_type {}; - -} // namespace boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/traits/type_traits_static_strides.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_static_strides.hpp deleted file mode 100644 index 47137287b..000000000 --- a/include/boost/numeric/ublas/tensor/traits/type_traits_static_strides.hpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_STRIDES_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_STTAIC_STRIDES_HPP - -#include - -namespace boost::numeric::ublas{ - -template class basic_static_extents; - -template class basic_static_strides; - -} // namespace boost::numeric::ublas - -namespace boost::numeric::ublas{ - - template - struct is_strides< basic_static_strides< basic_static_extents, L > > : std::true_type {}; - - template - struct is_static< basic_static_strides< basic_static_extents, L > > : std::true_type {}; - - template - struct is_static_rank< basic_static_strides< basic_static_extents, L > > : std::true_type {}; - - template - struct strides> - { - template - using type = basic_static_strides, Layout>; - }; - -} // namespace boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/traits/type_traits_strides.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_strides.hpp deleted file mode 100644 index f31fb67a9..000000000 --- a/include/boost/numeric/ublas/tensor/traits/type_traits_strides.hpp +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_STRIDES_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_STRIDES_HPP - -namespace boost::numeric::ublas { - - /// @brief checks if the type is tensor strides or not - template - struct is_strides : std::false_type {}; - - template - inline static constexpr bool const is_strides_v = is_strides::value; - - template - struct strides; - - /** @brief type alias of result of strides::type - * - * @tparam E extents type either basic_extents or basic_static_extents - * - * @tparam Layout either first_order or last_order - * - */ - template - using strides_t = typename strides::template type; - -} // namespace boost::numeric::ublas - -#include -#include -#include - -#endif diff --git a/include/boost/numeric/ublas/tensor/traits/type_traits_tensor.hpp b/include/boost/numeric/ublas/tensor/traits/type_traits_tensor.hpp deleted file mode 100644 index b2bb161cc..000000000 --- a/include/boost/numeric/ublas/tensor/traits/type_traits_tensor.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_TENSOR_HPP -#define BOOST_UBLAS_TENSOR_TYPE_TRAITS_TENSOR_HPP - -#include -#include -#include - -namespace boost::numeric::ublas{ - - template class tensor_core; - -} // namespace boost::numeric::ublas - - -namespace boost::numeric::ublas { - - /// @brief Checks if the type is valid tensor - template - struct is_valid_tensor: std::false_type{}; - - template - struct is_valid_tensor< tensor_core >: std::true_type{}; - - template - inline static constexpr bool is_valid_tensor_v = is_valid_tensor::value; - -} // namespace boost::numeric::ublas - -#endif diff --git a/include/boost/numeric/ublas/tensor/type_traits.hpp b/include/boost/numeric/ublas/tensor/type_traits.hpp index cf1b865c7..bd12bd4b6 100644 --- a/include/boost/numeric/ublas/tensor/type_traits.hpp +++ b/include/boost/numeric/ublas/tensor/type_traits.hpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,10 +13,7 @@ #ifndef BOOST_UBLAS_TENSOR_TYPE_TRAITS_HPP #define BOOST_UBLAS_TENSOR_TYPE_TRAITS_HPP -#include -#include - -#include -#include +#include "traits/basic_type_traits.hpp" +#include "traits/storage_traits.hpp" #endif diff --git a/test/tensor/Jamfile b/test/tensor/Jamfile index 839d3a323..723f5b11a 100644 --- a/test/tensor/Jamfile +++ b/test/tensor/Jamfile @@ -32,35 +32,43 @@ explicit unit_test_framework ; test-suite boost-ublas-tensor-test : - [ run test_tensor.cpp - test_strides.cpp + [ run test_algorithms.cpp + test_einstein_notation.cpp test_expression.cpp - test_operators_comparison.cpp - test_operators_arithmetic.cpp - test_multiplication.cpp - test_multi_index_utility.cpp - test_multi_index.cpp - test_extents.cpp test_expression_evaluation.cpp - test_einstein_notation.cpp - test_algorithms.cpp - test_tensor_matrix_vector.cpp + test_extents_dynamic.cpp + test_extents_dynamic_rank_static.cpp + test_extents_functions.cpp + test_fixed_rank_expression_evaluation.cpp + test_fixed_rank_extents.cpp + test_fixed_rank_functions.cpp + test_fixed_rank_operators_arithmetic.cpp + test_fixed_rank_operators_comparison.cpp + test_fixed_rank_strides.cpp + test_fixed_rank_tensor.cpp + test_fixed_rank_tensor_matrix_vector.cpp test_functions.cpp - test_static_tensor.cpp + test_multi_index.cpp + test_multi_index_utility.cpp + test_multiplication.cpp + test_operators_arithmetic.cpp + test_operators_comparison.cpp + test_static_expression_evaluation.cpp test_static_extents.cpp - test_static_strides.cpp test_static_operators_arithmetic.cpp test_static_operators_comparison.cpp - test_static_expression_evaluation.cpp + test_static_strides.cpp + test_static_tensor.cpp test_static_tensor_matrix_vector.cpp - test_fixed_rank_tensor.cpp - test_fixed_rank_extents.cpp - test_fixed_rank_strides.cpp - test_fixed_rank_operators_arithmetic.cpp - test_fixed_rank_operators_comparison.cpp - test_fixed_rank_expression_evaluation.cpp - test_fixed_rank_tensor_matrix_vector.cpp - test_fixed_rank_functions.cpp - unit_test_framework + test_strides.cpp + test_tensor.cpp + test_tensor_matrix_vector.cpp + unit_test_framework + : + : + : + : test_tensor + : + # ] ; diff --git a/test/tensor/test_algorithms.cpp b/test/tensor/test_algorithms.cpp index 5a11a9c3a..477ee1e0c 100644 --- a/test/tensor/test_algorithms.cpp +++ b/test/tensor/test_algorithms.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -15,42 +15,37 @@ #include #include #include -#include -#include -#include -#include +#include #include "utility.hpp" #include -BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms, - * boost::unit_test::depends_on("test_extents") - * boost::unit_test::depends_on("test_strides")) +BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms/*, + * boost::unit_test::depends_on("test_shape_dynamic") * boost::unit_test::depends_on("test_strides")*/ + ) // BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms) using test_types = zip>::with_t; -using test_types2 = std::tuple>; +using test_types2 = std::tuple>; struct fixture { - using extents_type = boost::numeric::ublas::extents<>; - 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; + using extents_t = boost::numeric::ublas::extents<>; + const std::vector extents = + { + extents_t{1,1}, // 1 + extents_t{1,2}, // 2 + extents_t{2,1}, // 3 + extents_t{2,3}, // 4 + extents_t{2,3,1}, // 5 + extents_t{4,1,3}, // 6 + extents_t{1,2,3}, // 7 + extents_t{4,2,3}, // 8 + extents_t{4,2,3,5} + }; }; @@ -58,401 +53,364 @@ struct fixture 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; - + namespace ublas = boost::numeric::ublas; + using value_type = value; + using vector_t = std::vector; - for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto b = vector_type(product(n)); - auto c = vector_type(product(n)); + constexpr auto first_order = ublas::layout::first_order{}; + constexpr auto last_order = ublas::layout::last_order {}; - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - auto wb = ublas::strides_t,ublas::layout::last_order> (n); - auto wc = ublas::strides_t,ublas::layout::first_order>(n); - auto v = value_type{}; - for(auto i = 0ul; i < a.size(); ++i, v+=1){ - a[i]=v; - } + for(auto const& n : extents) { - 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() ); + auto a = vector_t(product(n)); + auto b = vector_t(product(n)); + auto c = vector_t(product(n)); - for(auto i = 1ul; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i], a[i] ); + auto wa = ublas::to_strides(n,first_order); + auto wb = ublas::to_strides(n,last_order ); + auto wc = ublas::to_strides(n,first_order); - using size_type = typename ublas::strides_t,ublas::layout::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::runtime_error ); - BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), p0, b.data(), wb.data() ), std::runtime_error ); - BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), p0 ), std::runtime_error ); - - value_type* c0 = nullptr; - BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c0, wc.data(), b.data(), wb.data() ), std::runtime_error ); + auto v = value_type{}; + for(auto i = 0ul; i < a.size(); ++i, v+=1){ + a[i]=v; } - // special case rank == 0 - { - auto n = ublas::extents<>{}; + ublas::copy( ublas::size(n), n.data(), b.data(), wb.data(), a.data(), wa.data() ); + ublas::copy( ublas::size(n), n.data(), c.data(), wc.data(), b.data(), wb.data() ); - auto a = vector_type(product(n)); - auto b = vector_type(product(n)); - auto c = vector_type(product(n)); + for(auto i = 1ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i], a[i] ); + std::size_t const*const p0 = nullptr; + value_type* c0 = nullptr; - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - auto wb = ublas::strides_t,ublas::layout::last_order> (n); - auto wc = ublas::strides_t,ublas::layout::first_order>(n); + BOOST_CHECK_THROW( ublas::copy( ublas::size(n), p0, c.data(), wc.data(), b.data(), wb.data() ), std::runtime_error ); + BOOST_CHECK_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), p0, b.data(), wb.data() ), std::runtime_error ); + BOOST_CHECK_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc.data(), b.data(), p0 ), std::runtime_error ); + BOOST_CHECK_THROW( ublas::copy( ublas::size(n), n.data(), c0, wc.data(), b.data(), wb.data() ), std::runtime_error ); + } +} - 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_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, test_types2, fixture ) +{ + namespace ublas = boost::numeric::ublas; + using value_type = value; + using vector_t = std::vector; + constexpr auto first_order = ublas::layout::first_order{}; - BOOST_CHECK_NO_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() ) ); + for(auto const& n : extents) { - } + value_type* a = nullptr; + auto c = vector_t(ublas::product(n)); + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); + } + for(auto const& n : extents) { -} + value_type* a = nullptr; + value_type* c = nullptr; + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, test_types2, fixture ) -{ - using namespace boost::numeric; - using value_type = value; - using vector_type = std::vector; + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); - for(auto const& n : extents) { + } - value_type* a = nullptr; - auto c = vector_type(product(n)); + for(auto const& n : extents) { - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - auto wc = ublas::strides_t,ublas::layout::first_order>(n); + auto a = vector_t(product(n)); + value_type* c = nullptr; - BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); - - } + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); - for(auto const& n : extents) { + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c, wc.data(), a.data(), wa.data() ), std::runtime_error ); - value_type* a = nullptr; - value_type* c = nullptr; + } - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - auto wc = ublas::strides_t,ublas::layout::first_order>(n); + for(auto const& n : extents) { - BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); + auto a = vector_t(product(n)); + auto c = vector_t(product(n)); - } - for(auto const& n : extents) { + size_t* wa = nullptr; + auto wc = ublas::to_strides(n,first_order); - auto a = vector_type(product(n)); - value_type* c = nullptr; + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - auto wc = ublas::strides_t,ublas::layout::first_order>(n); + } - BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c, wc.data(), a.data(), wa.data() ), std::runtime_error ); - - } + for(auto const& n : extents) { - for(auto const& n : extents) { + auto a = vector_t(product(n)); + auto c = vector_t(product(n)); - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); - size_t* wa = nullptr; - auto wc = ublas::strides_t,ublas::layout::first_order>(n); - BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); - - } + size_t* wc = nullptr; + auto wa = ublas::to_strides(n,first_order); - for(auto const& n : extents) { + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); + } - size_t* wc = nullptr; - auto wa = ublas::strides_t,ublas::layout::first_order>(n); + for(auto const& n : extents) { - BOOST_REQUIRE_THROW( ublas::copy( n.size(), n.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); - - } + auto a = vector_t(product(n)); + auto c = vector_t(product(n)); - for(auto const& n : extents) { + size_t* m = nullptr; + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); - - size_t* m = nullptr; - auto wc = ublas::strides_t,ublas::layout::first_order>(n); - auto wa = ublas::strides_t,ublas::layout::first_order>(n); + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), m, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); - BOOST_REQUIRE_THROW( ublas::copy( n.size(), m, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); - - } + } } 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; + namespace ublas = boost::numeric::ublas; + using value_type = value; + using vector_t = std::vector; + constexpr auto first_order = ublas::layout::first_order{}; + constexpr auto last_order = ublas::layout::last_order {}; - for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto b = vector_type(product(n)); - auto c = vector_type(product(n)); + for(auto const& n : extents) { - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - auto wb = ublas::strides_t,ublas::layout::last_order> (n); - auto wc = ublas::strides_t,ublas::layout::first_order>(n); + auto a = vector_t(ublas::product(n)); + auto b = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); - auto v = value_type{}; - for(auto i = 0ul; i < a.size(); ++i, v+=1){ - a[i]=v; - } + auto wa = ublas::to_strides(n,first_order); + auto wb = ublas::to_strides(n,last_order ); + auto wc = ublas::to_strides(n,first_order); - 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);} ); + auto v = value_type{}; + for(auto i = 0ul; i < a.size(); ++i, v+=1){ + a[i]=v; + } - using size_type = typename ublas::strides_t,ublas::layout::first_order>::value_type; + ublas::transform( ublas::size(n), n.data(), b.data(), wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ); + ublas::transform( ublas::size(n), n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a - value_type(1);} ); - size_type zero = 0; - ublas::transform(zero, n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a + value_type(1);} ); + auto zero = std::size_t{0}; + ublas::transform(zero, n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a + value_type(1);} ); - value_type* c0 = nullptr; - const size_type* s0 = nullptr; - size_type const*const p0 = nullptr; + value_type* c0 = nullptr; + const std::size_t* s0 = nullptr; + std::size_t const*const p0 = nullptr; - BOOST_CHECK_THROW(ublas::transform( n.size(), n.data(), c0, wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); - BOOST_CHECK_THROW(ublas::transform( n.size(), n.data(), b.data(), s0, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); - BOOST_CHECK_THROW(ublas::transform( n.size(), p0, b.data(), wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); + BOOST_CHECK_THROW(ublas::transform( ublas::size(n), n.data(), c0, wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); + BOOST_CHECK_THROW(ublas::transform( ublas::size(n), n.data(), b.data(), s0, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); + BOOST_CHECK_THROW(ublas::transform( ublas::size(n), p0, b.data(), wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); - for(auto i = 1ul; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i], a[i] ); + for(auto i = 1ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i], a[i] ); - } + } } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform_exceptions, value, test_types2, fixture ) { - using namespace boost::numeric; - using value_type = value; - using vector_type = std::vector; - - for(auto const& n : extents) { - - value_type* a = nullptr; - auto c = vector_type(product(n)); - - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - auto wc = ublas::strides_t,ublas::layout::first_order>(n); - - BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - value_type* a = nullptr; - value_type* c = nullptr; - - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - auto wc = ublas::strides_t,ublas::layout::first_order>(n); - - BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c, wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } + namespace ublas = boost::numeric::ublas; + using value_type = value; + using vector_t = std::vector; - for(auto const& n : extents) { + constexpr auto first_order = ublas::layout::first_order{}; - auto a = vector_type(product(n)); - value_type* c = nullptr; + for(auto const& n : extents) { - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - auto wc = ublas::strides_t,ublas::layout::first_order>(n); + value_type* a = nullptr; + auto c = vector_t(ublas::product(n)); - BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c, wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } - - for(auto const& n : extents) { + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); + BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), n.data(), c.data(), wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - size_t* wa = nullptr; - auto wc = ublas::strides_t,ublas::layout::first_order>(n); + } - BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc.data(), a.data(), wa, [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } + for(auto const& n : extents) { - for(auto const& n : extents) { + value_type* a = nullptr; + value_type* c = nullptr; - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); - size_t* wc = nullptr; - auto wa = ublas::strides_t,ublas::layout::first_order>(n); + BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), n.data(), c, wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - BOOST_REQUIRE_THROW( ublas::transform( n.size(), n.data(), c.data(), wc, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto a = vector_type(product(n)); - auto c = vector_type(product(n)); - - size_t* m = nullptr; - auto wc = ublas::strides_t,ublas::layout::first_order>(n); - auto wa = ublas::strides_t,ublas::layout::first_order>(n); + auto a = vector_t(ublas::product(n)); + value_type* c = nullptr; - BOOST_REQUIRE_THROW( ublas::transform( n.size(), m, c.data(), wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } -} + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); -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; + BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), n.data(), c, wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); + } - for(auto const& n : extents) { + for(auto const& n : extents) { - auto const s = product(n); + auto a = vector_t(product(n)); + auto c = vector_t(product(n)); - auto a = vector_type(product(n)); - // auto b = vector_type(product(n)); - // auto c = vector_type(product(n)); + size_t* wa = nullptr; + auto wc = ublas::to_strides(n,first_order); - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - // auto wb = ublas::strides_t,ublas::layout::last_order> (n); - // auto wc = ublas::strides_t,ublas::layout::first_order>(n); + BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), n.data(), c.data(), wc.data(), a.data(), wa, [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - 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); + for(auto const& n : extents) { - BOOST_CHECK_EQUAL( acc, value_type( static_cast< inner_type_t >( s*(s+1) / 2 ) ) ); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); - using size_type = typename ublas::strides_t,ublas::layout::first_order>::value_type; - size_type zero = 0; - (void)ublas::accumulate(zero, n.data(), a.data(), wa.data(),v); + size_t* wc = nullptr; + auto wa = ublas::to_strides(n,first_order); - value_type* c0 = nullptr; - size_type const*const p0 = nullptr; + BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), n.data(), c.data(), wc, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), n.data(), c0, wa.data(), v), std::runtime_error); - BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), n.data(), a.data(), p0, v), std::runtime_error); - BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), p0, a.data(), wa.data(), v), std::runtime_error); + } + for(auto const& n : extents) { - auto acc2 = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v, - [](auto const& l, auto const& r){return l + r; }); + auto a = vector_t(product(n)); + auto c = vector_t(product(n)); - BOOST_CHECK_EQUAL( acc2, value_type( static_cast< inner_type_t >( s*(s+1) / 2 ) ) ); + size_t* m = nullptr; + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); - (void)ublas::accumulate(zero, n.data(), a.data(), wa.data(), v, [](auto const& l, auto const& r){return l + r; }); + BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), m, c.data(), wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), n.data(), c0, wa.data(), v,[](auto const& l, auto const& r){return l + r; }), std::runtime_error); - BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), n.data(), a.data(), p0, v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); - BOOST_CHECK_THROW((void)ublas::accumulate( n.size(), p0, a.data(), wa.data(),v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); - - } + } } - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, value, test_types2, fixture ) +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; - - for(auto const& n : extents) { + namespace ublas = boost::numeric::ublas; + using value_type = value; + using vector_t = std::vector; - value_type* a = nullptr; + constexpr auto first_order = ublas::layout::first_order{}; - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - BOOST_REQUIRE_THROW( (void)ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0} ), std::runtime_error ); - - } + for(auto const& n : extents) { - for(auto const& n : extents) { + auto const s = ublas::product(n); - value_type* a = nullptr; + auto a = vector_t(ublas::product(n)); + auto wa = ublas::to_strides(n,first_order); - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - BOOST_REQUIRE_THROW( (void)ublas::accumulate( n.size(), n.data(), a, wa.data(), value_type{0},[](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); - + auto v = value_type{}; + for(auto i = 0ul; i < a.size(); ++i, v+=value_type(1)){ + a[i]=v; } - for(auto const& n : extents) { + auto acc = ublas::accumulate( ublas::size(n), n.data(), a.data(), wa.data(), v); - auto a = vector_type(product(n)); + auto sum = std::div(s*(s+1),2).quot; - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - size_t p = 0u; - BOOST_CHECK_EQUAL ( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0} ), value_type{0} ); - - } - - for(auto const& n : extents) { + BOOST_CHECK_EQUAL( acc, value_type( static_cast< inner_type_t >( sum ) ) ); - auto a = vector_type(product(n)); + auto zero = std::size_t{0}; + (void)ublas::accumulate(zero, n.data(), a.data(), wa.data(),v); - auto wa = ublas::strides_t,ublas::layout::first_order>(n); - size_t p = 0u; - BOOST_CHECK_EQUAL( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), value_type{0} ); - - } + value_type* c0 = nullptr; + std::size_t const*const p0 = nullptr; - for(auto const& n : extents) { + BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), n.data(), c0, wa.data(), v), std::runtime_error); + BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), n.data(), a.data(), p0, v), std::runtime_error); + BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), p0, a.data(), wa.data(), v), std::runtime_error); - auto a = vector_type(product(n)); - size_t* wa = nullptr; + auto acc2 = ublas::accumulate( ublas::size(n), n.data(), a.data(), wa.data(), v, + [](auto const& l, auto const& r){return l + r; }); - BOOST_REQUIRE_THROW( (void)ublas::accumulate( n.size(), n.data(), a.data(), wa, value_type{0} ), std::runtime_error ); - - } + BOOST_CHECK_EQUAL( acc2, value_type( static_cast< inner_type_t >( sum ) ) ); - for(auto const& n : extents) { + (void)ublas::accumulate(zero, n.data(), a.data(), wa.data(), v, [](auto const& l, auto const& r){return l + r; }); - auto a = vector_type(product(n)); + BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), n.data(), c0, wa.data(), v,[](auto const& l, auto const& r){return l + r; }), std::runtime_error); + BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), n.data(), a.data(), p0, v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); + BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), p0, a.data(), wa.data(),v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); - auto wa = ublas::strides_t,ublas::layout::first_order>(n); + } +} - size_t* m = nullptr; - BOOST_REQUIRE_THROW( (void)ublas::accumulate( n.size(), m, a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); - - } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, value, test_types2, fixture ) +{ + namespace ublas = boost::numeric::ublas; + using value_type = value; + using vector_t = std::vector; + constexpr auto first_order = ublas::layout::first_order{}; + + + for(auto const& n : extents) { + value_type* a = nullptr; + auto wa = ublas::to_strides(n,first_order); + BOOST_REQUIRE_THROW( (void)ublas::accumulate( ublas::size(n), n.data(), a, wa.data(), value_type{0} ), std::runtime_error ); + + } + + for(auto const& n : extents) { + value_type* a = nullptr; + auto wa = ublas::to_strides(n,first_order); + BOOST_REQUIRE_THROW( (void)ublas::accumulate( ublas::size(n), n.data(), a, wa.data(), value_type{0},[](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); + } + + for(auto const& n : extents) { + auto a = vector_t(product(n)); + auto wa = ublas::to_strides(n,first_order); + size_t p = 0u; + BOOST_CHECK_EQUAL ( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0} ), value_type{0} ); + } + + for(auto const& n : extents) { + auto a = vector_t(product(n)); + auto wa = ublas::to_strides(n,first_order); + size_t p = 0u; + BOOST_CHECK_EQUAL( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), value_type{0} ); + } + + for(auto const& n : extents) { + auto a = vector_t(product(n)); + size_t* wa = nullptr; + BOOST_REQUIRE_THROW( (void)ublas::accumulate( ublas::size(n), n.data(), a.data(), wa, value_type{0} ), std::runtime_error ); + } + + for(auto const& n : extents) { + auto a = vector_t(product(n)); + auto wa = ublas::to_strides(n,first_order); + size_t* m = nullptr; + BOOST_REQUIRE_THROW( (void)ublas::accumulate( ublas::size(n), m, a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); + } } @@ -460,282 +418,146 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, template void init(std::vector& a) { - auto v = V(1); - for(auto i = 0u; i < a.size(); ++i, ++v){ - a[i] = v; - } + auto v = V(1); + for(auto i = 0u; i < a.size(); ++i, ++v){ + a[i] = v; + } } template void init(std::vector>& a) { - auto v = std::complex(1,1); - for(auto i = 0u; i < a.size(); ++i){ - a[i] = v; - v.real(v.real()+1); - v.imag(v.imag()+1); - } + auto v = std::complex(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; - using extents_type = ublas::extents<>; - using strides_type = ublas::strides_t; - using size_type = typename extents_type::value_type; - using permutation_type = std::vector; + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; +// using layout_t = typename value::second_type; + using vector_t = std::vector; + using base_t = typename extents_t::base_type; + using permutation_type = std::vector; + constexpr auto first_order = ublas::layout::first_order{}; - for(auto const& n : extents) { - auto p = n.size(); - auto s = product(n); + for(auto const& n : extents) { - 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 p = ublas::size(n); + auto s = ublas::product(n); - auto wa = strides_type(n); + auto pi = permutation_type(p); + auto a = vector_t(s); + auto b1 = vector_t(s); + auto b2 = vector_t(s); + auto c1 = vector_t(s); + auto c2 = vector_t(s); - init(a); + auto wa = ublas::to_strides(n,first_order); - // so wie last-order. - for(auto i = size_type(0), j = p; i < n.size(); ++i, --j) - pi[i] = j; + init(a); - auto nc = typename extents_type::base_type (p); - for(auto i = 0u; i < p; ++i) - nc[pi[i]-1] = n[i]; + // so wie last-order. + for(auto i = std::size_t{0}, j = p; i < ublas::size(n); ++i, --j) + pi[i] = j; - 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]; + auto nc_base = base_t(p); + for(auto i = 0u; i < p; ++i) + nc_base[pi[i]-1] = n[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() ); + auto nc = extents_t(std::move(nc_base)); - if(!std::is_compound_v) - for(auto i = 0ul; i < s; ++i) - BOOST_CHECK_EQUAL( c1[i], c2[i] ); + auto wc = ublas::to_strides(nc,first_order); + auto wc_pi = base_t(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() ); - auto nb = typename extents_type::base_type (p); - for(auto i = 0u; i < p; ++i) - nb[pi[i]-1] = nc[i]; + if(!std::is_compound_v) + for(auto i = 0ul; i < s; ++i) + BOOST_CHECK_EQUAL( c1[i], c2[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() ); + auto nb_base = base_t(p); + for(auto i = 0u; i < p; ++i) + nb_base[pi[i]-1] = nc[i]; - if(!std::is_compound_v) - for(auto i = 0ul; i < s; ++i) - BOOST_CHECK_EQUAL( b1[i], b2[i] ); + auto nb = extents_t(std::move(nb_base)); - for(auto i = 0ul; i < s; ++i) - BOOST_CHECK_EQUAL( a[i], b2[i] ); + auto wb = ublas::to_strides(nb,first_order); + auto wb_pi = base_t(p); + for(auto i = 0u; i < p; ++i) + wb_pi[pi[i]-1] = wb[i]; - size_type zero = 0; - ublas::trans( zero, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() ); - ublas::trans( zero, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() ); + 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() ); - value_type *c0 = nullptr; - size_type const*const s0 = nullptr; + if(!std::is_compound_v) + for(auto i = 0ul; i < s; ++i) + BOOST_CHECK_EQUAL( b1[i], b2[i] ); - BOOST_CHECK_THROW(ublas::trans( p, n.data(), pi.data(), c0, wc.data(), a.data(), wa.data()), std::runtime_error); - BOOST_CHECK_THROW(ublas::trans( p, s0, pi.data(), c2.data(),wc.data(), a.data(), wa.data()), std::runtime_error); - BOOST_CHECK_THROW(ublas::trans( p, n.data(), pi.data(), c2.data(), s0, a.data(), wa.data()), std::runtime_error); - BOOST_CHECK_THROW(ublas::trans( p, n.data(), s0, c2.data(), wc.data(), a.data(), wa.data()), std::runtime_error); + for(auto i = 0ul; i < s; ++i) + BOOST_CHECK_EQUAL( a[i], b2[i] ); - } -} + auto zero = std::size_t{0}; + ublas::trans( zero, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() ); + ublas::trans( zero, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() ); + value_type *c0 = nullptr; + std::size_t const*const s0 = nullptr; -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans_exceptions, 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; - using extents_type = ublas::extents<>; - using strides_type = ublas::strides_t; - using size_type = typename extents_type::value_type; - using permutation_type = std::vector; - - for(auto const& n : extents) { + BOOST_CHECK_THROW(ublas::trans( p, n.data(), pi.data(), c0, wc.data(), a.data(), wa.data()), std::runtime_error); + BOOST_CHECK_THROW(ublas::trans( p, s0, pi.data(), c2.data(),wc.data(), a.data(), wa.data()), std::runtime_error); + BOOST_CHECK_THROW(ublas::trans( p, n.data(), pi.data(), c2.data(), s0, a.data(), wa.data()), std::runtime_error); + BOOST_CHECK_THROW(ublas::trans( p, n.data(), s0, c2.data(), wc.data(), a.data(), wa.data()), std::runtime_error); - auto p = n.size(); - auto s = product(n); - - auto pi = permutation_type(p); - value_type* a = nullptr; - auto c = vector_type(s); - - auto wa = strides_type(n); - - auto nc = typename extents_type::base_type (p); - auto wc = strides_type(n); - auto wc_pi = typename strides_type::base_type (p); - - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), a, wa.data(), c.data(), wc.data() ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto p = n.size(); - auto s = product(n); - - auto pi = permutation_type(p); - value_type* a = nullptr; - auto c = vector_type(s); - - auto wa = strides_type(n); - auto nc = typename extents_type::base_type (p); - - auto wc = strides_type(n); - - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto p = n.size(); - - auto pi = permutation_type(p); - value_type* a = nullptr; - value_type* c = nullptr; - - auto wa = strides_type(n); - auto nc = typename extents_type::base_type (p); - - auto wc = strides_type(n); - - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto p = n.size(); - auto s = product(n); - - auto pi = permutation_type(p); - auto a = vector_type(s); - auto c = vector_type(s); - - auto wa = strides_type(n); - - auto nc = typename extents_type::base_type (p); - - size_t* wc = nullptr; - - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto p = n.size(); - auto s = product(n); - - auto pi = permutation_type(p); - auto a = vector_type(s); - auto c = vector_type(s); - - auto wc = strides_type(n); - auto nc = typename extents_type::base_type (p); - - size_t* wa = nullptr; - - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto p = n.size(); - auto s = product(n); - - auto pi = permutation_type(p); - auto a = vector_type(s); - auto c = vector_type(s); - - size_t* wc = nullptr; - - auto nc = typename extents_type::base_type (p); - - size_t* wa = nullptr; - - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi.data(), c.data(), wc, a.data(), wa ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto p = n.size(); - auto s = product(n); - - size_type* pi = nullptr; - auto a = vector_type(s); - auto c = vector_type(s); - - auto wa = strides_type(n); - - auto nc = typename extents_type::base_type (p); - auto wc = strides_type(n); - - BOOST_REQUIRE_THROW( ublas::trans( p, nc.data(), pi, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto p = n.size(); - auto s = product(n); - - auto pi = permutation_type(p); - auto a = vector_type(s); - auto c = vector_type(s); - - auto wa = strides_type(n); - size_t* nc = nullptr; - - auto wc = strides_type(n); - - BOOST_REQUIRE_THROW( ublas::trans( p, nc, pi.data(), c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - size_type p = 1; - auto s = product(n); - - auto pi = permutation_type(p); - auto a = vector_type(s); - auto c = vector_type(s); + } +} - auto wa = strides_type(n); - auto nc = typename extents_type::base_type (p); - - auto wc = strides_type(n); - ublas::trans( p, nc.data(), pi.data(), c.data(), wc.data(), a.data(), wa.data() ); - - } +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans_exceptions, value, test_types, fixture ) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_t = typename value::second_type; + using vector_t = std::vector; + using permutation_type = std::vector; + + constexpr auto layout = layout_t{}; + + std::size_t* nnullptr = nullptr; + value_type * anullptr = nullptr; + + for(auto const& n : extents) { + auto p = ublas::size(n); + auto s = ublas::product(n); + auto pi = permutation_type(p); + auto a = vector_t(s); + auto c = vector_t(s); + auto wa = ublas::to_strides(n,layout); + auto wc = ublas::to_strides(n,layout); + if(p>1){ + BOOST_REQUIRE_THROW( ublas::trans( p, nnullptr, pi.data(), c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , nnullptr , c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), c.data(), nnullptr , a.data(), nnullptr ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), c.data(), wc.data(), a.data(), nnullptr ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), c.data(), nnullptr , a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), anullptr, wc.data(), anullptr, wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), c.data(), wc.data(), anullptr, wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), anullptr, wc.data(), a.data(), wa.data() ), std::runtime_error ); + } + + // ublas::trans( p, n.data(), pi.data(), c.data(), wc.data(), a.data(), wa.data() ); + } } diff --git a/test/tensor/test_einstein_notation.cpp b/test/tensor/test_einstein_notation.cpp index 0abda5b96..400011a7c 100644 --- a/test/tensor/test_einstein_notation.cpp +++ b/test/tensor/test_einstein_notation.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,15 +12,18 @@ // And we acknowledge the support from all contributors. -#include -#include #include - #include + +#include +#include + + #include "utility.hpp" -BOOST_AUTO_TEST_SUITE ( test_einstein_notation, * boost::unit_test::depends_on("test_multi_index") ) +BOOST_AUTO_TEST_SUITE ( test_einstein_notation/*, + *boost::unit_test::depends_on("test_multi_index") */) using test_types = zip>::with_t; @@ -29,94 +32,115 @@ using test_types = zip>::with_t; - 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( static_cast< inner_type_t >(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( static_cast< inner_type_t >(i+1) ); - - - - auto AB = A(_,_e) * B(_e,_); + namespace ublas = boost::numeric::ublas; + + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using tensor_t = ublas::tensor_dynamic; + // NOLINTNEXTLINE(google-build-using-namespace) + using namespace boost::numeric::ublas::index; + + { + auto A = tensor_t(5,3); + auto B = tensor_t{3,4}; + // auto C = tensor_t{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_t( static_cast< inner_type_t >(i+1) ); + } + } - // std::cout << "A = " << A << std::endl; - // std::cout << "B = " << B << std::endl; - // std::cout << "AB = " << AB << std::endl; + 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_t( static_cast< inner_type_t >(i+1) ); + } + } - 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 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){ + auto e0 = B.extents().at(0); + auto sum = std::div(e0*(e0+1),2); + auto quot = value_t(sum.quot); + BOOST_CHECK_EQUAL( AB.at(i,j) , A.at(i,0)*quot ); + } } + } - { - 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( static_cast< inner_type_t >(i+1) ); + { + auto A = tensor_t{4,5,3}; + auto B = tensor_t{3,4,2}; - 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( static_cast< inner_type_t >(i+1) ); + 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_t( static_cast< inner_type_t >(i+1) ); + } + } + } - auto AB = A(_d,_,_f) * B(_f,_d,_); + 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_t( static_cast< inner_type_t >(i+1) ); + } + } + } - // 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 ); + auto AB = A(_d,_,_f) * B(_f,_d,_); - 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( static_cast< inner_type_t >(nf * nd) ) ); + // 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_t( static_cast< inner_type_t >(nf * nd) ) ); + } } + } - { - auto A = tensor_type{4,3}; - auto B = tensor_type{3,4,2}; + { + auto A = tensor_t{{4,3}}; + auto B = tensor_t{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( static_cast< inner_type_t >(i+1) ); + 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_t( static_cast< inner_type_t >(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( static_cast< inner_type_t >(i+1) ); - auto AB = A(_d,_f) * B(_f,_d,_); + 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_t( static_cast< inner_type_t >(i+1) ); + } + } + } - // 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 ); + auto AB = A(_d,_f) * B(_f,_d,_); - for(auto i = 0u; i < AB.extents().at(0); ++i) - BOOST_CHECK_EQUAL ( AB.at( i ) , value_type( static_cast< inner_type_t >(nf * nd) ) ); + // 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_t( static_cast< inner_type_t >(nf * nd) ) ); } + + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_expression.cpp b/test/tensor/test_expression.cpp index 64ce969df..3d884e72c 100644 --- a/test/tensor/test_expression.cpp +++ b/test/tensor/test_expression.cpp @@ -11,7 +11,7 @@ - +#include #include #include #include @@ -28,49 +28,53 @@ using test_types = zip>::with_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{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 + + const std::vector extents { - } - std::vector 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 + }; }; 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::dynamic_tensor; - using tensor_expression_type = typename tensor_type::super_type; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using tensor_t = ublas::tensor_dynamic; + using expression_t = typename tensor_t::super_type; for(auto const& e : extents) { - auto v = value_type{}; - auto t = tensor_type(e); + if(!ublas::is_valid(e)){ + continue; + } - for(auto& tt: t){ tt = v; v+=value_type{1}; } - const auto& tensor_expression_const = static_cast( t ); + auto v = value_t{}; + auto t = tensor_t(e); - for(auto i = 0ul; i < t.size(); ++i) + for(auto& tt: t){ tt = v; v+=value_t{1}; } + const auto& tensor_expression_const = static_cast( t ); + + for(auto i = 0ul; i < t.size(); ++i){ BOOST_CHECK_EQUAL( tensor_expression_const()(i), t(i) ); + } } } @@ -79,36 +83,39 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_access, value, test_ty 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::dynamic_tensor; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using tensor_t = ublas::tensor_dynamic; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); + auto uplus1 = [](auto const& a){ return a+value_t{1}; }; + //auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_t(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}; } + auto t = tensor_t(e); + auto v = value_t{}; + for(auto& tt: t) { tt = v; v+=value_t{1}; } - const auto uexpr = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + const auto uexpr = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - for(auto i = 0ul; i < t.size(); ++i) + 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( uexpr, uplus1 ); + auto uexpr_uexpr = ublas::detail::make_unary_tensor_expression( uexpr, uplus1 ); - for(auto i = 0ul; i < t.size(); ++i) + 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 > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_e) >, tensor_t > ) ); 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_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_uexpr_e_e) >, tensor_t > ) ); } @@ -117,52 +124,58 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_expression, value, test_typ 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::dynamic_tensor; - - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, std::placeholders::_1, value_type(2) ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using tensor_t = ublas::tensor_dynamic; + + auto uplus1 = [](auto const& a){ return a+value_t{1}; }; + auto uplus2 = [](auto const& a){ return a+value_t{2}; }; + //auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_t(1) ); + //auto uplus2 = std::bind( std::plus{}, std::placeholders::_1, value_t(2) ); + auto bplus = std::plus {}; + auto bminus = std::minus{}; 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 t = tensor_t(e); + auto v = value_t{}; + for(auto& tt: t){ tt = v; v+=value_t{1}; } - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, tensor_t > ) ); - for(auto i = 0ul; i < t.size(); ++i) + for(auto i = 0ul; i < t.size(); ++i){ BOOST_CHECK_EQUAL( uexpr1(i), uplus1(t(i)) ); + } - for(auto i = 0ul; i < t.size(); ++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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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 > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, tensor_t > ) ); - for(auto i = 0ul; i < t.size(); ++i) + 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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 > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) ); - for(auto i = 0ul; i < t.size(); ++i) + for(auto i = 0ul; i < t.size(); ++i){ BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) ); + } } diff --git a/test/tensor/test_expression_evaluation.cpp b/test/tensor/test_expression_evaluation.cpp index 648134998..5863aa963 100644 --- a/test/tensor/test_expression_evaluation.cpp +++ b/test/tensor/test_expression_evaluation.cpp @@ -12,64 +12,63 @@ + #include #include +#include #include #include "utility.hpp" #include #include -BOOST_AUTO_TEST_SUITE(test_tensor_expression); - +BOOST_AUTO_TEST_SUITE(test_tensor_expression) using test_types = zip>::with_t; - struct fixture { - using extents_type = boost::numeric::ublas::extents<>; - 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 + using extents_t = boost::numeric::ublas::extents<>; + + const std::vector extents = { - } - std::vector extents; +// extents_t{}, // 0 + + extents_t{1,1}, // 1 + extents_t{1,2}, // 2 + extents_t{2,1}, // 3 + + extents_t{2,3}, // 4 + extents_t{2,3,1}, // 5 + extents_t{1,2,3}, // 6 + extents_t{1,1,2,3}, // 7 + extents_t{1,2,3,1,1}, // 8 + + extents_t{4,2,3}, // 9 + extents_t{4,2,1,3}, // 10 + extents_t{4,2,1,3,1}, // 11 + extents_t{1,4,2,1,3,1} // 12 + }; }; 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::dynamic_tensor; - - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using tensor_t = ublas::tensor_dynamic; + + auto uplus1 = [](auto const& a){ return a + value_t(1); }; + auto uplus2 = [](auto const& a){ return value_t(2) + a; }; + auto bplus = std::plus {}; + auto bminus = std::minus{}; 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 t = tensor_t(e); + auto v = value_t{}; + for(auto& tt: t){ tt = v; v+=value_t{1}; } BOOST_CHECK( ublas::detail::retrieve_extents( t ) == e ); @@ -77,20 +76,20 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_retrieve_extents, value // uexpr1 = t+1 // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); @@ -100,39 +99,39 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_retrieve_extents, value for(auto i = 0u; i < extents.size()-1; ++i) { - auto v = value_type{}; + auto v = value_t{}; - auto t1 = tensor_type(extents[i]); - for(auto& tt: t1){ tt = v; v+=value_type{1}; } + auto t1 = tensor_t(extents[i]); + for(auto& tt: t1){ tt = v; v+=value_t{1}; } - auto t2 = tensor_type(extents[i+1]); - for(auto& tt: t2){ tt = v; v+=value_type{2}; } + auto t2 = tensor_t(extents[i+1]); + for(auto& tt: t2){ tt = v; v+=value_t{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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t2, bminus ); + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( 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( t2, bexpr_uexpr, bminus ); + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( t2, bexpr_uexpr, bminus ); BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); } @@ -146,22 +145,21 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_retrieve_extents, value 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::dynamic_tensor; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using tensor_t = ublas::tensor_dynamic; - - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + auto uplus1 = [](auto const& a){ return a + value_t(1); }; + auto uplus2 = [](auto const& a){ return value_t(2) + a; }; + auto bplus = std::plus {}; + auto bminus = std::minus{}; 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 t = tensor_t(e); + auto v = value_t{}; + for(auto& tt: t){ tt = v; v+=value_t{1}; } BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); @@ -169,20 +167,20 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_all_extents_equal, valu // uexpr1 = t+1 // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t, bminus ); + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); @@ -192,52 +190,52 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_all_extents_equal, valu for(auto i = 0u; i < extents.size()-1; ++i) { - auto v = value_type{}; + auto v = value_t{}; - auto t1 = tensor_type(extents[i]); - for(auto& tt: t1){ tt = v; v+=value_type{1}; } + auto t1 = tensor_t(extents[i]); + for(auto& tt: t1){ tt = v; v+=value_t{1}; } - auto t2 = tensor_type(extents[i+1]); - for(auto& tt: t2){ tt = v; v+=value_type{2}; } + auto t2 = tensor_t(extents[i+1]); + for(auto& tt: t2){ tt = v; v+=value_t{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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( uexpr1, uexpr2, bplus ); + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t2, bminus ); + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( 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( t2, bexpr_uexpr, bminus ); + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( 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( uexpr1, t2, bplus ); + auto bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr2, t1, bplus ); + auto bexpr_bexpr_uexpr3 = ublas::detail::make_binary_tensor_expression( 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( t1, bexpr_bexpr_uexpr3, bplus ); + auto bexpr_bexpr_uexpr4 = ublas::detail::make_binary_tensor_expression( t1, bexpr_bexpr_uexpr3, bplus ); BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); } diff --git a/test/tensor/test_extents.cpp b/test/tensor/test_extents.cpp deleted file mode 100644 index 2dd9257ff..000000000 --- a/test/tensor/test_extents.cpp +++ /dev/null @@ -1,731 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#include -#include -#include -#include -#include - -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; - - - auto e0 = extents{}; - BOOST_CHECK( e0.empty()); - BOOST_CHECK ( e0.size() == 0 ); - - auto e1 = extents{1,1}; - BOOST_CHECK(!e1.empty()); - BOOST_CHECK ( e1.size() == 2 ); - - auto e2 = extents{1,2}; - BOOST_CHECK(!e2.empty()); - BOOST_CHECK ( e2.size() == 2 ); - - auto e3 = extents{2,1}; - BOOST_CHECK (!e3.empty()); - BOOST_CHECK ( e3.size() == 2 ); - - auto e4 = extents{2,3}; - BOOST_CHECK(!e4.empty()); - BOOST_CHECK ( e4.size() == 2 ); - - auto e5 = extents{2,3,1}; - BOOST_CHECK (!e5.empty()); - BOOST_CHECK ( e5.size() == 3 ); - - auto e6 = extents{1,2,3}; // 6 - BOOST_CHECK(!e6.empty()); - BOOST_CHECK ( e6.size() == 3 ); - - auto e7 = extents{4,2,3}; // 7 - BOOST_CHECK(!e7.empty()); - BOOST_CHECK ( 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); -} - -BOOST_AUTO_TEST_CASE(test_static_rank_extents_ctor) -{ - namespace ub = boost::numeric::ublas; - - - auto e0 = ub::extents<0>{}; - BOOST_CHECK( e0.empty()); - BOOST_CHECK ( e0.size() == 0); - - auto e1 = ub::extents<2>{1,1}; - BOOST_CHECK(!e1.empty()); - BOOST_CHECK ( e1.size() == 2); - - auto e2 = ub::extents<2>{1,2}; - BOOST_CHECK(!e2.empty()); - BOOST_CHECK ( e2.size() == 2); - - auto e3 = ub::extents<2>{2,1}; - BOOST_CHECK (!e3.empty()); - BOOST_CHECK ( e3.size() == 2); - - auto e4 = ub::extents<2>{2,3}; - BOOST_CHECK(!e4.empty()); - BOOST_CHECK ( e4.size() == 2); - - auto e5 = ub::extents<3>{2,3,1}; - BOOST_CHECK (!e5.empty()); - BOOST_CHECK ( e5.size() == 3); - - auto e6 = ub::extents<3>{1,2,3}; // 6 - BOOST_CHECK(!e6.empty()); - BOOST_CHECK ( e6.size() == 3); - - auto e7 = ub::extents<3>{4,2,3}; // 7 - BOOST_CHECK(!e7.empty()); - BOOST_CHECK ( e7.size() == 3); - - BOOST_CHECK_THROW( ub::extents<2>({1,0}), std::length_error); - BOOST_CHECK_THROW( ub::extents<1>({0} ), std::length_error); - BOOST_CHECK_THROW( ub::extents<1>({3} ), std::length_error); - BOOST_CHECK_THROW( ub::extents<2>({0,1}), std::length_error); - BOOST_CHECK_THROW( ub::extents<2>({1,1,2}), std::out_of_range); -} - - -struct fixture { - using extents_type = boost::numeric::ublas::extents<>; - template - using static_rank_extents_type = boost::numeric::ublas::extents; - - 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 - - extents_type{1,4,1}, // 13 - extents_type{1,1,1,1}, // 14 - extents_type{1,4,1,1,1}, // 15 - extents_type{1,1,2,1,1,1}, // 16 - extents_type{1,1,2,3,1,1}, // 17 - } - {} - std::vector 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(),18); - - 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_REQUIRE_EQUAL(extents[13].size(), 3); - BOOST_REQUIRE_EQUAL(extents[14].size(), 4); - BOOST_REQUIRE_EQUAL(extents[15].size(), 5); - BOOST_REQUIRE_EQUAL(extents[16].size(), 6); - BOOST_REQUIRE_EQUAL(extents[17].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_CHECK_EQUAL(extents[13][0],1); - BOOST_CHECK_EQUAL(extents[13][1],4); - BOOST_CHECK_EQUAL(extents[13][2],1); - - BOOST_CHECK_EQUAL(extents[14][0],1); - BOOST_CHECK_EQUAL(extents[14][1],1); - BOOST_CHECK_EQUAL(extents[14][2],1); - BOOST_CHECK_EQUAL(extents[14][3],1); - - BOOST_CHECK_EQUAL(extents[15][0],1); - BOOST_CHECK_EQUAL(extents[15][1],4); - BOOST_CHECK_EQUAL(extents[15][2],1); - BOOST_CHECK_EQUAL(extents[15][3],1); - BOOST_CHECK_EQUAL(extents[15][4],1); - - BOOST_CHECK_EQUAL(extents[16][0],1); - BOOST_CHECK_EQUAL(extents[16][1],1); - BOOST_CHECK_EQUAL(extents[16][2],2); - BOOST_CHECK_EQUAL(extents[16][3],1); - BOOST_CHECK_EQUAL(extents[16][4],1); - BOOST_CHECK_EQUAL(extents[16][5],1); - - BOOST_CHECK_EQUAL(extents[17][0],1); - BOOST_CHECK_EQUAL(extents[17][1],1); - BOOST_CHECK_EQUAL(extents[17][2],2); - BOOST_CHECK_EQUAL(extents[17][3],3); - BOOST_CHECK_EQUAL(extents[17][4],1); - BOOST_CHECK_EQUAL(extents[17][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(),18); - - 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} - auto e13 = extents[13]; // {1,4,1} - auto e14 = extents[14]; // {1,1,1,1} - auto e15 = extents[15]; // {1,4,1,1,1} - auto e16 = extents[16]; // {1,1,2,1,1,1} - auto e17 = extents[17]; // {1,1,2,3,1,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_REQUIRE_EQUAL(e13.size(), 3); - BOOST_REQUIRE_EQUAL(e14.size(), 4); - BOOST_REQUIRE_EQUAL(e15.size(), 5); - BOOST_REQUIRE_EQUAL(e16.size(), 6); - BOOST_REQUIRE_EQUAL(e17.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_CHECK_EQUAL(e13[0],1); - BOOST_CHECK_EQUAL(e13[1],4); - BOOST_CHECK_EQUAL(e13[2],1); - - BOOST_CHECK_EQUAL(e14[0],1); - BOOST_CHECK_EQUAL(e14[1],1); - BOOST_CHECK_EQUAL(e14[2],1); - BOOST_CHECK_EQUAL(e14[3],1); - - BOOST_CHECK_EQUAL(e15[0],1); - BOOST_CHECK_EQUAL(e15[1],4); - BOOST_CHECK_EQUAL(e15[2],1); - BOOST_CHECK_EQUAL(e15[3],1); - BOOST_CHECK_EQUAL(e15[4],1); - - BOOST_CHECK_EQUAL(e16[0],1); - BOOST_CHECK_EQUAL(e16[1],1); - BOOST_CHECK_EQUAL(e16[2],2); - BOOST_CHECK_EQUAL(e16[3],1); - BOOST_CHECK_EQUAL(e16[4],1); - BOOST_CHECK_EQUAL(e16[5],1); - - BOOST_CHECK_EQUAL(e17[0],1); - BOOST_CHECK_EQUAL(e17[1],1); - BOOST_CHECK_EQUAL(e17[2],2); - BOOST_CHECK_EQUAL(e17[3],3); - BOOST_CHECK_EQUAL(e17[4],1); - BOOST_CHECK_EQUAL(e17[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(),18); - - 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} - auto e13 = extents[13]; // {1,4,1} - auto e14 = extents[14]; // {1,1,1,1} - auto e15 = extents[15]; // {1,4,1,1,1} - auto e16 = extents[16]; // {1,1,2,1,1,1} - auto e17 = extents[17]; // {1,1,2,3,1,1} - - BOOST_CHECK( e0.empty ( )); - BOOST_CHECK( ! is_scalar(e0)); - BOOST_CHECK( ! is_vector(e0)); - BOOST_CHECK( ! is_matrix(e0)); - BOOST_CHECK( ! is_tensor(e0)); - - BOOST_CHECK( ! e1.empty ( ) ); - BOOST_CHECK( is_scalar(e1) ); - BOOST_CHECK( ! is_vector(e1) ); - BOOST_CHECK( ! is_matrix(e1) ); - BOOST_CHECK( ! is_tensor(e1) ); - - BOOST_CHECK( ! e2.empty ( ) ); - BOOST_CHECK( ! is_scalar(e2) ); - BOOST_CHECK( is_vector(e2) ); - BOOST_CHECK( ! is_matrix(e2) ); - BOOST_CHECK( ! is_tensor(e2) ); - - BOOST_CHECK( ! e3.empty ( ) ); - BOOST_CHECK( ! is_scalar(e3) ); - BOOST_CHECK( is_vector(e3) ); - BOOST_CHECK( ! is_matrix(e3) ); - BOOST_CHECK( ! is_tensor(e3) ); - - BOOST_CHECK( ! e4.empty ( ) ); - BOOST_CHECK( ! is_scalar(e4) ); - BOOST_CHECK( ! is_vector(e4) ); - BOOST_CHECK( is_matrix(e4) ); - BOOST_CHECK( ! is_tensor(e4) ); - - BOOST_CHECK( ! e5.empty ( ) ); - BOOST_CHECK( ! is_scalar(e5) ); - BOOST_CHECK( ! is_vector(e5) ); - BOOST_CHECK( is_matrix(e5) ); - BOOST_CHECK( ! is_tensor(e5) ); - - BOOST_CHECK( ! e6.empty ( ) ); - BOOST_CHECK( ! is_scalar(e6) ); - BOOST_CHECK( ! is_vector(e6) ); - BOOST_CHECK( ! is_matrix(e6) ); - BOOST_CHECK( is_tensor(e6) ); - - BOOST_CHECK( ! e7.empty ( ) ); - BOOST_CHECK( ! is_scalar(e7) ); - BOOST_CHECK( ! is_vector(e7) ); - BOOST_CHECK( ! is_matrix(e7) ); - BOOST_CHECK( is_tensor(e7) ); - - BOOST_CHECK( ! e8.empty ( ) ); - BOOST_CHECK( ! is_scalar(e8) ); - BOOST_CHECK( ! is_vector(e8) ); - BOOST_CHECK( ! is_matrix(e8) ); - BOOST_CHECK( is_tensor(e8) ); - - BOOST_CHECK( ! e9.empty ( ) ); - BOOST_CHECK( ! is_scalar(e9) ); - BOOST_CHECK( ! is_vector(e9) ); - BOOST_CHECK( ! is_matrix(e9) ); - BOOST_CHECK( is_tensor(e9) ); - - BOOST_CHECK( ! e10.empty( ) ); - BOOST_CHECK( ! is_scalar(e10) ); - BOOST_CHECK( ! is_vector(e10) ); - BOOST_CHECK( ! is_matrix(e10) ); - BOOST_CHECK( is_tensor(e10) ); - - BOOST_CHECK( ! e11.empty( ) ); - BOOST_CHECK( ! is_scalar(e11) ); - BOOST_CHECK( ! is_vector(e11) ); - BOOST_CHECK( ! is_matrix(e11) ); - BOOST_CHECK( is_tensor(e11) ); - - BOOST_CHECK( ! e12.empty( ) ); - BOOST_CHECK( ! is_scalar(e12) ); - BOOST_CHECK( ! is_vector(e12) ); - BOOST_CHECK( ! is_matrix(e12) ); - BOOST_CHECK( is_tensor(e12) ); - - BOOST_CHECK( ! e13.empty( ) ); - BOOST_CHECK( ! is_scalar(e13) ); - BOOST_CHECK( is_vector(e13) ); - BOOST_CHECK( ! is_matrix(e13) ); - BOOST_CHECK( ! is_tensor(e13) ); - - BOOST_CHECK( ! e14.empty( ) ); - BOOST_CHECK( is_scalar(e14) ); - BOOST_CHECK( ! is_vector(e14) ); - BOOST_CHECK( ! is_matrix(e14) ); - BOOST_CHECK( ! is_tensor(e14) ); - - BOOST_CHECK( ! e15.empty( ) ); - BOOST_CHECK( ! is_scalar(e15) ); - BOOST_CHECK( is_vector(e15) ); - BOOST_CHECK( ! is_matrix(e15) ); - BOOST_CHECK( ! is_tensor(e15) ); - - BOOST_CHECK( ! e16.empty( ) ); - BOOST_CHECK( ! is_scalar(e16) ); - BOOST_CHECK( ! is_vector(e16) ); - BOOST_CHECK( ! is_matrix(e16) ); - BOOST_CHECK( is_tensor(e16) ); - - BOOST_CHECK( ! e17.empty( ) ); - BOOST_CHECK( ! is_scalar(e17) ); - BOOST_CHECK( ! is_vector(e17) ); - BOOST_CHECK( ! is_matrix(e17) ); - BOOST_CHECK( is_tensor(e17) ); -} - -BOOST_FIXTURE_TEST_CASE(test_extents_squeeze, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("squeeze")) -{ - BOOST_REQUIRE_EQUAL(extents.size(),18); - - auto e0 = squeeze(extents[ 0]); // {} - auto e1 = squeeze(extents[ 1]); // {1,1} - auto e2 = squeeze(extents[ 2]); // {1,2} - auto e3 = squeeze(extents[ 3]); // {2,1} - - auto e4 = squeeze(extents[ 4]); // {2,3} - auto e5 = squeeze(extents[ 5]); // {2,3} - auto e6 = squeeze(extents[ 6]); // {2,3} - auto e7 = squeeze(extents[ 7]); // {2,3} - auto e8 = squeeze(extents[ 8]); // {2,3} - - auto e9 = squeeze(extents[ 9]); // {4,2,3} - auto e10 = squeeze(extents[10]); // {4,2,3} - auto e11 = squeeze(extents[11]); // {4,2,3} - auto e12 = squeeze(extents[12]); // {4,2,3} - - auto e13 = squeeze(extents[13]); // {1,4} - auto e14 = squeeze(extents[14]); // {1,1} - auto e15 = squeeze(extents[15]); // {1,4} - auto e16 = squeeze(extents[16]); // {2,1} - auto e17 = squeeze(extents[17]); // {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_CHECK( (e13 == extents_type{1,4}) ); - BOOST_CHECK( (e14 == extents_type{1,1}) ); - BOOST_CHECK( (e15 == extents_type{1,4}) ); - BOOST_CHECK( (e16 == extents_type{2,1}) ); - BOOST_CHECK( (e17 == extents_type{2,3}) ); - -} - -BOOST_FIXTURE_TEST_CASE(test_extents_comparison, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("compare")) -{ - - using namespace boost::numeric; - - auto s0 = ublas::static_extents<>{}; - auto s1 = ublas::static_extents<1,1>{}; - auto s2 = ublas::static_extents<1,4,2,1,3,1>{}; - auto s3 = ublas::static_extents<1,4,2,1,1,1>{}; - - auto d0 = ublas::extents<0>{}; - auto d1 = ublas::extents<2>{1,1}; - auto d2 = ublas::extents<6>{1,4,2,1,3,1}; - auto d3 = ublas::extents<6>{1,4,2,1,1,1}; - - auto e0 = extents[ 0]; // {} - auto e1 = extents[ 1]; // {1,1} - auto e2 = extents[12]; // {1,4,2,1,3,1} - - // static_extents<...> == extents<> - BOOST_TEST( s0 == e0 ); - BOOST_TEST( s1 == e1 ); - BOOST_TEST( s2 == e2 ); - - BOOST_TEST( e0 == s0 ); - BOOST_TEST( e1 == s1 ); - BOOST_TEST( e2 == s2 ); - - BOOST_TEST( s0 != e1 ); - BOOST_TEST( s0 != e2 ); - BOOST_TEST( s1 != e0 ); - BOOST_TEST( s1 != e2 ); - BOOST_TEST( s2 != e0 ); - BOOST_TEST( s2 != e1 ); - BOOST_TEST( s3 != e0 ); - BOOST_TEST( s3 != e1 ); - BOOST_TEST( s3 != e2 ); - - BOOST_TEST( e1 != s0 ); - BOOST_TEST( e2 != s0 ); - BOOST_TEST( e0 != s1 ); - BOOST_TEST( e2 != s1 ); - BOOST_TEST( e0 != s2 ); - BOOST_TEST( e1 != s2 ); - BOOST_TEST( e0 != s3 ); - BOOST_TEST( e1 != s3 ); - BOOST_TEST( e2 != s3 ); - - // extents == extents<> - BOOST_TEST( d0 == e0 ); - BOOST_TEST( d1 == e1 ); - BOOST_TEST( d2 == e2 ); - - BOOST_TEST( e0 == d0 ); - BOOST_TEST( e1 == d1 ); - BOOST_TEST( e2 == d2 ); - - BOOST_TEST( d0 != e1 ); - BOOST_TEST( d0 != e2 ); - BOOST_TEST( d1 != e0 ); - BOOST_TEST( d1 != e2 ); - BOOST_TEST( d2 != e0 ); - BOOST_TEST( d2 != e1 ); - BOOST_TEST( d3 != e0 ); - BOOST_TEST( d3 != e1 ); - BOOST_TEST( d3 != e2 ); - - BOOST_TEST( e1 != d0 ); - BOOST_TEST( e2 != d0 ); - BOOST_TEST( e0 != d1 ); - BOOST_TEST( e2 != d1 ); - BOOST_TEST( e0 != d2 ); - BOOST_TEST( e1 != d2 ); - BOOST_TEST( e0 != d3 ); - BOOST_TEST( e1 != d3 ); - BOOST_TEST( e2 != d3 ); - - // static_extents<...> == extents - - BOOST_TEST( s0 == d0 ); - BOOST_TEST( s1 == d1 ); - BOOST_TEST( s2 == d2 ); - BOOST_TEST( s3 == d3 ); - - BOOST_TEST( d0 == s0 ); - BOOST_TEST( d1 == s1 ); - BOOST_TEST( d2 == s2 ); - BOOST_TEST( d3 == s3 ); - - BOOST_TEST( s0 != d1 ); - BOOST_TEST( s0 != d2 ); - BOOST_TEST( s0 != d3 ); - BOOST_TEST( s1 != d0 ); - BOOST_TEST( s1 != d2 ); - BOOST_TEST( s1 != d3 ); - BOOST_TEST( s2 != d0 ); - BOOST_TEST( s2 != d1 ); - BOOST_TEST( s2 != d3 ); - BOOST_TEST( s3 != d0 ); - BOOST_TEST( s3 != d1 ); - BOOST_TEST( s3 != d2 ); - - BOOST_TEST( d1 != s0 ); - BOOST_TEST( d2 != s0 ); - BOOST_TEST( d3 != s0 ); - BOOST_TEST( d0 != s1 ); - BOOST_TEST( d2 != s1 ); - BOOST_TEST( d3 != s1 ); - BOOST_TEST( d0 != s2 ); - BOOST_TEST( d1 != s2 ); - BOOST_TEST( d3 != s2 ); - BOOST_TEST( d0 != s3 ); - BOOST_TEST( d1 != s3 ); - BOOST_TEST( d2 != s3 ); - -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_product, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("product")) -{ - - auto e0 = product(extents[ 0]); // {} - auto e1 = product(extents[ 1]); // {1,1} - auto e2 = product(extents[ 2]); // {1,2} - auto e3 = product(extents[ 3]); // {2,1} - auto e4 = product(extents[ 4]); // {2,3} - auto e5 = product(extents[ 5]); // {2,3,1} - auto e6 = product(extents[ 6]); // {1,2,3} - auto e7 = product(extents[ 7]); // {1,1,2,3} - auto e8 = product(extents[ 8]); // {1,2,3,1,1} - auto e9 = product(extents[ 9]); // {4,2,3} - auto e10 = product(extents[10]); // {4,2,1,3} - auto e11 = product(extents[11]); // {4,2,1,3,1} - auto e12 = product(extents[12]); // {1,4,2,1,3,1} - auto e13 = product(extents[13]); // {1,4,1} - auto e14 = product(extents[14]); // {1,1,1,1} - auto e15 = product(extents[15]); // {1,4,1,1,1} - auto e16 = product(extents[16]); // {1,1,2,1,1,1} - auto e17 = product(extents[17]); // {1,1,2,3,1,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_CHECK_EQUAL( e13, 4 ); - BOOST_CHECK_EQUAL( e14, 1 ); - BOOST_CHECK_EQUAL( e15, 4 ); - BOOST_CHECK_EQUAL( e16, 2 ); - BOOST_CHECK_EQUAL( e17, 6 ); - - -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_extents_dynamic.cpp b/test/tensor/test_extents_dynamic.cpp new file mode 100644 index 000000000..fe4761b88 --- /dev/null +++ b/test/tensor/test_extents_dynamic.cpp @@ -0,0 +1,190 @@ +// +// Copyright (c) 2018 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include + +BOOST_AUTO_TEST_SUITE ( test_extents_dynamic ) + + +struct fixture +{ + using extents = boost::numeric::ublas::extents<>; + +// static inline auto n = extents{}; + static inline auto n1 = extents{1}; + static inline auto n2 = extents{2}; + static inline auto n11 = extents{1,1}; + static inline auto n12 = extents{1,2}; + static inline auto n21 = extents{2,1}; + static inline auto n22 = extents{2,2}; + static inline auto n32 = extents{3,2}; + static inline auto n111 = extents{1,1,1}; + static inline auto n211 = extents{2,1,1}; + static inline auto n121 = extents{1,2,1}; + static inline auto n112 = extents{1,1,2}; + static inline auto n123 = extents{1,2,3}; + static inline auto n321 = extents{3,2,1}; + static inline auto n213 = extents{2,1,3}; + static inline auto n432 = extents{4,3,2}; +}; + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_empty, + fixture, + *boost::unit_test::label("dynamic_extents") *boost::unit_test::label("empty")) +{ + namespace ublas = boost::numeric::ublas; + +// BOOST_CHECK( ublas::empty(n )); + BOOST_CHECK(!ublas::empty(n1 )); + BOOST_CHECK(!ublas::empty(n2 )); + BOOST_CHECK(!ublas::empty(n11 )); + BOOST_CHECK(!ublas::empty(n12 )); + BOOST_CHECK(!ublas::empty(n21 )); + BOOST_CHECK(!ublas::empty(n22 )); + BOOST_CHECK(!ublas::empty(n32 )); + BOOST_CHECK(!ublas::empty(n111)); + BOOST_CHECK(!ublas::empty(n211)); + BOOST_CHECK(!ublas::empty(n121)); + BOOST_CHECK(!ublas::empty(n112)); + BOOST_CHECK(!ublas::empty(n123)); + BOOST_CHECK(!ublas::empty(n321)); + BOOST_CHECK(!ublas::empty(n213)); + BOOST_CHECK(!ublas::empty(n432)); + + BOOST_CHECK_THROW( extents({1,1,0}), std::invalid_argument); + BOOST_CHECK_THROW( extents({1,0}) , std::invalid_argument); + BOOST_CHECK_THROW( extents({0} ) , std::invalid_argument); + BOOST_CHECK_THROW( extents({0,1}) , std::invalid_argument); +} + + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_size, + fixture, + *boost::unit_test::label("dynamic_extents") *boost::unit_test::label("size")) +{ + namespace ublas = boost::numeric::ublas; + + +// BOOST_CHECK_EQUAL(ublas::size(n ),0); + BOOST_CHECK_EQUAL(ublas::size(n1 ),1); + BOOST_CHECK_EQUAL(ublas::size(n2 ),1); + BOOST_CHECK_EQUAL(ublas::size(n11 ),2); + BOOST_CHECK_EQUAL(ublas::size(n12 ),2); + BOOST_CHECK_EQUAL(ublas::size(n21 ),2); + BOOST_CHECK_EQUAL(ublas::size(n22 ),2); + BOOST_CHECK_EQUAL(ublas::size(n32 ),2); + BOOST_CHECK_EQUAL(ublas::size(n111),3); + BOOST_CHECK_EQUAL(ublas::size(n211),3); + BOOST_CHECK_EQUAL(ublas::size(n121),3); + BOOST_CHECK_EQUAL(ublas::size(n112),3); + BOOST_CHECK_EQUAL(ublas::size(n123),3); + BOOST_CHECK_EQUAL(ublas::size(n321),3); + BOOST_CHECK_EQUAL(ublas::size(n213),3); + BOOST_CHECK_EQUAL(ublas::size(n432),3); +} + + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_at_read, + fixture, + *boost::unit_test::label("dynamic_extents") *boost::unit_test::label("at_read")) +{ + BOOST_CHECK_EQUAL(n1 .at(0),1); + BOOST_CHECK_EQUAL(n2 .at(0),2); + + BOOST_CHECK_EQUAL(n11 .at(0),1); + BOOST_CHECK_EQUAL(n11 .at(1),1); + + BOOST_CHECK_EQUAL(n12 .at(0),1); + BOOST_CHECK_EQUAL(n12 .at(1),2); + + BOOST_CHECK_EQUAL(n21 .at(0),2); + BOOST_CHECK_EQUAL(n21 .at(1),1); + + BOOST_CHECK_EQUAL(n22 .at(0),2); + BOOST_CHECK_EQUAL(n22 .at(1),2); + + BOOST_CHECK_EQUAL(n32 .at(0),3); + BOOST_CHECK_EQUAL(n32 .at(1),2); + + BOOST_CHECK_EQUAL(n432.at(0),4); + BOOST_CHECK_EQUAL(n432.at(1),3); + BOOST_CHECK_EQUAL(n432.at(2),2); + + +// BOOST_CHECK_THROW( (void)n .at(0), std::out_of_range); + BOOST_CHECK_THROW( (void)n32.at(2), std::out_of_range); + BOOST_CHECK_THROW( (void)n32.at(5), std::out_of_range); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_at_write, + fixture, + *boost::unit_test::label("dynamic_extents") *boost::unit_test::label("at_write")) +{ + auto n3 = extents{1}; + n3 = extents{3}; + BOOST_CHECK_EQUAL(n3.at(0),3); + + auto n34 = extents{1,1}; + n34 = extents{3,4}; + BOOST_CHECK_EQUAL(n34.at(0),3); + BOOST_CHECK_EQUAL(n34.at(1),4); + + + auto n345 = extents{1,1,1}; + n345 = extents{3,4,5}; + BOOST_CHECK_EQUAL(n345.at(0),3); + BOOST_CHECK_EQUAL(n345.at(1),4); + BOOST_CHECK_EQUAL(n345.at(2),5); + + + auto n5432 = extents{1,1,1,1}; + n5432 = extents{5,4,3,2}; + BOOST_CHECK_EQUAL(n5432.at(0),5); + BOOST_CHECK_EQUAL(n5432.at(1),4); + BOOST_CHECK_EQUAL(n5432.at(2),3); + BOOST_CHECK_EQUAL(n5432.at(3),2); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_operator_access_read, + fixture, + *boost::unit_test::label("dynamic_extents") *boost::unit_test::label("operator_access_read")) +{ + BOOST_CHECK_EQUAL(n1 [0],1); + BOOST_CHECK_EQUAL(n2 [0],2); + + BOOST_CHECK_EQUAL(n11 [0],1); + BOOST_CHECK_EQUAL(n11 [1],1); + + BOOST_CHECK_EQUAL(n12 [0],1); + BOOST_CHECK_EQUAL(n12 [1],2); + + BOOST_CHECK_EQUAL(n21 [0],2); + BOOST_CHECK_EQUAL(n21 [1],1); + + BOOST_CHECK_EQUAL(n22 [0],2); + BOOST_CHECK_EQUAL(n22 [1],2); + + BOOST_CHECK_EQUAL(n32 [0],3); + BOOST_CHECK_EQUAL(n32 [1],2); + + BOOST_CHECK_EQUAL(n432[0],4); + BOOST_CHECK_EQUAL(n432[1],3); + BOOST_CHECK_EQUAL(n432[2],2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_extents_dynamic_rank_static.cpp b/test/tensor/test_extents_dynamic_rank_static.cpp new file mode 100644 index 000000000..c7d4a6a9d --- /dev/null +++ b/test/tensor/test_extents_dynamic_rank_static.cpp @@ -0,0 +1,155 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// +// 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 +#include + +BOOST_AUTO_TEST_SUITE ( test_shape_dynamic_static_rank ) + + +struct fixture +{ + template + using shape_t = boost::numeric::ublas::extents; + +// static inline auto n = shape_t<0>{}; + static inline auto n1 = shape_t<1>{1}; + static inline auto n2 = shape_t<1>{2}; + static inline auto n11 = shape_t<2>{1,1}; + static inline auto n12 = shape_t<2>{1,2}; + static inline auto n21 = shape_t<2>{2,1}; + static inline auto n22 = shape_t<2>{2,2}; + static inline auto n32 = shape_t<2>{3,2}; + static inline auto n111 = shape_t<3>{1,1,1}; + static inline auto n211 = shape_t<3>{2,1,1}; + static inline auto n121 = shape_t<3>{1,2,1}; + static inline auto n112 = shape_t<3>{1,1,2}; + static inline auto n123 = shape_t<3>{1,2,3}; + static inline auto n321 = shape_t<3>{3,2,1}; + static inline auto n213 = shape_t<3>{2,1,3}; + static inline auto n432 = shape_t<3>{4,3,2}; +}; + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_static_empty, + fixture, + *boost::unit_test::label("dynamic_extents_rank_static") *boost::unit_test::label("empty")) +{ + namespace ublas = boost::numeric::ublas; +// BOOST_CHECK( ublas::empty(n )); + BOOST_CHECK(!ublas::empty(n1 )); + BOOST_CHECK(!ublas::empty(n2 )); + BOOST_CHECK(!ublas::empty(n11 )); + BOOST_CHECK(!ublas::empty(n12 )); + BOOST_CHECK(!ublas::empty(n21 )); + BOOST_CHECK(!ublas::empty(n22 )); + BOOST_CHECK(!ublas::empty(n32 )); + BOOST_CHECK(!ublas::empty(n111)); + BOOST_CHECK(!ublas::empty(n211)); + BOOST_CHECK(!ublas::empty(n121)); + BOOST_CHECK(!ublas::empty(n112)); + BOOST_CHECK(!ublas::empty(n123)); + BOOST_CHECK(!ublas::empty(n321)); + BOOST_CHECK(!ublas::empty(n213)); + BOOST_CHECK(!ublas::empty(n432)); + + BOOST_CHECK_THROW( shape_t<3>({1,1,0}), std::invalid_argument); + BOOST_CHECK_THROW( shape_t<2>({1,0}), std::invalid_argument); + BOOST_CHECK_THROW( shape_t<1>({0} ), std::invalid_argument); + BOOST_CHECK_THROW( shape_t<2>({0,1}), std::invalid_argument); +} + + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_static_size, + fixture, + *boost::unit_test::label("dynamic_extents_rank_static") *boost::unit_test::label("size")) +{ + namespace ublas = boost::numeric::ublas; + +// BOOST_CHECK_EQUAL(ublas::size(n ),0); + BOOST_CHECK_EQUAL(ublas::size(n1 ),1); + BOOST_CHECK_EQUAL(ublas::size(n2 ),1); + BOOST_CHECK_EQUAL(ublas::size(n11 ),2); + BOOST_CHECK_EQUAL(ublas::size(n12 ),2); + BOOST_CHECK_EQUAL(ublas::size(n21 ),2); + BOOST_CHECK_EQUAL(ublas::size(n22 ),2); + BOOST_CHECK_EQUAL(ublas::size(n32 ),2); + BOOST_CHECK_EQUAL(ublas::size(n111),3); + BOOST_CHECK_EQUAL(ublas::size(n211),3); + BOOST_CHECK_EQUAL(ublas::size(n121),3); + BOOST_CHECK_EQUAL(ublas::size(n112),3); + BOOST_CHECK_EQUAL(ublas::size(n123),3); + BOOST_CHECK_EQUAL(ublas::size(n321),3); + BOOST_CHECK_EQUAL(ublas::size(n213),3); + BOOST_CHECK_EQUAL(ublas::size(n432),3); +} + + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_static_at_read, + fixture, + *boost::unit_test::label("dynamic_extents_rank_static") *boost::unit_test::label("at_read")) +{ + BOOST_CHECK_EQUAL(n1 .at(0),1); + BOOST_CHECK_EQUAL(n2 .at(0),2); + + BOOST_CHECK_EQUAL(n11 .at(0),1); + BOOST_CHECK_EQUAL(n11 .at(1),1); + + BOOST_CHECK_EQUAL(n12 .at(0),1); + BOOST_CHECK_EQUAL(n12 .at(1),2); + + BOOST_CHECK_EQUAL(n21 .at(0),2); + BOOST_CHECK_EQUAL(n21 .at(1),1); + + BOOST_CHECK_EQUAL(n22 .at(0),2); + BOOST_CHECK_EQUAL(n22 .at(1),2); + + BOOST_CHECK_EQUAL(n32 .at(0),3); + BOOST_CHECK_EQUAL(n32 .at(1),2); + + BOOST_CHECK_EQUAL(n432.at(0),4); + BOOST_CHECK_EQUAL(n432.at(1),3); + BOOST_CHECK_EQUAL(n432.at(2),2); + + +// BOOST_CHECK_THROW( (void)n .at(0), std::out_of_range); + BOOST_CHECK_THROW( (void)n32.at(2), std::out_of_range); + BOOST_CHECK_THROW( (void)n32.at(5), std::out_of_range); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_static_operator_access_read, + fixture, + *boost::unit_test::label("dynamic_extents_rank_static") *boost::unit_test::label("operator_access_read")) +{ + BOOST_CHECK_EQUAL(n1 [0],1); + BOOST_CHECK_EQUAL(n2 [0],2); + + BOOST_CHECK_EQUAL(n11 [0],1); + BOOST_CHECK_EQUAL(n11 [1],1); + + BOOST_CHECK_EQUAL(n12 [0],1); + BOOST_CHECK_EQUAL(n12 [1],2); + + BOOST_CHECK_EQUAL(n21 [0],2); + BOOST_CHECK_EQUAL(n21 [1],1); + + BOOST_CHECK_EQUAL(n22 [0],2); + BOOST_CHECK_EQUAL(n22 [1],2); + + BOOST_CHECK_EQUAL(n32 [0],3); + BOOST_CHECK_EQUAL(n32 [1],2); + + BOOST_CHECK_EQUAL(n432[0],4); + BOOST_CHECK_EQUAL(n432[1],3); + BOOST_CHECK_EQUAL(n432[2],2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_extents_functions.cpp b/test/tensor/test_extents_functions.cpp new file mode 100644 index 000000000..868afd26e --- /dev/null +++ b/test/tensor/test_extents_functions.cpp @@ -0,0 +1,634 @@ +// +// Copyright (c) 2020, Cem Bassoy, cem.bassoy@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#include +#include + +#include +#include + + + +BOOST_AUTO_TEST_SUITE(test_shape_functions) + +struct fixture_extents_dynamic_rank +{ + using shape_t = boost::numeric::ublas::extents<>; + + static inline auto n = shape_t{}; + static inline auto n1 = shape_t{1}; + static inline auto n2 = shape_t{2}; + static inline auto n11 = shape_t{1,1}; + static inline auto n12 = shape_t{1,2}; + static inline auto n21 = shape_t{2,1}; + static inline auto n22 = shape_t{2,2}; + static inline auto n32 = shape_t{3,2}; + static inline auto n111 = shape_t{1,1,1}; + static inline auto n211 = shape_t{2,1,1}; + static inline auto n121 = shape_t{1,2,1}; + static inline auto n112 = shape_t{1,1,2}; + static inline auto n123 = shape_t{1,2,3}; + static inline auto n321 = shape_t{3,2,1}; + static inline auto n213 = shape_t{2,1,3}; + static inline auto n432 = shape_t{4,3,2}; +}; + +struct fixture_extents_static_rank +{ + template + using extents_static_rank = boost::numeric::ublas::extents; + + static constexpr inline auto n = extents_static_rank<0>{}; + static constexpr inline auto n1 = extents_static_rank<1>{1}; + static constexpr inline auto n2 = extents_static_rank<1>{2}; + static constexpr inline auto n11 = extents_static_rank<2>{{1,1}}; + static constexpr inline auto n12 = extents_static_rank<2>{{1,2}}; + static constexpr inline auto n21 = extents_static_rank<2>{{2,1}}; + static constexpr inline auto n22 = extents_static_rank<2>{{2,2}}; + static constexpr inline auto n32 = extents_static_rank<2>{{3,2}}; + static constexpr inline auto n111 = extents_static_rank<3>{{1,1,1}}; + static constexpr inline auto n211 = extents_static_rank<3>{{2,1,1}}; + static constexpr inline auto n121 = extents_static_rank<3>{{1,2,1}}; + static constexpr inline auto n112 = extents_static_rank<3>{{1,1,2}}; + static constexpr inline auto n123 = extents_static_rank<3>{{1,2,3}}; + static constexpr inline auto n321 = extents_static_rank<3>{{3,2,1}}; + static constexpr inline auto n213 = extents_static_rank<3>{{2,1,3}}; + static constexpr inline auto n432 = extents_static_rank<3>{{4,3,2}}; + + static constexpr inline auto tuple = std::make_tuple( n,n1,n2,n11,n12,n21,n22,n32,n111,n211,n121,n112,n123,n321,n213,n432 ); + +}; + + + +struct fixture_extents_static +{ + template + using extents_static = boost::numeric::ublas::extents; + + static inline auto n = extents_static<> {}; + static inline auto n1 = extents_static<1> {}; + static inline auto n2 = extents_static<2> {}; + static inline auto n11 = extents_static<1,1> {}; + static inline auto n12 = extents_static<1,2> {}; + static inline auto n21 = extents_static<2,1> {}; + static inline auto n22 = extents_static<2,2> {}; + static inline auto n32 = extents_static<3,2> {}; + static inline auto n111 = extents_static<1,1,1> {}; + static inline auto n211 = extents_static<2,1,1> {}; + static inline auto n121 = extents_static<1,2,1> {}; + static inline auto n112 = extents_static<1,1,2> {}; + static inline auto n123 = extents_static<1,2,3> {}; + static inline auto n321 = extents_static<3,2,1> {}; + static inline auto n213 = extents_static<2,1,3> {}; + static inline auto n432 = extents_static<4,3,2> {}; + + + +}; + + + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_is_scalar, + fixture_extents_dynamic_rank, + *boost::unit_test::label("extents_dynamic_rank") + *boost::unit_test::label("is_scalar")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_scalar( n )); + BOOST_CHECK ( ub::is_scalar( n1 )); + BOOST_CHECK ( !ub::is_scalar( n2 )); + BOOST_CHECK ( ub::is_scalar( n11 )); + BOOST_CHECK ( !ub::is_scalar( n12 )); + BOOST_CHECK ( !ub::is_scalar( n21 )); + BOOST_CHECK ( !ub::is_scalar( n22 )); + BOOST_CHECK ( !ub::is_scalar( n32 )); + BOOST_CHECK ( ub::is_scalar( n111 )); + BOOST_CHECK ( !ub::is_scalar( n211 )); + BOOST_CHECK ( !ub::is_scalar( n121 )); + BOOST_CHECK ( !ub::is_scalar( n112 )); + BOOST_CHECK ( !ub::is_scalar( n123 )); + BOOST_CHECK ( !ub::is_scalar( n321 )); + BOOST_CHECK ( !ub::is_scalar( n213 )); + BOOST_CHECK ( !ub::is_scalar( n432 )); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_is_scalar, + fixture_extents_static_rank, + *boost::unit_test::label("extents_static_rank") + *boost::unit_test::label("is_scalar")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_scalar( n )); + BOOST_CHECK ( ub::is_scalar( n1 )); + BOOST_CHECK ( !ub::is_scalar( n2 )); + BOOST_CHECK ( ub::is_scalar( n11 )); + BOOST_CHECK ( !ub::is_scalar( n12 )); + BOOST_CHECK ( !ub::is_scalar( n21 )); + BOOST_CHECK ( !ub::is_scalar( n22 )); + BOOST_CHECK ( !ub::is_scalar( n32 )); + BOOST_CHECK ( ub::is_scalar( n111 )); + BOOST_CHECK ( !ub::is_scalar( n211 )); + BOOST_CHECK ( !ub::is_scalar( n121 )); + BOOST_CHECK ( !ub::is_scalar( n112 )); + BOOST_CHECK ( !ub::is_scalar( n123 )); + BOOST_CHECK ( !ub::is_scalar( n321 )); + BOOST_CHECK ( !ub::is_scalar( n213 )); + BOOST_CHECK ( !ub::is_scalar( n432 )); + +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_is_scalar, + fixture_extents_static, + *boost::unit_test::label("extents_static") + *boost::unit_test::label("is_scalar")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_scalar( n )); +//FIXME: BOOST_CHECK ( ub::is_scalar( n1 )); + BOOST_CHECK ( !ub::is_scalar( n2 )); + BOOST_CHECK ( ub::is_scalar( n11 )); + BOOST_CHECK ( !ub::is_scalar( n12 )); + BOOST_CHECK ( !ub::is_scalar( n21 )); + BOOST_CHECK ( !ub::is_scalar( n22 )); + BOOST_CHECK ( !ub::is_scalar( n32 )); + BOOST_CHECK ( ub::is_scalar( n111 )); + BOOST_CHECK ( !ub::is_scalar( n211 )); + BOOST_CHECK ( !ub::is_scalar( n121 )); + BOOST_CHECK ( !ub::is_scalar( n112 )); + BOOST_CHECK ( !ub::is_scalar( n123 )); + BOOST_CHECK ( !ub::is_scalar( n321 )); + BOOST_CHECK ( !ub::is_scalar( n213 )); + BOOST_CHECK ( !ub::is_scalar( n432 )); + +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_is_vector, + fixture_extents_dynamic_rank, + *boost::unit_test::label("extents_dynamic_rank") + *boost::unit_test::label("is_vector")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_vector( n )); + BOOST_CHECK ( ub::is_vector( n1 )); + BOOST_CHECK ( ub::is_vector( n2 )); + BOOST_CHECK ( ub::is_vector( n11 )); + BOOST_CHECK ( ub::is_vector( n12 )); + BOOST_CHECK ( ub::is_vector( n21 )); + BOOST_CHECK ( !ub::is_vector( n22 )); + BOOST_CHECK ( !ub::is_vector( n32 )); + BOOST_CHECK ( ub::is_vector( n111 )); + BOOST_CHECK ( ub::is_vector( n211 )); + BOOST_CHECK ( ub::is_vector( n121 )); + BOOST_CHECK ( !ub::is_vector( n112 )); + BOOST_CHECK ( !ub::is_vector( n123 )); + BOOST_CHECK ( !ub::is_vector( n321 )); + BOOST_CHECK ( !ub::is_vector( n213 )); + BOOST_CHECK ( !ub::is_vector( n432 )); +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_is_vector, + fixture_extents_static_rank, + *boost::unit_test::label("extents_static_rank") + *boost::unit_test::label("is_vector")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_vector( n )); + BOOST_CHECK ( ub::is_vector( n1 )); + BOOST_CHECK ( ub::is_vector( n2 )); + BOOST_CHECK ( ub::is_vector( n11 )); + BOOST_CHECK ( ub::is_vector( n12 )); + BOOST_CHECK ( ub::is_vector( n21 )); + BOOST_CHECK ( !ub::is_vector( n22 )); + BOOST_CHECK ( !ub::is_vector( n32 )); + BOOST_CHECK ( ub::is_vector( n111 )); + BOOST_CHECK ( ub::is_vector( n211 )); + BOOST_CHECK ( ub::is_vector( n121 )); + BOOST_CHECK ( !ub::is_vector( n112 )); + BOOST_CHECK ( !ub::is_vector( n123 )); + BOOST_CHECK ( !ub::is_vector( n321 )); + BOOST_CHECK ( !ub::is_vector( n213 )); + BOOST_CHECK ( !ub::is_vector( n432 )); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_is_vector, + fixture_extents_static, + *boost::unit_test::label("extents_static") + *boost::unit_test::label("is_vector")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_vector( n1 )); +//FIXME: BOOST_CHECK ( ub::is_vector( n2 )); + BOOST_CHECK ( ub::is_vector( n11 )); + BOOST_CHECK ( ub::is_vector( n12 )); + BOOST_CHECK ( ub::is_vector( n21 )); + BOOST_CHECK ( !ub::is_vector( n22 )); + BOOST_CHECK ( !ub::is_vector( n32 )); + BOOST_CHECK ( ub::is_vector( n111 )); + BOOST_CHECK ( ub::is_vector( n211 )); + BOOST_CHECK ( ub::is_vector( n121 )); + BOOST_CHECK ( !ub::is_vector( n112 )); + BOOST_CHECK ( !ub::is_vector( n123 )); + BOOST_CHECK ( !ub::is_vector( n321 )); + BOOST_CHECK ( !ub::is_vector( n213 )); + BOOST_CHECK ( !ub::is_vector( n432 )); +} + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_is_matrix, + fixture_extents_dynamic_rank, + *boost::unit_test::label("extents_dynamic_rank") + *boost::unit_test::label("is_matrix")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_matrix( n )); + BOOST_CHECK ( ub::is_matrix( n1 )); + BOOST_CHECK ( ub::is_matrix( n2 )); + BOOST_CHECK ( ub::is_matrix( n11 )); + BOOST_CHECK ( ub::is_matrix( n12 )); + BOOST_CHECK ( ub::is_matrix( n21 )); + BOOST_CHECK ( ub::is_matrix( n22 )); + BOOST_CHECK ( ub::is_matrix( n32 )); + BOOST_CHECK ( ub::is_matrix( n111 )); + BOOST_CHECK ( ub::is_matrix( n211 )); + BOOST_CHECK ( ub::is_matrix( n121 )); + BOOST_CHECK ( !ub::is_matrix( n112 )); + BOOST_CHECK ( !ub::is_matrix( n123 )); + BOOST_CHECK ( ub::is_matrix( n321 )); + BOOST_CHECK ( !ub::is_matrix( n213 )); + BOOST_CHECK ( !ub::is_matrix( n432 )); +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_is_matrix, + fixture_extents_static_rank, + *boost::unit_test::label("extents_static_rank") + *boost::unit_test::label("is_matrix")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_matrix( n )); + BOOST_CHECK ( ub::is_matrix( n1 )); + BOOST_CHECK ( ub::is_matrix( n2 )); + BOOST_CHECK ( ub::is_matrix( n11 )); + BOOST_CHECK ( ub::is_matrix( n12 )); + BOOST_CHECK ( ub::is_matrix( n21 )); + BOOST_CHECK ( ub::is_matrix( n22 )); + BOOST_CHECK ( ub::is_matrix( n32 )); + BOOST_CHECK ( ub::is_matrix( n111 )); + BOOST_CHECK ( ub::is_matrix( n211 )); + BOOST_CHECK ( ub::is_matrix( n121 )); + BOOST_CHECK ( !ub::is_matrix( n112 )); + BOOST_CHECK ( !ub::is_matrix( n123 )); + BOOST_CHECK ( ub::is_matrix( n321 )); + BOOST_CHECK ( !ub::is_matrix( n213 )); + BOOST_CHECK ( !ub::is_matrix( n432 )); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_is_matrix, + fixture_extents_static, + *boost::unit_test::label("extents_static") + *boost::unit_test::label("is_matrix")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_matrix( n )); +//FIXME: BOOST_CHECK ( !ub::is_matrix( n1 )); + BOOST_CHECK ( !ub::is_matrix( n2 )); + BOOST_CHECK ( ub::is_matrix( n11 )); + BOOST_CHECK ( ub::is_matrix( n12 )); + BOOST_CHECK ( ub::is_matrix( n21 )); + BOOST_CHECK ( ub::is_matrix( n22 )); + BOOST_CHECK ( ub::is_matrix( n32 )); + BOOST_CHECK ( ub::is_matrix( n111 )); + BOOST_CHECK ( ub::is_matrix( n211 )); + BOOST_CHECK ( ub::is_matrix( n121 )); + BOOST_CHECK ( !ub::is_matrix( n112 )); + BOOST_CHECK ( !ub::is_matrix( n123 )); + BOOST_CHECK ( ub::is_matrix( n321 )); + BOOST_CHECK ( !ub::is_matrix( n213 )); + BOOST_CHECK ( !ub::is_matrix( n432 )); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_is_tensor, + fixture_extents_dynamic_rank, + *boost::unit_test::label("extents_dynamic_rank") + *boost::unit_test::label("is_tensor")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_tensor( n )); + BOOST_CHECK ( !ub::is_tensor( n1 )); + BOOST_CHECK ( !ub::is_tensor( n2 )); + BOOST_CHECK ( !ub::is_tensor( n11 )); + BOOST_CHECK ( !ub::is_tensor( n12 )); + BOOST_CHECK ( !ub::is_tensor( n21 )); + BOOST_CHECK ( !ub::is_tensor( n22 )); + BOOST_CHECK ( !ub::is_tensor( n32 )); + BOOST_CHECK ( !ub::is_tensor( n111 )); + BOOST_CHECK ( !ub::is_tensor( n211 )); + BOOST_CHECK ( !ub::is_tensor( n121 )); + BOOST_CHECK ( ub::is_tensor( n112 )); + BOOST_CHECK ( ub::is_tensor( n123 )); + BOOST_CHECK ( !ub::is_tensor( n321 )); + BOOST_CHECK ( ub::is_tensor( n213 )); + BOOST_CHECK ( ub::is_tensor( n432 )); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_is_tensor, + fixture_extents_static_rank, + *boost::unit_test::label("extents_static_rank") + *boost::unit_test::label("is_tensor")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_tensor( n )); + BOOST_CHECK ( !ub::is_tensor( n1 )); + BOOST_CHECK ( !ub::is_tensor( n2 )); + BOOST_CHECK ( !ub::is_tensor( n11 )); + BOOST_CHECK ( !ub::is_tensor( n12 )); + BOOST_CHECK ( !ub::is_tensor( n21 )); + BOOST_CHECK ( !ub::is_tensor( n22 )); + BOOST_CHECK ( !ub::is_tensor( n32 )); + BOOST_CHECK ( !ub::is_tensor( n111 )); + BOOST_CHECK ( !ub::is_tensor( n211 )); + BOOST_CHECK ( !ub::is_tensor( n121 )); + BOOST_CHECK ( ub::is_tensor( n112 )); + BOOST_CHECK ( ub::is_tensor( n123 )); + BOOST_CHECK ( !ub::is_tensor( n321 )); + BOOST_CHECK ( ub::is_tensor( n213 )); + BOOST_CHECK ( ub::is_tensor( n432 )); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_is_tensor, + fixture_extents_static, + *boost::unit_test::label("extents_static") + *boost::unit_test::label("is_tensor")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( !ub::is_tensor( n )); +//FIXME: BOOST_CHECK ( !ub::is_tensor( n1 )); + BOOST_CHECK ( !ub::is_tensor( n2 )); + BOOST_CHECK ( !ub::is_tensor( n11 )); + BOOST_CHECK ( !ub::is_tensor( n12 )); + BOOST_CHECK ( !ub::is_tensor( n21 )); + BOOST_CHECK ( !ub::is_tensor( n22 )); + BOOST_CHECK ( !ub::is_tensor( n32 )); + BOOST_CHECK ( !ub::is_tensor( n111 )); + BOOST_CHECK ( !ub::is_tensor( n211 )); + BOOST_CHECK ( !ub::is_tensor( n121 )); + BOOST_CHECK ( ub::is_tensor( n112 )); + BOOST_CHECK ( ub::is_tensor( n123 )); + BOOST_CHECK ( !ub::is_tensor( n321 )); + BOOST_CHECK ( ub::is_tensor( n213 )); + BOOST_CHECK ( ub::is_tensor( n432 )); +} + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_is_valid, + fixture_extents_dynamic_rank, + *boost::unit_test::label("extents_dynamic_rank") + *boost::unit_test::label("is_valid")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( ub::is_valid( n1 )); + BOOST_CHECK ( ub::is_valid( n2 )); + BOOST_CHECK ( ub::is_valid( n11 )); + BOOST_CHECK ( ub::is_valid( n12 )); + BOOST_CHECK ( ub::is_valid( n21 )); + BOOST_CHECK ( ub::is_valid( n22 )); + BOOST_CHECK ( ub::is_valid( n32 )); + BOOST_CHECK ( ub::is_valid( n111 )); + BOOST_CHECK ( ub::is_valid( n211 )); + BOOST_CHECK ( ub::is_valid( n121 )); + BOOST_CHECK ( ub::is_valid( n112 )); + BOOST_CHECK ( ub::is_valid( n123 )); + BOOST_CHECK ( ub::is_valid( n321 )); + BOOST_CHECK ( ub::is_valid( n213 )); + BOOST_CHECK ( ub::is_valid( n432 )); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_is_valid, + fixture_extents_static_rank, + *boost::unit_test::label("extents_static_rank") + *boost::unit_test::label("is_valid")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( ub::is_valid( n )); + BOOST_CHECK ( ub::is_valid( n1 )); + BOOST_CHECK ( ub::is_valid( n2 )); + BOOST_CHECK ( ub::is_valid( n11 )); + BOOST_CHECK ( ub::is_valid( n12 )); + BOOST_CHECK ( ub::is_valid( n21 )); + BOOST_CHECK ( ub::is_valid( n22 )); + BOOST_CHECK ( ub::is_valid( n32 )); + BOOST_CHECK ( ub::is_valid( n111 )); + BOOST_CHECK ( ub::is_valid( n211 )); + BOOST_CHECK ( ub::is_valid( n121 )); + BOOST_CHECK ( ub::is_valid( n112 )); + BOOST_CHECK ( ub::is_valid( n123 )); + BOOST_CHECK ( ub::is_valid( n321 )); + BOOST_CHECK ( ub::is_valid( n213 )); + BOOST_CHECK ( ub::is_valid( n432 )); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_is_valid, + fixture_extents_static, + *boost::unit_test::label("extents_static") + *boost::unit_test::label("is_valid")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK ( ub::is_valid( n )); +//FIXME: BOOST_CHECK ( ub::is_valid( n1 )); +//FIXME: BOOST_CHECK ( ub::is_valid( n2 )); + BOOST_CHECK ( ub::is_valid( n11 )); + BOOST_CHECK ( ub::is_valid( n12 )); + BOOST_CHECK ( ub::is_valid( n21 )); + BOOST_CHECK ( ub::is_valid( n22 )); + BOOST_CHECK ( ub::is_valid( n32 )); + BOOST_CHECK ( ub::is_valid( n111 )); + BOOST_CHECK ( ub::is_valid( n211 )); + BOOST_CHECK ( ub::is_valid( n121 )); + BOOST_CHECK ( ub::is_valid( n112 )); + BOOST_CHECK ( ub::is_valid( n123 )); + BOOST_CHECK ( ub::is_valid( n321 )); + BOOST_CHECK ( ub::is_valid( n213 )); + BOOST_CHECK ( ub::is_valid( n432 )); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_product, + fixture_extents_dynamic_rank, + *boost::unit_test::label("extents_dynamic_rank") + *boost::unit_test::label("product")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK_EQUAL ( ub::product( n ), 0U); + BOOST_CHECK_EQUAL ( ub::product( n1 ), 1U); + BOOST_CHECK_EQUAL ( ub::product( n2 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n11 ), 1U); + BOOST_CHECK_EQUAL ( ub::product( n12 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n21 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n22 ), 4U); + BOOST_CHECK_EQUAL ( ub::product( n32 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n111 ), 1U); + BOOST_CHECK_EQUAL ( ub::product( n211 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n121 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n112 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n123 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n321 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n213 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n432 ),24U); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_product, + fixture_extents_static_rank, + *boost::unit_test::label("extents_static_rank") + *boost::unit_test::label("product")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK_EQUAL ( ub::product( n ), 0U); + BOOST_CHECK_EQUAL ( ub::product( n1 ), 1U); + BOOST_CHECK_EQUAL ( ub::product( n2 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n11 ), 1U); + BOOST_CHECK_EQUAL ( ub::product( n12 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n21 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n22 ), 4U); + BOOST_CHECK_EQUAL ( ub::product( n32 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n111 ), 1U); + BOOST_CHECK_EQUAL ( ub::product( n211 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n121 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n112 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n123 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n321 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n213 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n432 ),24U); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_product, + fixture_extents_static, + *boost::unit_test::label("extents_static") + *boost::unit_test::label("product")) +{ + + namespace ub = boost::numeric::ublas; + BOOST_CHECK_EQUAL ( ub::product( n ), 0U); +//FIXME: BOOST_CHECK_EQUAL ( ub::product( n1 ), 1U); +//FIXME: BOOST_CHECK_EQUAL ( ub::product( n2 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n11 ), 1U); + BOOST_CHECK_EQUAL ( ub::product( n12 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n21 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n22 ), 4U); + BOOST_CHECK_EQUAL ( ub::product( n32 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n111 ), 1U); + BOOST_CHECK_EQUAL ( ub::product( n211 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n121 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n112 ), 2U); + BOOST_CHECK_EQUAL ( ub::product( n123 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n321 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n213 ), 6U); + BOOST_CHECK_EQUAL ( ub::product( n432 ),24U); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_equal, + fixture_extents_dynamic_rank, + *boost::unit_test::label("extents_dynamic_rank") + *boost::unit_test::label("equal")) +{ + BOOST_CHECK ( n == n ); + BOOST_CHECK ( n1 == n1 ); + BOOST_CHECK ( n2 == n2 ); + BOOST_CHECK ( n11 == n11 ); + BOOST_CHECK ( n12 == n12 ); + BOOST_CHECK ( n21 == n21 ); + BOOST_CHECK ( n22 == n22 ); + BOOST_CHECK ( n32 == n32 ); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_equal, + fixture_extents_static_rank, + *boost::unit_test::label("extents_static_rank") + *boost::unit_test::label("equal")) +{ + BOOST_CHECK ( n == n ); + BOOST_CHECK ( n1 == n1 ); + BOOST_CHECK ( n2 == n2 ); + BOOST_CHECK ( n11 == n11 ); + BOOST_CHECK ( n12 == n12 ); + BOOST_CHECK ( n21 == n21 ); + BOOST_CHECK ( n22 == n22 ); + BOOST_CHECK ( n32 == n32 ); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_equal, + fixture_extents_static, + *boost::unit_test::label("extents_static") + *boost::unit_test::label("equal")) +{ + BOOST_CHECK ( n == n ); + BOOST_CHECK ( n1 == n1 ); + BOOST_CHECK ( n2 == n2 ); + BOOST_CHECK ( n11 == n11 ); + BOOST_CHECK ( n12 == n12 ); + BOOST_CHECK ( n21 == n21 ); + BOOST_CHECK ( n22 == n22 ); + BOOST_CHECK ( n32 == n32 ); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_not_equal, + fixture_extents_dynamic_rank, + *boost::unit_test::label("extents_dynamic_rank") + *boost::unit_test::label("not_equal")) +{ + BOOST_CHECK ( ! (n != n ) ); + BOOST_CHECK ( ! (n1 != n1) ); + BOOST_CHECK ( ! (n2 != n2) ); + BOOST_CHECK ( ! (n11 != n11) ); + BOOST_CHECK ( ! (n12 != n12) ); + BOOST_CHECK ( ! (n21 != n21) ); + BOOST_CHECK ( ! (n22 != n22) ); + BOOST_CHECK ( ! (n32 != n32) ); + BOOST_CHECK ( (n2 != n1) ); + BOOST_CHECK ( (n11 != n12) ); + BOOST_CHECK ( (n12 != n21) ); + BOOST_CHECK ( (n21 != n22) ); + BOOST_CHECK ( (n22 != n32) ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_expression_evaluation.cpp b/test/tensor/test_fixed_rank_expression_evaluation.cpp index 97aba6aec..a1e06885b 100644 --- a/test/tensor/test_fixed_rank_expression_evaluation.cpp +++ b/test/tensor/test_fixed_rank_expression_evaluation.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,150 +12,150 @@ -#include -#include "utility.hpp" +#include +#include #include +#include "utility.hpp" + +#include #include +#include -BOOST_AUTO_TEST_SUITE(test_fixed_rank_tensor_expression); +BOOST_AUTO_TEST_SUITE(test_tensor_static_rank_expression) using test_types = zip>::with_t; + + struct fixture { - template - using extents_type = boost::numeric::ublas::extents; - - std::tuple< - extents_type<0>, // 0 - extents_type<2>, // 1 - extents_type<2>, // 2 - extents_type<2>, // 3 - extents_type<2>, // 4 - extents_type<3>, // 5 - extents_type<3>, // 6 - extents_type<3>, // 7 - extents_type<3>, // 8 - extents_type<4> // 9 - > extents = { - extents_type<0>{}, - extents_type<2>{1,1}, - extents_type<2>{1,2}, - extents_type<2>{2,1}, - extents_type<2>{2,3}, - extents_type<3>{2,3,1}, - extents_type<3>{4,1,3}, - extents_type<3>{1,2,3}, - extents_type<3>{4,2,3}, - extents_type<4>{4,2,3,5} - }; + template + using extents_t = boost::numeric::ublas::extents; + + static constexpr auto extents = + std::make_tuple( +// extents_t<0> {}, + extents_t<2> {1,1}, + extents_t<2> {1,2}, + extents_t<2> {2,1}, + extents_t<2> {2,3}, + extents_t<3> {2,3,1}, + extents_t<3> {4,1,3}, + extents_t<3> {1,2,3}, + extents_t<3> {4,2,3}, + extents_t<4>{4,2,3,5} ); }; -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_retrieve_extents, value, test_types, fixture) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_static_rank_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; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + auto uplus1 = [](auto const& a){return a + value_t(1); }; + auto uplus2 = [](auto const& a){return value_t(2) + a; }; + auto bplus = std::plus {}; + auto bminus = std::minus{}; - for_each_tuple(extents, [&](auto const&, auto & e){ - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - + for_each_in_tuple(extents, [&](auto const& /*unused*/, auto const& e){ - 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 ); + static constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - BOOST_CHECK( ublas::detail::retrieve_extents( uexpr1 ) == e ); - BOOST_CHECK( ublas::detail::retrieve_extents( uexpr2 ) == e ); + auto t = tensor_t(e); + auto v = value_t{}; + for(auto& tt: t){ tt = v; v+=value_t{1}; } - // bexpr_uexpr = (t+1) + (2+t) - auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_uexpr ) == e ); + BOOST_CHECK( ublas::detail::retrieve_extents( t ) == e ); + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - // bexpr_bexpr_uexpr = ((t+1) + (2+t)) - t - auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); + BOOST_CHECK( ublas::detail::retrieve_extents( uexpr1 ) == e ); + BOOST_CHECK( ublas::detail::retrieve_extents( uexpr2 ) == e ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t, bminus ); - for_each_tuple(extents, [&](auto I, auto& e1){ + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); - if ( I >= std::tuple_size_v - 1 ){ - return; - } - - using extents_type1 = std::decay_t; - using tensor_type1 = ublas::fixed_rank_tensor; + }); - for_each_tuple(extents, [&](auto J, auto& e2){ + for_each_in_tuple(extents, [&](auto I, auto const& e1){ - if( J != I + 1 ){ - return; - } - using extents_type2 = std::decay_t; - using tensor_type2 = ublas::fixed_rank_tensor; + if ( I >= std::tuple_size_v - 1 ){ + return; + } - auto v = value_type{}; + constexpr auto size1 = std::tuple_size_v>; + using tensor_type1 = ublas::tensor_static_rank; - tensor_type1 t1(e1); - for(auto& tt: t1){ tt = v; v+=value_type{1}; } + for_each_in_tuple(extents, [&,I](auto J, auto const& e2){ - tensor_type2 t2(e2); - for(auto& tt: t2){ tt = v; v+=value_type{2}; } + if( J != I + 1 ){ + return; + } - BOOST_CHECK( ublas::detail::retrieve_extents( t1 ) != ublas::detail::retrieve_extents( t2 ) ); + static constexpr auto size1 = std::tuple_size_v>; + static constexpr auto size2 = std::tuple_size_v>; + using tensor_type2 = ublas::tensor_static_rank; - // uexpr1 = t1+1 - // uexpr2 = 2+t2 - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + auto v = value_t{}; - 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 ) ); + tensor_type1 t1(e1); + for(auto& tt: t1){ tt = v; v+=value_t{1}; } - if constexpr( extents_type1::_size == extents_type2::_size ){ - // bexpr_uexpr = (t1+1) + (2+t2) - auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + tensor_type2 t2(e2); + for(auto& tt: t2){ tt = v; v+=value_t{2}; } - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_uexpr ) == ublas::detail::retrieve_extents(t1) ); + 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( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); - // bexpr_bexpr_uexpr = ((t1+1) + (2+t2)) - t2 - auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t2, bminus ); + 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 ) ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr1 ) == ublas::detail::retrieve_extents(t2) ); + if constexpr( size1 == size2 ){ + // bexpr_uexpr = (t1+1) + (2+t2) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_uexpr ) == ublas::detail::retrieve_extents(t1) ); - // bexpr_bexpr_uexpr = t2 - ((t1+1) + (2+t2)) - auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( t2, bexpr_uexpr, bminus ); - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); - } + // bexpr_bexpr_uexpr = ((t1+1) + (2+t2)) - t2 + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( 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( t2, bexpr_uexpr, bminus ); + + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); + } - }); }); + }); } @@ -164,122 +164,123 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_retrieve_ext -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_expression_all_extents_equal, value, test_types, fixture) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_static_rank_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; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; + auto uplus1 = [](auto const& a){return a + value_t(1); }; + auto uplus2 = [](auto const& a){return value_t(2) + a; }; + auto bplus = std::plus {}; + auto bminus = std::minus{}; - for_each_tuple(extents, [&](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - + for_each_in_tuple(extents, [&](auto const& /*unused*/, auto& e){ + static constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; - auto t = tensor_type(e); - auto v = value_type{}; - for(auto& tt: t){ tt = v; v+=value_type{1}; } + auto t = tensor_t(e); + auto v = value_t{}; + for(auto& tt: t){ tt = v; v+=value_t{1}; } - BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - BOOST_CHECK( ublas::detail::all_extents_equal( uexpr1, e ) ); - BOOST_CHECK( ublas::detail::all_extents_equal( uexpr2, e ) ); + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - // bexpr_uexpr = (t+1) + (2+t) - auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + BOOST_CHECK( ublas::detail::all_extents_equal( uexpr1, e ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( uexpr2, e ) ); - BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_uexpr, e ) ); + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr, t, bminus ); - BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); + // bexpr_bexpr_uexpr = ((t+1) + (2+t)) - t + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t, bminus ); - }); + BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); + + }); + + + for_each_in_tuple(extents, [&](auto I, auto& e1){ + if ( I >= std::tuple_size_v - 1){ + return; + } - for_each_tuple(extents, [&](auto I, auto& e1){ + static constexpr auto size1 = std::tuple_size_v>; + using tensor_type1 = ublas::tensor_static_rank; - if ( I >= std::tuple_size_v - 1){ - return; - } - - using extents_type1 = std::decay_t; - using tensor_type1 = ublas::fixed_rank_tensor; + for_each_in_tuple(extents, [&](auto J, auto& e2){ - for_each_tuple(extents, [&](auto J, auto& e2){ + if( J != I + 1 ){ + return; + } - if( J != I + 1 ){ - return; - } - using extents_type2 = std::decay_t; - using tensor_type2 = ublas::fixed_rank_tensor; + static constexpr auto size2 = std::tuple_size_v>; + using tensor_type2 = ublas::tensor_static_rank; - auto v = value_type{}; + auto v = value_t{}; - tensor_type1 t1(e1); - for(auto& tt: t1){ tt = v; v+=value_type{1}; } + tensor_type1 t1(e1); + for(auto& tt: t1){ tt = v; v+=value_t{1}; } - tensor_type2 t2(e2); - for(auto& tt: t2){ tt = v; v+=value_type{2}; } + tensor_type2 t2(e2); + for(auto& tt: t2){ tt = v; v+=value_t{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) ) ); + 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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + // uexpr1 = t1+1 + // uexpr2 = 2+t2 + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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) ) ); + 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) ) ); - if constexpr( extents_type1::_size == extents_type2::_size ){ - // bexpr_uexpr = (t1+1) + (2+t2) - auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + if constexpr( size1 == size2 ){ + // bexpr_uexpr = (t1+1) + (2+t2) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_uexpr, ublas::detail::retrieve_extents( bexpr_uexpr ) ) ); + 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( bexpr_uexpr, t2, bminus ); + // bexpr_bexpr_uexpr = ((t1+1) + (2+t2)) - t2 + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression( bexpr_uexpr, t2, bminus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr1, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr1 ) ) ); + 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( t2, bexpr_uexpr, bminus ); + // bexpr_bexpr_uexpr = t2 - ((t1+1) + (2+t2)) + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( t2, bexpr_uexpr, bminus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr2, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) ) ); + 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( uexpr1, t2, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_uexpr2, ublas::detail::retrieve_extents( bexpr_uexpr2 ) ) ); + // bexpr_uexpr2 = (t1+1) + t2 + auto bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression( 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( bexpr_uexpr2, t1, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr3, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr3 ) ) ); + // bexpr_uexpr2 = ((t1+1) + t2) + t1 + auto bexpr_bexpr_uexpr3 = ublas::detail::make_binary_tensor_expression( 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( t1, bexpr_bexpr_uexpr3, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); - } + // bexpr_uexpr2 = t1 + (((t1+1) + t2) + t1) + auto bexpr_bexpr_uexpr4 = ublas::detail::make_binary_tensor_expression( t1, bexpr_bexpr_uexpr3, bplus ); + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); + } - }); }); + }); } diff --git a/test/tensor/test_fixed_rank_extents.cpp b/test/tensor/test_fixed_rank_extents.cpp index 5d55d6b01..ac873f55c 100644 --- a/test/tensor/test_fixed_rank_extents.cpp +++ b/test/tensor/test_fixed_rank_extents.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -11,544 +11,543 @@ // #include -#include // Needed for squeeze -#include +#include #include -BOOST_AUTO_TEST_SUITE ( test_fixed_rank_extents ) +BOOST_AUTO_TEST_SUITE ( test_extents_static_size ) //*boost::unit_test::label("extents") //*boost::unit_test::label("constructor") -BOOST_AUTO_TEST_CASE(test_fixed_rank_extents_ctor) +BOOST_AUTO_TEST_CASE(test_extents_static_size_ctor) { - namespace ub = boost::numeric::ublas; - - - auto e0 = ub::extents<0>{}; - BOOST_CHECK( e0.empty()); - BOOST_CHECK ( e0.size() == 0); - - auto e1 = ub::extents<2>{1,1}; - BOOST_CHECK(!e1.empty()); - BOOST_CHECK ( e1.size() == 2); - - auto e2 = ub::extents<2>{1,2}; - BOOST_CHECK(!e2.empty()); - BOOST_CHECK ( e2.size() == 2); - - auto e3 = ub::extents<2>{2,1}; - BOOST_CHECK (!e3.empty()); - BOOST_CHECK ( e3.size() == 2); - - auto e4 = ub::extents<2>{2,3}; - BOOST_CHECK(!e4.empty()); - BOOST_CHECK ( e4.size() == 2); - - auto e5 = ub::extents<3>{2,3,1}; - BOOST_CHECK (!e5.empty()); - BOOST_CHECK ( e5.size() == 3); - - auto e6 = ub::extents<3>{1,2,3}; // 6 - BOOST_CHECK(!e6.empty()); - BOOST_CHECK ( e6.size() == 3); - - auto e7 = ub::extents<3>{4,2,3}; // 7 - BOOST_CHECK(!e7.empty()); - BOOST_CHECK ( e7.size() == 3); - - BOOST_CHECK_THROW( ub::extents<2>({1,0}), std::length_error); - BOOST_CHECK_THROW( ub::extents<1>({0} ), std::length_error); - BOOST_CHECK_THROW( ub::extents<1>({3} ), std::length_error); - BOOST_CHECK_THROW( ub::extents<2>({0,1}), std::length_error); - BOOST_CHECK_THROW( ub::extents<2>({1,1,2}), std::out_of_range); + namespace ub = boost::numeric::ublas; + + +// auto e = ub::extents<0>{}; + auto e11 = ub::extents<2>{1,1}; + auto e12 = ub::extents<2>{1,2}; + auto e21 = ub::extents<2>{2,1}; + auto e23 = ub::extents<2>{2,3}; + auto e231 = ub::extents<3>{2,3,1}; + auto e123 = ub::extents<3>{1,2,3}; // 6 + auto e423 = ub::extents<3>{4,2,3}; // 7 + + + BOOST_CHECK (!ub::empty(e11)); + BOOST_CHECK (!ub::empty(e12)); + BOOST_CHECK (!ub::empty(e21)); + BOOST_CHECK (!ub::empty(e23)); + BOOST_CHECK (!ub::empty(e231)); + BOOST_CHECK (!ub::empty(e123)); + BOOST_CHECK (!ub::empty(e423)); + + BOOST_CHECK ( ub::size (e11) == 2); + BOOST_CHECK ( ub::size (e12) == 2); + BOOST_CHECK ( ub::size (e21) == 2); + BOOST_CHECK ( ub::size (e23) == 2); + BOOST_CHECK ( ub::size(e231) == 3); + BOOST_CHECK ( ub::size(e123) == 3); + BOOST_CHECK ( ub::size(e423) == 3); + + + BOOST_CHECK_THROW( ub::extents<2>({1,0}), std::invalid_argument); + BOOST_CHECK_THROW( ub::extents<1>({0} ), std::invalid_argument); + BOOST_CHECK_THROW( ub::extents<2>({0,1}), std::invalid_argument); + BOOST_CHECK_THROW( ub::extents<2>({1,1,2}), std::length_error); } struct fixture { - template - using extents = boost::numeric::ublas::extents; - - extents<0> de0{}; // 0 - - extents<2> de1{1,1}; // 1 - extents<2> de2{1,2}; // 2 - extents<2> de3{2,1}; // 3 - - extents<2> de4{2,3}; // 4 - extents<3> de5{2,3,1}; // 5 - extents<3> de6{1,2,3}; // 6 - extents<4> de7{1,1,2,3}; // 7 - extents<5> de8{1,2,3,1,1}; // 8 - - extents<3> de9{4,2,3}; // 9 - extents<4> de10{4,2,1,3}; // 10 - extents<5> de11{4,2,1,3,1}; // 11 - extents<6> de12{1,4,2,1,3,1};// 12 - - extents<3> de13{1,4,1}; // 13 - extents<4> de14{1,1,1,1}; // 14 - extents<5> de15{1,4,1,1,1}; // 15 - extents<6> de16{1,1,2,1,1,1};// 16 - extents<6> de17{1,1,2,3,1,1};// 17 + template + using extents = boost::numeric::ublas::extents; + +// extents<0> de {}; + + extents<2> de11 {1,1}; + extents<2> de12 {1,2}; + extents<2> de21 {2,1}; + + extents<2> de23 {2,3}; + extents<3> de231 {2,3,1}; + extents<3> de123 {1,2,3}; + extents<4> de1123 {1,1,2,3}; + extents<5> de12311 {1,2,3,1,1}; + + extents<3> de423 {4,2,3}; + extents<4> de4213 {4,2,1,3}; + extents<5> de42131 {4,2,1,3,1}; + extents<6> de142131 {1,4,2,1,3,1}; + + extents<3> de141 {1,4,1}; + extents<4> de1111 {1,1,1,1}; + extents<5> de14111 {1,4,1,1,1}; + extents<6> de112111 {1,1,2,1,1,1}; + extents<6> de112311 {1,1,2,3,1,1}; }; -BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_access, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("access")) -{ - using namespace boost::numeric; - - BOOST_CHECK_EQUAL(de0.size(), 0); - BOOST_CHECK (de0.empty() ); - - BOOST_REQUIRE_EQUAL(de1.size(), 2); - BOOST_REQUIRE_EQUAL(de2.size(), 2); - BOOST_REQUIRE_EQUAL(de3.size(), 2); - BOOST_REQUIRE_EQUAL(de4.size(), 2); - BOOST_REQUIRE_EQUAL(de5.size(), 3); - BOOST_REQUIRE_EQUAL(de6.size(), 3); - BOOST_REQUIRE_EQUAL(de7.size(), 4); - BOOST_REQUIRE_EQUAL(de8.size(), 5); - BOOST_REQUIRE_EQUAL(de9.size(), 3); - BOOST_REQUIRE_EQUAL(de10.size(), 4); - BOOST_REQUIRE_EQUAL(de11.size(), 5); - BOOST_REQUIRE_EQUAL(de12.size(), 6); - BOOST_REQUIRE_EQUAL(de13.size(), 3); - BOOST_REQUIRE_EQUAL(de14.size(), 4); - BOOST_REQUIRE_EQUAL(de15.size(), 5); - BOOST_REQUIRE_EQUAL(de16.size(), 6); - BOOST_REQUIRE_EQUAL(de17.size(), 6); - - - BOOST_CHECK_EQUAL(de1[0],1); - BOOST_CHECK_EQUAL(de1[1],1); - - BOOST_CHECK_EQUAL(de2[0],1); - BOOST_CHECK_EQUAL(de2[1],2); - - BOOST_CHECK_EQUAL(de3[0],2); - BOOST_CHECK_EQUAL(de3[1],1); - - BOOST_CHECK_EQUAL(de4[0],2); - BOOST_CHECK_EQUAL(de4[1],3); - - BOOST_CHECK_EQUAL(de5[0],2); - BOOST_CHECK_EQUAL(de5[1],3); - BOOST_CHECK_EQUAL(de5[2],1); - - BOOST_CHECK_EQUAL(de6[0],1); - BOOST_CHECK_EQUAL(de6[1],2); - BOOST_CHECK_EQUAL(de6[2],3); - - BOOST_CHECK_EQUAL(de7[0],1); - BOOST_CHECK_EQUAL(de7[1],1); - BOOST_CHECK_EQUAL(de7[2],2); - BOOST_CHECK_EQUAL(de7[3],3); - - BOOST_CHECK_EQUAL(de8[0],1); - BOOST_CHECK_EQUAL(de8[1],2); - BOOST_CHECK_EQUAL(de8[2],3); - BOOST_CHECK_EQUAL(de8[3],1); - BOOST_CHECK_EQUAL(de8[4],1); - - BOOST_CHECK_EQUAL(de9[0],4); - BOOST_CHECK_EQUAL(de9[1],2); - BOOST_CHECK_EQUAL(de9[2],3); - - BOOST_CHECK_EQUAL(de10[0],4); - BOOST_CHECK_EQUAL(de10[1],2); - BOOST_CHECK_EQUAL(de10[2],1); - BOOST_CHECK_EQUAL(de10[3],3); - - BOOST_CHECK_EQUAL(de11[0],4); - BOOST_CHECK_EQUAL(de11[1],2); - BOOST_CHECK_EQUAL(de11[2],1); - BOOST_CHECK_EQUAL(de11[3],3); - BOOST_CHECK_EQUAL(de11[4],1); - - BOOST_CHECK_EQUAL(de12[0],1); - BOOST_CHECK_EQUAL(de12[1],4); - BOOST_CHECK_EQUAL(de12[2],2); - BOOST_CHECK_EQUAL(de12[3],1); - BOOST_CHECK_EQUAL(de12[4],3); - BOOST_CHECK_EQUAL(de12[5],1); - - BOOST_CHECK_EQUAL(de13[0],1); - BOOST_CHECK_EQUAL(de13[1],4); - BOOST_CHECK_EQUAL(de13[2],1); - - BOOST_CHECK_EQUAL(de14[0],1); - BOOST_CHECK_EQUAL(de14[1],1); - BOOST_CHECK_EQUAL(de14[2],1); - BOOST_CHECK_EQUAL(de14[3],1); - - BOOST_CHECK_EQUAL(de15[0],1); - BOOST_CHECK_EQUAL(de15[1],4); - BOOST_CHECK_EQUAL(de15[2],1); - BOOST_CHECK_EQUAL(de15[3],1); - BOOST_CHECK_EQUAL(de15[4],1); - - BOOST_CHECK_EQUAL(de16[0],1); - BOOST_CHECK_EQUAL(de16[1],1); - BOOST_CHECK_EQUAL(de16[2],2); - BOOST_CHECK_EQUAL(de16[3],1); - BOOST_CHECK_EQUAL(de16[4],1); - BOOST_CHECK_EQUAL(de16[5],1); - - BOOST_CHECK_EQUAL(de17[0],1); - BOOST_CHECK_EQUAL(de17[1],1); - BOOST_CHECK_EQUAL(de17[2],2); - BOOST_CHECK_EQUAL(de17[3],3); - BOOST_CHECK_EQUAL(de17[4],1); - BOOST_CHECK_EQUAL(de17[5],1); -} - -BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_copy_ctor, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("copy_ctor")) +BOOST_FIXTURE_TEST_CASE(test_extents_static_size_access, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("access")) { - auto e0 = de0; // {} - auto e1 = de1; // {1,1} - auto e2 = de2; // {1,2} - auto e3 = de3; // {2,1} - auto e4 = de4; // {2,3} - auto e5 = de5; // {2,3,1} - auto e6 = de6; // {1,2,3} - auto e7 = de7; // {1,1,2,3} - auto e8 = de8; // {1,2,3,1,1} - auto e9 = de9; // {4,2,3} - auto e10 = de10; // {4,2,1,3} - auto e11 = de11; // {4,2,1,3,1} - auto e12 = de12; // {1,4,2,1,3,1} - auto e13 = de13; // {1,4,1} - auto e14 = de14; // {1,1,1,1} - auto e15 = de15; // {1,4,1,1,1} - auto e16 = de16; // {1,1,2,1,1,1} - auto e17 = de17; // {1,1,2,3,1,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_REQUIRE_EQUAL(e13.size(), 3); - BOOST_REQUIRE_EQUAL(e14.size(), 4); - BOOST_REQUIRE_EQUAL(e15.size(), 5); - BOOST_REQUIRE_EQUAL(e16.size(), 6); - BOOST_REQUIRE_EQUAL(e17.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_CHECK_EQUAL(e13[0],1); - BOOST_CHECK_EQUAL(e13[1],4); - BOOST_CHECK_EQUAL(e13[2],1); - - BOOST_CHECK_EQUAL(e14[0],1); - BOOST_CHECK_EQUAL(e14[1],1); - BOOST_CHECK_EQUAL(e14[2],1); - BOOST_CHECK_EQUAL(e14[3],1); - - BOOST_CHECK_EQUAL(e15[0],1); - BOOST_CHECK_EQUAL(e15[1],4); - BOOST_CHECK_EQUAL(e15[2],1); - BOOST_CHECK_EQUAL(e15[3],1); - BOOST_CHECK_EQUAL(e15[4],1); - - BOOST_CHECK_EQUAL(e16[0],1); - BOOST_CHECK_EQUAL(e16[1],1); - BOOST_CHECK_EQUAL(e16[2],2); - BOOST_CHECK_EQUAL(e16[3],1); - BOOST_CHECK_EQUAL(e16[4],1); - BOOST_CHECK_EQUAL(e16[5],1); - - BOOST_CHECK_EQUAL(e17[0],1); - BOOST_CHECK_EQUAL(e17[1],1); - BOOST_CHECK_EQUAL(e17[2],2); - BOOST_CHECK_EQUAL(e17[3],3); - BOOST_CHECK_EQUAL(e17[4],1); - BOOST_CHECK_EQUAL(e17[5],1); - + namespace ublas = boost::numeric::ublas; + +// BOOST_REQUIRE_EQUAL(ublas::size(de), 0); +// BOOST_CHECK (ublas::empty(de) ); + + BOOST_REQUIRE_EQUAL(ublas::size(de11) , 2); + BOOST_REQUIRE_EQUAL(ublas::size(de12) , 2); + BOOST_REQUIRE_EQUAL(ublas::size(de21) , 2); + BOOST_REQUIRE_EQUAL(ublas::size(de23) , 2); + BOOST_REQUIRE_EQUAL(ublas::size(de231) , 3); + BOOST_REQUIRE_EQUAL(ublas::size(de123) , 3); + BOOST_REQUIRE_EQUAL(ublas::size(de1123) , 4); + BOOST_REQUIRE_EQUAL(ublas::size(de12311) , 5); + BOOST_REQUIRE_EQUAL(ublas::size(de423) , 3); + BOOST_REQUIRE_EQUAL(ublas::size(de4213) , 4); + BOOST_REQUIRE_EQUAL(ublas::size(de42131) , 5); + BOOST_REQUIRE_EQUAL(ublas::size(de142131), 6); + BOOST_REQUIRE_EQUAL(ublas::size(de141) , 3); + BOOST_REQUIRE_EQUAL(ublas::size(de1111) , 4); + BOOST_REQUIRE_EQUAL(ublas::size(de14111) , 5); + BOOST_REQUIRE_EQUAL(ublas::size(de112111), 6); + BOOST_REQUIRE_EQUAL(ublas::size(de112311), 6); + + + BOOST_CHECK_EQUAL(de11[0],1); + BOOST_CHECK_EQUAL(de11[1],1); + + BOOST_CHECK_EQUAL(de12[0],1); + BOOST_CHECK_EQUAL(de12[1],2); + + BOOST_CHECK_EQUAL(de21[0],2); + BOOST_CHECK_EQUAL(de21[1],1); + + BOOST_CHECK_EQUAL(de23[0],2); + BOOST_CHECK_EQUAL(de23[1],3); + + BOOST_CHECK_EQUAL(de231[0],2); + BOOST_CHECK_EQUAL(de231[1],3); + BOOST_CHECK_EQUAL(de231[2],1); + + BOOST_CHECK_EQUAL(de123[0],1); + BOOST_CHECK_EQUAL(de123[1],2); + BOOST_CHECK_EQUAL(de123[2],3); + + BOOST_CHECK_EQUAL(de1123[0],1); + BOOST_CHECK_EQUAL(de1123[1],1); + BOOST_CHECK_EQUAL(de1123[2],2); + BOOST_CHECK_EQUAL(de1123[3],3); + + BOOST_CHECK_EQUAL(de12311[0],1); + BOOST_CHECK_EQUAL(de12311[1],2); + BOOST_CHECK_EQUAL(de12311[2],3); + BOOST_CHECK_EQUAL(de12311[3],1); + BOOST_CHECK_EQUAL(de12311[4],1); + + BOOST_CHECK_EQUAL(de423[0],4); + BOOST_CHECK_EQUAL(de423[1],2); + BOOST_CHECK_EQUAL(de423[2],3); + + BOOST_CHECK_EQUAL(de4213[0],4); + BOOST_CHECK_EQUAL(de4213[1],2); + BOOST_CHECK_EQUAL(de4213[2],1); + BOOST_CHECK_EQUAL(de4213[3],3); + + BOOST_CHECK_EQUAL(de42131[0],4); + BOOST_CHECK_EQUAL(de42131[1],2); + BOOST_CHECK_EQUAL(de42131[2],1); + BOOST_CHECK_EQUAL(de42131[3],3); + BOOST_CHECK_EQUAL(de42131[4],1); + + BOOST_CHECK_EQUAL(de142131[0],1); + BOOST_CHECK_EQUAL(de142131[1],4); + BOOST_CHECK_EQUAL(de142131[2],2); + BOOST_CHECK_EQUAL(de142131[3],1); + BOOST_CHECK_EQUAL(de142131[4],3); + BOOST_CHECK_EQUAL(de142131[5],1); + + BOOST_CHECK_EQUAL(de141[0],1); + BOOST_CHECK_EQUAL(de141[1],4); + BOOST_CHECK_EQUAL(de141[2],1); + + BOOST_CHECK_EQUAL(de1111[0],1); + BOOST_CHECK_EQUAL(de1111[1],1); + BOOST_CHECK_EQUAL(de1111[2],1); + BOOST_CHECK_EQUAL(de1111[3],1); + + BOOST_CHECK_EQUAL(de14111[0],1); + BOOST_CHECK_EQUAL(de14111[1],4); + BOOST_CHECK_EQUAL(de14111[2],1); + BOOST_CHECK_EQUAL(de14111[3],1); + BOOST_CHECK_EQUAL(de14111[4],1); + + BOOST_CHECK_EQUAL(de112111[0],1); + BOOST_CHECK_EQUAL(de112111[1],1); + BOOST_CHECK_EQUAL(de112111[2],2); + BOOST_CHECK_EQUAL(de112111[3],1); + BOOST_CHECK_EQUAL(de112111[4],1); + BOOST_CHECK_EQUAL(de112111[5],1); + + BOOST_CHECK_EQUAL(de112311[0],1); + BOOST_CHECK_EQUAL(de112311[1],1); + BOOST_CHECK_EQUAL(de112311[2],2); + BOOST_CHECK_EQUAL(de112311[3],3); + BOOST_CHECK_EQUAL(de112311[4],1); + BOOST_CHECK_EQUAL(de112311[5],1); } -BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_is, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("query")) +BOOST_FIXTURE_TEST_CASE(test_extents_static_size_copy_ctor, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("copy_ctor")) { + namespace ublas = boost::numeric::ublas; + +// auto e = de; + auto e1 = de11; + auto e12 = de12; + auto e21 = de21; + auto e23 = de23; + auto e231 = de231; + auto e123 = de123; + auto e1123 = de1123; + auto e12311 = de12311; + auto e423 = de423; + auto e4213 = de4213; + auto e42131 = de42131; + auto e142131 = de142131; + auto e141 = de141; + auto e1111 = de1111; + auto e14111 = de14111; + auto e112111 = de112111; + auto e112311 = de112311; + + +// BOOST_CHECK (ublas::empty(e) ); + +// BOOST_REQUIRE_EQUAL(ublas::size(e) , 0); + BOOST_REQUIRE_EQUAL(ublas::size(e1) , 2); + BOOST_REQUIRE_EQUAL(ublas::size(e12) , 2); + BOOST_REQUIRE_EQUAL(ublas::size(e21) , 2); + BOOST_REQUIRE_EQUAL(ublas::size(e23) , 2); + BOOST_REQUIRE_EQUAL(ublas::size(e231), 3); + BOOST_REQUIRE_EQUAL(ublas::size(e123), 3); + BOOST_REQUIRE_EQUAL(ublas::size(e1123), 4); + BOOST_REQUIRE_EQUAL(ublas::size(e12311), 5); + BOOST_REQUIRE_EQUAL(ublas::size(e423), 3); + BOOST_REQUIRE_EQUAL(ublas::size(e4213), 4); + BOOST_REQUIRE_EQUAL(ublas::size(e42131), 5); + BOOST_REQUIRE_EQUAL(ublas::size(e142131), 6); + BOOST_REQUIRE_EQUAL(ublas::size(e141), 3); + BOOST_REQUIRE_EQUAL(ublas::size(e1111), 4); + BOOST_REQUIRE_EQUAL(ublas::size(e14111), 5); + BOOST_REQUIRE_EQUAL(ublas::size(e112111), 6); + BOOST_REQUIRE_EQUAL(ublas::size(e112311), 6); + + + BOOST_CHECK_EQUAL(e1[0],1); + BOOST_CHECK_EQUAL(e1[1],1); + + BOOST_CHECK_EQUAL(e12[0],1); + BOOST_CHECK_EQUAL(e12[1],2); + + BOOST_CHECK_EQUAL(e21[0],2); + BOOST_CHECK_EQUAL(e21[1],1); + + BOOST_CHECK_EQUAL(e23[0],2); + BOOST_CHECK_EQUAL(e23[1],3); + + BOOST_CHECK_EQUAL(e231[0],2); + BOOST_CHECK_EQUAL(e231[1],3); + BOOST_CHECK_EQUAL(e231[2],1); + + BOOST_CHECK_EQUAL(e123[0],1); + BOOST_CHECK_EQUAL(e123[1],2); + BOOST_CHECK_EQUAL(e123[2],3); + + BOOST_CHECK_EQUAL(e1123[0],1); + BOOST_CHECK_EQUAL(e1123[1],1); + BOOST_CHECK_EQUAL(e1123[2],2); + BOOST_CHECK_EQUAL(e1123[3],3); + + BOOST_CHECK_EQUAL(e12311[0],1); + BOOST_CHECK_EQUAL(e12311[1],2); + BOOST_CHECK_EQUAL(e12311[2],3); + BOOST_CHECK_EQUAL(e12311[3],1); + BOOST_CHECK_EQUAL(e12311[4],1); + + BOOST_CHECK_EQUAL(e423[0],4); + BOOST_CHECK_EQUAL(e423[1],2); + BOOST_CHECK_EQUAL(e423[2],3); + + BOOST_CHECK_EQUAL(e4213[0],4); + BOOST_CHECK_EQUAL(e4213[1],2); + BOOST_CHECK_EQUAL(e4213[2],1); + BOOST_CHECK_EQUAL(e4213[3],3); + + BOOST_CHECK_EQUAL(e42131[0],4); + BOOST_CHECK_EQUAL(e42131[1],2); + BOOST_CHECK_EQUAL(e42131[2],1); + BOOST_CHECK_EQUAL(e42131[3],3); + BOOST_CHECK_EQUAL(e42131[4],1); + + BOOST_CHECK_EQUAL(e142131[0],1); + BOOST_CHECK_EQUAL(e142131[1],4); + BOOST_CHECK_EQUAL(e142131[2],2); + BOOST_CHECK_EQUAL(e142131[3],1); + BOOST_CHECK_EQUAL(e142131[4],3); + BOOST_CHECK_EQUAL(e142131[5],1); + + BOOST_CHECK_EQUAL(e141[0],1); + BOOST_CHECK_EQUAL(e141[1],4); + BOOST_CHECK_EQUAL(e141[2],1); + + BOOST_CHECK_EQUAL(e1111[0],1); + BOOST_CHECK_EQUAL(e1111[1],1); + BOOST_CHECK_EQUAL(e1111[2],1); + BOOST_CHECK_EQUAL(e1111[3],1); + + BOOST_CHECK_EQUAL(e14111[0],1); + BOOST_CHECK_EQUAL(e14111[1],4); + BOOST_CHECK_EQUAL(e14111[2],1); + BOOST_CHECK_EQUAL(e14111[3],1); + BOOST_CHECK_EQUAL(e14111[4],1); + + BOOST_CHECK_EQUAL(e112111[0],1); + BOOST_CHECK_EQUAL(e112111[1],1); + BOOST_CHECK_EQUAL(e112111[2],2); + BOOST_CHECK_EQUAL(e112111[3],1); + BOOST_CHECK_EQUAL(e112111[4],1); + BOOST_CHECK_EQUAL(e112111[5],1); + + BOOST_CHECK_EQUAL(e112311[0],1); + BOOST_CHECK_EQUAL(e112311[1],1); + BOOST_CHECK_EQUAL(e112311[2],2); + BOOST_CHECK_EQUAL(e112311[3],3); + BOOST_CHECK_EQUAL(e112311[4],1); + BOOST_CHECK_EQUAL(e112311[5],1); - auto e0 = de0; // {} - auto e1 = de1; // {1,1} - auto e2 = de2; // {1,2} - auto e3 = de3; // {2,1} - auto e4 = de4; // {2,3} - auto e5 = de5; // {2,3,1} - auto e6 = de6; // {1,2,3} - auto e7 = de7; // {1,1,2,3} - auto e8 = de8; // {1,2,3,1,1} - auto e9 = de9; // {4,2,3} - auto e10 = de10; // {4,2,1,3} - auto e11 = de11; // {4,2,1,3,1} - auto e12 = de12; // {1,4,2,1,3,1} - auto e13 = de13; // {1,4,1} - auto e14 = de14; // {1,1,1,1} - auto e15 = de15; // {1,4,1,1,1} - auto e16 = de16; // {1,1,2,1,1,1} - auto e17 = de17; // {1,1,2,3,1,1} - - BOOST_CHECK( e0.empty ( )); - BOOST_CHECK( ! is_scalar(e0)); - BOOST_CHECK( ! is_vector(e0)); - BOOST_CHECK( ! is_matrix(e0)); - BOOST_CHECK( ! is_tensor(e0)); - - BOOST_CHECK( ! e1.empty ( ) ); - BOOST_CHECK( is_scalar(e1) ); - BOOST_CHECK( ! is_vector(e1) ); - BOOST_CHECK( ! is_matrix(e1) ); - BOOST_CHECK( ! is_tensor(e1) ); - - BOOST_CHECK( ! e2.empty ( ) ); - BOOST_CHECK( ! is_scalar(e2) ); - BOOST_CHECK( is_vector(e2) ); - BOOST_CHECK( ! is_matrix(e2) ); - BOOST_CHECK( ! is_tensor(e2) ); - - BOOST_CHECK( ! e3.empty ( ) ); - BOOST_CHECK( ! is_scalar(e3) ); - BOOST_CHECK( is_vector(e3) ); - BOOST_CHECK( ! is_matrix(e3) ); - BOOST_CHECK( ! is_tensor(e3) ); - - BOOST_CHECK( ! e4.empty ( ) ); - BOOST_CHECK( ! is_scalar(e4) ); - BOOST_CHECK( ! is_vector(e4) ); - BOOST_CHECK( is_matrix(e4) ); - BOOST_CHECK( ! is_tensor(e4) ); - - BOOST_CHECK( ! e5.empty ( ) ); - BOOST_CHECK( ! is_scalar(e5) ); - BOOST_CHECK( ! is_vector(e5) ); - BOOST_CHECK( is_matrix(e5) ); - BOOST_CHECK( ! is_tensor(e5) ); - - BOOST_CHECK( ! e6.empty ( ) ); - BOOST_CHECK( ! is_scalar(e6) ); - BOOST_CHECK( ! is_vector(e6) ); - BOOST_CHECK( ! is_matrix(e6) ); - BOOST_CHECK( is_tensor(e6) ); - - BOOST_CHECK( ! e7.empty ( ) ); - BOOST_CHECK( ! is_scalar(e7) ); - BOOST_CHECK( ! is_vector(e7) ); - BOOST_CHECK( ! is_matrix(e7) ); - BOOST_CHECK( is_tensor(e7) ); - - BOOST_CHECK( ! e8.empty ( ) ); - BOOST_CHECK( ! is_scalar(e8) ); - BOOST_CHECK( ! is_vector(e8) ); - BOOST_CHECK( ! is_matrix(e8) ); - BOOST_CHECK( is_tensor(e8) ); - - BOOST_CHECK( ! e9.empty ( ) ); - BOOST_CHECK( ! is_scalar(e9) ); - BOOST_CHECK( ! is_vector(e9) ); - BOOST_CHECK( ! is_matrix(e9) ); - BOOST_CHECK( is_tensor(e9) ); - - BOOST_CHECK( ! e10.empty( ) ); - BOOST_CHECK( ! is_scalar(e10) ); - BOOST_CHECK( ! is_vector(e10) ); - BOOST_CHECK( ! is_matrix(e10) ); - BOOST_CHECK( is_tensor(e10) ); - - BOOST_CHECK( ! e11.empty( ) ); - BOOST_CHECK( ! is_scalar(e11) ); - BOOST_CHECK( ! is_vector(e11) ); - BOOST_CHECK( ! is_matrix(e11) ); - BOOST_CHECK( is_tensor(e11) ); - - BOOST_CHECK( ! e12.empty( ) ); - BOOST_CHECK( ! is_scalar(e12) ); - BOOST_CHECK( ! is_vector(e12) ); - BOOST_CHECK( ! is_matrix(e12) ); - BOOST_CHECK( is_tensor(e12) ); - - BOOST_CHECK( ! e13.empty( ) ); - BOOST_CHECK( ! is_scalar(e13) ); - BOOST_CHECK( is_vector(e13) ); - BOOST_CHECK( ! is_matrix(e13) ); - BOOST_CHECK( ! is_tensor(e13) ); - - BOOST_CHECK( ! e14.empty( ) ); - BOOST_CHECK( is_scalar(e14) ); - BOOST_CHECK( ! is_vector(e14) ); - BOOST_CHECK( ! is_matrix(e14) ); - BOOST_CHECK( ! is_tensor(e14) ); - - BOOST_CHECK( ! e15.empty( ) ); - BOOST_CHECK( ! is_scalar(e15) ); - BOOST_CHECK( is_vector(e15) ); - BOOST_CHECK( ! is_matrix(e15) ); - BOOST_CHECK( ! is_tensor(e15) ); - - BOOST_CHECK( ! e16.empty( ) ); - BOOST_CHECK( ! is_scalar(e16) ); - BOOST_CHECK( ! is_vector(e16) ); - BOOST_CHECK( ! is_matrix(e16) ); - BOOST_CHECK( is_tensor(e16) ); - - BOOST_CHECK( ! e17.empty( ) ); - BOOST_CHECK( ! is_scalar(e17) ); - BOOST_CHECK( ! is_vector(e17) ); - BOOST_CHECK( ! is_matrix(e17) ); - BOOST_CHECK( is_tensor(e17) ); } -BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_squeeze, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("squeeze")) +BOOST_FIXTURE_TEST_CASE(test_extents_static_size_is, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("query")) { - auto e1 = squeeze(de1); // {1,1} - auto e2 = squeeze(de2); // {1,2} - auto e3 = squeeze(de3); // {2,1} - - auto e4 = squeeze(de4); // {2,3} - auto e5 = squeeze(de5); // {2,3} - auto e6 = squeeze(de6); // {2,3} - auto e7 = squeeze(de7); // {2,3} - auto e8 = squeeze(de8); // {2,3} - - auto e9 = squeeze(de9); // {4,2,3} - auto e10 = squeeze(de10); // {4,2,3} - auto e11 = squeeze(de11); // {4,2,3} - auto e12 = squeeze(de12); // {4,2,3} - - auto e13 = squeeze(de13); // {1,4} - auto e14 = squeeze(de14); // {1,1} - auto e15 = squeeze(de15); // {1,4} - auto e16 = squeeze(de16); // {2,1} - auto e17 = squeeze(de17); // {2,3} - - BOOST_CHECK( (e1 == extents<2>{1,1}) ); - BOOST_CHECK( (e2 == extents<2>{1,2}) ); - BOOST_CHECK( (e3 == extents<2>{2,1}) ); - - BOOST_CHECK( (e4 == extents<2>{2,3}) ); - BOOST_CHECK( (e5 == extents<2>{2,3}) ); - BOOST_CHECK( (e6 == extents<2>{2,3}) ); - BOOST_CHECK( (e7 == extents<2>{2,3}) ); - BOOST_CHECK( (e8 == extents<2>{2,3}) ); - - BOOST_CHECK( (e9 == extents<3>{4,2,3}) ); - BOOST_CHECK( (e10 == extents<3>{4,2,3}) ); - BOOST_CHECK( (e11 == extents<3>{4,2,3}) ); - BOOST_CHECK( (e12 == extents<3>{4,2,3}) ); - - BOOST_CHECK( (e13 == extents<2>{1,4}) ); - BOOST_CHECK( (e14 == extents<2>{1,1}) ); - BOOST_CHECK( (e15 == extents<2>{1,4}) ); - BOOST_CHECK( (e16 == extents<2>{2,1}) ); - BOOST_CHECK( (e17 == extents<2>{2,3}) ); - + namespace ublas = boost::numeric::ublas; + + +// auto e = de; + auto e11 = de11; + auto e12 = de12; + auto e21 = de21; + auto e23 = de23; + auto e231 = de231; + auto e123 = de123; + auto e1123 = de1123; + auto e12311 = de12311; + auto e423 = de423; + auto e4213 = de4213; + auto e42131 = de42131; + auto e142131 = de142131; + auto e141 = de141; + auto e1111 = de1111; + auto e14111 = de14111; + auto e112111 = de112111; + auto e112311 = de112311; + +// BOOST_CHECK( ublas::empty (e)); +// BOOST_CHECK( ! ublas::is_scalar(e)); +// BOOST_CHECK( ! ublas::is_vector(e)); +// BOOST_CHECK( ! ublas::is_matrix(e)); +// BOOST_CHECK( ! ublas::is_tensor(e)); + + BOOST_CHECK( ! ublas::empty (e11) ); + BOOST_CHECK( ublas::is_scalar(e11) ); + BOOST_CHECK( ublas::is_vector(e11) ); + BOOST_CHECK( ublas::is_matrix(e11) ); + BOOST_CHECK( ! ublas::is_tensor(e11) ); + + BOOST_CHECK( ! ublas::empty (e12) ); + BOOST_CHECK( ! ublas::is_scalar(e12) ); + BOOST_CHECK( ublas::is_vector(e12) ); + BOOST_CHECK( ublas::is_matrix(e12) ); + BOOST_CHECK( ! ublas::is_tensor(e12) ); + + BOOST_CHECK( ! ublas::empty (e21) ); + BOOST_CHECK( ! ublas::is_scalar(e21) ); + BOOST_CHECK( ublas::is_vector(e21) ); + BOOST_CHECK( ublas::is_matrix(e21) ); + BOOST_CHECK( ! ublas::is_tensor(e21) ); + + BOOST_CHECK( ! ublas::empty (e23) ); + BOOST_CHECK( ! ublas::is_scalar(e23) ); + BOOST_CHECK( ! ublas::is_vector(e23) ); + BOOST_CHECK( ublas::is_matrix(e23) ); + BOOST_CHECK( ! ublas::is_tensor(e23) ); + + BOOST_CHECK( ! ublas::empty (e231) ); + BOOST_CHECK( ! ublas::is_scalar(e231) ); + BOOST_CHECK( ! ublas::is_vector(e231) ); + BOOST_CHECK( ublas::is_matrix(e231) ); + BOOST_CHECK( ! ublas::is_tensor(e231) ); + + BOOST_CHECK( ! ublas::empty (e123) ); + BOOST_CHECK( ! ublas::is_scalar(e123) ); + BOOST_CHECK( ! ublas::is_vector(e123) ); + BOOST_CHECK( ! ublas::is_matrix(e123) ); + BOOST_CHECK( ublas::is_tensor(e123) ); + + BOOST_CHECK( ! ublas::empty (e1123) ); + BOOST_CHECK( ! ublas::is_scalar(e1123) ); + BOOST_CHECK( ! ublas::is_vector(e1123) ); + BOOST_CHECK( ! ublas::is_matrix(e1123) ); + BOOST_CHECK( ublas::is_tensor(e1123) ); + + BOOST_CHECK( ! ublas::empty (e12311) ); + BOOST_CHECK( ! ublas::is_scalar(e12311) ); + BOOST_CHECK( ! ublas::is_vector(e12311) ); + BOOST_CHECK( ! ublas::is_matrix(e12311) ); + BOOST_CHECK( ublas::is_tensor(e12311) ); + + BOOST_CHECK( ! ublas::empty (e423) ); + BOOST_CHECK( ! ublas::is_scalar(e423) ); + BOOST_CHECK( ! ublas::is_vector(e423) ); + BOOST_CHECK( ! ublas::is_matrix(e423) ); + BOOST_CHECK( ublas::is_tensor(e423) ); + + BOOST_CHECK( ! ublas::empty (e4213) ); + BOOST_CHECK( ! ublas::is_scalar(e4213) ); + BOOST_CHECK( ! ublas::is_vector(e4213) ); + BOOST_CHECK( ! ublas::is_matrix(e4213) ); + BOOST_CHECK( ublas::is_tensor(e4213) ); + + BOOST_CHECK( ! ublas::empty (e42131) ); + BOOST_CHECK( ! ublas::is_scalar(e42131) ); + BOOST_CHECK( ! ublas::is_vector(e42131) ); + BOOST_CHECK( ! ublas::is_matrix(e42131) ); + BOOST_CHECK( ublas::is_tensor(e42131) ); + + BOOST_CHECK( ! ublas::empty (e142131) ); + BOOST_CHECK( ! ublas::is_scalar(e142131) ); + BOOST_CHECK( ! ublas::is_vector(e142131) ); + BOOST_CHECK( ! ublas::is_matrix(e142131) ); + BOOST_CHECK( ublas::is_tensor(e142131) ); + + BOOST_CHECK( ! ublas::empty (e141) ); + BOOST_CHECK( ! ublas::is_scalar(e141) ); + BOOST_CHECK( ublas::is_vector(e141) ); + BOOST_CHECK( ublas::is_matrix(e141) ); + BOOST_CHECK( ! ublas::is_tensor(e141) ); + + BOOST_CHECK( ! ublas::empty (e1111) ); + BOOST_CHECK( ublas::is_scalar(e1111) ); + BOOST_CHECK( ublas::is_vector(e1111) ); + BOOST_CHECK( ublas::is_matrix(e1111) ); + BOOST_CHECK( ! ublas::is_tensor(e1111) ); + + BOOST_CHECK( ! ublas::empty (e14111) ); + BOOST_CHECK( ! ublas::is_scalar(e14111) ); + BOOST_CHECK( ublas::is_vector(e14111) ); + BOOST_CHECK( ublas::is_matrix(e14111) ); + BOOST_CHECK( ! ublas::is_tensor(e14111) ); + + BOOST_CHECK( ! ublas::empty (e112111) ); + BOOST_CHECK( ! ublas::is_scalar(e112111) ); + BOOST_CHECK( ! ublas::is_vector(e112111) ); + BOOST_CHECK( ! ublas::is_matrix(e112111) ); + BOOST_CHECK( ublas::is_tensor(e112111) ); + + BOOST_CHECK( ! ublas::empty (e112311) ); + BOOST_CHECK( ! ublas::is_scalar(e112311) ); + BOOST_CHECK( ! ublas::is_vector(e112311) ); + BOOST_CHECK( ! ublas::is_matrix(e112311) ); + BOOST_CHECK( ublas::is_tensor(e112311) ); } - -BOOST_FIXTURE_TEST_CASE(test_fixed_rank_extents_product, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("product")) +//BOOST_FIXTURE_TEST_CASE(test_extents_static_size_squeeze, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("squeeze")) +//{ +// auto e1 = squeeze(de1); // {1,1} +// auto e2 = squeeze(de2); // {1,2} +// auto 21 = squeeze(d21); // {2,1} + +// auto e4 = squeeze(de4); // {2,3} +// auto e231 = squeeze(de231); // {2,3} +// auto e123 = squeeze(de123); // {2,3} +// auto e1123 = squeeze(de1123); // {2,3} +// auto e12311 = squeeze(de12311); // {2,3} + +// auto e423 = squeeze(de423); // {4,2,3} +// auto e4213 = squeeze(de4213); // {4,2,3} +// auto e11 = squeeze(de11); // {4,2,3} +// auto e12 = squeeze(e142131); // {4,2,3} + +// auto e141 = squeeze(de141); // {1,4} +// auto e1111 = squeeze(de1111); // {1,1} +// auto e14111 = squeeze(de14111); // {1,4} +// auto e112111 = squeeze(de112111); // {2,1} +// auto e112311 = squeeze(de112311); // {2,3} + +// BOOST_CHECK( (e1 == extents<2>{1,1}) ); +// BOOST_CHECK( (e2 == extents<2>{1,2}) ); +// BOOST_CHECK( (21 == extents<2>{2,1}) ); + +// BOOST_CHECK( (e4 == extents<2>{2,3}) ); +// BOOST_CHECK( (e231 == extents<2>{2,3}) ); +// BOOST_CHECK( (e123 == extents<2>{2,3}) ); +// BOOST_CHECK( (e1123 == extents<2>{2,3}) ); +// BOOST_CHECK( (e12311 == extents<2>{2,3}) ); + +// BOOST_CHECK( (e423 == extents<3>{4,2,3}) ); +// BOOST_CHECK( (e4213 == extents<3>{4,2,3}) ); +// BOOST_CHECK( (e11 == extents<3>{4,2,3}) ); +// BOOST_CHECK( (e12 == extents<3>{4,2,3}) ); + +// BOOST_CHECK( (e141 == extents<2>{1,4}) ); +// BOOST_CHECK( (e1111 == extents<2>{1,1}) ); +// BOOST_CHECK( (e14111 == extents<2>{1,4}) ); +// BOOST_CHECK( (e112111 == extents<2>{2,1}) ); +// BOOST_CHECK( (e112311 == extents<2>{2,3}) ); + +//} + + +BOOST_FIXTURE_TEST_CASE(test_extents_static_size_product, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("product")) { - - auto e0 = product( de0 ); // {} - auto e1 = product( de1 ); // {1,1} - auto e2 = product( de2 ); // {1,2} - auto e3 = product( de3 ); // {2,1} - auto e4 = product( de4 ); // {2,3} - auto e5 = product( de5 ); // {2,3,1} - auto e6 = product( de6 ); // {1,2,3} - auto e7 = product( de7 ); // {1,1,2,3} - auto e8 = product( de8 ); // {1,2,3,1,1} - auto e9 = product( de9 ); // {4,2,3} - auto e10 = product( de10 ); // {4,2,1,3} - auto e11 = product( de11 ); // {4,2,1,3,1} - auto e12 = product( de12 ); // {1,4,2,1,3,1} - auto e13 = product( de13 ); // {1,4,1} - auto e14 = product( de14 ); // {1,1,1,1} - auto e15 = product( de15 ); // {1,4,1,1,1} - auto e16 = product( de16 ); // {1,1,2,1,1,1} - auto e17 = product( de17 ); // {1,1,2,3,1,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_CHECK_EQUAL( e13, 4 ); - BOOST_CHECK_EQUAL( e14, 1 ); - BOOST_CHECK_EQUAL( e15, 4 ); - BOOST_CHECK_EQUAL( e16, 2 ); - BOOST_CHECK_EQUAL( e17, 6 ); + namespace ublas = boost::numeric::ublas; + +// auto e = ublas::product( de ); + auto e11 = ublas::product( de11 ); + auto e12 = ublas::product( de12 ); + auto e21 = ublas::product( de21 ); + auto e23 = ublas::product( de23 ); + auto e231 = ublas::product( de231 ); + auto e123 = ublas::product( de123 ); + auto e1123 = ublas::product( de1123 ); + auto e12311 = ublas::product( de12311 ); + auto e423 = ublas::product( de423 ); + auto e4213 = ublas::product( de4213 ); + auto e42131 = ublas::product( de42131 ); + auto e142131 = ublas::product( de142131 ); + auto e141 = ublas::product( de141 ); + auto e1111 = ublas::product( de1111 ); + auto e14111 = ublas::product( de14111 ); + auto e112111 = ublas::product( de112111 ); + auto e112311 = ublas::product( de112311 ); + +// BOOST_CHECK_EQUAL( e , 0 ); + BOOST_CHECK_EQUAL( e11 , 1 ); + BOOST_CHECK_EQUAL( e12 , 2 ); + BOOST_CHECK_EQUAL( e21 , 2 ); + BOOST_CHECK_EQUAL( e23 , 6 ); + BOOST_CHECK_EQUAL( e231 , 6 ); + BOOST_CHECK_EQUAL( e123 , 6 ); + BOOST_CHECK_EQUAL( e1123 , 6 ); + BOOST_CHECK_EQUAL( e12311 , 6 ); + BOOST_CHECK_EQUAL( e423 , 24 ); + BOOST_CHECK_EQUAL( e4213 , 24 ); + BOOST_CHECK_EQUAL( e42131 , 24 ); + BOOST_CHECK_EQUAL( e142131, 24 ); + BOOST_CHECK_EQUAL( e141 , 4 ); + BOOST_CHECK_EQUAL( e1111 , 1 ); + BOOST_CHECK_EQUAL( e14111 , 4 ); + BOOST_CHECK_EQUAL( e112111, 2 ); + BOOST_CHECK_EQUAL( e112311, 6 ); } diff --git a/test/tensor/test_fixed_rank_functions.cpp b/test/tensor/test_fixed_rank_functions.cpp index 8ccea3f76..df3d4ce80 100644 --- a/test/tensor/test_fixed_rank_functions.cpp +++ b/test/tensor/test_fixed_rank_functions.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -23,7 +23,7 @@ #include "utility.hpp" // BOOST_AUTO_TEST_SUITE ( test_tensor_functions, * boost::unit_test::depends_on("test_tensor_contraction") ) -BOOST_AUTO_TEST_SUITE ( test_fixed_rank_tensor_functions) +BOOST_AUTO_TEST_SUITE ( test_tensor_extents_static_size_functions) using test_types = zip>::with_t; @@ -33,372 +33,427 @@ using test_types = zip>::with_t - using fixed_rank_extents_type = boost::numeric::ublas::extents; - - using dynamic_extents_type = boost::numeric::ublas::extents<>; - fixture() - : extents { - dynamic_extents_type{1,1}, // 1 - dynamic_extents_type{2,3}, // 2 - dynamic_extents_type{2,3,1}, // 3 - dynamic_extents_type{4,2,3}, // 4 - dynamic_extents_type{4,2,3,5}} // 5 - { - } - - std::tuple< - fixed_rank_extents_type<2>, - fixed_rank_extents_type<2>, - fixed_rank_extents_type<3>, - fixed_rank_extents_type<3>, - fixed_rank_extents_type<4> - > fixed_rank_extents{ - {1,1}, // 1 - {2,3}, // 2 - {2,3,1}, // 3 - {4,2,3}, // 4 - {4,2,3,5} // 5 + std::tuple< + boost::numeric::ublas::extents<2>, + boost::numeric::ublas::extents<2>, + boost::numeric::ublas::extents<3>, + boost::numeric::ublas::extents<3>, + boost::numeric::ublas::extents<4> + > extents_tuple{ + {1,1}, // 1 + {2,3}, // 2 + {2,3,1}, // 3 + {4,2,3}, // 4 + {4,2,3,5} // 5 }; - std::vector extents; + std::vector> extents_vector = + { + {1,1}, // 1 + {2,3}, // 2 + {2,3,1}, // 3 + {4,2,3}, // 4 + {4,2,3,5} // 5 + }; }; -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_prod_vector, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_prod_vector, value, test_types, fixture ) { - using namespace boost::numeric; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - for_each_tuple(fixed_rank_extents,[](auto const&, auto & n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::fixed_rank_tensor; - using vector_type = typename tensor_type::vector_type; - 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( static_cast< inner_type_t >(n[m]) ) * a[i]); - } - }); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + for_each_in_tuple(extents_tuple,[](auto const& /*unused*/, auto const& n){ + + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; + using vector_t = typename tensor_t::vector_type; + auto a = tensor_t(n); + a = 2; + + for (auto m = 0u; m < ublas::size(n); ++m) { + auto b = vector_t(n[m], value_t{1}); + + auto c = ublas::prod(a, b, m + 1); + + for (auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL(c[i], value_t( static_cast< inner_type_t >(n[m]) ) * a[i]); + } + }); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_prod_matrix, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_prod_matrix, value, test_types, fixture ) { - using namespace boost::numeric; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - for_each_tuple(fixed_rank_extents,[](auto const&, auto & n){ - using extents_type = typename std::decay::type; - using tensor_type = ublas::fixed_rank_tensor; - using matrix_type = typename tensor_type::matrix_type; - 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( static_cast< inner_type_t >(n[m]) ) * a[i]); - } - }); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + for_each_in_tuple(extents_tuple,[](auto const& /*unused*/, auto const & n){ + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; + using matrix_t = typename tensor_t::matrix_type; + + auto a = tensor_t(n); + a = 2; + for (auto m = 0u; m < ublas::size(n); ++m) { + + auto b = matrix_t ( n[m], n[m], value_t{1} ); + auto c = ublas::prod(a, b, m + 1); + + for (auto i = 0u; i < c.size(); ++i){ + BOOST_CHECK_EQUAL(c[i], value_t( static_cast< inner_type_t >(n[m]) ) * a[i]); + } + } + }); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_prod_tensor_1, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_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; - - auto const body = [](auto const& a, auto const& b){ - auto const pa = a.rank(); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phi = std::vector(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 *= value_type( static_cast< inner_type_t >( 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]); - } - }; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + auto check = [&](auto const& a, auto const& b, std::index_sequence /*unused*/) + { + namespace ublas = boost::numeric::ublas; - for_each_tuple(fixed_rank_extents,[&](auto const&, auto & n){ - auto n1 = n; - auto n2 = n; - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = - ublas::fixed_rank_tensor; - using tensor_type_2 = - ublas::fixed_rank_tensor; - auto a = tensor_type_1(n1, value_type{2}); - auto b = tensor_type_2(n2, value_type{3}); - body(a,b); - }); + constexpr auto q = sizeof...(qs); - for_each_tuple(fixed_rank_extents,[&](auto const& I, auto & n){ - auto n1 = n; - auto n2 = extents[I]; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = - ublas::fixed_rank_tensor; - using tensor_type_2 = - ublas::dynamic_tensor; - auto a = tensor_type_1(n1, value_type{2}); - auto b = tensor_type_2(n2, value_type{3}); - body(a,b); - }); + using tensorA = std::decay_t; + using tensorB = std::decay_t; - for_each_tuple(fixed_rank_extents,[&](auto const& I, auto & n){ - auto n1 = extents[I]; - auto n2 = n; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = - ublas::dynamic_tensor; - using tensor_type_2 = - ublas::fixed_rank_tensor; - auto a = tensor_type_1(n1, value_type{2}); - auto b = tensor_type_2(n2, value_type{3}); - body(a,b); - }); + using extentsA = typename tensorA::extents_type; + using extentsB = typename tensorB::extents_type; -} + static_assert(!ublas::is_static_v && !ublas::is_static_v ); -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_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; + constexpr auto one_of_extents_is_resizable = ublas::is_dynamic_rank_v || + ublas::is_dynamic_rank_v; + using phi_type = std::conditional_t, + std::array >; + auto phi = phi_type{}; + if constexpr(std::is_same_v>){ + phi.resize(q); + } + std::iota(phi.begin(), phi.end(), std::size_t{1}); + auto c = ublas::prod(a, b, phi); - auto compute_factorial = [](auto const& p){ - auto f = 1ul; - for(auto i = 1u; i <= p; ++i) - f *= i; - return f; - }; + auto const& na = a.extents(); + auto acc = std::size_t{1}; + for (auto i = 0ul; i < q; ++i){ + acc *= na.at(phi.at(i)-1); + } + const auto v = value_t(acc) * a[0] * b[0]; + BOOST_CHECK( std::all_of(c.begin(),c.end(),[v](auto cc){ return cc == v;})); + }; + + + for_each_in_tuple(extents_tuple,[&](auto const& /*I*/, auto const& n){ + constexpr auto size = std::tuple_size_v>; + constexpr auto modes = std::make_index_sequence{}; + using tensor_t = ublas::tensor_static_rank; + auto a = tensor_t(n); + auto b = tensor_t(n); + a = 2; + b = 3; + for_each_in_index(modes, a,b, check ); + }); + + for_each_in_tuple(extents_tuple,[&](auto const& I, auto const& n){ + auto const& nA = n; + auto const& nB = extents_vector[I]; + constexpr auto sizeA = std::tuple_size_v>; + constexpr auto modes = std::make_index_sequence{}; + using tensorA_type = ublas::tensor_static_rank; + using tensorB_type = ublas::tensor_dynamic; + auto a = tensorA_type(nA); + auto b = tensorB_type(nB); + a = 2; + b = 3; + + for_each_in_index(modes, a,b, check ); + }); + + for_each_in_tuple(extents_tuple,[&](auto const& I, auto const& n){ + auto const& nA = extents_vector[I]; + auto const& nB = n; + constexpr auto sizeB = std::tuple_size_v>; + constexpr auto modes = std::make_index_sequence{}; + using tensor_t_1 = ublas::tensor_dynamic; + using tensor_t_2 = ublas::tensor_static_rank; + auto a = tensor_t_1(nA); + auto b = tensor_t_2(nB); + a = 2; + b = 3; + for_each_in_index(modes, a,b, check ); + + }); +} - auto permute_extents_s_1 = [](auto const& pi, auto const& na){ +// TODO: +#if 0 - auto nb = ublas::extents<>(na); - assert(pi.size() == na.size()); - for(auto j = 0u; j < pi.size(); ++j) - nb[pi[j]-1] = na[j]; - return nb; - }; - auto permute_extents_s_2 = [](auto const& pi, auto const& na){ - auto tempn = na.base(); - assert(pi.size() == na.size()); - for(auto j = 0u; j < pi.size(); ++j) - tempn[pi[j]-1] = na[j]; - return ublas::extents::type::_size>(tempn.begin(),tempn.end()); - }; +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_prod_tensor_2, value, test_types, fixture ) +{ + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + constexpr auto to_array = [](std::index_sequence/*unused*/) { + return std::array{is...}; + }; + + auto compute_factorial = [](std::index_sequence/*unused*/) { + return ( 1 * ... * is ); + }; + /* + auto compute_factorial = [](auto const& p){ + auto f = 1ul; + for(auto i = 1u; i <= p; ++i) + f *= i; + return f; + }; +*/ + auto permute_extents_dynamic_rank = [](auto const& pi, auto const& na){ + auto nb = ublas::extents<>(na.begin(),na.end()); + assert(std::size(pi) == ublas::size(na)); + for(auto j = 0u; j < std::size(pi); ++j) + nb[pi[j]-1] = na[j]; + return nb; + }; + + auto permute_extents_static_rank = [](std::array const& pi, auto const& na){ + //constexpr auto size = std::tuple_size_v>; + auto na_base = na.base(); + assert(std::size(pi) == size); + for(auto j = 0u; j < std::size(pi); ++j) + na_base[pi[j]-1] = na[j]; + return ublas::extents(na_base.begin(),na_base.end()); + }; + + for_each_in_tuple(extents_tuple,[&](auto const& /*unused*/, auto const& n){ + auto const& na = n; + constexpr auto size = std::tuple_size_v>; + using tensorA_type = ublas::tensor_static_rank; + auto a = tensorA_type(na); + a = 2; + assert(a.rank() == size); + // auto const pa = a.rank(); + auto pi = to_array(std::make_index_sequence{}); + constexpr auto factorial = compute_factorial(std::make_index_sequence{}); + // auto pi = std::vector(pa); + // auto fac = compute_factorial(pa); + // std::iota(pi.begin(), pi.end(), 1); + + constexpr auto factorials = std::make_index_sequence{}; + + // for_each_in_tuple(factorials,[&](auto const& /*unused*/, auto const& /*unused*/){ + // using tensorB_type = ublas::tensor_dynamic; + // const auto nb = permute_extents_dynamic_rank(pi, na); + // const auto b = tensorB_type(nb, value_t{3}); + + // constexpr auto modes = std::make_index_sequence{}; + + // for_each_in_tuple(modes,[&](auto const& /*unused*/, auto const& /*unused*/){ + + + // const auto phia = to_array(std::make_index_sequence); + // const auto phib = std::array(q); + + // }); + + // for (auto f = 0ul; f < fac; ++f) { + // for (auto q = 0ul; q <= pa; ++q) { + + // auto phia = std::vector(q); + // auto phib = std::vector(q); + + // 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_t(1); + // for (auto i = 0ul; i < q; ++i) + // acc *= value_t( static_cast< inner_type_t >( 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()); + // } + }); + + for_each_in_tuple(extents_tuple,[&](auto const& /*unused*/, auto & /*n*/){ + // auto const& na = n; + // constexpr auto size = std::tuple_size_v>; + // using tensor_t_1 = ublas::tensor_static_rank; + // auto a = tensor_t_1(na, value_t{2}); + // auto const pa = a.rank(); + + // auto pi = std::vector(pa); + // auto fac = compute_factorial(pa); + // std::iota(pi.begin(), pi.end(), 1); + + // for (auto f = 0ul; f < fac; ++f) { + // auto nb = permute_extents_static_rank(pi, na); + + // using tensor_t_2 = ublas::tensor_static_rank; + // auto b = tensor_t_2(nb, value_t{3}); + + // for (auto q = 0ul; q <= pa; ++q) { + + // auto phia = std::vector(q); + // auto phib = std::vector(q); + + // 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); - for_each_tuple(fixed_rank_extents,[&](auto const&, auto & n){ - auto na = n; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::fixed_rank_tensor; - auto a = tensor_type_1(na, value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_s_1(pi, na); - using tensor_type_2 = ublas::dynamic_tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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 *= value_type( static_cast< inner_type_t >( 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()); - } - }); + // auto acc = value_t(1); + // for (auto i = 0ul; i < q; ++i){ + // acc *= value_t( static_cast< inner_type_t >( a.extents().at(phia.at(i) - 1) ) ); + // } - for_each_tuple(fixed_rank_extents,[&](auto const&, auto & n){ - auto na = n; - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::fixed_rank_tensor; - auto a = tensor_type_1(na, value_type{2}); - auto const pa = a.rank(); - - auto pi = std::vector(pa); - auto fac = compute_factorial(pa); - std::iota(pi.begin(), pi.end(), 1); - - for (auto f = 0ul; f < fac; ++f) { - auto nb = permute_extents_s_2(pi, na); - - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::fixed_rank_tensor; - auto b = tensor_type_2(nb, value_type{3}); - - for (auto q = 0ul; q <= pa; ++q) { - - auto phia = std::vector(q); - auto phib = std::vector(q); - - 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 *= value_type( static_cast< inner_type_t >( 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()); - } - }); + // 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()); + // } + }); +} +#endif -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_inner_prod, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_inner_prod, value, test_types, fixture ) { - using namespace boost::numeric; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - auto const body = [&](auto const& a, auto const& b){ - 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 ); - }; + using dtensor_t = ublas::tensor_dynamic; - for_each_tuple(fixed_rank_extents,[&](auto const&, auto & n){ - using extents_type_1 = typename std::decay::type; - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::fixed_rank_tensor; - using tensor_type_2 = ublas::fixed_rank_tensor; - auto a = tensor_type_1(n, value_type(2)); - auto b = tensor_type_2(n, value_type(1)); - body(a,b); + auto const body = [&](auto const& a, auto const& b){ + auto c = ublas::inner_prod(a, b); + auto r = std::inner_product(a.begin(),a.end(), b.begin(),value_t(0)); + BOOST_CHECK_EQUAL( c , r ); + }; - }); + for_each_in_tuple(extents_tuple,[&](auto const& /*unused*/, auto & n){ + constexpr auto size = std::tuple_size_v>; + using stensor_t = ublas::tensor_static_rank; + auto a = stensor_t(n); + auto b = stensor_t(n); + a = 2; + b = 3; + body(a,b); - for_each_tuple(fixed_rank_extents,[&](auto const& I, auto & n){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::fixed_rank_tensor; - using tensor_type_2 = ublas::dynamic_tensor; - auto a = tensor_type_1(n, value_type(2)); - auto b = tensor_type_2(extents[I], value_type(1)); - body(a,b); + }); - }); + for_each_in_tuple(extents_tuple,[&](auto const& I, auto & n){ + constexpr auto size = std::tuple_size_v>; + using stensor_t = ublas::tensor_static_rank; + auto a = stensor_t(n); + auto b = dtensor_t(extents_vector[I]); + a = 2; + b = 1; - for_each_tuple(fixed_rank_extents,[&](auto const& I, auto & n){ - using extents_type_2 = typename std::decay::type; - using tensor_type_1 = ublas::dynamic_tensor; - using tensor_type_2 = ublas::fixed_rank_tensor; - auto a = tensor_type_1(extents[I], value_type(2)); - auto b = tensor_type_2(n, value_type(1)); - body(a,b); + body(a,b); - }); + }); + + for_each_in_tuple(extents_tuple,[&](auto const& I, auto & n){ + constexpr auto size = std::tuple_size_v>; + using stensor_t = ublas::tensor_static_rank; + auto a = dtensor_t(extents_vector[I]); + auto b = stensor_t(n); + a = 2; + b = 1; + body(a,b); + + }); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_fixed_rank_tensor_outer_prod, value, test_types, fixture ) + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_outer_prod, value, test_types, fixture ) { - using namespace boost::numeric; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - for_each_tuple(fixed_rank_extents,[&](auto const&, auto const& n1){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::fixed_rank_tensor; - auto a = tensor_type_1(n1, value_type(2)); - for_each_tuple(fixed_rank_extents,[&](auto const& /*J*/, auto const& n2){ - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::fixed_rank_tensor; - auto b = tensor_type_2(n2, value_type(1)); - auto c = ublas::outer_prod(a, b); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - - }); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + for_each_in_tuple(extents_tuple,[&](auto const& /*unused*/, auto const& n1){ + constexpr auto size1 = std::tuple_size_v>; + using tensor_t_1 = ublas::tensor_static_rank; + auto a = tensor_t_1(n1); + a = 2; + for_each_in_tuple(extents_tuple,[&](auto const& /*J*/, auto const& n2){ + constexpr auto size2 = std::tuple_size_v>; + using tensor_t_2 = ublas::tensor_static_rank; + auto b = tensor_t_2(n2); + b = 1; + auto c = ublas::outer_prod(a, b); + + BOOST_CHECK ( std::all_of(c.begin(),c.end(), [&a,&b](auto cc){return cc == a[0]*b[0];}) ); }); - for_each_tuple(fixed_rank_extents,[&](auto const& I, auto const& /*n1*/){ - using tensor_type_1 = ublas::dynamic_tensor; - auto a = tensor_type_1(extents[I], value_type(2)); - for_each_tuple(fixed_rank_extents,[&](auto const& /*J*/, auto const& n2){ - using extents_type_2 = typename std::decay::type; - using tensor_type_2 = ublas::fixed_rank_tensor; - auto b = tensor_type_2(n2, value_type(1)); - auto c = ublas::outer_prod(a, b); + }); - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - }); + for_each_in_tuple(extents_tuple,[&](auto const& I, auto const& /*n1*/){ + using tensor_t_1 = ublas::tensor_dynamic; + auto a = tensor_t_1(extents_vector[I]); + a = 2; + for_each_in_tuple(extents_tuple,[&](auto const& /*J*/, auto const& n2){ + constexpr auto size = std::tuple_size_v>; + using tensor_t_2 = ublas::tensor_static_rank; + auto b = tensor_t_2(n2); + b = 1; + auto c = ublas::outer_prod(a, b); + BOOST_CHECK ( std::all_of(c.begin(),c.end(), [&a,&b](auto cc){return cc == a[0]*b[0];}) ); + +// for(auto const& cc : c) +// BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); }); - for_each_tuple(fixed_rank_extents,[&](auto const&, auto const& n1){ - using extents_type_1 = typename std::decay::type; - using tensor_type_1 = ublas::fixed_rank_tensor; - auto a = tensor_type_1(n1, value_type(2)); - for(auto n2 : extents){ - using tensor_type_2 = ublas::dynamic_tensor; - auto b = tensor_type_2(n2, value_type(1)); - auto c = ublas::outer_prod(a, b); + }); - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - } + for_each_in_tuple(extents_tuple,[&](auto const& /*unused*/, auto const& n1){ + constexpr auto size = std::tuple_size_v>; + using tensor_t_1 = ublas::tensor_static_rank; + auto a = tensor_t_1(n1); + a = 2; + for(auto const& n2 : extents_vector){ + using tensor_t_2 = ublas::tensor_dynamic; + auto b = tensor_t_2(n2); + b = 1; + auto c = ublas::outer_prod(a, b); - }); + BOOST_CHECK ( std::all_of(c.begin(),c.end(), [&a,&b](auto cc){return cc == a[0]*b[0];}) ); + +// for(auto const& cc : c) +// BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + } + + }); } diff --git a/test/tensor/test_fixed_rank_operators_arithmetic.cpp b/test/tensor/test_fixed_rank_operators_arithmetic.cpp index e5bbcf86a..08ef6b8f9 100644 --- a/test/tensor/test_fixed_rank_operators_arithmetic.cpp +++ b/test/tensor/test_fixed_rank_operators_arithmetic.cpp @@ -18,7 +18,7 @@ #include #include "utility.hpp" -BOOST_AUTO_TEST_SUITE(test_fixed_rank_tensor_arithmetic_operations) +BOOST_AUTO_TEST_SUITE(test_tensor_static_rank_arithmetic_operations) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; @@ -26,136 +26,131 @@ using test_types = zip::with_t - using extents_type = boost::numeric::ublas::extents; - - std::tuple< - extents_type<2>, // 1 - extents_type<2>, // 2 - extents_type<3>, // 3 - extents_type<3>, // 4 - extents_type<4> // 5 - > extents = { - extents_type<2>{1,1}, - extents_type<2>{2,3}, - extents_type<3>{4,1,3}, - extents_type<3>{4,2,3}, - extents_type<4>{4,2,3,5} - }; + template + using extents_t = boost::numeric::ublas::extents; + + std::tuple< + extents_t<2>, // 1 + extents_t<2>, // 2 + extents_t<3>, // 3 + extents_t<3>, // 4 + extents_t<4> // 5 + > extents = { + extents_t<2>{1,1}, + extents_t<2>{2,3}, + extents_t<3>{4,1,3}, + extents_t<3>{4,2,3}, + extents_t<4>{4,2,3,5} + }; }; 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; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto r = tensor_type (e); - auto v = value_type {}; + auto check = [](auto const& /*unused*/, auto& e) + { + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; + auto t = tensor_t (e); + auto t2 = tensor_t (e); + auto r = tensor_t (e); + auto v = value_t {}; - std::iota(t.begin(), t.end(), v); - std::iota(t2.begin(), t2.end(), v+2); - r = t + t + t + t2; + 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) ); + 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 + 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) ); + 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 + 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) ); + 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; + r = t2 - t + t2 - t; - for(auto i = 0ul; i < r.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 4 ); + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 4 ); - r = tensor_type (e,1) + tensor_type (e,1); + r = t * t * t * t2; - for(auto i = 0ul; i < r.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 2 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), t(i)*t(i)*t(i)*t2(i) ); - r = t * t * t * t2; + r = (t2/t2) * (t2/t2); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), t(i)*t(i)*t(i)*t2(i) ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 1 ); + }; - r = (t2/t2) * (t2/t2); - - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 1 ); - }; - - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } 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; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto v = value_type {}; + auto check = [](auto const& /*unused*/, auto& e) + { + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; + auto t = tensor_t (e); + auto t2 = tensor_t (e); + auto v = value_t {}; - std::iota(t.begin(), t.end(), v); - std::iota(t2.begin(), t2.end(), v+2); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - tensor_type r1 = t + 2 + t + 2; + tensor_t r1 = t + 2 + t + 2; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r1(i), 2*t(i) + 4 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r1(i), 2*t(i) + 4 ); - tensor_type r2 = 2 + t + 2 + t; + tensor_t r2 = 2 + t + 2 + t; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r2(i), 2*t(i) + 4 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r2(i), 2*t(i) + 4 ); - tensor_type r3 = (t-2) + (t-2); + tensor_t r3 = (t-2) + (t-2); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r3(i), 2*t(i) - 4 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r3(i), 2*t(i) - 4 ); - tensor_type r4 = (t*2) * (3*t); + tensor_t r4 = (t*2) * (3*t); - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r4(i), 2*3*t(i)*t(i) ); + 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; + tensor_t 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) ); + 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; + tensor_t 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 i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r6(i), (t2(i)/2+1) / (2/t2(i)+1) / t2(i) ); - }; + }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } @@ -164,79 +159,79 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value 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; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto r = tensor_type (e); - auto v = value_type {}; + auto check = [](auto const& /*unused*/, auto& e) + { + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; + auto t = tensor_t (e); + auto t2 = tensor_t (e); + auto r = tensor_t (e); + auto v = value_t {}; - std::iota(t.begin(), t.end(), v); - std::iota(t2.begin(), t2.end(), v+2); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - r = t + 2; - r += t; - r += 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 ); + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2*t(i) + 4 ); - r = 2 + t; - r += t; - r += 2; + 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 ); - 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; + r = (t-2); + 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 *= 3; - r *= t; + 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) ); + 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; + 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) ); + 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; + 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) ); + 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_t 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) ); - }; + tensor_t p = +r; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( p(i), r(i) ); + }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } diff --git a/test/tensor/test_fixed_rank_operators_comparison.cpp b/test/tensor/test_fixed_rank_operators_comparison.cpp index a4c60da0c..59338c387 100644 --- a/test/tensor/test_fixed_rank_operators_comparison.cpp +++ b/test/tensor/test_fixed_rank_operators_comparison.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -17,187 +17,181 @@ #include #include "utility.hpp" -BOOST_AUTO_TEST_SUITE(test_fixed_rank_tensor_comparison) +BOOST_AUTO_TEST_SUITE(test_tensor_static_rank_comparison) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; using test_types = zip::with_t; struct fixture { - template - using extents_type = boost::numeric::ublas::extents; - - std::tuple< - extents_type<2>, // 1 - extents_type<2>, // 2 - extents_type<3>, // 3 - extents_type<3>, // 4 - extents_type<4> // 5 + template + using extents_t = boost::numeric::ublas::extents; + + std::tuple< + extents_t<2>, // 1 + extents_t<2>, // 2 + extents_t<3>, // 3 + extents_t<3>, // 4 + extents_t<4> // 5 > extents = { - extents_type<2>{1,1}, - extents_type<2>{2,3}, - extents_type<3>{4,1,3}, - extents_type<3>{4,2,3}, - extents_type<4>{4,2,3,5} - }; + extents_t<2>{1,1}, + extents_t<2>{2,3}, + extents_t<3>{4,1,3}, + extents_t<3>{4,2,3}, + extents_t<4>{4,2,3,5} + }; }; 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; - - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - 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_each_tuple(extents,check); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + auto check = [](auto const& /*unused*/, auto& e) + { + using extents_t = std::decay_t; + using tensor_t = ublas::tensor_static_rank, layout_t>; + auto t = tensor_t (e); + auto t2 = tensor_t (e); + auto v = value_t {}; + + 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_each_in_tuple(extents,check); } 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; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; + for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e) { + using extents_t = std::decay_t; + using tensor_t = ublas::tensor_static_rank, layout_t>; - auto t = tensor_type (e); - auto t2 = tensor_type (e); - auto v = value_type {}; + auto t = tensor_t (e); + auto t2 = tensor_t (e); + auto v = value_t {}; - std::iota(t.begin(), t.end(), v); - std::iota(t2.begin(), t2.end(), v+2); + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); - BOOST_CHECK( t == t ); - BOOST_CHECK( t != t2 ); + BOOST_CHECK( t == t ); + BOOST_CHECK( t != t2 ); - if(t.empty()) - return; + 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 ); + 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_each_tuple(extents,check); } -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; - +//BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_scalar, value, test_types, fixture) +//{ +// namespace ublas = boost::numeric::ublas; +// using value_t = typename value::first_type; +// using layout_t = typename value::second_type; - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - 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}) ); +// for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e) { +// using extents_t = std::decay_t; +// using tensor_t = ublas::tensor_static_rank, layout_t>; - if(e.empty()) - return; +// BOOST_CHECK( tensor_t(e,value_t{2}) == tensor_t(e,value_t{2}) ); +// BOOST_CHECK( tensor_t(e,value_t{2}) != tensor_t(e,value_t{1}) ); - 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) ); +// if(ublas::empty(e)) +// return; - 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_t(e,2) < 2) ); +// BOOST_CHECK( !(tensor_t(e,2) > 2) ); +// BOOST_CHECK( (tensor_t(e,2) >= 2) ); +// BOOST_CHECK( (tensor_t(e,2) <= 2) ); +// BOOST_CHECK( (tensor_t(e,2) == 2) ); +// BOOST_CHECK( (tensor_t(e,2) != 3) ); - 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( !(2 > tensor_t(e,2)) ); +// BOOST_CHECK( !(2 < tensor_t(e,2)) ); +// BOOST_CHECK( (2 <= tensor_t(e,2)) ); +// BOOST_CHECK( (2 >= tensor_t(e,2)) ); +// BOOST_CHECK( (2 == tensor_t(e,2)) ); +// BOOST_CHECK( (3 != tensor_t(e,2)) ); +// BOOST_CHECK( !( tensor_t(e,2)+3 < 5) ); +// BOOST_CHECK( !( tensor_t(e,2)+3 > 5) ); +// BOOST_CHECK( ( tensor_t(e,2)+3 >= 5) ); +// BOOST_CHECK( ( tensor_t(e,2)+3 <= 5) ); +// BOOST_CHECK( ( tensor_t(e,2)+3 == 5) ); +// BOOST_CHECK( ( tensor_t(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( !( 5 > tensor_t(e,2)+3) ); +// BOOST_CHECK( !( 5 < tensor_t(e,2)+3) ); +// BOOST_CHECK( ( 5 >= tensor_t(e,2)+3) ); +// BOOST_CHECK( ( 5 <= tensor_t(e,2)+3) ); +// BOOST_CHECK( ( 5 == tensor_t(e,2)+3) ); +// BOOST_CHECK( ( 6 != tensor_t(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( !( tensor_t(e,2)+tensor_t(e,3) < 5) ); +// BOOST_CHECK( !( tensor_t(e,2)+tensor_t(e,3) > 5) ); +// BOOST_CHECK( ( tensor_t(e,2)+tensor_t(e,3) >= 5) ); +// BOOST_CHECK( ( tensor_t(e,2)+tensor_t(e,3) <= 5) ); +// BOOST_CHECK( ( tensor_t(e,2)+tensor_t(e,3) == 5) ); +// BOOST_CHECK( ( tensor_t(e,2)+tensor_t(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)) ); - }; +// BOOST_CHECK( !( 5 > tensor_t(e,2)+tensor_t(e,3)) ); +// BOOST_CHECK( !( 5 < tensor_t(e,2)+tensor_t(e,3)) ); +// BOOST_CHECK( ( 5 >= tensor_t(e,2)+tensor_t(e,3)) ); +// BOOST_CHECK( ( 5 <= tensor_t(e,2)+tensor_t(e,3)) ); +// BOOST_CHECK( ( 5 == tensor_t(e,2)+tensor_t(e,3)) ); +// BOOST_CHECK( ( 6 != tensor_t(e,2)+tensor_t(e,3)) ); -for_each_tuple(extents,check); +// }); -} +//} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_strides.cpp b/test/tensor/test_fixed_rank_strides.cpp index c90cba953..c7efd6413 100644 --- a/test/tensor/test_fixed_rank_strides.cpp +++ b/test/tensor/test_fixed_rank_strides.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -10,152 +10,175 @@ // Google and Fraunhofer IOSB, Ettlingen, Germany // - +#if 0 #include #include -#include - -//BOOST_AUTO_TEST_SUITE(test_strides, * boost::unit_test::depends_on("test_extents")); +#include BOOST_AUTO_TEST_SUITE(test_fixed_rank_strides) using test_types = std::tuple; +template +using strides =boost::numeric::ublas::strides,L>; + BOOST_AUTO_TEST_CASE_TEMPLATE( test_fixed_rank_strides_ctor, value, test_types) { - namespace ub = boost::numeric::ublas; - - ub::basic_fixed_rank_strides s0{ub::extents<0>{}}; - BOOST_CHECK ( s0.empty()); - BOOST_CHECK_EQUAL ( s0.size(), 0); - - ub::basic_fixed_rank_strides s1{ub::extents<2>{1,1}}; - BOOST_CHECK (!s1.empty()); - BOOST_CHECK_EQUAL ( s1.size(), 2); - - ub::basic_fixed_rank_strides s2{ub::extents<2>{1,2}}; - BOOST_CHECK (!s2.empty()); - BOOST_CHECK_EQUAL ( s2.size(), 2); - - ub::basic_fixed_rank_strides s3{ub::extents<2>{2,1}}; - BOOST_CHECK (!s3.empty()); - BOOST_CHECK_EQUAL ( s3.size(), 2); - - ub::basic_fixed_rank_strides s4{ub::extents<2>{2,3}}; - BOOST_CHECK (!s4.empty()); - BOOST_CHECK_EQUAL ( s4.size(), 2); - - ub::basic_fixed_rank_strides s5{ub::extents<3>{2,3,1}}; - BOOST_CHECK (!s5.empty()); - BOOST_CHECK_EQUAL ( s5.size(), 3); - - ub::basic_fixed_rank_strides s6{ub::extents<3>{1,2,3}}; - BOOST_CHECK (!s6.empty()); - BOOST_CHECK_EQUAL ( s6.size(), 3); - - ub::basic_fixed_rank_strides s7{ub::extents<3>{4,2,3}}; - BOOST_CHECK (!s7.empty()); - BOOST_CHECK_EQUAL ( s7.size(), 3); + namespace ublas = boost::numeric::ublas; +// using layout_type = value; +// constexpr auto layout = value{}; + + auto s0 = strides<0,value>{}; + auto s1 = strides<1,value>({1} ); + auto s3 = strides<1,value>({3} ); + auto s11 = strides<2,value>({1,1} ); + auto s12 = strides<2,value>({1,2} ); + auto s21 = strides<2,value>({2,1} ); + auto s23 = strides<2,value>({2,3} ); + auto s231 = strides<3,value>({2,3,1} ); + auto s123 = strides<3,value>({1,2,3} ); + auto s423 = strides<3,value>({4,2,3} ); + + BOOST_CHECK ( s0.empty()); + BOOST_CHECK (! s1.empty()); + BOOST_CHECK (! s3.empty()); + BOOST_CHECK (! s11.empty()); + BOOST_CHECK (! s12.empty()); + BOOST_CHECK (! s21.empty()); + BOOST_CHECK (! s23.empty()); + BOOST_CHECK (!s231.empty()); + BOOST_CHECK (!s123.empty()); + BOOST_CHECK (!s423.empty()); + + + BOOST_CHECK_EQUAL ( s0.size(), 0); + BOOST_CHECK_EQUAL ( s1.size(), 3); + BOOST_CHECK_EQUAL ( s3.size(), 1); + BOOST_CHECK_EQUAL ( s11.size(), 2); + BOOST_CHECK_EQUAL ( s12.size(), 2); + BOOST_CHECK_EQUAL ( s21.size(), 2); + BOOST_CHECK_EQUAL ( s23.size(), 2); + BOOST_CHECK_EQUAL ( s231.size(), 3); + BOOST_CHECK_EQUAL ( s123.size(), 3); + BOOST_CHECK_EQUAL ( s423.size(), 3); } BOOST_AUTO_TEST_CASE( test_fixed_rank_strides_ctor_access_first_order) { - namespace ub = boost::numeric::ublas; - - ub::basic_fixed_rank_strides s1{ub::extents<2>{1,1}}; - BOOST_REQUIRE_EQUAL( s1.size(),2); - BOOST_CHECK_EQUAL ( s1[0], 1); - BOOST_CHECK_EQUAL ( s1[1], 1); - - ub::basic_fixed_rank_strides s2{ub::extents<2>{1,2}}; - BOOST_REQUIRE_EQUAL ( s2.size(),2); - BOOST_CHECK_EQUAL ( s2[0], 1); - BOOST_CHECK_EQUAL ( s2[1], 1); - - ub::basic_fixed_rank_strides s3{ub::extents<2>{2,1}}; - BOOST_REQUIRE_EQUAL ( s3.size(),2); - BOOST_CHECK_EQUAL ( s3[0], 1); - BOOST_CHECK_EQUAL ( s3[1], 1); - - ub::basic_fixed_rank_strides s4{ub::extents<2>{2,3}}; - BOOST_REQUIRE_EQUAL ( s4.size(),2); - BOOST_CHECK_EQUAL ( s4[0], 1); - BOOST_CHECK_EQUAL ( s4[1], 2); - - ub::basic_fixed_rank_strides s5{ub::extents<3>{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); - - ub::basic_fixed_rank_strides s6{ub::extents<3>{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); - - ub::basic_fixed_rank_strides s7{ub::extents<3>{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); - - ub::basic_fixed_rank_strides s8{ub::extents<3>{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); + using value = boost::numeric::ublas::layout::first_order; +// constexpr auto layout = boost::numeric::ublas::layout::first_order{}; + + auto s1 = strides<1,value>({1} ); + auto s3 = strides<1,value>({3} ); + auto s11 = strides<2,value>({1,1} ); + auto s12 = strides<2,value>({1,2} ); + auto s21 = strides<2,value>({2,1} ); + auto s23 = strides<2,value>({2,3} ); + auto s231 = strides<3,value>({2,3,1} ); + auto s213 = strides<3,value>({2,3,1} ); + auto s123 = strides<3,value>({1,2,3} ); + auto s423 = strides<3,value>({4,2,3} ); + + + BOOST_REQUIRE_EQUAL ( s1.size(),1); + BOOST_REQUIRE_EQUAL ( s3.size(),1); + BOOST_REQUIRE_EQUAL ( s11.size(),2); + BOOST_REQUIRE_EQUAL ( s12.size(),2); + BOOST_REQUIRE_EQUAL ( s21.size(),2); + BOOST_REQUIRE_EQUAL ( s23.size(),2); + BOOST_REQUIRE_EQUAL ( s231.size(),3); + BOOST_REQUIRE_EQUAL ( s213.size(),3); + BOOST_REQUIRE_EQUAL ( s123.size(),3); + BOOST_REQUIRE_EQUAL ( s423.size(),3); + + BOOST_CHECK_EQUAL ( s11[0], 1); + BOOST_CHECK_EQUAL ( s11[1], 1); + + BOOST_CHECK_EQUAL ( s12[0], 1); + BOOST_CHECK_EQUAL ( s12[1], 1); + + BOOST_CHECK_EQUAL ( s21[0], 1); + BOOST_CHECK_EQUAL ( s21[1], 1); + + BOOST_CHECK_EQUAL ( s23[0], 1); + BOOST_CHECK_EQUAL ( s23[1], 2); + + BOOST_CHECK_EQUAL ( s231[0], 1); + BOOST_CHECK_EQUAL ( s231[1], 2); + BOOST_CHECK_EQUAL ( s231[2], 6); + + BOOST_CHECK_EQUAL ( s123[0], 1); + BOOST_CHECK_EQUAL ( s123[1], 1); + BOOST_CHECK_EQUAL ( s123[2], 2); + + BOOST_CHECK_EQUAL ( s213[0], 1); + BOOST_CHECK_EQUAL ( s213[1], 2); + BOOST_CHECK_EQUAL ( s213[2], 2); + + BOOST_CHECK_EQUAL ( s423[0], 1); + BOOST_CHECK_EQUAL ( s423[1], 4); + BOOST_CHECK_EQUAL ( s423[2], 8); } BOOST_AUTO_TEST_CASE( test_fixed_rank_strides_ctor_access_last_order) { - namespace ub = boost::numeric::ublas; - - ub::basic_fixed_rank_strides s1{ub::extents<2>{1,1}}; - BOOST_REQUIRE_EQUAL( s1.size(),2); - BOOST_CHECK_EQUAL ( s1[0], 1); - BOOST_CHECK_EQUAL ( s1[1], 1); - - ub::basic_fixed_rank_strides s2{ub::extents<2>{1,2}}; - BOOST_REQUIRE_EQUAL ( s2.size(),2); - BOOST_CHECK_EQUAL ( s2[0], 1); - BOOST_CHECK_EQUAL ( s2[1], 1); - - ub::basic_fixed_rank_strides s3{ub::extents<2>{2,1}}; - BOOST_REQUIRE_EQUAL ( s3.size(),2); - BOOST_CHECK_EQUAL ( s3[0], 1); - BOOST_CHECK_EQUAL ( s3[1], 1); - - ub::basic_fixed_rank_strides s4{ub::extents<2>{2,3}}; - BOOST_REQUIRE_EQUAL ( s4.size(),2); - BOOST_CHECK_EQUAL ( s4[0], 3); - BOOST_CHECK_EQUAL ( s4[1], 1); - - ub::basic_fixed_rank_strides s5{ub::extents<3>{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); - - ub::basic_fixed_rank_strides s6{ub::extents<3>{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); - - ub::basic_fixed_rank_strides s7{ub::extents<3>{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); - - ub::basic_fixed_rank_strides s8{ub::extents<3>{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); + using value = boost::numeric::ublas::layout::first_order; + // constexpr auto layout = boost::numeric::ublas::layout::first_order{}; + + auto s1 = strides<1,value>({1} ); + auto s3 = strides<1,value>({3} ); + auto s11 = strides<2,value>({1,1} ); + auto s12 = strides<2,value>({1,2} ); + auto s21 = strides<2,value>({2,1} ); + auto s23 = strides<2,value>({2,3} ); + auto s231 = strides<3,value>({2,3,1} ); + auto s213 = strides<3,value>({2,3,1} ); + auto s123 = strides<3,value>({1,2,3} ); + auto s423 = strides<3,value>({4,2,3} ); + + BOOST_REQUIRE_EQUAL ( s1.size(),1); + BOOST_REQUIRE_EQUAL ( s3.size(),1); + BOOST_REQUIRE_EQUAL ( s11.size(),2); + BOOST_REQUIRE_EQUAL ( s12.size(),2); + BOOST_REQUIRE_EQUAL ( s21.size(),2); + BOOST_REQUIRE_EQUAL ( s23.size(),2); + BOOST_REQUIRE_EQUAL ( s231.size(),3); + BOOST_REQUIRE_EQUAL ( s213.size(),3); + BOOST_REQUIRE_EQUAL ( s123.size(),3); + BOOST_REQUIRE_EQUAL ( s423.size(),3); + + BOOST_CHECK_EQUAL ( s11[0], 1); + BOOST_CHECK_EQUAL ( s11[1], 1); + + BOOST_CHECK_EQUAL ( s12[0], 1); + BOOST_CHECK_EQUAL ( s12[1], 1); + + BOOST_CHECK_EQUAL ( s21[0], 1); + BOOST_CHECK_EQUAL ( s21[1], 1); + + BOOST_CHECK_EQUAL ( s23[0], 3); + BOOST_CHECK_EQUAL ( s23[1], 1); + + BOOST_CHECK_EQUAL ( s231[0], 3); + BOOST_CHECK_EQUAL ( s231[1], 1); + BOOST_CHECK_EQUAL ( s231[2], 1); + + BOOST_CHECK_EQUAL ( s123[0], 6); + BOOST_CHECK_EQUAL ( s123[1], 3); + BOOST_CHECK_EQUAL ( s123[2], 1); + + BOOST_CHECK_EQUAL ( s213[0], 3); + BOOST_CHECK_EQUAL ( s213[1], 3); + BOOST_CHECK_EQUAL ( s213[2], 1); + + BOOST_CHECK_EQUAL ( s423[0], 6); + BOOST_CHECK_EQUAL ( s423[1], 3); + BOOST_CHECK_EQUAL ( s423[2], 1); + } BOOST_AUTO_TEST_SUITE_END() + +#endif diff --git a/test/tensor/test_fixed_rank_tensor.cpp b/test/tensor/test_fixed_rank_tensor.cpp index 918020ddf..b7050c897 100644 --- a/test/tensor/test_fixed_rank_tensor.cpp +++ b/test/tensor/test_fixed_rank_tensor.cpp @@ -18,358 +18,356 @@ #include #include "utility.hpp" -BOOST_AUTO_TEST_SUITE ( test_fixed_rank_tensor ) +BOOST_AUTO_TEST_SUITE ( test_tensor_static_rank ) using test_types = zip>::with_t; 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; - - auto a1 = ublas::fixed_rank_tensor{}; - BOOST_CHECK_EQUAL( a1.size() , 0ul ); - BOOST_CHECK( a1.empty() ); - BOOST_CHECK_EQUAL( a1.data() , nullptr); - - auto a2 = ublas::fixed_rank_tensor{1,1}; - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - BOOST_CHECK_NE( a2.data() , nullptr); - - auto a3 = ublas::fixed_rank_tensor{2,1}; - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - BOOST_CHECK_NE( a3.data() , nullptr); - - auto a4 = ublas::fixed_rank_tensor{1,2}; - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - BOOST_CHECK_NE( a4.data() , nullptr); - - auto a5 = ublas::fixed_rank_tensor{2,1}; - BOOST_CHECK_EQUAL( a5.size() , 2 ); - BOOST_CHECK( !a5.empty() ); - BOOST_CHECK_NE( a5.data() , nullptr); - - auto a6 = ublas::fixed_rank_tensor{4,3,2}; - BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); - BOOST_CHECK( !a6.empty() ); - BOOST_CHECK_NE( a6.data() , nullptr); - - auto a7 = ublas::fixed_rank_tensor{4,1,2}; - BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); - BOOST_CHECK( !a7.empty() ); - BOOST_CHECK_NE( a7.data() , nullptr); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + auto a2 = ublas::tensor_static_rank{1,1}; + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + BOOST_CHECK_NE( a2.data() , nullptr); + + auto a3 = ublas::tensor_static_rank{2,1}; + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + BOOST_CHECK_NE( a3.data() , nullptr); + + auto a4 = ublas::tensor_static_rank{1,2}; + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + BOOST_CHECK_NE( a4.data() , nullptr); + + auto a5 = ublas::tensor_static_rank{2,1}; + BOOST_CHECK_EQUAL( a5.size() , 2 ); + BOOST_CHECK( !a5.empty() ); + BOOST_CHECK_NE( a5.data() , nullptr); + + auto a6 = ublas::tensor_static_rank{4,3,2}; + BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); + BOOST_CHECK( !a6.empty() ); + BOOST_CHECK_NE( a6.data() , nullptr); + + auto a7 = ublas::tensor_static_rank{4,1,2}; + BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); + BOOST_CHECK( !a7.empty() ); + BOOST_CHECK_NE( a7.data() , nullptr); } struct fixture { - template - using extents_type = boost::numeric::ublas::extents; - - std::tuple< - extents_type<2>, // 1 - extents_type<2>, // 2 - extents_type<3>, // 3 - extents_type<3>, // 4 - extents_type<4> // 5 + template + using extents_t = boost::numeric::ublas::extents; + + std::tuple< + extents_t<2>, // 1 + extents_t<2>, // 2 + extents_t<3>, // 3 + extents_t<3>, // 4 + extents_t<4> // 5 > extents = { - extents_type<2>{1,1}, - extents_type<2>{2,3}, - extents_type<3>{4,1,3}, - extents_type<3>{4,2,3}, - extents_type<4>{4,2,3,5} - }; + extents_t<2>{1,1}, + extents_t<2>{2,3}, + extents_t<3>{4,1,3}, + extents_t<3>{4,2,3}, + extents_t<4>{4,2,3,5} + }; }; 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; - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - auto t = ublas::fixed_rank_tensor{e}; - - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - 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); - } - }); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ + constexpr auto size = std::tuple_size_v>; + auto t = ublas::tensor_static_rank{e}; + + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + if(ublas::empty(e)) { + BOOST_CHECK ( t.empty() ); + BOOST_CHECK_EQUAL ( t.data() , nullptr); + } + else{ + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + } + }); } 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; - - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - auto r = ublas::fixed_rank_tensor{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] ); - - }); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ + constexpr auto size = std::tuple_size_v>; + auto r = ublas::tensor_static_rank{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(ublas::empty(e)) { + 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] ); + + }); } 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 other_layout_type = std::conditional_t::value, ublas::layout::last_order, ublas::layout::first_order>; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using other_layout_t = std::conditional_t::value, ublas::layout::last_order, ublas::layout::first_order>; - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - auto r = tensor_type{e}; - ublas::fixed_rank_tensor t = r; - tensor_type q = t; + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; + using other_tensor_t = ublas::tensor_static_rank; + auto r = tensor_t(e); + other_tensor_t t = r; + tensor_t 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 ( 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() ); + 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] ); + 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; - - auto check = [](auto const&, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - auto r = tensor_type{e}; - auto t = std::move(r); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - 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_each_tuple(extents,check); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + auto check = [](auto const& /*unused*/, auto& e) + { + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; + auto r = tensor_t{e}; + auto t = std::move(r); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + + if(ublas::empty(e)) { + BOOST_CHECK ( t.empty() ); + BOOST_CHECK_EQUAL ( t.data() , nullptr); + } + else{ + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + } + + }; + + for_each_in_tuple(extents,check); } 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; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - std::random_device device{}; - std::minstd_rand0 generator(device()); + std::random_device device{}; + std::minstd_rand0 generator(device()); - using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; - auto distribution = distribution_type(1,6); + using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; + auto distribution = distribution_type(1,6); - for_each_tuple(extents, [&](auto const&, auto const& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; + for_each_in_tuple(extents, [&](auto const& /*unused*/, auto const& e){ + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; - auto r = value_type( static_cast< inner_type_t >(distribution(generator)) ); - auto t = tensor_type{e,r}; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( t[i], r ); + auto r = value_t( static_cast< inner_type_t >(distribution(generator)) ); + auto t = tensor_t(e); + t = 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; - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - using array_type = typename tensor_type::array_type; - - auto a = array_type(product(e)); - auto v = value_type {}; - - for(auto& aa : a){ - aa = v; - v += value_type{1}; - } - auto t = tensor_type{e, a}; - v = value_type{}; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - for(auto i = 0ul; i < t.size(); ++i, v+=value_type{1}) - BOOST_CHECK_EQUAL( t[i], v); + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; + using container_t = typename tensor_t::container_type; - }); + auto a = container_t(product(e)); + auto v = value_t {}; + + for(auto& aa : a){ + aa = v; + v += value_t{1}; + } + auto t = tensor_t(e, a); + v = value_t{}; + + for(auto i = 0ul; i < t.size(); ++i, v+=value_t{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; - - for_each_tuple(extents, [](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - - 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 ); - } + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - }); + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; + + auto t = tensor_t{e}; + auto v = value_t {}; + for(auto i = 0ul; i < t.size(); ++i, v+=value_t{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; - - auto check1 = [](const auto& t) - { - auto v = value_type{}; - for(auto k = 0ul; k < t.size(); ++k){ - BOOST_CHECK_EQUAL(t[k], v); - v+=value_type{1}; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + auto check1 = [](const auto& t) + { + auto v = value_t{}; + for(auto k = 0ul; k < t.size(); ++k){ + BOOST_CHECK_EQUAL(t[k], v); + v+=value_t{1}; + } + }; + + auto check2 = [](const auto& t) + { + std::array k = {0,0}; + auto r = std::is_same::value ? 1 : 0; + auto q = std::is_same::value ? 1 : 0; + auto v = value_t{}; + 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_t{1}; + } + } + }; + + auto check3 = [](const auto& t) + { + std::array k = {0,0,0}; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? 2 : 0; + auto o = op_type{}; + auto v = value_t{}; + 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_t{1}; } - }; - - auto check2 = [](const auto& t) - { - std::array k; - auto r = std::is_same::value ? 1 : 0; - auto q = std::is_same::value ? 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 check4 = [](const auto& t) + { + static constexpr auto order = 4; + std::array k = {0,0,0,0}; + using op_type = std::conditional_t, std::minus<>, std::plus<>>; + auto r = std::is_same_v ? (order-1) : 0; + auto o = op_type{}; + auto v = value_t{}; + for(k[o(r,0)] = 0ul; k[o(r,0)] < t.size(o(r,0)); ++k[o(r,0)]){ + 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_t{1}; + } } - }; - - auto check3 = [](const auto& t) - { - std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 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 auto& t) - { - std::array k; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 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&, auto const& e) { - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - 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 constexpr(extents_type::_size == 1) check1(t); - else if constexpr(extents_type::_size == 2) check2(t); - else if constexpr(extents_type::_size == 3) check3(t); - else if constexpr(extents_type::_size == 4) check4(t); - - }; - - for_each_tuple(extents,check); + } + } + }; + + auto check = [check1,check2,check3,check4](auto const& /*unused*/, auto const& e) { + constexpr auto size = std::tuple_size_v>; + using tensor_t = ublas::tensor_static_rank; + auto t = tensor_t(e); + auto v = value_t {}; + for(auto i = 0ul; i < t.size(); ++i){ + t[i] = v; + v+=value_t{1}; + } + + if constexpr(size == 1) check1(t); + else if constexpr(size == 2) check2(t); + else if constexpr(size == 3) check3(t); + else if constexpr(size == 4) check4(t); + + }; + + for_each_in_tuple(extents,check); } @@ -377,41 +375,42 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, 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; - - for_each_tuple(extents,[&](auto const&, auto& efrom){ - - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - - for_each_tuple(extents,[&](auto const&, auto& eto){ - using extents_type = std::decay_t; - using to_extents_type = std::decay_t; - if constexpr( extents_type::_size == to_extents_type::_size ){ - - 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(product(efrom),product(eto)); ++i) - BOOST_CHECK_EQUAL( t[i], v ); - - BOOST_CHECK_EQUAL ( t.size() , product(eto) ); - BOOST_CHECK_EQUAL ( t.rank() , eto.size() ); - BOOST_CHECK ( t.extents() == eto ); - - if(efrom != eto){ - for(auto i = product(efrom); i < t.size(); ++i) - BOOST_CHECK_EQUAL( t[i], value_type{} ); - } - } - }); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + for_each_in_tuple(extents,[&](auto const& /*unused*/, auto const& efrom){ + + using efrom_t = std::decay_t; + using tensor_t = ublas::tensor_static_rank, layout_t>; + + for_each_in_tuple(extents,[&](auto const& /*unused*/, auto& eto){ + using eto_t = std::decay_t; + + if constexpr( std::tuple_size_v == std::tuple_size_v ){ + + auto v = value_t {}; + v+=value_t{1}; + auto t = tensor_t(efrom); + t = v; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( t[i], v ); + + auto t2 = reshape(t,eto); + for(auto i = 0ul; i < std::min(ublas::product(efrom),ublas::product(eto)); ++i) + BOOST_CHECK_EQUAL( t2[i], v ); + + BOOST_CHECK_EQUAL ( t2.size() , ublas::product(eto) ); + BOOST_CHECK_EQUAL ( t2.rank() , ublas::size (eto) ); + BOOST_CHECK ( t2.extents() == eto ); + + if(efrom != eto){ + for(auto i = product(efrom); i < t.size(); ++i) + BOOST_CHECK_EQUAL( t2[i], value_t{} ); + } + } }); + }); } @@ -419,88 +418,92 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixtu 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; - - for_each_tuple(extents,[&](auto const&, auto& e_t){ - - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; - - for_each_tuple(extents,[&](auto const&, auto& e_r){ - using extents_type = std::decay_t; - using r_extents_type = std::decay_t; - if constexpr( extents_type::_size == r_extents_type::_size ){ - - 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() , product(e_r) ); - 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() , product(e_t) ); - BOOST_CHECK_EQUAL ( r.rank() , e_t.size() ); - BOOST_CHECK ( r.extents() == e_t ); - - } - }); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + + for_each_in_tuple(extents,[&](auto const& /*unused*/, auto const& e_t){ + using e_tt = std::decay_t< decltype(e_t) >; + using tensor_t = ublas::tensor_static_rank, layout_t>; + + for_each_in_tuple(extents,[&](auto const& /*unused*/, auto& e_r){ + + using e_rt = std::decay_t< decltype(e_r) >; + + if constexpr( std::tuple_size_v == std::tuple_size_v ){ + + auto v = value_t {} + value_t{1}; + auto w = value_t {} + value_t{2}; + auto t = tensor_t(e_t); + auto r = tensor_t(e_r); + + t = v; + r = w; + + std::swap( r, t ); + + BOOST_CHECK ( std::all_of(t.begin(),t.end(),[w](auto tt){return tt == w; } ) ) ; + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e_r) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e_r) ); + BOOST_CHECK ( t.extents() == e_r ); + BOOST_CHECK ( t.strides() == ublas::to_strides(e_r,layout_t{}) ); + + BOOST_CHECK ( std::all_of(r.begin(),r.end(),[v](auto tt){return tt == v; } ) ) ; + BOOST_CHECK_EQUAL ( r.size() , ublas::product(e_t) ); + BOOST_CHECK_EQUAL ( r.rank() , ublas::size (e_t) ); + BOOST_CHECK ( r.extents() == e_t ); + BOOST_CHECK ( r.strides() == ublas::to_strides(e_t,layout_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; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; - for_each_tuple(extents,[](auto const&, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::fixed_rank_tensor; + for_each_in_tuple(extents,[](auto const& /*unused*/, auto const& e){ + using et = std::decay_t< decltype(e) >; + using tensor_t = ublas::tensor_static_rank, layout_t>; - auto v = value_type {} + value_type{1}; - auto t = tensor_type{e, v}; + auto v = value_t {} + value_t{1}; + auto t = tensor_t(e); + t = 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.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() ); + 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() ) ) ; - } - }); + if(!t.empty()) { + BOOST_CHECK( t.data() == std::addressof( *t.begin () ) ) ; + BOOST_CHECK( t.data() == std::addressof( *t.cbegin() ) ) ; + } + }); } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, 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::fixed_rank_tensor; - - std::vector vec(30); - BOOST_CHECK_THROW(tensor_type({5,5},vec), std::runtime_error); - - auto t = tensor_type{{5,5}}; - auto i = ublas::index::index_type<4>{}; - BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::runtime_error); + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using tensor_t = ublas::tensor_static_rank; + + auto vec = std::vector(1); + BOOST_CHECK_THROW(tensor_t({5,5},vec), std::length_error); + + // Does not throw but results in a static assertion +// auto t = tensor_t{{5,5}}; +// auto i = ublas::index::index_type<4>{}; +// BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::runtime_error); } diff --git a/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp b/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp index e6cba14e9..5ed7a4f56 100644 --- a/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp +++ b/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -19,35 +19,35 @@ #include "utility.hpp" -BOOST_AUTO_TEST_SUITE ( test_fixed_rank_tensor_matrix_interoperability ) ; +BOOST_AUTO_TEST_SUITE ( test_tensor_static_rank_matrix_interoperability ) using test_types = zip::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; + using layout = typename value::second_type; + using tensor = ublas::tensor_static_rank; + using matrix = typename tensor::matrix_type; - ublas::fixed_rank_tensor a2 = matrix_type(1,1); + auto a2 = tensor( matrix(1,1) ); BOOST_CHECK_EQUAL( a2.size() , 1 ); BOOST_CHECK( !a2.empty() ); BOOST_CHECK_NE( a2.data() , nullptr); - ublas::fixed_rank_tensor a3 = matrix_type(2,1); + auto a3 = tensor( matrix(2,1) ); BOOST_CHECK_EQUAL( a3.size() , 2 ); BOOST_CHECK( !a3.empty() ); BOOST_CHECK_NE( a3.data() , nullptr); - ublas::fixed_rank_tensor a4 = matrix_type(1,2); + auto a4 = tensor( matrix(1,2) ); BOOST_CHECK_EQUAL( a4.size() , 2 ); BOOST_CHECK( !a4.empty() ); BOOST_CHECK_NE( a4.data() , nullptr); - ublas::fixed_rank_tensor a5 = matrix_type(2,3); + auto a5 = tensor( matrix(2,3) ); BOOST_CHECK_EQUAL( a5.size() , 6 ); BOOST_CHECK( !a5.empty() ); BOOST_CHECK_NE( a5.data() , nullptr); @@ -56,28 +56,28 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types) BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, value, test_types) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_static_rank; using vector_type = typename tensor_type::vector_type; - ublas::fixed_rank_tensor a2 = vector_type(1); + auto a2 = tensor_type( vector_type(1) ); BOOST_CHECK_EQUAL( a2.size() , 1 ); BOOST_CHECK( !a2.empty() ); BOOST_CHECK_NE( a2.data() , nullptr); - ublas::fixed_rank_tensor a3 = vector_type(2); + auto a3 = tensor_type( vector_type(2) ); BOOST_CHECK_EQUAL( a3.size() , 2 ); BOOST_CHECK( !a3.empty() ); BOOST_CHECK_NE( a3.data() , nullptr); - ublas::fixed_rank_tensor a4 = vector_type(2); + auto a4 = tensor_type( vector_type(2) ); BOOST_CHECK_EQUAL( a4.size() , 2 ); BOOST_CHECK( !a4.empty() ); BOOST_CHECK_NE( a4.data() , nullptr); - ublas::fixed_rank_tensor a5 = vector_type(3); + auto a5 = tensor_type( vector_type(3) ); BOOST_CHECK_EQUAL( a5.size() , 3 ); BOOST_CHECK( !a5.empty() ); BOOST_CHECK_NE( a5.data() , nullptr); @@ -93,12 +93,14 @@ struct fixture extents_type<2>, // 0 extents_type<2>, // 1 extents_type<2>, // 2 - extents_type<2> // 3 - > extents = { - {1,2}, - {2,1}, - {9,7}, - {12,12}, + extents_type<2>, // 3 + extents_type<2> // 4 + > extents = { + {1,1}, + {1,2}, + {2,1}, + {6,6}, + {9,7}, }; }; @@ -107,159 +109,158 @@ struct fixture 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::fixed_rank_tensor; - - assert(e.size()==2); - etensor_type t = matrix_type{e[0],e[1]}; - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - BOOST_CHECK_NE ( t.data() , nullptr); - }; - - for_each_tuple(extents,check); + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + auto check = [](auto const& /*unused*/, auto& e) { + constexpr auto size = std::tuple_size_v>; + using tensor = ublas::tensor_static_rank; + using matrix = typename tensor::matrix_type; + + assert(ublas::size(e)==2); + tensor t = matrix{e[0],e[1]}; + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + }; + + for_each_in_tuple(extents,check); } 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::fixed_rank_tensor; - assert(e.size()==2); - if(e.empty()) - return; + auto check = [](auto const& /*unused*/, auto& e) { + constexpr auto size = std::tuple_size_v>; + using tensor = ublas::tensor_static_rank; + using vector = typename tensor::vector_type; - etensor_type t = vector_type(product(e)); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - BOOST_CHECK ( !t.empty() ); - BOOST_CHECK_NE ( t.data() , nullptr); - }; + assert(ublas::size(e)==2); + if(ublas::empty(e)) + return; + + tensor t = vector (product(e)); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::fixed_rank_tensor; - - assert(e.size() == 2); - auto t = etensor_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() , product(e) ); - 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_each_tuple(extents,check); + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + + + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e) { + using etype = std::decay_t; + constexpr auto size = std::tuple_size_v; + using tensor = ublas::tensor_static_rank; + using matrix = typename tensor::matrix_type; + + assert(ublas::size(e) == 2); + auto t = tensor{e[1],e[0]}; + auto r = matrix(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() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + 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_each_in_tuple(extents,check); } 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::fixed_rank_tensor; - - assert(e.size() == 2); - auto t = etensor_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() , product(e) ); - 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) ); - } - }; + auto check = [](auto const& /*unused*/, auto& e) { + constexpr auto size = std::tuple_size_v>; + using tensor_type = ublas::tensor_static_rank; + using vector_type = typename tensor_type::vector_type; - for_each_tuple(extents,check); + assert(ublas::size(e) == 2); + auto t = tensor_type{e[1],e[0]}; + 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() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + 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_each_in_tuple(extents,check); } 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::fixed_rank_tensor; - - assert(e.size() == 2); - auto t = etensor_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() , product(e) ); - 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_each_tuple(extents,check); + auto check = [](auto const& /*unused*/, auto& e) { + constexpr auto size = std::tuple_size_v>; + using tensor_type = ublas::tensor_static_rank; + using matrix_type = typename tensor_type::matrix_type; + + assert(ublas::size(e) == 2); + auto t = tensor_type{e[1],e[0]}; + 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() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + 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_each_in_tuple(extents,check); } @@ -267,36 +268,35 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, te 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::fixed_rank_tensor; - - assert(e.size() == 2); - auto t = etensor_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() , product(e) ); - 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) ); - } - }; + auto check = [](auto const& /*unused*/, auto& e) { + constexpr auto size = std::tuple_size_v>; + using tensor_type = ublas::tensor_static_rank; + using vector_type = typename tensor_type::vector_type; - for_each_tuple(extents,check); + assert(ublas::size(e) == 2); + auto t = tensor_type{e[1],e[0]}; + 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() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + 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_each_in_tuple(extents,check); } @@ -305,57 +305,57 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, te 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::fixed_rank_tensor; - - assert(e.size() == 2); - auto t = etensor_type{}; - auto r = matrix_type(e[0],e[1]); - std::iota(r.data().begin(),r.data().end(), 1); - t = r + 3*r; - etensor_type s = r + 3*r; - etensor_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() , product(e) ); - 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() , product(e) ); - 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() , product(e) ); - 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_each_tuple(extents,check); + auto check = [](auto const& /*unused*/, auto& e) { + constexpr auto size = std::tuple_size_v>; + using tensor_type = ublas::tensor_static_rank; + using matrix_type = typename tensor_type::matrix_type; + + assert(ublas::size(e) == 2); + auto t = tensor_type{e[1],e[0]}; + 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() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + 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() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( s.rank() , ublas::size (e) ); + 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() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( q.rank() , ublas::size (e) ); + 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_each_in_tuple(extents,check); } @@ -365,106 +365,107 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_t 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::fixed_rank_tensor; - - assert(e.size() == 2); - auto t = etensor_type{}; - auto r = vector_type(e[0]*e[1]); - std::iota(r.data().begin(),r.data().end(), 1); - t = r + 3*r; - etensor_type s = r + 3*r; - etensor_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() , product(e) ); - 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() , product(e) ); - 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() , product(e) ); - 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) ); - } - }; + auto check = [](auto const& /*unused*/, auto& e) { + constexpr auto size = std::tuple_size_v>; + using tensor_type = ublas::tensor_static_rank; + using vector_type = typename tensor_type::vector_type; - for_each_tuple(extents,check); + assert(ublas::size(e) == 2); + auto t = tensor_type{e[1],e[0]}; + 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() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + 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() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( s.rank() , ublas::size (e) ); + 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() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( q.rank() , ublas::size (e) ); + 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_each_in_tuple(extents,check); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::fixed_rank_tensor; - - if(product(e) <= 2) - return; - assert(e.size() == 2); - auto Q = etensor_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); - - etensor_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_each_tuple(extents,check); + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + + + auto check = [](auto const& /*unused*/, auto& e) { + constexpr auto size = std::tuple_size_v>; + using tensor = ublas::tensor_static_rank; + using matrix = typename tensor::matrix_type; + using vector = typename tensor::vector_type; + + if(product(e) <= 2) + return; + assert(ublas::size(e) == 2); + auto Q = tensor{e[0],1}; + auto A = matrix(e[0],e[1]); + auto b = vector(e[1]); + auto c = vector(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 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); + + const auto n = e[1]; + const auto ab = value(std::div(n*(n+1),2).quot); + const auto ref = ab+4*Q(0)+2*c(0); + BOOST_CHECK( std::all_of(T.begin(),T.end(), [ref](auto cc){ return ref == cc; }) ); + +// 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_each_in_tuple(extents,check); } diff --git a/test/tensor/test_functions.cpp b/test/tensor/test_functions.cpp index e1d32bef0..c5a55048c 100644 --- a/test/tensor/test_functions.cpp +++ b/test/tensor/test_functions.cpp @@ -22,7 +22,6 @@ #include "utility.hpp" -// BOOST_AUTO_TEST_SUITE ( test_tensor_functions, * boost::unit_test::depends_on("test_tensor_contraction") ) BOOST_AUTO_TEST_SUITE ( test_tensor_functions) @@ -52,10 +51,10 @@ struct fixture BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_vector, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; using vector_type = typename tensor_type::vector_type; @@ -63,7 +62,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_vector, value, test_types, f auto a = tensor_type(n, value_type{2}); - for(auto m = 0u; m < n.size(); ++m){ + for(auto m = 0u; m < ublas::size(n); ++m){ auto b = vector_type (n[m], value_type{1} ); @@ -78,30 +77,28 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_vector, value, test_types, f auto a = tensor_type(n, value_type{2}); auto b = vector_type(n[0], value_type{1}); - auto zero_rank_empty_tensor = tensor_type{}; auto empty = vector_type{}; BOOST_CHECK_THROW(prod(a, b, 0), std::length_error); BOOST_CHECK_THROW(prod(a, b, 9), std::length_error); - BOOST_CHECK_THROW(prod(zero_rank_empty_tensor, b, 1), std::length_error); BOOST_CHECK_THROW(prod(a, empty, 2), std::length_error); } BOOST_AUTO_TEST_CASE( test_tensor_prod_vector_exception ) { - using namespace boost::numeric; - using value_type = float; - using layout_type = ublas::layout::first_order; - using d_tensor_type = ublas::dynamic_tensor; - using vector_type = typename d_tensor_type::vector_type; - - auto t1 = d_tensor_type{ublas::extents<>{},1.f}; - auto v1 = vector_type{3,value_type{1}}; - - BOOST_REQUIRE_THROW(prod(t1,v1,0),std::length_error); - BOOST_REQUIRE_THROW(prod(t1,v1,1),std::length_error); - BOOST_REQUIRE_THROW(prod(t1,v1,3),std::length_error); +// namespace ublas = boost::numeric::ublas; +// using value_type = float; +// using layout_type = ublas::layout::first_order; +// using d_tensor_type = ublas::tensor_dynamic; +// using vector_type = typename d_tensor_type::vector_type; + +// auto t1 = d_tensor_type{ublas::extents<>{},1.f}; +// auto v1 = vector_type{3,value_type{1}}; + +// BOOST_REQUIRE_THROW(prod(t1,v1,0),std::length_error); +// BOOST_REQUIRE_THROW(prod(t1,v1,1),std::length_error); +// BOOST_REQUIRE_THROW(prod(t1,v1,3),std::length_error); } @@ -109,10 +106,10 @@ BOOST_AUTO_TEST_CASE( test_tensor_prod_vector_exception ) BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_matrix, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; using matrix_type = typename tensor_type::matrix_type; @@ -120,7 +117,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_matrix, value, test_types, f auto a = tensor_type(n, value_type{2}); - for(auto m = 0u; m < n.size(); ++m){ + for(auto m = 0u; m < ublas::size(n); ++m){ auto b = matrix_type ( n[m], n[m], value_type{1} ); @@ -136,39 +133,37 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_matrix, value, test_types, f auto a = tensor_type(n, value_type{2}); auto b = matrix_type(n[0], n[0], value_type{1}); - auto zero_rank_empty_tensor = tensor_type{}; auto empty = matrix_type{}; BOOST_CHECK_THROW(prod(a, b, 0), std::length_error); BOOST_CHECK_THROW(prod(a, b, 9), std::length_error); - BOOST_CHECK_THROW(prod(zero_rank_empty_tensor, b, 1), std::length_error); - BOOST_CHECK_THROW(prod(a, empty, 2), std::length_error); + BOOST_CHECK_THROW(prod(a, empty, 2), std::invalid_argument); } BOOST_AUTO_TEST_CASE( test_tensor_prod_matrix_exception ) { - using namespace boost::numeric; - using value_type = float; - using layout_type = ublas::layout::first_order; - using d_extents_type = ublas::extents<>; - using d_tensor_type = ublas::dynamic_tensor; - using matrix_type = typename d_tensor_type::matrix_type; +// namespace ublas = boost::numeric::ublas; +// using value_type = float; +// using layout_type = ublas::layout::first_order; +// using d_extents_type = ublas::extents<>; +// using d_tensor_type = ublas::tensor_dynamic; +// using matrix_type = typename d_tensor_type::matrix_type; - auto t1 = d_tensor_type{d_extents_type{},1.f}; - auto m1 = matrix_type{3,3,value_type{1}}; +// auto t1 = d_tensor_type{d_extents_type{},1.f}; +// auto m1 = matrix_type{3,3,value_type{1}}; - BOOST_REQUIRE_THROW(prod(t1,m1,0),std::length_error); - BOOST_REQUIRE_THROW(prod(t1,m1,1),std::length_error); - BOOST_REQUIRE_THROW(prod(t1,m1,3),std::length_error); +// BOOST_REQUIRE_THROW(prod(t1,m1,0),std::length_error); +// BOOST_REQUIRE_THROW(prod(t1,m1,1),std::length_error); +// BOOST_REQUIRE_THROW(prod(t1,m1,3),std::length_error); } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_1, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; // left-hand and right-hand side have the // the same number of elements @@ -202,13 +197,13 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_1, value, test_types, BOOST_AUTO_TEST_CASE( test_tensor_prod_tensor_1_exception ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = float; using layout_type = ublas::layout::first_order; using d_extents_type = ublas::extents<>; - using d_tensor_type = ublas::dynamic_tensor; + using d_tensor_type = ublas::tensor_dynamic; + - auto t1 = d_tensor_type{}; std::vector phia = {1,2,3}; std::vector phib = {1,2,3,4,5}; @@ -236,10 +231,11 @@ BOOST_AUTO_TEST_CASE( test_tensor_prod_tensor_1_exception ) BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_2, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor_dynamic; + using extents_type = typename tensor_type::extents_type; auto compute_factorial = [](auto const& p){ @@ -250,11 +246,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_2, value, test_types, }; 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; + auto nb_base = na.base(); + assert(pi.size() == ublas::size(na)); + for(auto j = 0u; j < pi.size(); ++j) + nb_base[pi[j]-1] = na[j]; + return extents_type(nb_base); }; @@ -304,22 +300,22 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_2, value, test_types, auto phia = std::vector(3); auto sphia = std::vector(2); - BOOST_CHECK_THROW(ublas::prod(tensor_type{}, tensor_type({2,1,2}), phia, phia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2,3}), tensor_type(), phia, phia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2,4}), tensor_type({2,1}), phia, phia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2}), tensor_type({2,1,2}), phia, phia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2}), tensor_type({2,1,3}), sphia, phia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2}), tensor_type({2,2}), phia, sphia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2}), tensor_type({4,4}), sphia, phia), std::runtime_error); +// BOOST_CHECK_THROW(ublas::prod(tensor_type{}, tensor_type({2,1,2}), phia, phia), std::runtime_error); +// BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2,3}), tensor_type(), phia, phia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type{1,2,4}, tensor_type{2,1}, phia, phia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type{1,2}, tensor_type{2,1,2}, phia, phia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type{1,2}, tensor_type{2,1,3}, sphia, phia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type{1,2}, tensor_type{2,2}, phia, sphia), std::runtime_error); + BOOST_CHECK_THROW(ublas::prod(tensor_type{1,2}, tensor_type{4,4}, sphia, phia), std::runtime_error); } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_inner_prod, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; for(auto const& n : extents) { @@ -333,19 +329,19 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_inner_prod, value, test_types, fi BOOST_CHECK_EQUAL( c , r ); } - BOOST_CHECK_THROW(ublas::inner_prod(tensor_type({1,2,3}), tensor_type({1,2,3,4})), std::length_error); // rank different - BOOST_CHECK_THROW(ublas::inner_prod(tensor_type(), tensor_type()), std::length_error); //empty tensor - BOOST_CHECK_THROW(ublas::inner_prod(tensor_type({1,2,3}), tensor_type({3,2,1})), std::length_error); // different extent + BOOST_CHECK_THROW(ublas::inner_prod(tensor_type{1,2,3}, tensor_type{1,2,3,4}), std::length_error); // rank different +// BOOST_CHECK_THROW(ublas::inner_prod(tensor_type(), tensor_type()), std::length_error); //empty tensor + BOOST_CHECK_THROW(ublas::inner_prod(tensor_type{1,2,3}, tensor_type{3,2,1}), std::length_error); // different extent } BOOST_AUTO_TEST_CASE( test_tensor_inner_prod_exception ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = float; using layout_type = ublas::layout::first_order; using d_extents_type = ublas::extents<>; - using d_tensor_type = ublas::dynamic_tensor; + using d_tensor_type = ublas::tensor_dynamic; auto t1 = d_tensor_type{d_extents_type{1,2},1.f}; auto t2 = d_tensor_type{d_extents_type{1,2,3},1.f}; @@ -354,10 +350,10 @@ BOOST_AUTO_TEST_CASE( test_tensor_inner_prod_exception ) BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_norm, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; for(auto const& n : extents) { @@ -373,10 +369,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_norm, value, test_types, fixture auto c = ublas::inner_prod(a, a); auto r = std::inner_product(a.begin(),a.end(), a.begin(),value_type(0)); - tensor_type var = (a+a)/2.0f; // std::complex/int not allowed as expression is captured + tensor_type var = (a+a)/value_type(2); // std::complex/int not allowed as expression is captured auto r2 = ublas::norm( var ); - BOOST_CHECK_THROW(ublas::norm(tensor_type{}), std::runtime_error); +// BOOST_CHECK_THROW(ublas::norm(tensor_type{}), std::runtime_error); BOOST_CHECK_EQUAL( c , r ); BOOST_CHECK_EQUAL( std::sqrt( c ) , r2 ); @@ -386,13 +382,13 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_norm, value, test_types, fixture BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = float; using complex_type = std::complex; using layout_type = ublas::layout::first_order; - using tensor_complex_type = ublas::dynamic_tensor; - using tensor_type = ublas::dynamic_tensor; + using tensor_complex_type = ublas::tensor_dynamic; + using tensor_type = ublas::tensor_dynamic; for(auto const& n : extents) { @@ -460,10 +456,10 @@ BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_outer_prod, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; for(auto const& n1 : extents) { auto a = tensor_type(n1, value_type(2)); @@ -500,10 +496,10 @@ void init(std::vector>& a) BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_trans, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; auto fak = [](auto const& p){ auto f = 1ul; @@ -521,8 +517,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_trans, value, test_types, fixture for(auto const& n : extents) { - auto const p = n.size(); - auto const s = product(n); + auto const p = ublas::size(n); + auto const s = ublas::product(n); auto aref = tensor_type(n); auto v = value_type{}; for(auto i = 0u; i < s; ++i, v+=1) diff --git a/test/tensor/test_multi_index.cpp b/test/tensor/test_multi_index.cpp index 63289e52f..fdbbac7de 100644 --- a/test/tensor/test_multi_index.cpp +++ b/test/tensor/test_multi_index.cpp @@ -29,46 +29,46 @@ using test_types = zip>::with_t ind(_a, _b); + ublas::multi_index<2> ind(i::_a, i::_b); BOOST_CHECK_EQUAL ( get<0>( ind ), 1 ) ; BOOST_CHECK_EQUAL ( get<1>( ind ), 2 ) ; @@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_class_construction ) { - multi_index<2> ind(_d,_c); + ublas::multi_index<2> ind(i::_d,i::_c); BOOST_CHECK_EQUAL ( ind[0] , 4 ) ; BOOST_CHECK_EQUAL ( ind[1] , 3 ) ; @@ -86,58 +86,59 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_class_construction ) BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, test_types ) { - using namespace boost::numeric::ublas; + namespace ublas = boost::numeric::ublas; + namespace i = ublas::index; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; auto t = std::make_tuple ( - index::_a, // 0 - index::_b, // 1 - index::_c, // 2 - index::_d, // 3 - index::_e // 4 + i::_a, // 0 + i::_b, // 1 + i::_c, // 2 + i::_d, // 3 + i::_e // 4 ); { - auto a = tensor_type(extents<>{2,3}, value_type{2}); + auto a = tensor_type(ublas::extents<>{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() ) ; + BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), i::_a() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), i::_c() ) ; } { - auto a = tensor_type(extents<>{2,3}, value_type{2}); + auto a = tensor_type(ublas::extents<>{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() ) ; + BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), i::_c() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), i::_a() ) ; } { - auto a = tensor_type(extents<>{2,3}, value_type{2}); + auto a = tensor_type(ublas::extents<>{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() ) ; + BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), i::_c() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), i::_d() ) ; } { - auto a = tensor_type(extents<>{2,3,4}, value_type{2}); + auto a = tensor_type(ublas::extents<>{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_CHECK_EQUAL (std::get<0>(a_ind.second)(), i::_c() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), i::_d() ) ; + BOOST_CHECK_EQUAL (std::get<2>(a_ind.second)(), i::_a() ) ; } } diff --git a/test/tensor/test_multi_index_utility.cpp b/test/tensor/test_multi_index_utility.cpp index a4ed17e1c..3cd35de9a 100644 --- a/test/tensor/test_multi_index_utility.cpp +++ b/test/tensor/test_multi_index_utility.cpp @@ -19,40 +19,40 @@ 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; + namespace ublas = boost::numeric::ublas; + namespace i = boost::numeric::ublas::index; { constexpr auto tuple = std::tuple<>{}; - constexpr auto has_a = has_index::value; - constexpr auto has_b = has_index::value; + constexpr auto has_a = ublas::has_index::value; + constexpr auto has_b = ublas::has_index::value; BOOST_CHECK( !has_a ); BOOST_CHECK( !has_b ); } { - constexpr auto tuple = std::make_tuple(_a); - constexpr auto has_a = has_index::value; - constexpr auto has_b = has_index::value; + constexpr auto tuple = std::make_tuple(i::_a); + constexpr auto has_a = ublas::has_index::value; + constexpr auto has_b = ublas::has_index::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::value; - constexpr auto has_b = has_index::value; - constexpr auto has_c = has_index::value; - constexpr auto has_d = has_index::value; - constexpr auto has_e = has_index::value; - constexpr auto has__ = has_index::value; + constexpr auto tuple = std::make_tuple(i::_a,i::_b,i::_,i::_c,i::_d); + constexpr auto has_a = ublas::has_index::value; + constexpr auto has_b = ublas::has_index::value; + constexpr auto has_c = ublas::has_index::value; + constexpr auto has_d = ublas::has_index::value; + constexpr auto has_e = ublas::has_index::value; + constexpr auto has = ublas::has_index::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_CHECK( has ); } } @@ -60,55 +60,55 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_has_index ) BOOST_AUTO_TEST_CASE ( test_multi_index_valid ) { - using namespace boost::numeric::ublas; - using namespace boost::numeric::ublas::index; + namespace ublas = boost::numeric::ublas; + namespace i = ublas::index; { constexpr auto tuple = std::tuple<>{}; - constexpr auto valid = valid_multi_index::value; + constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } { - constexpr auto tuple = std::make_tuple(_a); - constexpr auto valid = valid_multi_index::value; + constexpr auto tuple = std::make_tuple(i::_a); + constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } { - constexpr auto tuple = std::make_tuple(_a,_,_b); - constexpr auto valid = valid_multi_index::value; + constexpr auto tuple = std::make_tuple(i::_a,i::_,i::_b); + constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } { - constexpr auto tuple = std::make_tuple(_a,_,_b,_b); - constexpr auto valid = valid_multi_index::value; + constexpr auto tuple = std::make_tuple(i::_a,i::_,i::_b,i::_b); + constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( !valid ); } { - constexpr auto tuple = std::make_tuple(_c,_a,_,_b,_b); - constexpr auto valid = valid_multi_index::value; + constexpr auto tuple = std::make_tuple(i::_c,i::_a,i::_,i::_b,i::_b); + constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( !valid ); } { - constexpr auto tuple = std::make_tuple(_c,_a,_,_b); - constexpr auto valid = valid_multi_index::value; + constexpr auto tuple = std::make_tuple(i::_c,i::_a,i::_,i::_b); + constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } { - constexpr auto tuple = std::make_tuple(_,_c,_a,_,_b); - constexpr auto valid = valid_multi_index::value; + constexpr auto tuple = std::make_tuple(i::_,i::_c,i::_a,i::_,i::_b); + constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } { - constexpr auto tuple = std::make_tuple(_,_c,_a,_,_b,_); - constexpr auto valid = valid_multi_index::value; + constexpr auto tuple = std::make_tuple(i::_,i::_c,i::_a,i::_,i::_b,i::_); + constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } } @@ -119,136 +119,136 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_valid ) BOOST_AUTO_TEST_CASE ( test_multi_index_number_equal_indices ) { - using namespace boost::numeric::ublas; - using namespace boost::numeric::ublas::index; + namespace ublas = boost::numeric::ublas; + namespace i = ublas::index; { constexpr auto lhs = std::tuple<>{}; constexpr auto rhs = std::tuple<>{}; - constexpr auto num = number_equal_indexes::value; + constexpr auto num = ublas::number_equal_indexes::value; BOOST_CHECK_EQUAL( num, 0 ); } { - constexpr auto lhs = std::make_tuple(_a); + constexpr auto lhs = std::make_tuple(i::_a); constexpr auto rhs = std::tuple<>{}; - constexpr auto num = number_equal_indexes::value; + constexpr auto num = ublas::number_equal_indexes::value; BOOST_CHECK_EQUAL( num, 0 ); } { constexpr auto lhs = std::tuple<>{}; - constexpr auto rhs = std::make_tuple(_a); - constexpr auto num = number_equal_indexes::value; + constexpr auto rhs = std::make_tuple(i::_a); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_b); + constexpr auto rhs = std::make_tuple(i::_a); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_a); + constexpr auto rhs = std::make_tuple(i::_a); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_a,i::_b); + constexpr auto rhs = std::make_tuple(i::_a); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_b); + constexpr auto rhs = std::make_tuple(i::_a,i::_b); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_a); + constexpr auto rhs = std::make_tuple(i::_a); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_a,i::_b); + constexpr auto rhs = std::make_tuple(i::_a,i::_b); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_b,i::_a); + constexpr auto rhs = std::make_tuple(i::_a,i::_b); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_c); + constexpr auto rhs = std::make_tuple(i::_a,i::_b); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_c); + constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d); + constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d); + constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d,i::_); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d,i::_); + constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d,i::_); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d,i::_); + constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_,i::_a,i::_d,i::_); + constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_); + constexpr auto num = ublas::number_equal_indexes::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::value; + constexpr auto lhs = std::make_tuple(i::_,i::_a,i::_d,i::_); + constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_,i::_); + constexpr auto num = ublas::number_equal_indexes::value; BOOST_CHECK_EQUAL( num, 1 ); } } @@ -261,42 +261,42 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_number_equal_indices ) BOOST_AUTO_TEST_CASE ( test_multi_index_index_position ) { - using namespace boost::numeric::ublas; - using namespace boost::numeric::ublas::index; + namespace ublas = boost::numeric::ublas; + namespace i = ublas::index; { constexpr auto tuple = std::tuple<>{}; - constexpr auto ind = index_position::value; + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,0); } { - constexpr auto tuple = std::make_tuple(_); - constexpr auto ind = index_position::value; + constexpr auto tuple = std::make_tuple(i::_); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,0); } { - constexpr auto tuple = std::make_tuple(_); - constexpr auto ind = index_position::value; + constexpr auto tuple = std::make_tuple(i::_); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,1); } { - constexpr auto tuple = std::make_tuple(_,_a); - constexpr auto ind = index_position::value; + constexpr auto tuple = std::make_tuple(i::_,i::_a); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,0); } { - constexpr auto tuple = std::make_tuple(_,_a); - constexpr auto ind = index_position::value; + constexpr auto tuple = std::make_tuple(i::_,i::_a); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,1); } { - constexpr auto tuple = std::make_tuple(_,_a); - constexpr auto ind = index_position::value; + constexpr auto tuple = std::make_tuple(i::_,i::_a); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,2); } @@ -304,26 +304,26 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position ) { - constexpr auto tuple = std::make_tuple(_c,_,_a); - constexpr auto ind = index_position::value; + constexpr auto tuple = std::make_tuple(i::_c,i::_,i::_a); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,0); } { - constexpr auto tuple = std::make_tuple(_c,_,_a,_); - constexpr auto ind = index_position::value; + constexpr auto tuple = std::make_tuple(i::_c,i::_,i::_a,i::_); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,1); } { - constexpr auto tuple = std::make_tuple(_c,_,_a); - constexpr auto ind = index_position::value; + constexpr auto tuple = std::make_tuple(i::_c,i::_,i::_a); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,2); } { - constexpr auto tuple = std::make_tuple(_c,_,_a); - constexpr auto ind = index_position::value; + constexpr auto tuple = std::make_tuple(i::_c,i::_,i::_a); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,3); } @@ -338,71 +338,71 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position ) BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) { - using namespace boost::numeric::ublas; - using namespace boost::numeric::ublas::index; + namespace ublas = boost::numeric::ublas; + namespace i = ublas::index; { constexpr auto lhs = std::tuple<>{}; constexpr auto rhs = std::tuple<>{}; - auto array = index_position_pairs(lhs, rhs); + auto array = ublas::index_position_pairs(lhs, rhs); BOOST_CHECK_EQUAL(array.size(), 0ul ); } { - constexpr auto lhs = std::make_tuple(_a); + constexpr auto lhs = std::make_tuple(i::_a); constexpr auto rhs = std::tuple<>{}; - auto array = index_position_pairs(lhs, rhs); + auto array = ublas::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); + constexpr auto rhs = std::make_tuple(i::_a); + auto array = ublas::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); + constexpr auto lhs = std::make_tuple(i::_b); + constexpr auto rhs = std::make_tuple(i::_a); + auto array = ublas::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 ); + constexpr auto lhs = std::make_tuple(i::_a); + constexpr auto rhs = std::make_tuple(i::_a); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); + constexpr auto lhs = std::make_tuple(i::_a,i::_b); + constexpr auto rhs = std::make_tuple(i::_a); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); + constexpr auto lhs = std::make_tuple(i::_b); + constexpr auto rhs = std::make_tuple(i::_a,i::_b); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); + constexpr auto lhs = std::make_tuple(i::_a); + constexpr auto rhs = std::make_tuple(i::_a); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_ASSERT(array.size() == 1ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); BOOST_CHECK_EQUAL(array[0].second, 0 ); } @@ -410,10 +410,10 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) { - 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 ); + constexpr auto lhs = std::make_tuple(i::_a,i::_b); + constexpr auto rhs = std::make_tuple(i::_a,i::_b); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); @@ -421,10 +421,10 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) } { - 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 ); + constexpr auto lhs = std::make_tuple(i::_b,i::_a); + constexpr auto rhs = std::make_tuple(i::_a,i::_b); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); @@ -432,10 +432,10 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) } { - 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 ); + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_c); + constexpr auto rhs = std::make_tuple(i::_a,i::_b); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); @@ -443,10 +443,10 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) } { - 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 ); + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_c); + constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); @@ -454,10 +454,10 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) } { - 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 ); + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d); + constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); @@ -467,10 +467,10 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) } { - 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 ); + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d); + constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d,i::_); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); @@ -480,10 +480,10 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) } { - 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 ); + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d,i::_); + constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d,i::_); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); @@ -493,10 +493,10 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) } { - 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 ); + constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d,i::_); + constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); @@ -504,19 +504,19 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) } { - 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 ); + constexpr auto lhs = std::make_tuple(i::_,i::_a,i::_d,i::_); + constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_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 ); + constexpr auto lhs = std::make_tuple(i::_,i::_a,i::_d,i::_); + constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_,i::_); + auto array = ublas::index_position_pairs(lhs, rhs); + BOOST_STATIC_ASSERT(array.size() == 1ul ); BOOST_CHECK_EQUAL(array[0].first , 2 ); BOOST_CHECK_EQUAL(array[0].second, 2 ); } @@ -524,39 +524,39 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) -BOOST_AUTO_TEST_CASE ( test_multi_index_array_to_vector ) -{ - using namespace boost::numeric::ublas; - using namespace boost::numeric::ublas::index; +//BOOST_AUTO_TEST_CASE ( test_multi_index_array_to_vector ) +//{ +// namespace ublas = boost::numeric::ublas; +// namespace i = ublas::index; - auto check = [](auto const& lhs, auto const& rhs) - { - auto array = index_position_pairs(lhs, rhs); +// auto check = [](auto const& lhs, auto const& rhs) +// { +// auto array = ublas::index_position_pairs(lhs, rhs); - auto vector_pair = array_to_vector( array ); +// auto vector_pair = ublas::array_to_vector( array ); - BOOST_CHECK_EQUAL(vector_pair.first .size(), array.size() ); - BOOST_CHECK_EQUAL(vector_pair.second.size(), array.size() ); +// 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 ); - } +// 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)); -} +// check(std::tuple<>{} , std::tuple<>{}); +// check(std::make_tuple(i::_a) , std::tuple<>{}); +// check(std::tuple<>{} , std::make_tuple(i::_a)); +// check(std::make_tuple(i::_a) , std::make_tuple(i::_b)); +// check(std::make_tuple(i::_a) , std::make_tuple(i::_a)); +// check(std::make_tuple(i::_a,i::_b), std::make_tuple(i::_a)); +// check(std::make_tuple(i::_a) , std::make_tuple(i::_a,i::_b)); +// check(std::make_tuple(i::_a,i::_b), std::make_tuple(i::_a,i::_b)); +// check(std::make_tuple(i::_b,i::_a), std::make_tuple(i::_a,i::_b)); +// check(std::make_tuple(i::_b,i::_a,i::_c), std::make_tuple(i::_a,i::_b,i::_d)); +//} diff --git a/test/tensor/test_multiplication.cpp b/test/tensor/test_multiplication.cpp index 19affdeb8..c5ed51e5f 100644 --- a/test/tensor/test_multiplication.cpp +++ b/test/tensor/test_multiplication.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -16,10 +16,7 @@ #include #include -#include -#include -#include -#include +#include #include "utility.hpp" #include @@ -35,386 +32,384 @@ using test_types = zip>::with_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{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; + using extents_t = boost::numeric::ublas::extents<>; + const std::vector extents = + { + extents_t{1,1}, // 1 + extents_t{1,2}, // 2 + extents_t{2,1}, // 3 + extents_t{2,3}, // 4 + extents_t{5,4}, // 5 + extents_t{2,3,1}, // 6 + extents_t{4,1,3}, // 7 + extents_t{1,2,3}, // 8 + extents_t{4,2,3}, // 9 + extents_t{4,2,3,5} // 10 + }; }; 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 vector_type = std::vector; - using extents_type = ublas::extents<>; - using strides_type = ublas::strides_t; - using extents_type_base = typename extents_type::base_type; - using size_type = typename extents_type_base::value_type; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using vector_t = std::vector; + using extents_t = ublas::extents<>; + using extents_base_t = typename extents_t::base_type; - for(auto const& na : extents) { + for(auto const& na : extents) { - if(na.size() > 2) - continue; + if(ublas::size(na) > 2) + continue; - auto a = vector_type(product(na), 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 (product(nb), value_type{1} ); + auto a = vector_t(ublas::product(na), value_t{2}); + auto wa = ublas::to_strides(na,layout_t{}); + for(auto m = std::size_t{0}; m < ublas::size(na); ++m){ + auto nb = extents_t {na[m],std::size_t{1}}; + auto wb = ublas::to_strides(nb,layout_t{}); + auto b = vector_t (ublas::product(nb), value_t{1} ); - auto nc_base = extents_type_base(std::max(na.size()-1, size_type{2}), 1); + auto nc_base = extents_base_t(std::max(std::size_t{ublas::size(na)-1u}, std::size_t{2}), 1); - for(auto i = 0u, j = 0u; i < na.size(); ++i) - if(i != m) - nc_base[j++] = na[i]; + for(auto i = 0ul, j = 0ul; i < ublas::size(na); ++i) + if(i != m) + nc_base[j++] = na[i]; - auto nc = extents_type (nc_base); - auto wc = strides_type (nc); - auto c = vector_type (product(nc), value_type{0}); + auto nc = extents_t (nc_base); + auto wc = ublas::to_strides(nc,layout_t{}); + auto c = vector_t (ublas::product(nc), value_t{0}); - ublas::detail::recursive::mtv( - size_type(m), - c.data(), nc.data(), wc.data(), - a.data(), na.data(), wa.data(), - b.data()); + ublas::detail::recursive::mtv( + m, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data()); + auto v = value_t(na[m]); + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); - for(auto i = 0u; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(na[m]) ) * a[i] ); +// for(auto i = 0u; i < c.size(); ++i) +// BOOST_CHECK_EQUAL( c[i] , value_t( static_cast< inner_type_t >(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 vector_type = std::vector; - using extents_type = ublas::extents<>; - using strides_type = ublas::strides_t; - // using extents_type_base = typename extents_type::base_type; - + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using vector_t = std::vector; + using extents_t = ublas::extents<>; - for(auto const& na : extents) { + for(auto const& na : extents) { - if(na.size() != 2) - continue; + if(ublas::size(na) != 2) + continue; - auto a = vector_type (product(na), value_type{2}); - auto wa = strides_type (na); + auto a = vector_t (ublas::product(na), value_t{2}); + auto wa = ublas::to_strides(na,layout_t{}); - auto nb = extents_type {na[1],na[0]}; - auto wb = strides_type (nb); - auto b = vector_type (product(nb), value_type{1} ); + auto nb = extents_t {na[1],na[0]}; + auto wb = ublas::to_strides(nb,layout_t{}); + auto b = vector_t (ublas::product(nb), value_t{1} ); - auto nc = extents_type {na[0],nb[1]}; -auto wc = strides_type (nc); -auto c = vector_type (product(nc)); + auto nc = extents_t {na[0],nb[1]}; + auto wc = ublas::to_strides(nc,layout_t{}); + auto c = vector_t (ublas::product(nc)); -ublas::detail::recursive::mtm( - c.data(), nc.data(), wc.data(), - a.data(), na.data(), wa.data(), - b.data(), nb.data(), wb.data()); + ublas::detail::recursive::mtm( + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + auto v = value_t(na[1])*a[0]; + BOOST_CHECK(std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v;})); -for(auto i = 0u; i < c.size(); ++i) -BOOST_CHECK_EQUAL( c[i] , value_type( static_cast< inner_type_t >(na[1]) ) * a[0] ); +// for(auto i = 0u; i < c.size(); ++i) +// BOOST_CHECK_EQUAL( c[i] , value_t( static_cast< inner_type_t >(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 vector_type = std::vector; - using extents_type = ublas::extents<>; - using strides_type = ublas::strides_t; - using extents_type_base = typename extents_type::base_type; - using size_type = typename extents_type_base::value_type; - + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using vector_t = std::vector; + using extents_t = ublas::extents<>; + using extents_base_t = typename extents_t::base_type; - for(auto const& na : extents) { + for(auto const& na : extents) { - auto a = vector_type(product(na), 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 a = vector_t(ublas::product(na), value_t{2}); + auto wa = ublas::to_strides(na,layout_t{}); + for(auto m = std::size_t{0}; m < ublas::size(na); ++m){ + auto b = vector_t (na[m], value_t{1} ); + auto nb = extents_t {na[m],1}; + auto wb = ublas::to_strides(nb,layout_t{}); - auto nc_base = extents_type_base(std::max(na.size()-1, size_type(2)),1); + auto nc_base = extents_base_t(std::max(std::size_t{ublas::size(na)-1u}, std::size_t{2}),1); - for(auto i = 0ul, j = 0ul; i < na.size(); ++i) - if(i != m) - nc_base[j++] = na[i]; + for(auto i = 0ul, j = 0ul; i < ublas::size(na); ++i) + if(i != m) + nc_base[j++] = na[i]; - auto nc = extents_type (nc_base); - auto wc = strides_type (nc); - auto c = vector_type (product(nc), value_type{0}); + auto nc = extents_t (nc_base); + auto wc = ublas::to_strides(nc,layout_t{}); + auto c = vector_t (ublas::product(nc), value_t{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()); + ublas::ttv(m+1, ublas::size(na), + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + auto v = value_t(na[m]); + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); - for(auto i = 0u; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i] , value_type(na[m]) * a[i] ); +// for(auto i = 0u; i < c.size(); ++i) +// BOOST_CHECK_EQUAL( c[i] , value_t(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 vector_type = std::vector; - using extents_type = ublas::extents<>; - using strides_type = ublas::strides_t; - using size_type = typename extents_type::value_type; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using vector_t = std::vector; + using extents_t = ublas::extents<>; + + + for(auto const& na : extents) { + + auto a = vector_t(ublas::product(na), value_t{2}); + auto wa = ublas::to_strides(na,layout_t{}); + for(auto m = std::size_t{0}; m < ublas::size(na); ++m){ + const auto nb = extents_t {na[m], na[m] }; + const auto b = vector_t (ublas::product(nb), value_t{1} ); + const auto wb = ublas::to_strides(nb,layout_t{}); - for(auto const& na : extents) { + const auto& nc = na; + const auto wc = ublas::to_strides(nc,layout_t{}); + auto c = vector_t (ublas::product(nc), value_t{0}); - auto a = vector_type(product(na), 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 (product(nb), value_type{1} ); - auto wb = strides_type (nb); + ublas::ttm(m+1, ublas::size(na), + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); - auto nc = na; - auto wc = strides_type (nc); - auto c = vector_type (product(nc), value_type{0}); + auto v = value_t(na[m]); + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); - 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( static_cast< inner_type_t >(na[m]) ) * a[i] ); +// for(auto i = 0u; i < c.size(); ++i) +// BOOST_CHECK_EQUAL( c[i] , value_t( static_cast< inner_type_t >(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 vector_type = std::vector; - using extents_type = ublas::extents<>; - using strides_type = ublas::strides_t; - using size_type = typename strides_type::value_type; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using vector_t = std::vector; + using extents_t = ublas::extents<>; + using extents_base_t = typename extents_t::base_type; - auto compute_factorial = [](auto const& p){ - auto f = 1ul; - for(auto i = 1u; i <= p; ++i) - f *= i; - return f; - }; + 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 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; - }; + auto permute_extents = [](auto const& pi, auto const& na){ + auto nb_base = na.base(); + assert(pi.size() == ublas::size(na)); + for(auto j = 0u; j < pi.size(); ++j) + nb_base[j] = na[pi[j]-1]; + return extents_t(nb_base); + }; - // left-hand and right-hand side have the - // the same number of elements + // 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 + // computing the inner product with + // different permutation tuples for + // right-hand side - for(auto const& na : extents) { + for(auto const& na : extents) { - auto wa = strides_type(na); - auto a = vector_type(product(na), value_type{2}); - auto pa = na.size(); - auto pia = std::vector(pa); - std::iota( pia.begin(), pia.end(), 1 ); + auto wa = ublas::to_strides(na,layout_t{}); + auto a = vector_t(ublas::product(na), value_t{2}); + auto pa = ublas::size(na); + auto pia = std::vector(pa); + std::iota( pia.begin(), pia.end(), std::size_t{1} ); - auto pib = pia; - auto pib_inv = compute_inverse_permutation(pib); + auto pib = pia; + auto pib_inv = compute_inverse_permutation(pib); - auto f = compute_factorial(pa); + auto f = compute_factorial(pa); - // for the number of possible permutations - // only permutation tuple pib is changed. - for(auto i = 0u; i < f; ++i) { + // 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(product(nb), value_type{3}); - auto pb = nb.size(); + auto nb = permute_extents( pib, na ); + auto wb = ublas::to_strides(nb,layout_t{}); + auto b = vector_t(ublas::product(nb), value_t{3}); + auto pb = ublas::size(nb); - // the number of contractions is changed. - for( auto q = size_type(0); q <= pa; ++q) { + // the number of contractions is changed. + for(auto q = std::size_t{0}; q <= pa; ++q) { - auto r = pa - q; - auto s = pb - 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 pc = r+s > 0 ? std::max(std::size_t{r+s},std::size_t{2}) : std::size_t{2}; - auto nc_base = std::vector( pc , 1 ); + auto nc_base = extents_base_t(pc,std::size_t{1}); - for(auto j = 0u; j < r; ++j) - nc_base[ j ] = na[ pia[j]-1 ]; + for(auto j = 0u; j < r; ++j) + nc_base[j] = na[pia[j]-1]; - for(auto j = 0u; j < s; ++j) - nc_base[ r + j ] = nb[ pib_inv[j]-1 ]; + for(auto j = 0u; j < s; ++j) + nc_base[r+j] = nb[ pib_inv[j]-1 ]; - auto nc = extents_type ( nc_base ); - auto wc = strides_type ( nc ); - auto c = vector_type ( product(nc), value_type(0) ); + auto nc = extents_t ( nc_base ); + auto wc = ublas::to_strides(nc,layout_t{}); + auto c = vector_t ( ublas::product(nc), value_t(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()); + 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 j = r; j < pa; ++j) - acc *= value_type( static_cast< inner_type_t >(na[pia[j]-1]) ); + auto acc = std::size_t{1}; + for(auto j = r; j < pa; ++j) + acc *= na[pia[j]-1]; - for(auto j = 0ul; j < c.size(); ++j) - BOOST_CHECK_EQUAL( c[j] , acc * a[0] * b[0] ); + auto v = value_t(acc)*a[0]*b[0]; - } + BOOST_CHECK( std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v; } ) ); - std::next_permutation(pib.begin(), pib.end()); - pib_inv = compute_inverse_permutation(pib); - } + } + + 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 vector_type = std::vector; - using extents_type = ublas::extents<>; - using strides_type = ublas::strides_t; - using size_type = typename strides_type::value_type; - - // left-hand and right-hand side have the - // the same number of elements + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using vector_t = std::vector; + using extents_t = ublas::extents<>; + using extents_base_t = typename extents_t::base_type; - // computing the inner product with - // different permutation tuples for - // right-hand side + // left-hand and right-hand side have the + // the same number of elements - for(auto const& na : extents) { + // computing the inner product with + // different permutation tuples for + // right-hand side - auto wa = strides_type(na); - auto a = vector_type(product(na), value_type{2}); - auto pa = na.size(); + for(auto const& na : extents) { - auto nb = na; - auto wb = strides_type(nb); - auto b = vector_type(product(nb), value_type{3}); - auto pb = nb.size(); + auto wa = ublas::to_strides(na,layout_t{}); + auto a = vector_t(ublas::product(na), value_t{2}); + auto pa = ublas::size(na); - // std::cout << "na = "; - // std::copy(na.begin(), na.end(), std::ostream_iterator(std::cout, " ")); - // std::cout << std::endl; + auto const& nb = na; + auto wb = ublas::to_strides(nb,layout_t{}); + auto b = vector_t(ublas::product(nb), value_t{3}); + auto pb = ublas::size(nb); - // std::cout << "nb = "; - // std::copy(nb.begin(), nb.end(), std::ostream_iterator(std::cout, " ")); - // std::cout << std::endl; + // std::cout << "na = "; + // std::copy(na.begin(), na.end(), std::ostream_iterator(std::cout, " ")); + // std::cout << std::endl; + // std::cout << "nb = "; + // std::copy(nb.begin(), nb.end(), std::ostream_iterator(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; + // the number of contractions is changed. + for( auto q = std::size_t{0}; q <= pa; ++q) { // pa - auto pc = r+s > 0 ? std::max(r+s, size_type(2)) : size_type(2); + auto r = pa - q; + auto s = pb - q; - auto nc_base = std::vector( pc , 1 ); + auto pc = r+s > 0 ? std::max(std::size_t{r+s},std::size_t{2}) : std::size_t{2}; - for(auto i = 0u; i < r; ++i) - nc_base[ i ] = na[ i ]; + auto nc_base = extents_base_t(pc,std::size_t{1}); - for(auto i = 0u; i < s; ++i) - nc_base[ r + i ] = nb[ i ]; + for(auto i = 0u; i < r; ++i) + nc_base[i] = na[i]; - auto nc = extents_type ( nc_base ); - auto wc = strides_type ( nc ); - auto c = vector_type ( product(nc), value_type{0} ); + for(auto i = 0u; i < s; ++i) + nc_base[r+i] = nb[i]; - // std::cout << "nc = "; - // std::copy(nc.begin(), nc.end(), std::ostream_iterator(std::cout, " ")); - // std::cout << std::endl; + auto nc = extents_t ( nc_base ); + auto wc = ublas::to_strides(nc,layout_t{}); + auto c = vector_t ( ublas::product(nc), value_t{0} ); - ublas::ttt(pa,pb,q, - c.data(), nc.data(), wc.data(), - a.data(), na.data(), wa.data(), - b.data(), nb.data(), wb.data()); + // std::cout << "nc = "; + // std::copy(nc.begin(), nc.end(), std::ostream_iterator(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( static_cast< inner_type_t >(na[i]) ); - for(auto i = 0u; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); + auto acc = std::size_t{1}; + for(auto i = r; i < pa; ++i) + acc *= na[i]; - } + auto v = value_t(acc)*a[0]*b[0]; + BOOST_CHECK( std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v; } ) ); } + + } } @@ -423,70 +418,68 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt, value, test_types, fixture ) 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_t,layout_type>; - using vector_type = std::vector; + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using vector_t = std::vector; + for(auto const& n : extents) { - for(auto const& n : extents) { + auto a = vector_t(ublas::product(n), value_t{2}); + auto b = vector_t(ublas::product(n), value_t{3}); + auto w = ublas::to_strides(n,layout_t{}); - auto a = vector_type(product(n), value_type{2}); - auto b = vector_type(product(n), value_type{3}); - auto w = strides_type(n); + auto c = ublas::inner(ublas::size(n), n.data(), a.data(), w.data(), b.data(), w.data(), value_t(0)); + auto cref = std::inner_product(a.begin(), a.end(), b.begin(), value_t(0)); - 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_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::extents<>; - using strides_type = ublas::strides_t; - using vector_type = std::vector; - + namespace ublas = boost::numeric::ublas; + using value_t = typename value::first_type; + using layout_t = typename value::second_type; + using extents_t = ublas::extents<>; + using vector_t = std::vector; - for(auto const& na : extents) { - auto a = vector_type(product(na), value_type{2}); - auto wa = strides_type(na); + for(auto const& na : extents) { - for(auto const& nb : extents) { + auto a = vector_t(ublas::product(na), value_t{2}); + auto wa = ublas::to_strides(na,layout_t{}); - auto b = vector_type(product(nb), value_type{3}); - auto wb = strides_type(nb); + for(auto const& nb : extents) { - auto c = vector_type(product(nb)*product(na)); - auto nc = typename extents_type::base_type(na.size()+nb.size()); + auto b = vector_t(ublas::product(nb), value_t{3}); + auto wb = ublas::to_strides(nb,layout_t{}); - 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 c = vector_t(ublas::product(nb)*ublas::product(na)); + auto nc_base = typename extents_t::base_type(ublas::size(na)+ublas::size(nb)); - auto wc = strides_type(extents_type(nc)); + for(auto i = 0u; i < ublas::size(na); ++i) + nc_base[i] = na[i]; + for(auto i = 0u; i < ublas::size(nb); ++i) + nc_base[i+ublas::size(na)] = nb[i]; - 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()); + auto nc = extents_t(nc_base); + auto wc = ublas::to_strides(nc,layout_t{}); - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - } + ublas::outer(c.data(), ublas::size(nc), nc.data(), wc.data(), + a.data(), ublas::size(na), na.data(), wa.data(), + b.data(), ublas::size(nb), nb.data(), wb.data()); + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); } + } + } diff --git a/test/tensor/test_operators_arithmetic.cpp b/test/tensor/test_operators_arithmetic.cpp index 723fffe11..98484ccf7 100644 --- a/test/tensor/test_operators_arithmetic.cpp +++ b/test/tensor/test_operators_arithmetic.cpp @@ -17,7 +17,7 @@ #include #include "utility.hpp" -BOOST_AUTO_TEST_SUITE(test_tensor_arithmetic_operations, * boost::unit_test::depends_on("test_tensor")) +BOOST_AUTO_TEST_SUITE(test_tensor_arithmetic_operations/*, * boost::unit_test::depends_on("test_tensor")*/) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; @@ -25,22 +25,21 @@ using test_types = zip::with_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 + using extents_type = boost::numeric::ublas::extents<>; + + std::vector extents = { - } - std::vector 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 + }; }; @@ -48,10 +47,10 @@ struct fixture BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; auto check = [](auto const& e) @@ -86,11 +85,6 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, valu 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) @@ -117,10 +111,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, valu BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; auto check = [](auto const& e) @@ -180,10 +174,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_assign_arithmetic_operations, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; auto check = [](auto const& e) diff --git a/test/tensor/test_operators_comparison.cpp b/test/tensor/test_operators_comparison.cpp index 6e4932f41..b6aeb191a 100644 --- a/test/tensor/test_operators_comparison.cpp +++ b/test/tensor/test_operators_comparison.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// Copyright (c) 2018 Cem Bassoy // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -19,155 +19,155 @@ #include "utility.hpp" -BOOST_AUTO_TEST_SUITE(test_tensor_comparison, * boost::unit_test::depends_on("test_tensor")) +BOOST_AUTO_TEST_SUITE(test_tensor_comparison/*, * boost::unit_test::depends_on("test_tensor")*/) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; using test_types = zip::with_t; struct fixture { - using extents_type = boost::numeric::ublas::extents<>; - 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; + using extents_type = boost::numeric::ublas::extents<>; + 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; }; 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::dynamic_tensor; - - - 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 ); + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor_dynamic; + + + 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::dynamic_tensor; - - - 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 ); + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor_dynamic; + + + 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 ); } @@ -175,70 +175,70 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions 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::dynamic_tensor; - - - 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); + namespace ublas = boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor_dynamic; + + + 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(ublas::empty(e)) + 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); } diff --git a/test/tensor/test_static_expression_evaluation.cpp b/test/tensor/test_static_expression_evaluation.cpp index df66b1ee3..7412eef01 100644 --- a/test/tensor/test_static_expression_evaluation.cpp +++ b/test/tensor/test_static_expression_evaluation.cpp @@ -18,42 +18,42 @@ #include -BOOST_AUTO_TEST_SUITE(test_static_tensor_expression) +BOOST_AUTO_TEST_SUITE(test_tensor_static_expression) using test_types = zip>::with_t; struct fixture { - template - using extents_type = boost::numeric::ublas::static_extents; - - std::tuple< - extents_type<1,1>, // 1 - extents_type<2,3>, // 2 - extents_type<4,1,3>, // 3 - extents_type<4,2,3>, // 4 - extents_type<4,2,3,5> // 5 + template + using extents_type = boost::numeric::ublas::extents; + + std::tuple< + extents_type<1,1>, // 1 + extents_type<2,3>, // 2 + extents_type<4,1,3>, // 3 + extents_type<4,2,3>, // 4 + extents_type<4,2,3,5> // 5 > extents; }; -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_retrieve_extents, value, test_types, fixture) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_static_expression_retrieve_extents, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto uplus1 = [](auto const& a){return a + value_type(1);}; + auto uplus2 = [](auto const& a){return value_type(2) + a;}; auto bplus = std::plus {}; auto bminus = std::minus{}; - for_each_tuple(extents, [&](auto const&, auto& e){ + for_each_in_tuple(extents, [&](auto const& /*unused*/, auto& e){ using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; - auto t = tensor_type{}; + auto t = tensor_type(); auto v = value_type{}; for(auto& tt: t){ tt = v; v+=value_type{1}; } @@ -82,23 +82,23 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_retrieve_extents }); - for_each_tuple(extents, [&](auto I, auto& e1){ + for_each_in_tuple(extents, [&](auto I, auto& e1){ if ( I >= std::tuple_size_v - 1){ return; } using extents_type1 = std::decay_t; - using tensor_type1 = ublas::static_tensor; + using tensor_type1 = ublas::tensor_static; - for_each_tuple(extents, [&](auto J, auto& e2){ + for_each_in_tuple(extents, [&](auto J, auto& e2){ if( J != I + 1 ){ return; } using extents_type2 = std::decay_t; - using tensor_type2 = ublas::static_tensor; + using tensor_type2 = ublas::tensor_static; auto v = value_type{}; @@ -129,20 +129,20 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_retrieve_extents -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_all_extents_equal, value, test_types, fixture) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_static_expression_all_extents_equal, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_type(1) ); - auto uplus2 = std::bind( std::plus{}, value_type(2), std::placeholders::_2 ); + auto uplus1 = [](auto const& a){return a + value_type(1);}; + auto uplus2 = [](auto const& a){return value_type(2) + a;}; auto bplus = std::plus {}; auto bminus = std::minus{}; - for_each_tuple(extents, [&](auto const&, auto& e){ + for_each_in_tuple(extents, [&](auto const& /*unused*/, auto& e){ using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto t = tensor_type{}; @@ -175,23 +175,23 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_all_extents_equa }); - for_each_tuple(extents, [&](auto I, auto& e1){ + for_each_in_tuple(extents, [&](auto I, auto& e1){ if ( I >= std::tuple_size_v - 1){ return; } using extents_type1 = std::decay_t; - using tensor_type1 = ublas::static_tensor; + using tensor_type1 = ublas::tensor_static; - for_each_tuple(extents, [&](auto J, auto& e2){ + for_each_in_tuple(extents, [&](auto J, auto& e2){ if( J != I + 1 ){ return; } using extents_type2 = std::decay_t; - using tensor_type2 = ublas::static_tensor; + using tensor_type2 = ublas::tensor_static; auto v = value_type{}; @@ -217,4 +217,4 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_static_tensor_expression_all_extents_equa } -BOOST_AUTO_TEST_SUITE_END(); +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_extents.cpp b/test/tensor/test_static_extents.cpp index e44040083..c92794886 100644 --- a/test/tensor/test_static_extents.cpp +++ b/test/tensor/test_static_extents.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -10,477 +10,356 @@ // Google and Fraunhofer IOSB, Ettlingen, Germany // -#include +#include #include #include #include "utility.hpp" BOOST_AUTO_TEST_SUITE(test_static_extents) -template -using extents = boost::numeric::ublas::basic_static_extents; -BOOST_AUTO_TEST_CASE(test_static_extents_ctor) { - using namespace boost::numeric; +struct fixture +{ + template + using extents = boost::numeric::ublas::extents; + + extents<> e0 {}; + extents<1> e1 {}; + extents<1, 1> e11 {}; + extents<2, 1> e21 {}; + extents<1, 2> e12 {}; + extents<2, 3> e23 {}; + extents<2, 1, 1> e211 {}; + extents<2, 3, 1> e231 {}; + extents<1, 2, 3> e123 {}; + extents<4, 2, 3> e423 {}; + extents<1, 2, 3, 4> e1234 {}; + extents<4, 2, 1, 3> e4213 {}; + extents<1, 2, 3, 4, 1> e12341 {}; + extents<4, 2, 1, 3, 1> e42131 {}; + extents<1, 4, 2, 1, 3, 1> e142131 {}; +}; - auto e0 = extents<>{}; - BOOST_CHECK(e0.empty()); - BOOST_CHECK_EQUAL(e0.size(), 0); +BOOST_FIXTURE_TEST_CASE(test_extents_static_ctor, fixture, + *boost::unit_test::label("extents_static") *boost::unit_test::label("ctor")) +{ - auto e1 = extents<1, 2>{}; - BOOST_CHECK(!e1.empty()); - BOOST_CHECK_EQUAL(e1.size(), 2); + namespace ublas = boost::numeric::ublas; + + BOOST_CHECK( ublas::empty( e0)); + BOOST_CHECK(! ublas::empty( e1)); + BOOST_CHECK(! ublas::empty( e11)); + BOOST_CHECK(! ublas::empty( e12)); + BOOST_CHECK(! ublas::empty( e21)); + BOOST_CHECK(! ublas::empty( e23)); + BOOST_CHECK(! ublas::empty( e211)); + BOOST_CHECK(! ublas::empty( e123)); + BOOST_CHECK(! ublas::empty( e423)); + BOOST_CHECK(! ublas::empty( e1234)); + BOOST_CHECK(! ublas::empty( e4213)); + BOOST_CHECK(! ublas::empty(e142131)); + + BOOST_CHECK_EQUAL( ublas::size( e0),0); + BOOST_CHECK_EQUAL( ublas::size( e1),1); + BOOST_CHECK_EQUAL( ublas::size( e11),2); + BOOST_CHECK_EQUAL( ublas::size( e12),2); + BOOST_CHECK_EQUAL( ublas::size( e21),2); + BOOST_CHECK_EQUAL( ublas::size( e23),2); + BOOST_CHECK_EQUAL( ublas::size( e211),3); + BOOST_CHECK_EQUAL( ublas::size( e123),3); + BOOST_CHECK_EQUAL( ublas::size( e423),3); + BOOST_CHECK_EQUAL( ublas::size( e1234),4); + BOOST_CHECK_EQUAL( ublas::size( e4213),4); + BOOST_CHECK_EQUAL( ublas::size(e142131),6); + + + BOOST_CHECK_EQUAL( ublas::size_v,0); + BOOST_CHECK_EQUAL( ublas::size_v,1); + BOOST_CHECK_EQUAL( ublas::size_v,2); + BOOST_CHECK_EQUAL( ublas::size_v,2); + BOOST_CHECK_EQUAL( ublas::size_v,2); + BOOST_CHECK_EQUAL( ublas::size_v,2); + BOOST_CHECK_EQUAL( ublas::size_v,3); + BOOST_CHECK_EQUAL( ublas::size_v,3); + BOOST_CHECK_EQUAL( ublas::size_v,3); + BOOST_CHECK_EQUAL( ublas::size_v,4); + BOOST_CHECK_EQUAL( ublas::size_v,4); + BOOST_CHECK_EQUAL( ublas::size_v,6); - auto e2 = extents<2, 3>{}; - BOOST_CHECK(!e2.empty()); - BOOST_CHECK_EQUAL(e2.size(), 2); +} - auto e3 = extents<4, 2, 3>{}; // 7 - BOOST_CHECK(!e3.empty()); - BOOST_CHECK_EQUAL(e3.size(), 3); +BOOST_FIXTURE_TEST_CASE(test_extents_static_product, fixture, + *boost::unit_test::label("extents_static") *boost::unit_test::label("product")) +{ + + namespace ublas = boost::numeric::ublas; + + BOOST_CHECK_EQUAL(ublas::product( e0), 0); + //FIXME: BOOST_CHECK_EQUAL(ublas::product( e1), 1); + BOOST_CHECK_EQUAL(ublas::product( e11), 1); + BOOST_CHECK_EQUAL(ublas::product( e12), 2); + BOOST_CHECK_EQUAL(ublas::product( e21), 2); + BOOST_CHECK_EQUAL(ublas::product( e23), 6); + BOOST_CHECK_EQUAL(ublas::product( e211), 2); + BOOST_CHECK_EQUAL(ublas::product( e123), 6); + BOOST_CHECK_EQUAL(ublas::product( e423), 24); + BOOST_CHECK_EQUAL(ublas::product( e1234), 24); + BOOST_CHECK_EQUAL(ublas::product( e4213), 24); + BOOST_CHECK_EQUAL(ublas::product(e142131), 24); + + + BOOST_CHECK_EQUAL(ublas::product_v, 0); + BOOST_CHECK_EQUAL(ublas::product_v, 1); + BOOST_CHECK_EQUAL(ublas::product_v, 1); + BOOST_CHECK_EQUAL(ublas::product_v, 2); + BOOST_CHECK_EQUAL(ublas::product_v, 2); + BOOST_CHECK_EQUAL(ublas::product_v, 6); + BOOST_CHECK_EQUAL(ublas::product_v, 2); + BOOST_CHECK_EQUAL(ublas::product_v, 6); + BOOST_CHECK_EQUAL(ublas::product_v, 24); + BOOST_CHECK_EQUAL(ublas::product_v, 24); + BOOST_CHECK_EQUAL(ublas::product_v, 24); + BOOST_CHECK_EQUAL(ublas::product_v, 24); } -struct fixture { - fixture() = default; - extents<> e0{}; // 0 - extents<1, 2, 3, 4> e1{}; // 1 - extents<1, 2, 3> e2{}; // 2 - extents<4, 2, 3> e3{}; // 3 - extents<4, 2, 1, 3> e4{}; // 4 - extents<1, 4, 2, 1, 3, 1> e5{}; // 5 +BOOST_FIXTURE_TEST_CASE(test_static_extents_access, fixture, + *boost::unit_test::label("extents_static") *boost::unit_test::label("access")) +{ + namespace ublas = boost::numeric::ublas; - std::tuple< - extents<> - > rank_0_extents; + BOOST_REQUIRE_EQUAL( ublas::size_v,0); + BOOST_REQUIRE_EQUAL( ublas::size_v,1); + BOOST_REQUIRE_EQUAL( ublas::size_v,2); + BOOST_REQUIRE_EQUAL( ublas::size_v,2); + BOOST_REQUIRE_EQUAL( ublas::size_v,2); + BOOST_REQUIRE_EQUAL( ublas::size_v,2); + BOOST_REQUIRE_EQUAL( ublas::size_v,3); + BOOST_REQUIRE_EQUAL( ublas::size_v,3); + BOOST_REQUIRE_EQUAL( ublas::size_v,3); + BOOST_REQUIRE_EQUAL( ublas::size_v,4); + BOOST_REQUIRE_EQUAL( ublas::size_v,4); + BOOST_REQUIRE_EQUAL( ublas::size_v,6); - std::tuple< - extents<1>, - extents<2> - > rank_1_extents; + + BOOST_CHECK_EQUAL((ublas::get_v), 1); + + BOOST_CHECK_EQUAL((ublas::get_v), 1); + BOOST_CHECK_EQUAL((ublas::get_v), 1); + + BOOST_CHECK_EQUAL((ublas::get_v), 1); + BOOST_CHECK_EQUAL((ublas::get_v), 2); + + BOOST_CHECK_EQUAL((ublas::get_v), 2); + BOOST_CHECK_EQUAL((ublas::get_v), 1); + + BOOST_CHECK_EQUAL((ublas::get_v), 2); + BOOST_CHECK_EQUAL((ublas::get_v), 3); + + BOOST_CHECK_EQUAL((ublas::get_v), 2); + BOOST_CHECK_EQUAL((ublas::get_v), 1); + BOOST_CHECK_EQUAL((ublas::get_v), 1); + + BOOST_CHECK_EQUAL((ublas::get_v), 1); + BOOST_CHECK_EQUAL((ublas::get_v), 2); + BOOST_CHECK_EQUAL((ublas::get_v), 3); + + BOOST_CHECK_EQUAL((ublas::get_v), 4); + BOOST_CHECK_EQUAL((ublas::get_v), 2); + BOOST_CHECK_EQUAL((ublas::get_v), 3); + + BOOST_CHECK_EQUAL((ublas::get_v), 1); + BOOST_CHECK_EQUAL((ublas::get_v), 2); + BOOST_CHECK_EQUAL((ublas::get_v), 3); + BOOST_CHECK_EQUAL((ublas::get_v), 4); + + BOOST_CHECK_EQUAL((ublas::get_v), 4); + BOOST_CHECK_EQUAL((ublas::get_v), 2); + BOOST_CHECK_EQUAL((ublas::get_v), 1); + BOOST_CHECK_EQUAL((ublas::get_v), 3); + + //FIXME: BOOST_CHECK_EQUAL(e1 [0], 1); + + BOOST_CHECK_EQUAL(e11[0], 1); + BOOST_CHECK_EQUAL(e11[1], 1); + + BOOST_CHECK_EQUAL(e12[0], 1); + BOOST_CHECK_EQUAL(e12[1], 2); + + BOOST_CHECK_EQUAL(e21[0], 2); + BOOST_CHECK_EQUAL(e21[1], 1); + + BOOST_CHECK_EQUAL(e23[0], 2); + BOOST_CHECK_EQUAL(e23[1], 3); + + BOOST_CHECK_EQUAL(e211[0], 2); + BOOST_CHECK_EQUAL(e211[1], 1); + BOOST_CHECK_EQUAL(e211[2], 1); + + BOOST_CHECK_EQUAL(e123[0], 1); + BOOST_CHECK_EQUAL(e123[1], 2); + BOOST_CHECK_EQUAL(e123[2], 3); + + BOOST_CHECK_EQUAL(e423[0], 4); + BOOST_CHECK_EQUAL(e423[1], 2); + BOOST_CHECK_EQUAL(e423[2], 3); + + BOOST_CHECK_EQUAL(e1234[0], 1); + BOOST_CHECK_EQUAL(e1234[1], 2); + BOOST_CHECK_EQUAL(e1234[2], 3); + BOOST_CHECK_EQUAL(e1234[3], 4); + + BOOST_CHECK_EQUAL(e4213[0], 4); + BOOST_CHECK_EQUAL(e4213[1], 2); + BOOST_CHECK_EQUAL(e4213[2], 1); + BOOST_CHECK_EQUAL(e4213[3], 3); +} + +struct fixture_second +{ + template + using extents = boost::numeric::ublas::extents; std::tuple< - extents<1,1>, - extents<2,2> - > rank_2_extents; + extents<> + > empty; std::tuple< - extents<1>, + //FIXME: extents<1>, extents<1,1>, extents<1,1,1>, extents<1,1,1,1> - > scalars; + > scalars; std::tuple< extents<1,2>, - extents<1,3,1>, + extents<2,1>, + extents<1,2,1>, + extents<2,1,1>, extents<1,4,1,1>, - extents<5,1,1,1,1>, - extents<6,1,1,1,1,1> - > vectors; + extents<5,1,1,1,1> + > vectors; std::tuple< extents<2,3>, extents<3,2,1>, extents<4,4,1,1>, extents<6,6,1,1,1,1> - > matrices; + > matrices; std::tuple< - extents<3,3,3>, - extents<4,4,4,1>, - extents<5,5,5,1,1>, + extents<1,2,3>, + extents<1,2,3>, + extents<1,2,3,1>, + extents<4,2,3>, + extents<4,2,3,1>, + extents<4,2,3,1,1>, extents<6,6,6,1,1,1>, extents<6,6,1,1,1,6> - > tensors; + > tensors; }; -BOOST_FIXTURE_TEST_CASE(test_static_extents_product, fixture, - *boost::unit_test::label("static_extents") * - boost::unit_test::label("product")) { - - using namespace boost::numeric::ublas; - - auto p0 = product(e0); // {} - auto p1 = product(e1); // {1,2,3,4} - auto p2 = product(e2); // {1,2,3} - auto p3 = product(e3); // {4,2,3} - auto p4 = product(e4); // {4,2,1,3} - auto p5 = product(e5); // {1,4,2,1,3,1} - - auto sp0 = product(e0); // {} - auto sp1 = product(e1); // {1,2,3,4} - auto sp2 = product(e2); // {1,2,3} - auto sp3 = product(e3); // {4,2,3} - auto sp4 = product(e4); // {4,2,1,3} - auto sp5 = product(e5); // {1,4,2,1,3,1} - - BOOST_CHECK_EQUAL(p0, 0); - BOOST_CHECK_EQUAL(p1, 24); - BOOST_CHECK_EQUAL(p2, 6); - BOOST_CHECK_EQUAL(p3, 24); - BOOST_CHECK_EQUAL(p4, 24); - BOOST_CHECK_EQUAL(p5, 24); - - BOOST_CHECK_EQUAL(sp0, 0); - BOOST_CHECK_EQUAL(sp1, 24); - BOOST_CHECK_EQUAL(sp2, 6); - BOOST_CHECK_EQUAL(sp3, 24); - BOOST_CHECK_EQUAL(sp4, 24); - BOOST_CHECK_EQUAL(sp5, 24); -} -BOOST_FIXTURE_TEST_CASE(test_static_extents_access, fixture, - *boost::unit_test::label("static_extents") * - boost::unit_test::label("access")) { - using namespace boost::numeric; - - BOOST_CHECK_EQUAL(e0.size(), 0); - BOOST_CHECK(e0.empty()); - - BOOST_REQUIRE_EQUAL(e1.size(), 4); - BOOST_REQUIRE_EQUAL(e2.size(), 3); - BOOST_REQUIRE_EQUAL(e3.size(), 3); - BOOST_REQUIRE_EQUAL(e4.size(), 4); - BOOST_REQUIRE_EQUAL(e5.size(), 6); - - BOOST_CHECK_EQUAL(e1[0], 1); - BOOST_CHECK_EQUAL(e1[1], 2); - BOOST_CHECK_EQUAL(e1[2], 3); - BOOST_CHECK_EQUAL(e1[3], 4); - - BOOST_CHECK_EQUAL(e2[0], 1); - BOOST_CHECK_EQUAL(e2[1], 2); - BOOST_CHECK_EQUAL(e2[2], 3); - - BOOST_CHECK_EQUAL(e3[0], 4); - BOOST_CHECK_EQUAL(e3[1], 2); - BOOST_CHECK_EQUAL(e3[2], 3); - - BOOST_CHECK_EQUAL(e4[0], 4); - BOOST_CHECK_EQUAL(e4[1], 2); - BOOST_CHECK_EQUAL(e4[2], 1); - BOOST_CHECK_EQUAL(e4[3], 3); - - BOOST_CHECK_EQUAL(e5[0], 1); - BOOST_CHECK_EQUAL(e5[1], 4); - BOOST_CHECK_EQUAL(e5[2], 2); - BOOST_CHECK_EQUAL(e5[3], 1); - BOOST_CHECK_EQUAL(e5[4], 3); - BOOST_CHECK_EQUAL(e5[5], 1); -} +BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture_second, + *boost::unit_test::label("extents_static") *boost::unit_test::label("is_scalar_vector_matrix_tensor")) { -BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture, - *boost::unit_test::label("static_extents") * - boost::unit_test::label("query")) { - - using namespace boost::numeric::ublas; - // e0 ==> {} - // e1 ==> {0,0,0,0} - // e2 ==> {1,2,3} - // e3 ==> {4,2,3} - // e4 ==> {4,2,1,3} - // e5 ==> {1,4,2,1,3,1} - - BOOST_CHECK( e0.empty( )); - BOOST_CHECK( !is_scalar( e0)); - BOOST_CHECK( !is_vector( e0)); - BOOST_CHECK( !is_matrix( e0)); - BOOST_CHECK( !is_tensor( e0)); - BOOST_CHECK( !is_scalar( e0)); - BOOST_CHECK( !is_vector( e0)); - BOOST_CHECK( !is_matrix( e0)); - BOOST_CHECK( !is_tensor( e0)); - - BOOST_CHECK( ! e1.empty( ) ); - BOOST_CHECK( !is_scalar( e1) ); - BOOST_CHECK( !is_vector( e1) ); - BOOST_CHECK( !is_matrix( e1) ); - BOOST_CHECK( is_tensor( e1) ); - BOOST_CHECK( !is_scalar( e1) ); - BOOST_CHECK( !is_vector( e1) ); - BOOST_CHECK( !is_matrix( e1) ); - BOOST_CHECK( is_tensor( e1) ); - - BOOST_CHECK( ! e2.empty( ) ); - BOOST_CHECK( !is_scalar( e2) ); - BOOST_CHECK( !is_vector( e2) ); - BOOST_CHECK( !is_matrix( e2) ); - BOOST_CHECK( is_tensor( e2) ); - BOOST_CHECK( !is_scalar( e2) ); - BOOST_CHECK( !is_vector( e2) ); - BOOST_CHECK( !is_matrix( e2) ); - BOOST_CHECK( is_tensor( e2) ); - - BOOST_CHECK( ! e3.empty( ) ); - BOOST_CHECK( !is_scalar( e3) ); - BOOST_CHECK( !is_vector( e3) ); - BOOST_CHECK( !is_matrix( e3) ); - BOOST_CHECK( is_tensor( e3) ); - BOOST_CHECK( !is_scalar( e3) ); - BOOST_CHECK( !is_vector( e3) ); - BOOST_CHECK( !is_matrix( e3) ); - BOOST_CHECK( is_tensor( e3) ); - - BOOST_CHECK( ! e4.empty( ) ); - BOOST_CHECK( !is_scalar( e4) ); - BOOST_CHECK( !is_vector( e4) ); - BOOST_CHECK( !is_matrix( e4) ); - BOOST_CHECK( is_tensor( e4) ); - BOOST_CHECK( !is_scalar( e4) ); - BOOST_CHECK( !is_vector( e4) ); - BOOST_CHECK( !is_matrix( e4) ); - BOOST_CHECK( is_tensor( e4) ); - - BOOST_CHECK( ! e5.empty( ) ); - BOOST_CHECK( !is_scalar( e5) ); - BOOST_CHECK( !is_vector( e5) ); - BOOST_CHECK( !is_matrix( e5) ); - BOOST_CHECK( is_tensor( e5) ); - BOOST_CHECK( !is_scalar( e5) ); - BOOST_CHECK( !is_vector( e5) ); - BOOST_CHECK( !is_matrix( e5) ); - BOOST_CHECK( is_tensor( e5) ); - - boost::numeric::ublas::basic_static_extents e14; - BOOST_CHECK( ! e14.empty( ) ); - BOOST_CHECK( ! is_scalar(e14) ); - BOOST_CHECK( is_vector(e14) ); - BOOST_CHECK( ! is_matrix(e14) ); - BOOST_CHECK( ! is_tensor(e14) ); - BOOST_CHECK( ! is_scalar(e14) ); - BOOST_CHECK( is_vector(e14) ); - BOOST_CHECK( ! is_matrix(e14) ); - BOOST_CHECK( ! is_tensor(e14) ); - - - for_each_tuple(rank_0_extents,[](auto const&, auto& e){ - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - }); + namespace ublas = boost::numeric::ublas; + for_each_in_tuple(scalars,[](auto const& /*unused*/, auto const& e){ + BOOST_CHECK( ublas::is_scalar(e) ); + BOOST_CHECK( ublas::is_vector(e) ); + BOOST_CHECK( ublas::is_matrix(e) ); + BOOST_CHECK( !ublas::is_tensor(e) ); - for_each_tuple(rank_1_extents,[](auto const& I, auto const& e){ - if( I == 0 ){ - BOOST_CHECK( is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - }else{ - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - } - }); + BOOST_CHECK( ublas::is_scalar_v); + BOOST_CHECK( ublas::is_vector_v); + BOOST_CHECK( ublas::is_matrix_v); + BOOST_CHECK( !ublas::is_tensor_v); - for_each_tuple(rank_2_extents,[](auto const& I, auto const& e){ - if( I == 0 ){ - BOOST_CHECK( is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - }else{ - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - } }); - for_each_tuple(scalars,[](auto const&, auto& e){ - BOOST_CHECK( is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - }); + for_each_in_tuple(vectors,[](auto const& /*unused*/, auto& e){ + BOOST_CHECK( !ublas::is_scalar(e) ); + BOOST_CHECK( ublas::is_vector(e) ); + BOOST_CHECK( ublas::is_matrix(e) ); + BOOST_CHECK( !ublas::is_tensor(e) ); - for_each_tuple(vectors,[](auto const&, auto& e){ - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); + BOOST_CHECK( !ublas::is_scalar_v); + BOOST_CHECK( ublas::is_vector_v); + BOOST_CHECK( ublas::is_matrix_v); + BOOST_CHECK( !ublas::is_tensor_v); }); - for_each_tuple(matrices,[](auto const&, auto& e){ - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( is_matrix(e) ); - BOOST_CHECK( !is_tensor(e) ); - - }); + for_each_in_tuple(matrices,[](auto const& /*unused*/, auto& e){ + BOOST_CHECK( !ublas::is_scalar(e) ); + BOOST_CHECK( !ublas::is_vector(e) ); + BOOST_CHECK( ublas::is_matrix(e) ); + BOOST_CHECK( !ublas::is_tensor(e) ); - for_each_tuple(tensors,[](auto const&, auto& e){ - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( is_tensor(e) ); - BOOST_CHECK( !is_scalar(e) ); - BOOST_CHECK( !is_vector(e) ); - BOOST_CHECK( !is_matrix(e) ); - BOOST_CHECK( is_tensor(e) ); + BOOST_CHECK( !ublas::is_scalar_v); + BOOST_CHECK( !ublas::is_vector_v); + BOOST_CHECK( ublas::is_matrix_v); + BOOST_CHECK( !ublas::is_tensor_v); }); -} + for_each_in_tuple(tensors,[](auto const& /*unused*/, auto& e){ + BOOST_CHECK( !ublas::is_scalar(e) ); + BOOST_CHECK( !ublas::is_vector(e) ); + BOOST_CHECK( !ublas::is_matrix(e) ); + BOOST_CHECK( ublas::is_tensor(e) ); -BOOST_FIXTURE_TEST_CASE(test_static_extents_valid, fixture, *boost::unit_test::label("static_extents") *boost::unit_test::label("valid")) -{ - using namespace boost::numeric::ublas; - for_each_tuple(rank_0_extents,[](auto const&, auto& e){ - BOOST_CHECK(!is_valid(e)); - BOOST_CHECK(!is_valid(e)); + BOOST_CHECK( !ublas::is_scalar_v); + BOOST_CHECK( !ublas::is_vector_v); + BOOST_CHECK( !ublas::is_matrix_v); + BOOST_CHECK( ublas::is_tensor_v); }); - for_each_tuple(rank_1_extents,[](auto const& I, auto const& e){ - if( I== 0 ){ - BOOST_CHECK(is_valid(e)); - }else{ - BOOST_CHECK(!is_valid(e)); - BOOST_CHECK(!is_valid(e)); - } - }); - - for_each_tuple(rank_2_extents,[](auto const&, auto& e){ - BOOST_CHECK(is_valid(e)); - BOOST_CHECK(is_valid(e)); - }); - - for_each_tuple(scalars,[](auto const&, auto& e){ - BOOST_CHECK(is_valid(e)); - BOOST_CHECK(is_valid(e)); - }); - - for_each_tuple(vectors,[](auto const&, auto& e){ - BOOST_CHECK(is_valid(e)); - BOOST_CHECK(is_valid(e)); - }); - - for_each_tuple(matrices,[](auto const&, auto& e){ - BOOST_CHECK(is_valid(e)); - BOOST_CHECK(is_valid(e)); - }); - - for_each_tuple(tensors,[](auto const&, auto& e){ - BOOST_CHECK(is_valid(e)); - BOOST_CHECK(is_valid(e)); - }); } -BOOST_FIXTURE_TEST_CASE(test_static_extents_comparsion_operator, fixture, *boost::unit_test::label("static_extents") *boost::unit_test::label("comparsion_operator")) +BOOST_FIXTURE_TEST_CASE(test_static_extents_valid, fixture_second, + *boost::unit_test::label("extents_extents") *boost::unit_test::label("valid")) { + namespace ublas = boost::numeric::ublas; - auto const compare_extents = [](auto const& e1, auto const& e2){ - if(e1.size() != e2.size()) return false; - for(auto i = 0ul ; i < e1.size(); i++){ - if(e1[i] != e2[i]){ - return false; - } - } - return true; - }; - - for_each_tuple(rank_0_extents,[&](auto const&, auto const& e1){ - for_each_tuple(rank_1_extents,[&](auto const&, auto const& e2){ - BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); - }); - }); +//FIXME: BOOST_CHECK(!ublas::is_valid (extents<0>{}) ); +//FIXME: BOOST_CHECK( ublas::is_valid (extents<2>{}) ); +//FIXME: BOOST_CHECK( ublas::is_valid (extents<3>{}) ); - for_each_tuple(rank_1_extents,[&](auto const&, auto const& e1){ - for_each_tuple(rank_1_extents,[&](auto const&, auto const& e2){ - BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); - }); - }); + BOOST_CHECK(!ublas::is_valid_v> ); + BOOST_CHECK( ublas::is_valid_v> ); + BOOST_CHECK( ublas::is_valid_v> ); - for_each_tuple(rank_1_extents,[&](auto const&, auto const& e1){ - for_each_tuple(rank_2_extents,[&](auto const&, auto const& e2){ - BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); - }); - }); - - for_each_tuple(scalars,[&](auto const&, auto const& e1){ - for_each_tuple(scalars,[&](auto const&, auto const& e2){ - BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); - }); - }); - - for_each_tuple(scalars,[&](auto const&, auto const& e1){ - for_each_tuple(vectors,[&](auto const&, auto const& e2){ - BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); - }); - }); - for_each_tuple(scalars,[&](auto const&, auto const& e1){ - for_each_tuple(matrices,[&](auto const&, auto const& e2){ - BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); - }); - }); + for_each_in_tuple(scalars ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid (e) ); }); + for_each_in_tuple(vectors ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid (e) ); }); + for_each_in_tuple(matrices ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid (e) ); }); + for_each_in_tuple(tensors ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid (e) ); }); - for_each_tuple(scalars,[&](auto const&, auto const& e1){ - for_each_tuple(tensors,[&](auto const&, auto const& e2){ - BOOST_CHECK(compare_extents(e1,e2) == (e1 == e2)); - }); - }); + for_each_in_tuple(scalars ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid_v ); }); + for_each_in_tuple(vectors ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid_v ); }); + for_each_in_tuple(matrices ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid_v ); }); + for_each_in_tuple(tensors ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid_v ); }); } -BOOST_FIXTURE_TEST_CASE(test_static_extents_squeeze, fixture, *boost::unit_test::label("static_extents") *boost::unit_test::label("squeeze")) -{ - auto e_sq2 = squeeze(e2 ) ;//==> {2,3} - auto e_sq3 = squeeze(e3 ) ;//==> {4,2,3} - auto e_sq4 = squeeze(e4 ) ;//==> {4,2,3} - auto e_sq5 = squeeze(e5 ) ;//==> {4,2,3} - - BOOST_CHECK( (e_sq2 == extents<2,3>{}) ); - BOOST_CHECK( (e_sq3 == extents<4,2,3>{}) ); - - BOOST_CHECK( (e_sq4 == extents<4,2,3>{}) ); - BOOST_CHECK( (e_sq5 == extents<4,2,3>{}) ); -} - -BOOST_AUTO_TEST_CASE(test_static_extents_exception) +BOOST_FIXTURE_TEST_CASE(test_static_extents_comparsion_operator, fixture, + *boost::unit_test::label("extents_static") *boost::unit_test::label("equals")) { - using namespace boost::numeric::ublas; - - basic_static_extents e1; - for(auto i = e1.size(); i < 3; i++){ - BOOST_REQUIRE_THROW( (void)e1.at(i),std::out_of_range ); - } - - BOOST_REQUIRE_THROW((void)e1.at(std::numeric_limits::max()),std::out_of_range); + namespace ublas = boost::numeric::ublas; + + BOOST_CHECK( e0 == e0 ); + BOOST_CHECK( e1 == e1 ); + BOOST_CHECK( e11 == e11 ); + BOOST_CHECK( e21 == e21 ); + BOOST_CHECK( e12 == e12 ); + BOOST_CHECK( e23 == e23 ); + BOOST_CHECK( e231 == e231 ); + BOOST_CHECK( e211 == e211 ); + BOOST_CHECK( e123 == e123 ); + BOOST_CHECK( e423 == e423 ); + BOOST_CHECK( e1234 == e1234 ); + BOOST_CHECK( e4213 == e4213 ); + BOOST_CHECK( e142131 == e142131 ); } diff --git a/test/tensor/test_static_operators_arithmetic.cpp b/test/tensor/test_static_operators_arithmetic.cpp index 97a75cc5d..71e1447ad 100644 --- a/test/tensor/test_static_operators_arithmetic.cpp +++ b/test/tensor/test_static_operators_arithmetic.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,7 +18,7 @@ #include #include "utility.hpp" -BOOST_AUTO_TEST_SUITE(test_static_tensor_arithmetic_operations) +BOOST_AUTO_TEST_SUITE(test_tensor_static_arithmetic_operations) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; @@ -27,9 +27,9 @@ using test_types = zip::with_t - using extents_type = boost::numeric::ublas::static_extents; + using extents_type = boost::numeric::ublas::extents; - fixture() {} + fixture() = default; std::tuple< extents_type<1,1>, // 1 @@ -44,15 +44,15 @@ struct fixture BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) + auto check = [](auto const& /*unused*/, auto& e) { using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto t = tensor_type (); auto t2 = tensor_type (); auto r = tensor_type (); @@ -99,22 +99,22 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, valu BOOST_CHECK_EQUAL ( r(i), 1 ); }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) + auto check = [](auto const& /*unused*/, auto& e) { using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto t = tensor_type (); auto t2 = tensor_type (); auto v = value_type {}; @@ -154,7 +154,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } @@ -163,15 +163,15 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_assign_arithmetic_operations, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) + auto check = [](auto const& /*unused*/, auto& e) { using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto t = tensor_type (); auto t2 = tensor_type (); auto r = tensor_type (); @@ -235,7 +235,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_assign_arithmetic_operations, valu BOOST_CHECK_EQUAL ( p(i), r(i) ); }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } diff --git a/test/tensor/test_static_operators_comparison.cpp b/test/tensor/test_static_operators_comparison.cpp index 045cea23a..9010482d0 100644 --- a/test/tensor/test_static_operators_comparison.cpp +++ b/test/tensor/test_static_operators_comparison.cpp @@ -17,17 +17,18 @@ #include #include "utility.hpp" -BOOST_AUTO_TEST_SUITE(test_static_tensor_comparison) +BOOST_AUTO_TEST_SUITE(test_tensor_static_comparison) using double_extended = boost::multiprecision::cpp_bin_float_double_extended; using test_types = zip::with_t; struct fixture { + template - using extents_type = boost::numeric::ublas::static_extents; + using extents_type = boost::numeric::ublas::extents; - fixture() {} + fixture()= default; std::tuple< extents_type<1,1>, // 1 @@ -41,14 +42,14 @@ struct fixture { BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) + auto check = [](auto const& /*unused*/, auto& e) { using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto t = tensor_type (); auto t2 = tensor_type (); auto v = value_type {}; @@ -74,22 +75,22 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison, value, test_types, fi BOOST_CHECK( t2 >= t ); }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) + auto check = [](auto const& /*unused*/, auto& e) { using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto t = tensor_type (); auto t2 = tensor_type (); @@ -120,7 +121,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } @@ -128,20 +129,20 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_scalar, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) + for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e) { using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; BOOST_CHECK( tensor_type(value_type{2}) == tensor_type(value_type{2}) ); BOOST_CHECK( tensor_type(value_type{2}) != tensor_type(value_type{1}) ); - if(e.empty()) + if(ublas::empty(e)) return; BOOST_CHECK( !(tensor_type(2) < 2) ); @@ -189,9 +190,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_scalar, value, te BOOST_CHECK( ( 5 == tensor_type(2)+tensor_type(3)) ); BOOST_CHECK( ( 6 != tensor_type(2)+tensor_type(3)) ); - }; - - for_each_tuple(extents,check); + }); } diff --git a/test/tensor/test_static_strides.cpp b/test/tensor/test_static_strides.cpp index 72b11c58c..5f5a203e9 100644 --- a/test/tensor/test_static_strides.cpp +++ b/test/tensor/test_static_strides.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2020, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -10,10 +10,7 @@ // Google and Fraunhofer IOSB, Ettlingen, Germany // -#include -#include -#include -#include +#include #include BOOST_AUTO_TEST_SUITE(test_static_strides) @@ -21,137 +18,139 @@ BOOST_AUTO_TEST_SUITE(test_static_strides) using test_types = std::tuple; -template -using extents_type = boost::numeric::ublas::basic_static_extents; -template -using strides_type = boost::numeric::ublas::strides_t; +template +using extents = boost::numeric::ublas::extents; + +using first_order = boost::numeric::ublas::layout::first_order; +using last_order = boost::numeric::ublas::layout::last_order; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_static_strides_ctor, value, test_types) +{ + namespace ublas = boost::numeric::ublas; + + constexpr auto s11 = ublas::to_strides_v,first_order>; + constexpr auto s12 = ublas::to_strides_v,first_order>; + constexpr auto s21 = ublas::to_strides_v,first_order>; + constexpr auto s23 = ublas::to_strides_v,first_order>; + constexpr auto s231 = ublas::to_strides_v,first_order>; + constexpr auto s123 = ublas::to_strides_v,first_order>; + constexpr auto s423 = ublas::to_strides_v,first_order>; + + BOOST_CHECK_EQUAL(s11.empty(), false); + BOOST_CHECK_EQUAL(s12.empty(), false); + BOOST_CHECK_EQUAL(s21.empty(), false); + BOOST_CHECK_EQUAL(s23.empty(), false); + BOOST_CHECK_EQUAL(s231.empty(), false); + BOOST_CHECK_EQUAL(s123.empty(), false); + BOOST_CHECK_EQUAL(s423.empty(), false); + + BOOST_CHECK_EQUAL(s11.size(), 2); + BOOST_CHECK_EQUAL(s12.size(), 2); + BOOST_CHECK_EQUAL(s21.size(), 2); + BOOST_CHECK_EQUAL(s23.size(), 2); + BOOST_CHECK_EQUAL(s231.size(), 3); + BOOST_CHECK_EQUAL(s123.size(), 3); + BOOST_CHECK_EQUAL(s423.size(), 3); +} -BOOST_AUTO_TEST_CASE_TEMPLATE(test_static_strides_ctor, value, test_types) { - using namespace boost::numeric; +BOOST_AUTO_TEST_CASE(test_static_strides_ctor_access_first_order) +{ + namespace ublas = boost::numeric::ublas; - strides_type, ublas::layout::first_order> s1{}; - BOOST_CHECK_EQUAL(s1.empty(), false); - BOOST_CHECK_EQUAL(s1.size(), 2); + constexpr auto s11 = ublas::to_strides_v,first_order>; + constexpr auto s12 = ublas::to_strides_v,first_order>; + constexpr auto s21 = ublas::to_strides_v,first_order>; + constexpr auto s23 = ublas::to_strides_v,first_order>; + constexpr auto s231 = ublas::to_strides_v,first_order>; + constexpr auto s213 = ublas::to_strides_v,first_order>; + constexpr auto s123 = ublas::to_strides_v,first_order>; + constexpr auto s423 = ublas::to_strides_v,first_order>; - strides_type, ublas::layout::first_order> s2{}; - BOOST_CHECK_EQUAL(s2.empty(), false); - BOOST_CHECK_EQUAL(s2.size(), 2); + BOOST_REQUIRE_EQUAL(s11.size(), 2); + BOOST_REQUIRE_EQUAL(s12.size(), 2); + BOOST_REQUIRE_EQUAL(s21.size(), 2); + BOOST_REQUIRE_EQUAL(s23.size(), 2); + BOOST_REQUIRE_EQUAL(s231.size(), 3); + BOOST_REQUIRE_EQUAL(s213.size(), 3); + BOOST_REQUIRE_EQUAL(s123.size(), 3); + BOOST_REQUIRE_EQUAL(s423.size(), 3); - strides_type, ublas::layout::first_order> s3{}; - BOOST_CHECK_EQUAL(s3.empty(), false); - BOOST_CHECK_EQUAL(s3.size(), 2); - strides_type, ublas::layout::first_order> s4{}; - BOOST_CHECK_EQUAL(s4.empty(), false); - BOOST_CHECK_EQUAL(s4.size(), 2); + BOOST_CHECK_EQUAL(s11[0], 1); + BOOST_CHECK_EQUAL(s11[1], 1); - strides_type, ublas::layout::first_order> s5{}; - BOOST_CHECK_EQUAL(s5.empty(), false); - BOOST_CHECK_EQUAL(s5.size(), 3); + BOOST_CHECK_EQUAL(s12[0], 1); + BOOST_CHECK_EQUAL(s12[1], 1); - strides_type, ublas::layout::first_order> s6{}; - BOOST_CHECK_EQUAL(s6.empty(), false); - BOOST_CHECK_EQUAL(s6.size(), 3); + BOOST_CHECK_EQUAL(s21[0], 1); + BOOST_CHECK_EQUAL(s21[1], 2); // NOTE: is this the way we want to have it? - strides_type, ublas::layout::first_order> s7{}; - BOOST_CHECK_EQUAL(s7.empty(), false); - BOOST_CHECK_EQUAL(s7.size(), 3); -} + BOOST_CHECK_EQUAL(s23[0], 1); + BOOST_CHECK_EQUAL(s23[1], 2); + + BOOST_CHECK_EQUAL(s231[0], 1); + BOOST_CHECK_EQUAL(s231[1], 2); + BOOST_CHECK_EQUAL(s231[2], 6); + + BOOST_CHECK_EQUAL(s123[0], 1); + BOOST_CHECK_EQUAL(s123[1], 1); + BOOST_CHECK_EQUAL(s123[2], 2); -BOOST_AUTO_TEST_CASE(test_static_strides_ctor_access_first_order) { - using namespace boost::numeric; - - strides_type, ublas::layout::first_order> s1{}; - BOOST_REQUIRE_EQUAL(s1.size(), 2); - BOOST_CHECK_EQUAL(s1[0], 1); - BOOST_CHECK_EQUAL(s1[1], 1); - - strides_type, ublas::layout::first_order> s2{}; - BOOST_REQUIRE_EQUAL(s2.size(), 2); - BOOST_CHECK_EQUAL(s2[0], 1); - BOOST_CHECK_EQUAL(s2[1], 1); - - strides_type, ublas::layout::first_order> s3{}; - BOOST_REQUIRE_EQUAL(s3.size(), 2); - BOOST_CHECK_EQUAL(s3[0], 1); - BOOST_CHECK_EQUAL(s3[1], 1); - - strides_type, ublas::layout::first_order> s4{}; - BOOST_REQUIRE_EQUAL(s4.size(), 2); - BOOST_CHECK_EQUAL(s4[0], 1); - BOOST_CHECK_EQUAL(s4[1], 2); - - strides_type, ublas::layout::first_order> s5{}; - 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, ublas::layout::first_order> s6{}; - 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, ublas::layout::first_order> s7{}; - 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, ublas::layout::first_order> s8{}; - 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_CHECK_EQUAL(s213[0], 1); + BOOST_CHECK_EQUAL(s213[1], 2); + BOOST_CHECK_EQUAL(s213[2], 2); + + BOOST_CHECK_EQUAL(s423[0], 1); + BOOST_CHECK_EQUAL(s423[1], 4); + BOOST_CHECK_EQUAL(s423[2], 8); } -BOOST_AUTO_TEST_CASE(test_static_strides_ctor_access_last_order) { - using namespace boost::numeric; - - strides_type, ublas::layout::last_order> s1{}; - BOOST_REQUIRE_EQUAL(s1.size(), 2); - BOOST_CHECK_EQUAL(s1[0], 1); - BOOST_CHECK_EQUAL(s1[1], 1); - - strides_type, ublas::layout::last_order> s2{}; - BOOST_REQUIRE_EQUAL(s2.size(), 2); - BOOST_CHECK_EQUAL(s2[0], 1); - BOOST_CHECK_EQUAL(s2[1], 1); - - strides_type, ublas::layout::last_order> s3{}; - BOOST_REQUIRE_EQUAL(s3.size(), 2); - BOOST_CHECK_EQUAL(s3[0], 1); - BOOST_CHECK_EQUAL(s3[1], 1); - - strides_type, ublas::layout::last_order> s4{}; - BOOST_REQUIRE_EQUAL(s4.size(), 2); - BOOST_CHECK_EQUAL(s4[0], 3); - BOOST_CHECK_EQUAL(s4[1], 1); - - strides_type, ublas::layout::last_order> s5{}; - 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, ublas::layout::last_order> s6{}; - 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, ublas::layout::last_order> s7{}; - 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, ublas::layout::last_order> s8{}; - 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_CASE(test_static_strides_ctor_access_last_order) +{ + namespace ublas = boost::numeric::ublas; + + constexpr auto s11 = ublas::to_strides_v,last_order>; + constexpr auto s12 = ublas::to_strides_v,last_order>; + constexpr auto s21 = ublas::to_strides_v,last_order>; + constexpr auto s23 = ublas::to_strides_v,last_order>; + constexpr auto s231 = ublas::to_strides_v,last_order>; + constexpr auto s213 = ublas::to_strides_v,last_order>; + constexpr auto s123 = ublas::to_strides_v,last_order>; + constexpr auto s423 = ublas::to_strides_v,last_order>; + + BOOST_REQUIRE_EQUAL(s11.size(), 2); + BOOST_REQUIRE_EQUAL(s12.size(), 2); + BOOST_REQUIRE_EQUAL(s21.size(), 2); + BOOST_REQUIRE_EQUAL(s23.size(), 2); + BOOST_REQUIRE_EQUAL(s231.size(), 3); + BOOST_REQUIRE_EQUAL(s213.size(), 3); + BOOST_REQUIRE_EQUAL(s123.size(), 3); + BOOST_REQUIRE_EQUAL(s423.size(), 3); + + + BOOST_CHECK_EQUAL(s11[0], 1); + BOOST_CHECK_EQUAL(s11[1], 1); + + BOOST_CHECK_EQUAL(s12[0], 2); //NOTE: is this the way we want the stride to be computed? + BOOST_CHECK_EQUAL(s12[1], 1); + + BOOST_CHECK_EQUAL(s21[0], 1); + BOOST_CHECK_EQUAL(s21[1], 1); + + BOOST_CHECK_EQUAL(s23[0], 3); + BOOST_CHECK_EQUAL(s23[1], 1); + + BOOST_CHECK_EQUAL(s231[0], 3); + BOOST_CHECK_EQUAL(s231[1], 1); + BOOST_CHECK_EQUAL(s231[2], 1); + + BOOST_CHECK_EQUAL(s123[0], 6); + BOOST_CHECK_EQUAL(s123[1], 3); + BOOST_CHECK_EQUAL(s123[2], 1); + + BOOST_CHECK_EQUAL(s213[0], 3); + BOOST_CHECK_EQUAL(s213[1], 3); + BOOST_CHECK_EQUAL(s213[2], 1); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_tensor.cpp b/test/tensor/test_static_tensor.cpp index 1fef8617d..653a2726b 100644 --- a/test/tensor/test_static_tensor.cpp +++ b/test/tensor/test_static_tensor.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -15,51 +15,45 @@ #include #include -//#ifndef BOOST_TEST_DYN_LINK -//#define BOOST_TEST_DYN_LINK -//#endif - -//#define BOOST_TEST_MODULE TestStaticTensor - #include #include "utility.hpp" -BOOST_AUTO_TEST_SUITE ( test_static_tensor ) +BOOST_AUTO_TEST_SUITE ( test_tensor_static ) using test_types = zip>::with_t; BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto a1 = ublas::static_tensor,layout_type>{}; - BOOST_CHECK_EQUAL( a1.size() , 0ul ); - BOOST_CHECK( a1.empty() ); +// auto a1 = ublas::tensor_static,layout_type>{}; +// BOOST_CHECK_EQUAL( a1.size() , 0ul ); +// BOOST_CHECK( a1.empty() ); - auto a2 = ublas::static_tensor,layout_type>{}; + auto a2 = ublas::tensor_static,layout_type>{}; BOOST_CHECK_EQUAL( a2.size() , 1 ); BOOST_CHECK( !a2.empty() ); - auto a3 = ublas::static_tensor,layout_type>{}; + auto a3 = ublas::tensor_static,layout_type>{}; BOOST_CHECK_EQUAL( a3.size() , 2 ); BOOST_CHECK( !a3.empty() ); - auto a4 = ublas::static_tensor,layout_type>{}; + auto a4 = ublas::tensor_static,layout_type>{}; BOOST_CHECK_EQUAL( a4.size() , 2 ); BOOST_CHECK( !a4.empty() ); - auto a5 = ublas::static_tensor,layout_type>{}; + auto a5 = ublas::tensor_static,layout_type>{}; BOOST_CHECK_EQUAL( a5.size() , 2 ); BOOST_CHECK( !a5.empty() ); - auto a6 = ublas::static_tensor,layout_type>{}; + auto a6 = ublas::tensor_static,layout_type>{}; BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); BOOST_CHECK( !a6.empty() ); - auto a7 = ublas::static_tensor,layout_type>{}; + auto a7 = ublas::tensor_static,layout_type>{}; BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); BOOST_CHECK( !a7.empty() ); @@ -69,9 +63,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) struct fixture { template - using extents_type = boost::numeric::ublas::static_extents; + using extents_type = boost::numeric::ublas::extents; - fixture() {} + fixture()=default; std::tuple< extents_type<1,1>, // 1 @@ -85,17 +79,17 @@ struct fixture BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - for_each_tuple(extents, [](auto const&, auto& e){ + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ using extents_type = std::decay_t; - auto t = ublas::static_tensor{}; + auto t = ublas::tensor_static{}; - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - if(e.empty()) { + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); + if(ublas::empty(e)) { BOOST_CHECK ( t.empty() ); } else{ @@ -108,14 +102,14 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents, value, test_types, BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - for_each_tuple(extents, [](auto const&, auto& e){ + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ using extents_type = std::decay_t; - auto r = ublas::static_tensor{0}; + auto r = ublas::tensor_static{0}; auto t = r; BOOST_CHECK_EQUAL ( t.size() , r.size() ); @@ -123,7 +117,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fix BOOST_CHECK ( t.strides() == r.strides() ); BOOST_CHECK ( t.extents() == r.extents() ); - if(e.empty()) { + if(ublas::empty(e)) { BOOST_CHECK ( t.empty() ); } else{ @@ -139,17 +133,17 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fix BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; using other_layout_type = std::conditional_t::value, ublas::layout::last_order, ublas::layout::first_order>; - for_each_tuple(extents, [](auto const&, auto& e){ + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto r = tensor_type{0}; - ublas::static_tensor t = r; + ublas::tensor_static t = r; tensor_type q = t; BOOST_CHECK_EQUAL ( t.size() , r.size() ); @@ -170,20 +164,20 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_typ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_move_ctor, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - auto check = [](auto const&, auto& e) + auto check = [](auto const& /*unused*/, auto& e) { using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto r = tensor_type{}; auto t = std::move(r); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - if(e.empty()) { + if(ublas::empty(e)) { BOOST_CHECK ( t.empty() ); } else{ @@ -192,13 +186,13 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_move_ctor, value, test_types }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; @@ -208,9 +202,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_ty using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; auto distribution = distribution_type(1,6); - for_each_tuple(extents, [&](auto const&, auto const& e){ + for_each_in_tuple(extents, [&](auto const& /*unused*/, auto const& e){ using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto r = value_type( static_cast< inner_type_t >(distribution(generator)) ); auto t = tensor_type{r}; @@ -224,23 +218,23 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_ty BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_array, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - for_each_tuple(extents, [](auto const&, auto& e){ + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; - using array_type = typename tensor_type::array_type; + using tensor_type = ublas::tensor_static; + using container_type = typename tensor_type::container_type; - auto a = array_type(); + auto a = container_type(); auto v = value_type {}; for(auto& aa : a){ aa = v; v += value_type{1}; } - auto t = tensor_type{a}; + auto t = tensor_type(a); v = value_type{}; for(auto i = 0ul; i < t.size(); ++i, v+=value_type{1}) @@ -253,13 +247,13 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_array, value, test_t BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_single_index_access, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - for_each_tuple(extents, [](auto const&, auto& e){ + for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto t = tensor_type{}; auto v = value_type {}; @@ -278,7 +272,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_single_index_access, va BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; @@ -293,7 +287,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check2 = [](const auto& t) { - std::array k; + std::array k = {0,0}; auto r = std::is_same::value ? 1 : 0; auto q = std::is_same::value ? 1 : 0; auto v = value_type{}; @@ -307,7 +301,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check3 = [](const auto& t) { - std::array k; + std::array k= {0,0,0}; using op_type = std::conditional_t, std::minus<>, std::plus<>>; auto r = std::is_same_v ? 2 : 0; auto o = op_type{}; @@ -324,7 +318,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check4 = [](const auto& t) { - std::array k; + std::array k= {0,0,0,0}; using op_type = std::conditional_t, std::minus<>, std::plus<>>; auto r = std::is_same_v ? 3 : 0; auto o = op_type{}; @@ -341,9 +335,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, } }; - auto check = [check1,check2,check3,check4](auto const&, auto const& e) { + auto check = [check1,check2,check3,check4](auto const& /*unused*/, auto const& e) { using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto t = tensor_type{}; auto v = value_type {}; for(auto i = 0ul; i < t.size(); ++i){ @@ -351,25 +345,25 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, v+=value_type{1}; } - if constexpr ( extents_type::_size == 1) check1(t); - else if constexpr ( extents_type::_size == 2) check2(t); - else if constexpr ( extents_type::_size == 3) check3(t); - else if constexpr ( extents_type::_size == 4) check4(t); + if constexpr ( std::tuple_size_v == 1) check1(t); + else if constexpr ( std::tuple_size_v == 2) check2(t); + else if constexpr ( std::tuple_size_v == 3) check3(t); + else if constexpr ( std::tuple_size_v == 4) check4(t); }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - for_each_tuple(extents,[](auto const&, auto& e){ + for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e){ using extents_type = std::decay_t; - using tensor_type = ublas::static_tensor; + using tensor_type = ublas::tensor_static; auto v = value_type {} + value_type{1}; auto t = tensor_type{v}; @@ -380,7 +374,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_ty 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) { + if(!t.empty()) { BOOST_CHECK( t.data() == std::addressof( *t.begin () ) ) ; BOOST_CHECK( t.data() == std::addressof( *t.cbegin() ) ) ; } @@ -388,17 +382,17 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_ty } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, 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::static_tensor, layout_type>; +//BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, value, test_types, fixture) +//{ +// namespace ublas = boost::numeric::ublas; +// using value_type = typename value::first_type; +// using layout_type = typename value::second_type; +// using tensor_type = ublas::tensor_static, layout_type>; - auto t = tensor_type{}; - auto i = ublas::index::index_type<4>{}; - BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::runtime_error); +// auto t = tensor_type{}; +// auto i = ublas::index::index_type<4>{}; +// BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::runtime_error); -} +//} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_tensor_matrix_vector.cpp b/test/tensor/test_static_tensor_matrix_vector.cpp index bce3749ad..22c2ba434 100644 --- a/test/tensor/test_static_tensor_matrix_vector.cpp +++ b/test/tensor/test_static_tensor_matrix_vector.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -21,58 +21,58 @@ -BOOST_AUTO_TEST_SUITE ( test_static_tensor_matrix_interoperability ) ; +BOOST_AUTO_TEST_SUITE ( test_tensor_static_matrix_interoperability ) using test_types = zip::with_t; -BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types) +BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, pair, test_types) { - using namespace boost::numeric; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::matrix_type; - ublas::static_tensor,layout_type> a2 = matrix_type(1,1); + ublas::tensor_static,layout> a2 = matrix(1,1); BOOST_CHECK_EQUAL( a2.size() , 1 ); BOOST_CHECK( !a2.empty() ); - ublas::static_tensor,layout_type> a3 = matrix_type(2,1); + ublas::tensor_static,layout> a3 = matrix(2,1); BOOST_CHECK_EQUAL( a3.size() , 2 ); BOOST_CHECK( !a3.empty() ); - ublas::static_tensor,layout_type> a4 = matrix_type(1,2); + ublas::tensor_static,layout> a4 = matrix(1,2); BOOST_CHECK_EQUAL( a4.size() , 2 ); BOOST_CHECK( !a4.empty() ); - ublas::static_tensor,layout_type> a5 = matrix_type(2,3); + ublas::tensor_static,layout> a5 = matrix(2,3); BOOST_CHECK_EQUAL( a5.size() , 6 ); BOOST_CHECK( !a5.empty() ); } -BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, value, test_types) +BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, pair, test_types) { - using namespace boost::numeric; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using vector = typename tensor::vector_type; - ublas::static_tensor,layout_type> a2 = vector_type(1); + ublas::tensor_static,layout> a2 = vector(1); BOOST_CHECK_EQUAL( a2.size() , 1 ); BOOST_CHECK( !a2.empty() ); - ublas::static_tensor,layout_type> a3 = vector_type(2); + ublas::tensor_static,layout> a3 = vector(2); BOOST_CHECK_EQUAL( a3.size() , 2 ); BOOST_CHECK( !a3.empty() ); - ublas::static_tensor,layout_type> a4 = vector_type(2); + ublas::tensor_static,layout> a4 = vector(2); BOOST_CHECK_EQUAL( a4.size() , 2 ); BOOST_CHECK( !a4.empty() ); - ublas::static_tensor,layout_type> a5 = vector_type(3); + ublas::tensor_static,layout> a5 = vector(3); BOOST_CHECK_EQUAL( a5.size() , 3 ); BOOST_CHECK( !a5.empty() ); } @@ -81,96 +81,96 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, value, test_types) struct fixture { template - using extents_type = boost::numeric::ublas::static_extents; + using shape = boost::numeric::ublas::extents; - fixture() {} + fixture()=default; std::tuple< - extents_type<1,1>, // 0 - extents_type<2,3>, // 1 - extents_type<9,7>, // 2 - extents_type<15,17> // 3 - > extents;; + shape<1,1>, // 0 + shape<2,3>, // 1 + shape<5,8>, // 2 + shape<9,7> // 3 + > extents; }; -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::static_tensor; - - assert(e.size()==2); - etensor_type t = matrix_type{e[0],e[1]}; - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::matrix_type; + + auto check = [](auto const& /*unused*/, auto& e) { + using shape = std::decay_t; + using etensor = ublas::tensor_static; + + assert(ublas::size(e)==2); + etensor t = matrix{e[0],e[1]}; + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, pair, 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::static_tensor; - - if constexpr( extents_type::at(1) == 1 ){ - assert(e.size()==2); - if(e.empty()) + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using vector = typename tensor::vector_type; + + auto check = [](auto const& /*unused*/, auto& e) { + using shape = std::decay_t; + using etensor = ublas::tensor_static; + + if constexpr( ublas::get_v == 1 ){ + assert(ublas::size(e)==2); + if(ublas::empty(e)) return; - etensor_type t = vector_type(product(e)); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + etensor t = vector(ublas::product(e)); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); } }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::static_tensor; - - assert(e.size() == 2); - auto t = etensor_type{}; - auto r = matrix_type(e[0],e[1]); + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::matrix_type; + + auto check = [](auto const& /*unused*/, auto& e) { + using shape = std::decay_t; + using etensor = ublas::tensor_static; + + assert(ublas::size(e) == 2); + auto t = etensor{}; + auto r = matrix(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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); for(auto j = 0ul; j < t.size(1); ++j){ @@ -180,34 +180,34 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, value, te } }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, pair, 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using vector = typename tensor::vector_type; - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::static_tensor; + auto check = [](auto const& /*unused*/, auto& e) { + using shape = std::decay_t; + using etensor = ublas::tensor_static; - assert(e.size() == 2); + assert(ublas::size(e) == 2); - if constexpr( extents_type::at(1) == 1 ){ - auto t = etensor_type{}; - auto r = vector_type(e[0]*e[1]); + if constexpr( ublas::get_v == 1 ){ + auto t = etensor{}; + auto r = vector(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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product (e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); for(auto i = 0ul; i < t.size(); ++i){ @@ -216,32 +216,32 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, value, te } }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::static_tensor; - - assert(e.size() == 2); - auto t = etensor_type{}; - auto r = matrix_type(e[0],e[1]); + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::matrix_type; + + auto check = [](auto const& /*unused*/, auto& e) { + using shape = std::decay_t; + using etensor = ublas::tensor_static; + + assert(ublas::size(e) == 2); + auto t = etensor{}; + auto r = matrix(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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); for(auto j = 0ul; j < t.size(1); ++j){ @@ -251,36 +251,36 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, te } }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, pair, 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::static_tensor; - - assert(e.size() == 2); - if constexpr( extents_type::at(1) == 1 ){ - auto t = etensor_type{}; - auto r = vector_type(e[0]*e[1]); + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using vector = typename tensor::vector_type; + + auto check = [](auto const& /*unused*/, auto& e) { + using shape = std::decay_t; + using etensor = ublas::tensor_static; + + assert(ublas::size(e) == 2); + if constexpr( ublas::get_v == 1 ){ + auto t = etensor{}; + auto r = vector(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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); for(auto i = 0ul; i < t.size(); ++i){ @@ -289,50 +289,50 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, te } }; - for_each_tuple(extents,check); + for_each_in_tuple(extents,check); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::static_tensor; - - assert(e.size() == 2); - auto t = etensor_type{}; - auto r = matrix_type(e[0],e[1]); + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::matrix_type; + + for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e) { + using shape = std::decay_t; + using etensor = ublas::tensor_static; + + assert(ublas::size(e) == 2); + auto t = etensor{}; + auto r = matrix(e[0],e[1]); std::iota(r.data().begin(),r.data().end(), 1); t = r + 3*r; - etensor_type s = r + 3*r; - etensor_type q = s + r + 3*r + s; // + 3*r + etensor s = r + 3*r; + etensor 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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); 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() , product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , e.size() ); + BOOST_CHECK_EQUAL ( s.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( s.rank() , ublas::size (e) ); BOOST_CHECK ( !s.empty() ); 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() , product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , e.size() ); + BOOST_CHECK_EQUAL ( q.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( q.rank() , ublas::size (e) ); BOOST_CHECK ( !q.empty() ); @@ -343,9 +343,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_t BOOST_CHECK_EQUAL( q.at(i,j), 3*s.at(i,j) ); } } - }; - - for_each_tuple(extents,check); + }); } @@ -353,44 +351,44 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_t -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, pair, 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; - - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; - using etensor_type = ublas::static_tensor; - - assert(e.size() == 2); - if constexpr( extents_type::at(1) == 1 ){ - auto t = etensor_type{}; - auto r = vector_type(e[0]*e[1]); - std::iota(r.data().begin(),r.data().end(), 1); + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using vector = typename tensor::vector_type; + + for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e) { + using shape = std::decay_t; + using etensor = ublas::tensor_static; + + assert(ublas::size(e) == 2); + if constexpr( ublas::get_v == 1 ){ + auto t = etensor{}; + auto r = vector(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), value{1}); t = r + 3*r; - etensor_type s = r + 3*r; - etensor_type q = s + r + 3*r + s; // + 3*r + etensor s = r + 3*r; + etensor 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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); 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() , product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , e.size() ); + BOOST_CHECK_EQUAL ( s.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( s.rank() , ublas::size (e) ); BOOST_CHECK ( !s.empty() ); 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() , product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , e.size() ); + BOOST_CHECK_EQUAL ( q.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( q.rank() , ublas::size (e) ); BOOST_CHECK ( !q.empty() ); @@ -401,36 +399,35 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, value, test_t BOOST_CHECK_EQUAL( q.at(i), 3*s.at(i) ); } } - }; - - for_each_tuple(extents,check); + }); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::matrix_type; + using vector = typename tensor::vector_type; - auto check = [](auto const&, auto& e) { - using extents_type = std::decay_t; + for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e) { + using shape = std::decay_t; - if(product(e) <= 2) + if constexpr(ublas::product_v <= 2) return; - assert(e.size() == 2); - auto Q = ublas::static_tensor,layout_type>{} ; - 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); + assert(ublas::size_v == 2); + + auto Q = ublas::tensor_static,1>,layout>{} ; + auto A = matrix(e[0],e[1]); + auto b = vector(e[1]); + auto c = vector(e[0]); + std::iota(b.data().begin(),b.data().end(), value{1}); + std::fill(A.data().begin(),A.data().end(), value{1}); + std::fill(c.data().begin(),c.data().end(), value{2}); std::fill(Q.begin(),Q.end(), 2); decltype(Q) T = Q + (ublas::prod(A , b) + 2*c) + 3*Q; @@ -442,17 +439,15 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, value, BOOST_CHECK_EQUAL ( T.rank() , Q.rank() ); BOOST_CHECK ( !T.empty() ); - 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) ); - } - - }; + auto n = e[1]; + auto ab = value(std::div(n*(n+1),2).quot); + const auto ref = ab+4*Q(0)+2*c(0); + BOOST_CHECK( std::all_of(T.begin(),T.end(), [ref](auto cc){ return ref == cc; }) ); +// BOOST_CHECK_EQUAL( T(i), ab+4*Q(0)+2*c(0) ); - for_each_tuple(extents,check); + }); } diff --git a/test/tensor/test_strides.cpp b/test/tensor/test_strides.cpp index 25d292223..71ef94256 100644 --- a/test/tensor/test_strides.cpp +++ b/test/tensor/test_strides.cpp @@ -12,157 +12,149 @@ #include -#include -#include - -//BOOST_AUTO_TEST_SUITE(test_strides, * boost::unit_test::depends_on("test_extents")); +#include BOOST_AUTO_TEST_SUITE(test_strides) using test_types = std::tuple; +using extents = boost::numeric::ublas::extents<>; +using first_order = boost::numeric::ublas::layout::first_order; +using last_order = boost::numeric::ublas::layout::last_order; + + BOOST_AUTO_TEST_CASE_TEMPLATE( test_strides_ctor, value, test_types) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; + constexpr auto layout = value{}; + + auto s1 = ublas::to_strides(extents {1},layout); + auto s5 = ublas::to_strides(extents {5},layout); + auto s11 = ublas::to_strides(extents {1,1},layout); + auto s12 = ublas::to_strides(extents {1,2},layout); + auto s21 = ublas::to_strides(extents {2,1},layout); + auto s23 = ublas::to_strides(extents {2,3},layout); + auto s231 = ublas::to_strides(extents{2,3,1},layout); + auto s123 = ublas::to_strides(extents{1,2,3},layout); + auto s423 = ublas::to_strides(extents{4,2,3},layout); + + BOOST_CHECK (! s1.empty()); + BOOST_CHECK (! s5.empty()); + BOOST_CHECK (! s11.empty()); + BOOST_CHECK (! s12.empty()); + BOOST_CHECK (! s21.empty()); + BOOST_CHECK (! s23.empty()); + BOOST_CHECK (!s231.empty()); + BOOST_CHECK (!s123.empty()); + BOOST_CHECK (!s423.empty()); + + BOOST_CHECK_EQUAL ( s1.size(), 1); + BOOST_CHECK_EQUAL ( s5.size(), 1); + BOOST_CHECK_EQUAL ( s11.size(), 2); + BOOST_CHECK_EQUAL ( s12.size(), 2); + BOOST_CHECK_EQUAL ( s21.size(), 2); + BOOST_CHECK_EQUAL ( s23.size(), 2); + BOOST_CHECK_EQUAL ( s231.size(), 3); + BOOST_CHECK_EQUAL ( s123.size(), 3); + BOOST_CHECK_EQUAL ( s423.size(), 3); +} - using extents_type = ublas::basic_extents; - using strides_type = ublas::strides_t; +BOOST_AUTO_TEST_CASE( test_strides_ctor_access_first_order) +{ + namespace ublas = boost::numeric::ublas; + constexpr auto layout = first_order{}; - strides_type s0{}; - BOOST_CHECK ( s0.empty()); - BOOST_CHECK_EQUAL ( s0.size(), 0); + auto s1 = ublas::to_strides(extents {1},layout); + auto s5 = ublas::to_strides(extents {5},layout); + auto s11 = ublas::to_strides(extents {1,1},layout); + auto s12 = ublas::to_strides(extents {1,2},layout); + auto s21 = ublas::to_strides(extents {2,1},layout); + auto s23 = ublas::to_strides(extents {2,3},layout); + auto s231 = ublas::to_strides(extents{2,3,1},layout); + auto s123 = ublas::to_strides(extents{1,2,3},layout); + auto s423 = ublas::to_strides(extents{4,2,3},layout); - strides_type s1{extents_type{1,1}}; - BOOST_CHECK (!s1.empty()); - BOOST_CHECK_EQUAL ( s1.size(), 2); + BOOST_REQUIRE_EQUAL ( s11 .size(),2); + BOOST_REQUIRE_EQUAL ( s12 .size(),2); + BOOST_REQUIRE_EQUAL ( s21 .size(),2); + BOOST_REQUIRE_EQUAL ( s23 .size(),2); + BOOST_REQUIRE_EQUAL ( s231.size(),3); + BOOST_REQUIRE_EQUAL ( s123.size(),3); + BOOST_REQUIRE_EQUAL ( s423.size(),3); - 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); + BOOST_CHECK_EQUAL ( s11[0], 1); + BOOST_CHECK_EQUAL ( s11[1], 1); - strides_type s4{extents_type{2,3}}; - BOOST_CHECK (!s4.empty()); - BOOST_CHECK_EQUAL ( s4.size(), 2); + BOOST_CHECK_EQUAL ( s12[0], 1); + BOOST_CHECK_EQUAL ( s12[1], 1); - strides_type s5{extents_type{2,3,1}}; - BOOST_CHECK (!s5.empty()); - BOOST_CHECK_EQUAL ( s5.size(), 3); + BOOST_CHECK_EQUAL ( s21[0], 1); + BOOST_CHECK_EQUAL ( s21[1], 1); - 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_CHECK_EQUAL ( s23[0], 1); + BOOST_CHECK_EQUAL ( s23[1], 2); -BOOST_AUTO_TEST_CASE( test_strides_ctor_access_first_order) -{ - using namespace boost::numeric; - - using extents_type = ublas::basic_extents; - using strides_type = ublas::strides_t; - - 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_CHECK_EQUAL ( s231[0], 1); + BOOST_CHECK_EQUAL ( s231[1], 2); + BOOST_CHECK_EQUAL ( s231[2], 6); + + BOOST_CHECK_EQUAL ( s123[0], 1); + BOOST_CHECK_EQUAL ( s123[1], 1); + BOOST_CHECK_EQUAL ( s123[2], 2); + + BOOST_CHECK_EQUAL ( s423[0], 1); + BOOST_CHECK_EQUAL ( s423[1], 4); + BOOST_CHECK_EQUAL ( s423[2], 8); } BOOST_AUTO_TEST_CASE( test_strides_ctor_access_last_order) { - using namespace boost::numeric; - - using extents_type = ublas::basic_extents; - using strides_type = ublas::strides_t; - - 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); + namespace ublas = boost::numeric::ublas; + constexpr auto layout = last_order{}; + + auto s1 = ublas::to_strides(extents {1},layout); + auto s5 = ublas::to_strides(extents {5},layout); + auto s11 = ublas::to_strides(extents {1,1},layout); + auto s12 = ublas::to_strides(extents {1,2},layout); + auto s21 = ublas::to_strides(extents {2,1},layout); + auto s23 = ublas::to_strides(extents {2,3},layout); + auto s231 = ublas::to_strides(extents{2,3,1},layout); + auto s123 = ublas::to_strides(extents{1,2,3},layout); + auto s423 = ublas::to_strides(extents{4,2,3},layout); + + BOOST_REQUIRE_EQUAL ( s11 .size(),2); + BOOST_REQUIRE_EQUAL ( s12 .size(),2); + BOOST_REQUIRE_EQUAL ( s21 .size(),2); + BOOST_REQUIRE_EQUAL ( s23 .size(),2); + BOOST_REQUIRE_EQUAL ( s231.size(),3); + BOOST_REQUIRE_EQUAL ( s123.size(),3); + BOOST_REQUIRE_EQUAL ( s423.size(),3); + + BOOST_CHECK_EQUAL ( s11[0], 1); + BOOST_CHECK_EQUAL ( s11[1], 1); + + BOOST_CHECK_EQUAL ( s12[0], 1); + BOOST_CHECK_EQUAL ( s12[1], 1); + + BOOST_CHECK_EQUAL ( s21[0], 1); + BOOST_CHECK_EQUAL ( s21[1], 1); + + BOOST_CHECK_EQUAL ( s23[0], 3); + BOOST_CHECK_EQUAL ( s23[1], 1); + + BOOST_CHECK_EQUAL ( s231[0], 3); + BOOST_CHECK_EQUAL ( s231[1], 1); + BOOST_CHECK_EQUAL ( s231[2], 1); + + BOOST_CHECK_EQUAL ( s123[0], 6); + BOOST_CHECK_EQUAL ( s123[1], 3); + BOOST_CHECK_EQUAL ( s123[2], 1); + + BOOST_CHECK_EQUAL ( s423[0], 6); + BOOST_CHECK_EQUAL ( s423[1], 3); + BOOST_CHECK_EQUAL ( s423[2], 1); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_tensor.cpp b/test/tensor/test_tensor.cpp index 4ded6b1a0..ce16c8916 100644 --- a/test/tensor/test_tensor.cpp +++ b/test/tensor/test_tensor.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,14 +18,13 @@ #ifndef BOOST_TEST_DYN_LINK #define BOOST_TEST_DYN_LINK #endif - +// NOLINTNEXTLINE #define BOOST_TEST_MODULE Tensor #include #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>::with_t; @@ -33,15 +32,15 @@ using test_types = zip>::with_t; + using tensor_type = ublas::tensor_dynamic; - auto a1 = tensor_type{}; - BOOST_CHECK_EQUAL( a1.size() , 0ul ); - BOOST_CHECK( a1.empty() ); - BOOST_CHECK_EQUAL( a1.data() , nullptr); +// 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 ); @@ -82,7 +81,6 @@ struct fixture using extents_type = boost::numeric::ublas::extents<>; fixture() : extents { - extents_type{}, // 0 extents_type{1,1}, // 1 extents_type{1,2}, // 2 extents_type{2,1}, // 3 @@ -100,16 +98,16 @@ struct fixture BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; auto check = [](auto const& e) { auto t = tensor_type{e}; - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); - if(e.empty()) { + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size(e) ); + if(ublas::empty(e)) { BOOST_CHECK ( t.empty() ); BOOST_CHECK_EQUAL ( t.data() , nullptr); } @@ -126,10 +124,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents, value, test_types, BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; auto check = [](auto const& e) { @@ -140,7 +138,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fix BOOST_CHECK ( t.strides() == r.strides() ); BOOST_CHECK ( t.extents() == r.extents() ); - if(e.empty()) { + if(ublas::empty(e)) { BOOST_CHECK ( t.empty() ); BOOST_CHECK_EQUAL ( t.data() , nullptr); } @@ -160,12 +158,12 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fix BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; using other_layout_type = std::conditional_t::value, ublas::layout::last_order, ublas::layout::first_order>; - using other_tensor_type = ublas::dynamic_tensor; + using other_tensor_type = ublas::tensor_dynamic; for(auto const& e : extents) @@ -191,19 +189,19 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_typ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_move_ctor, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; auto check = [](auto const& e) { auto r = tensor_type{e}; auto t = std::move(r); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - if(e.empty()) { + if(ublas::empty(e)) { BOOST_CHECK ( t.empty() ); BOOST_CHECK_EQUAL ( t.data() , nullptr); } @@ -221,10 +219,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_move_ctor, value, test_types BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_types, fixture ) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; std::random_device device{}; std::minstd_rand0 generator(device()); @@ -244,14 +242,14 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_ty BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_array, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; - using array_type = typename tensor_type::array_type; + using tensor_type = ublas::tensor_dynamic; + using container_type = typename tensor_type::container_type; for(auto const& e : extents) { - auto a = array_type(product(e)); + auto a = container_type(product(e)); auto v = value_type {}; for(auto& aa : a){ @@ -270,10 +268,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_array, value, test_t BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_single_index_access, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; for(auto const& e : extents) { auto t = tensor_type{e}; @@ -292,10 +290,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_single_index_access, va BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; auto check1 = [](const tensor_type& t) { auto v = value_type{}; @@ -307,7 +305,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check2 = [](const tensor_type& t) { - std::array k; + std::array k = {0,0}; auto r = std::is_same::value ? 1 : 0; auto q = std::is_same::value ? 1 : 0; auto v = value_type{}; @@ -321,7 +319,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check3 = [](const tensor_type& t) { - std::array k; + std::array k = {0,0,0}; using op_type = std::conditional_t, std::minus<>, std::plus<>>; auto r = std::is_same_v ? 2 : 0; auto o = op_type{}; @@ -338,7 +336,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, auto check4 = [](const tensor_type& t) { - std::array k; + std::array k = {0,0,0,0}; using op_type = std::conditional_t, std::minus<>, std::plus<>>; auto r = std::is_same_v ? 3 : 0; auto o = op_type{}; @@ -379,10 +377,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; for(auto const& efrom : extents){ for(auto const& eto : extents){ @@ -393,17 +391,17 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixtu for(auto i = 0ul; i < t.size(); ++i) BOOST_CHECK_EQUAL( t[i], v ); - t.reshape(eto); - for(auto i = 0ul; i < std::min(product(efrom),product(eto)); ++i) - BOOST_CHECK_EQUAL( t[i], v ); + auto r = reshape(t,eto); + for(auto i = 0ul; i < std::min(ublas::product(efrom),ublas::product(eto)); ++i) + BOOST_CHECK_EQUAL( r[i], v ); - BOOST_CHECK_EQUAL ( t.size() , product(eto) ); - BOOST_CHECK_EQUAL ( t.rank() , eto.size() ); - BOOST_CHECK ( t.extents() == eto ); + BOOST_CHECK_EQUAL ( r.size() , ublas::product(eto) ); + BOOST_CHECK_EQUAL ( r.rank() , ublas::size (eto) ); + BOOST_CHECK ( r.extents() == eto ); if(efrom != eto){ for(auto i = product(efrom); i < t.size(); ++i) - BOOST_CHECK_EQUAL( t[i], value_type{} ); + BOOST_CHECK_EQUAL( r[i], value_type{} ); } } } @@ -414,10 +412,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixtu BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_swap, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; for(auto const& e_t : extents){ for(auto const& e_r : extents) { @@ -431,15 +429,15 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_swap, value, test_types, fixture) for(auto i = 0ul; i < t.size(); ++i) BOOST_CHECK_EQUAL( t[i], w ); - BOOST_CHECK_EQUAL ( t.size() , product(e_r) ); - BOOST_CHECK_EQUAL ( t.rank() , e_r.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e_r) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e_r) ); 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() , product(e_t) ); - BOOST_CHECK_EQUAL ( r.rank() , e_t.size() ); + BOOST_CHECK_EQUAL ( r.size() , ublas::product(e_t) ); + BOOST_CHECK_EQUAL ( r.rank() , ublas::size (e_t) ); BOOST_CHECK ( r.extents() == e_t ); @@ -451,10 +449,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_swap, value, test_types, fixture) BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; for(auto const& e : extents) { @@ -467,7 +465,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_ty 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) { + if(!t.empty()) { BOOST_CHECK( t.data() == std::addressof( *t.begin () ) ) ; BOOST_CHECK( t.data() == std::addressof( *t.cbegin() ) ) ; } @@ -476,17 +474,17 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_ty BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, value, test_types, fixture) { - using namespace boost::numeric; + namespace ublas = boost::numeric::ublas; using value_type = typename value::first_type; using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; + using tensor_type = ublas::tensor_dynamic; - std::vector vec(30); - BOOST_CHECK_THROW(tensor_type({5,5},vec), std::runtime_error); + std::vector vec(2); + BOOST_CHECK_THROW(tensor_type({5,5},vec), std::invalid_argument); auto t = tensor_type{{5,5}}; auto i = ublas::index::index_type<4>{}; - BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::runtime_error); + BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::invalid_argument); } diff --git a/test/tensor/test_tensor_matrix_vector.cpp b/test/tensor/test_tensor_matrix_vector.cpp index 7672bb31a..bea8566a1 100644 --- a/test/tensor/test_tensor_matrix_vector.cpp +++ b/test/tensor/test_tensor_matrix_vector.cpp @@ -19,67 +19,65 @@ #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::with_t; -BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types) +BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, pair, test_types) { - using namespace boost::numeric; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::matrix_type; - tensor_type a2 = matrix_type(1,1); + tensor a2 = matrix(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); + tensor a3 = matrix(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); + tensor a4 = matrix(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); + tensor a5 = matrix(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) +BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, pair, test_types) { - using namespace boost::numeric; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using vector = typename tensor::vector_type; - tensor_type a2 = vector_type(1); + tensor a2 = vector(1); BOOST_CHECK_EQUAL( a2.size() , 1 ); BOOST_CHECK( !a2.empty() ); BOOST_CHECK_NE( a2.data() , nullptr); - tensor_type a3 = vector_type(2); + tensor a3 = vector(2); BOOST_CHECK_EQUAL( a3.size() , 2 ); BOOST_CHECK( !a3.empty() ); BOOST_CHECK_NE( a3.data() , nullptr); - tensor_type a4 = vector_type(2); + tensor a4 = vector(2); BOOST_CHECK_EQUAL( a4.size() , 2 ); BOOST_CHECK( !a4.empty() ); BOOST_CHECK_NE( a4.data() , nullptr); - tensor_type a5 = vector_type(3); + tensor a5 = vector(3); BOOST_CHECK_EQUAL( a5.size() , 3 ); BOOST_CHECK( !a5.empty() ); BOOST_CHECK_NE( a5.data() , nullptr); @@ -88,34 +86,35 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, value, test_types) struct fixture { - using extents_type = boost::numeric::ublas::extents<>; - fixture() - : extents{ - extents_type{1,1}, // 1 - extents_type{2,3}, // 2 - extents_type{9,11}, // 2 - extents_type{15,17}} // 3 - { - } - std::vector extents; + using extents_type = boost::numeric::ublas::extents<>; + fixture() + : extents{ + extents_type{1,1}, // 1 + extents_type{2,3}, // 2 + extents_type{5,6}, // 3 + extents_type{9,7}} // 4 + { + } + + std::vector extents; }; -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + assert(ublas::size(e)==2); + tensor t = matrix{e[0],e[1]}; + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); }; @@ -125,22 +124,22 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, value, } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, pair, 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using vector = typename tensor::vector_type; auto check = [](auto const& e) { - assert(e.size()==2); - if(e.empty()) + assert(ublas::size(e)==2); + if(ublas::empty(e)) return; - tensor_type t = vector_type(product(e)); - BOOST_CHECK_EQUAL ( t.size() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + tensor t = vector(ublas::product(e)); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); }; @@ -151,26 +150,27 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, value, -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::matrix_type; + auto check = [](auto const& e) { - assert(e.size() == 2); - auto t = tensor_type{}; - auto r = matrix_type(e[0],e[1]); + assert(ublas::size(e) == 2); + auto t = tensor(e); + auto r = matrix(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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); @@ -186,26 +186,26 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, value, te } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, pair, 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using vector = typename tensor::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); + assert(ublas::size(e) == 2); + auto t = tensor(e); + auto r = vector(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), value{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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); @@ -218,27 +218,27 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, value, te check(e); } -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::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); + assert(ublas::size(e) == 2); + auto t = tensor(e); + auto r = matrix(e[0],e[1]); + std::iota(r.data().begin(),r.data().end(), value{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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); @@ -256,27 +256,27 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, te -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, pair, 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using vector = typename tensor::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); + assert(ublas::size(e) == 2); + auto t = tensor(e); + auto r = vector(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), value{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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); BOOST_CHECK ( !t.empty() ); BOOST_CHECK_NE ( t.data() , nullptr); @@ -293,43 +293,43 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, te -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::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); + assert(ublas::size(e) == 2); + auto t = tensor(e); + auto r = matrix(e[0],e[1]); + std::iota(r.data().begin(),r.data().end(), value{1}); t = r + 3*r; - tensor_type s = r + 3*r; - tensor_type q = s + r + 3*r + s; // + 3*r + tensor s = r + 3*r; + tensor 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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); 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() , product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , e.size() ); + BOOST_CHECK_EQUAL ( s.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( s.rank() , ublas::size (e) ); 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() , product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , e.size() ); + BOOST_CHECK_EQUAL ( q.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( q.rank() , ublas::size (e) ); BOOST_CHECK ( !q.empty() ); BOOST_CHECK_NE ( q.data() , nullptr); @@ -352,43 +352,43 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_t -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, pair, 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::dynamic_tensor; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using vector = typename tensor::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); + assert(ublas::size(e) == 2); + auto t = tensor(e); + auto r = vector(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), value{1}); t = r + 3*r; - tensor_type s = r + 3*r; - tensor_type q = s + r + 3*r + s; // + 3*r + tensor s = r + 3*r; + tensor 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() , product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( t.rank() , ublas::size(e) ); 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() , product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , e.size() ); + BOOST_CHECK_EQUAL ( s.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( s.rank() , ublas::size(e) ); 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() , product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , e.size() ); + BOOST_CHECK_EQUAL ( q.size() , ublas::product(e) ); + BOOST_CHECK_EQUAL ( q.rank() , ublas::size(e) ); BOOST_CHECK ( !q.empty() ); BOOST_CHECK_NE ( q.data() , nullptr); @@ -407,30 +407,31 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, value, test_t -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, value, test_types, fixture ) +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, pair, 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::dynamic_tensor; - using matrix_type = typename tensor_type::matrix_type; - using vector_type = typename tensor_type::vector_type; + namespace ublas = boost::numeric::ublas; + using value = typename pair::first_type; + using layout = typename pair::second_type; + using tensor = ublas::tensor_dynamic; + using matrix = typename tensor::matrix_type; + using vector = typename tensor::vector_type; auto check = [](auto const& e) { if(product(e) <= 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; + + assert(ublas::size(e) == 2); + auto Q = tensor{e[0],1}; + auto A = matrix(e[0],e[1]); + auto b = vector(e[1]); + auto c = vector(e[0]); + std::iota(b.data().begin(),b.data().end(), value{1}); + std::fill(A.data().begin(),A.data().end(), value{1}); + std::fill(c.data().begin(),c.data().end(), value{2}); + std::fill(Q.begin(),Q.end(), value{2}); + + tensor 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)); @@ -440,11 +441,12 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, value, 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) ); - } + const auto n = e[1]; + const auto ab = value(std::div(n*(n+1),2).quot); + const auto ref = ab+4*Q(0)+2*c(0); + BOOST_CHECK( std::all_of(T.begin(),T.end(), [ref](auto cc){ return ref == cc; }) ); + +// BOOST_CHECK_EQUAL( T(i), ab+4*Q(0)+2*c(0) ); }; diff --git a/test/tensor/utility.hpp b/test/tensor/utility.hpp index 6dc5f1a45..93571be2a 100644 --- a/test/tensor/utility.hpp +++ b/test/tensor/utility.hpp @@ -14,6 +14,8 @@ #define _BOOST_UBLAS_TEST_TENSOR_UTILITY_ #include +#include +#include template struct zip_helper; @@ -48,55 +50,38 @@ struct zip_helper, type1, types1...> template using zip = zip_helper,types...>; -template -struct for_each_tuple_impl{ - static_assert(sizeof...(Ts) > I, "Static Assert in boost::numeric::ublas::detail::for_each_tuple"); - auto operator()(std::tuple& t, CallBack call_back) - { - call_back(I,std::get(t)); - if constexpr(sizeof...(Ts) - 1 > I){ - for_each_tuple_impl it; - it(t,call_back); - } - } -}; - -template -auto for_each_tuple(std::tuple& t, CallBack call_back){ - if constexpr (std::tuple_size_v> == 0u ) - return; - for_each_tuple_impl<0,CallBack,Ts...> f; - f(t,call_back); +template +void for_each_in_tuple(std::tuple const& tuple, UnaryOp&& op) +{ + auto invoke_op_for_tuple = [&](std::index_sequence) { + (..., std::invoke(op, Is, std::get(tuple))); + }; + invoke_op_for_tuple(std::make_index_sequence>>{}); } +namespace boost::numeric::ublas +{ -template -struct list{ - static constexpr size_t size = sizeof...(Ts); -}; +template +void for_each_in_index(std::index_sequence, TA const& a, TB const& b, UnaryOp&& op) +{ + (..., std::invoke(op,a,b,std::index_sequence{}) ); +} -template -struct for_each_list_impl{ - constexpr decltype(auto) operator()(list l, CallBack call_back){ - using new_list = list; - using value_type = T; - call_back(I,value_type{}); - - if constexpr(new_list::size != 0){ - for_each_list_impl it; - it(new_list{},call_back); - } - } -}; +}// namespace boost::numeric::ublas +//template +//void for_each_in_tuple(std::index_sequence, UnaryOp&& op) +//{ +// auto invoke_op_for_tuple = [&](std::index_sequence) { +// (..., std::invoke(op, Is, Is)); +// }; + +// invoke_op_for_tuple(std::make_index_sequence::size()>{}); +//} -template -auto for_each_list(list l, CallBack call_back){ - for_each_list_impl<0,CallBack,Ts...> f; - f(l,call_back); -} #include From e09bdeb8a04820bb22c4979b6a469a8a155b2951 Mon Sep 17 00:00:00 2001 From: rainmaker6 Date: Mon, 7 Jun 2021 11:34:38 +0530 Subject: [PATCH 27/36] refactor(docs): convert HTML documentation using AsciiDoc This is GSoC 2021 project of Shikhar Vashistha who copied existing uBlas documentation and used AsciiDoc for formatting. --- doc/.gitignore | 2 + doc/Jamfile | 30 + doc/banded.html | 580 ------- doc/blas.html | 452 ------ doc/bounded_array.html | 219 --- doc/container_concept.html | 629 -------- doc/expression_concept.html | 1074 ------------- doc/hermitian.html | 597 ------- doc/index.html | 432 ----- doc/iterator_concept.html | 1168 -------------- doc/js/jquery-1.3.2.min.js | 19 - doc/js/jquery.toc-gw.js | 166 -- doc/matrix.html | 768 --------- doc/matrix_expression.html | 1428 ----------------- doc/matrix_proxy.html | 1428 ----------------- doc/matrix_sparse.html | 983 ------------ doc/operations_overview.html | 277 ---- doc/options.html | 247 --- doc/overview.html | 965 ----------- doc/products.html | 318 ---- doc/range.html | 229 --- doc/release_notes.html | 110 -- doc/storage_concept.html | 157 -- doc/storage_sparse.html | 288 ---- doc/symmetric.html | 588 ------- doc/tensor.html | 652 -------- doc/tensor/extents.html | 250 --- doc/tensor/strides.html | 238 --- doc/tensor/tensor_expression.html | 272 ---- doc/tensor/tensor_index.html | 262 --- doc/triangular.html | 602 ------- doc/types_overview.html | 608 ------- doc/ublas-docinfo-footer.html | 7 + doc/ublas.adoc | 86 + doc/ublas.css | 59 - doc/ublas/banded.adoc | 394 +++++ doc/ublas/blas.adoc | 230 +++ doc/ublas/bounded_array.adoc | 146 ++ doc/ublas/container_concept.adoc | 395 +++++ doc/ublas/expression_concept.adoc | 604 +++++++ doc/ublas/hermitian.adoc | 409 +++++ doc/ublas/index.adoc | 230 +++ doc/ublas/iterator_concept.adoc | 639 ++++++++ doc/ublas/matrix.adoc | 552 +++++++ doc/ublas/matrix_expression.adoc | 1313 +++++++++++++++ doc/ublas/matrix_proxy.adoc | 1144 +++++++++++++ doc/ublas/matrix_sparse.adoc | 660 ++++++++ doc/ublas/operations_overview.adoc | 283 ++++ doc/ublas/options.adoc | 188 +++ doc/ublas/overview.adoc | 582 +++++++ doc/ublas/products.adoc | 200 +++ doc/ublas/range.adoc | 191 +++ doc/ublas/release_notes.adoc | 80 + doc/{ => ublas}/samples/Jamfile.v2 | 0 .../samples/assignment_examples.cpp | 0 doc/{ => ublas}/samples/banded_adaptor.cpp | 0 doc/{ => ublas}/samples/banded_matrix.cpp | 0 doc/{ => ublas}/samples/bounded_array.cpp | 0 doc/{ => ublas}/samples/compressed_matrix.cpp | 0 doc/{ => ublas}/samples/compressed_vector.cpp | 0 doc/{ => ublas}/samples/coordinate_matrix.cpp | 0 doc/{ => ublas}/samples/coordinate_vector.cpp | 0 doc/{ => ublas}/samples/ex_triangular.cpp | 0 doc/{ => ublas}/samples/hermitian_adaptor.cpp | 0 doc/{ => ublas}/samples/hermitian_matrix.cpp | 0 doc/{ => ublas}/samples/identity_matrix.cpp | 0 doc/{ => ublas}/samples/map_array.cpp | 0 doc/{ => ublas}/samples/mapped_matrix.cpp | 0 doc/{ => ublas}/samples/mapped_vector.cpp | 0 doc/{ => ublas}/samples/matrix.cpp | 0 doc/{ => ublas}/samples/matrix_binary.cpp | 0 .../samples/matrix_binary_scalar.cpp | 0 doc/{ => ublas}/samples/matrix_column.cpp | 0 .../samples/matrix_column_project.cpp | 0 .../samples/matrix_matrix_binary.cpp | 0 .../samples/matrix_matrix_solve.cpp | 0 doc/{ => ublas}/samples/matrix_range.cpp | 0 .../samples/matrix_range_project.cpp | 0 doc/{ => ublas}/samples/matrix_row.cpp | 0 .../samples/matrix_row_project.cpp | 0 doc/{ => ublas}/samples/matrix_slice.cpp | 0 .../samples/matrix_slice_project.cpp | 0 doc/{ => ublas}/samples/matrix_unary.cpp | 0 .../samples/matrix_vector_binary.cpp | 0 .../samples/matrix_vector_range.cpp | 0 .../samples/matrix_vector_slice.cpp | 0 .../samples/matrix_vector_solve.cpp | 0 doc/{ => ublas}/samples/range.cpp | 0 doc/{ => ublas}/samples/slice.cpp | 0 doc/{ => ublas}/samples/symmetric_adaptor.cpp | 0 doc/{ => ublas}/samples/symmetric_matrix.cpp | 0 .../samples/triangular_adaptor.cpp | 0 doc/{ => ublas}/samples/triangular_matrix.cpp | 0 doc/{ => ublas}/samples/unbounded_array.cpp | 0 doc/{ => ublas}/samples/unit_vector.cpp | 0 doc/{ => ublas}/samples/vector.cpp | 0 doc/{ => ublas}/samples/vector_binary.cpp | 0 .../samples/vector_binary_outer.cpp | 0 .../samples/vector_binary_redux.cpp | 0 .../samples/vector_binary_scalar.cpp | 0 doc/{ => ublas}/samples/vector_range.cpp | 0 .../samples/vector_range_project.cpp | 0 doc/{ => ublas}/samples/vector_slice.cpp | 0 .../samples/vector_slice_project.cpp | 0 doc/{ => ublas}/samples/vector_unary.cpp | 0 .../samples/vector_unary_redux.cpp | 0 doc/{ => ublas}/samples/zero_matrix.cpp | 0 doc/{ => ublas}/samples/zero_vector.cpp | 0 doc/ublas/storage_concept.adoc | 109 ++ doc/ublas/storage_sparse.adoc | 210 +++ doc/ublas/symmetric.adoc | 401 +++++ doc/ublas/tensor.adoc | 351 ++++ doc/ublas/tensor/extents.adoc | 136 ++ doc/ublas/tensor/strides.adoc | 155 ++ doc/ublas/tensor/tensor_expression.adoc | 175 ++ doc/ublas/tensor/tensor_index.adoc | 53 + doc/ublas/triangular.adoc | 416 +++++ doc/ublas/types_overview.adoc | 352 ++++ doc/ublas/unbounded_array.adoc | 147 ++ doc/ublas/vector.adoc | 555 +++++++ doc/ublas/vector_expression.adoc | 913 +++++++++++ doc/ublas/vector_proxy.adoc | 443 +++++ doc/ublas/vector_sparse.adoc | 551 +++++++ doc/unbounded_array.html | 219 --- doc/vector.html | 755 --------- doc/vector_expression.html | 974 ----------- doc/vector_proxy.html | 527 ------ doc/vector_sparse.html | 800 --------- index.html | 28 +- 129 files changed, 13357 insertions(+), 19343 deletions(-) create mode 100644 doc/.gitignore create mode 100644 doc/Jamfile delete mode 100644 doc/banded.html delete mode 100644 doc/blas.html delete mode 100644 doc/bounded_array.html delete mode 100644 doc/container_concept.html delete mode 100644 doc/expression_concept.html delete mode 100644 doc/hermitian.html delete mode 100644 doc/index.html delete mode 100644 doc/iterator_concept.html delete mode 100644 doc/js/jquery-1.3.2.min.js delete mode 100644 doc/js/jquery.toc-gw.js delete mode 100644 doc/matrix.html delete mode 100644 doc/matrix_expression.html delete mode 100644 doc/matrix_proxy.html delete mode 100644 doc/matrix_sparse.html delete mode 100644 doc/operations_overview.html delete mode 100644 doc/options.html delete mode 100644 doc/overview.html delete mode 100644 doc/products.html delete mode 100644 doc/range.html delete mode 100644 doc/release_notes.html delete mode 100644 doc/storage_concept.html delete mode 100644 doc/storage_sparse.html delete mode 100644 doc/symmetric.html delete mode 100644 doc/tensor.html delete mode 100644 doc/tensor/extents.html delete mode 100644 doc/tensor/strides.html delete mode 100644 doc/tensor/tensor_expression.html delete mode 100644 doc/tensor/tensor_index.html delete mode 100644 doc/triangular.html delete mode 100644 doc/types_overview.html create mode 100644 doc/ublas-docinfo-footer.html create mode 100644 doc/ublas.adoc delete mode 100644 doc/ublas.css create mode 100644 doc/ublas/banded.adoc create mode 100644 doc/ublas/blas.adoc create mode 100644 doc/ublas/bounded_array.adoc create mode 100644 doc/ublas/container_concept.adoc create mode 100644 doc/ublas/expression_concept.adoc create mode 100644 doc/ublas/hermitian.adoc create mode 100644 doc/ublas/index.adoc create mode 100644 doc/ublas/iterator_concept.adoc create mode 100644 doc/ublas/matrix.adoc create mode 100644 doc/ublas/matrix_expression.adoc create mode 100644 doc/ublas/matrix_proxy.adoc create mode 100644 doc/ublas/matrix_sparse.adoc create mode 100644 doc/ublas/operations_overview.adoc create mode 100644 doc/ublas/options.adoc create mode 100644 doc/ublas/overview.adoc create mode 100644 doc/ublas/products.adoc create mode 100644 doc/ublas/range.adoc create mode 100644 doc/ublas/release_notes.adoc rename doc/{ => ublas}/samples/Jamfile.v2 (100%) rename doc/{ => ublas}/samples/assignment_examples.cpp (100%) rename doc/{ => ublas}/samples/banded_adaptor.cpp (100%) rename doc/{ => ublas}/samples/banded_matrix.cpp (100%) rename doc/{ => ublas}/samples/bounded_array.cpp (100%) rename doc/{ => ublas}/samples/compressed_matrix.cpp (100%) rename doc/{ => ublas}/samples/compressed_vector.cpp (100%) rename doc/{ => ublas}/samples/coordinate_matrix.cpp (100%) rename doc/{ => ublas}/samples/coordinate_vector.cpp (100%) rename doc/{ => ublas}/samples/ex_triangular.cpp (100%) rename doc/{ => ublas}/samples/hermitian_adaptor.cpp (100%) rename doc/{ => ublas}/samples/hermitian_matrix.cpp (100%) rename doc/{ => ublas}/samples/identity_matrix.cpp (100%) rename doc/{ => ublas}/samples/map_array.cpp (100%) rename doc/{ => ublas}/samples/mapped_matrix.cpp (100%) rename doc/{ => ublas}/samples/mapped_vector.cpp (100%) rename doc/{ => ublas}/samples/matrix.cpp (100%) rename doc/{ => ublas}/samples/matrix_binary.cpp (100%) rename doc/{ => ublas}/samples/matrix_binary_scalar.cpp (100%) rename doc/{ => ublas}/samples/matrix_column.cpp (100%) rename doc/{ => ublas}/samples/matrix_column_project.cpp (100%) rename doc/{ => ublas}/samples/matrix_matrix_binary.cpp (100%) rename doc/{ => ublas}/samples/matrix_matrix_solve.cpp (100%) rename doc/{ => ublas}/samples/matrix_range.cpp (100%) rename doc/{ => ublas}/samples/matrix_range_project.cpp (100%) rename doc/{ => ublas}/samples/matrix_row.cpp (100%) rename doc/{ => ublas}/samples/matrix_row_project.cpp (100%) rename doc/{ => ublas}/samples/matrix_slice.cpp (100%) rename doc/{ => ublas}/samples/matrix_slice_project.cpp (100%) rename doc/{ => ublas}/samples/matrix_unary.cpp (100%) rename doc/{ => ublas}/samples/matrix_vector_binary.cpp (100%) rename doc/{ => ublas}/samples/matrix_vector_range.cpp (100%) rename doc/{ => ublas}/samples/matrix_vector_slice.cpp (100%) rename doc/{ => ublas}/samples/matrix_vector_solve.cpp (100%) rename doc/{ => ublas}/samples/range.cpp (100%) rename doc/{ => ublas}/samples/slice.cpp (100%) rename doc/{ => ublas}/samples/symmetric_adaptor.cpp (100%) rename doc/{ => ublas}/samples/symmetric_matrix.cpp (100%) rename doc/{ => ublas}/samples/triangular_adaptor.cpp (100%) rename doc/{ => ublas}/samples/triangular_matrix.cpp (100%) rename doc/{ => ublas}/samples/unbounded_array.cpp (100%) rename doc/{ => ublas}/samples/unit_vector.cpp (100%) rename doc/{ => ublas}/samples/vector.cpp (100%) rename doc/{ => ublas}/samples/vector_binary.cpp (100%) rename doc/{ => ublas}/samples/vector_binary_outer.cpp (100%) rename doc/{ => ublas}/samples/vector_binary_redux.cpp (100%) rename doc/{ => ublas}/samples/vector_binary_scalar.cpp (100%) rename doc/{ => ublas}/samples/vector_range.cpp (100%) rename doc/{ => ublas}/samples/vector_range_project.cpp (100%) rename doc/{ => ublas}/samples/vector_slice.cpp (100%) rename doc/{ => ublas}/samples/vector_slice_project.cpp (100%) rename doc/{ => ublas}/samples/vector_unary.cpp (100%) rename doc/{ => ublas}/samples/vector_unary_redux.cpp (100%) rename doc/{ => ublas}/samples/zero_matrix.cpp (100%) rename doc/{ => ublas}/samples/zero_vector.cpp (100%) create mode 100644 doc/ublas/storage_concept.adoc create mode 100644 doc/ublas/storage_sparse.adoc create mode 100644 doc/ublas/symmetric.adoc create mode 100644 doc/ublas/tensor.adoc create mode 100644 doc/ublas/tensor/extents.adoc create mode 100644 doc/ublas/tensor/strides.adoc create mode 100644 doc/ublas/tensor/tensor_expression.adoc create mode 100644 doc/ublas/tensor/tensor_index.adoc create mode 100644 doc/ublas/triangular.adoc create mode 100644 doc/ublas/types_overview.adoc create mode 100644 doc/ublas/unbounded_array.adoc create mode 100644 doc/ublas/vector.adoc create mode 100644 doc/ublas/vector_expression.adoc create mode 100644 doc/ublas/vector_proxy.adoc create mode 100644 doc/ublas/vector_sparse.adoc delete mode 100644 doc/unbounded_array.html delete mode 100644 doc/vector.html delete mode 100644 doc/vector_expression.html delete mode 100644 doc/vector_proxy.html delete mode 100644 doc/vector_sparse.html diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 000000000..ed5fc760e --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,2 @@ +/html/ +/pdf/ \ No newline at end of file diff --git a/doc/Jamfile b/doc/Jamfile new file mode 100644 index 000000000..63e8b036a --- /dev/null +++ b/doc/Jamfile @@ -0,0 +1,30 @@ +# Copyright 2021 Shikhar Vashistha +# +# Distributed under the Boost Software License, Version 1.0. +# (http://www.boost.org/LICENSE_1_0.txt) +# Copyright 2021 Shikhar Vashistha +# +# Distributed under the Boost Software License, Version 1.0. +# (http://www.boost.org/LICENSE_1_0.txt) + +import asciidoctor ; + +html ublas.html : ublas.adoc ; + +install html_ : ublas.html : html ; + +pdf ublas.pdf : ublas.adoc ; + +explicit ublas.pdf ; + +install pdf_ : ublas.pdf : pdf ; + +explicit pdf_ ; + +alias boostdoc ; + +explicit boostdoc ; + +alias boostrelease : html_ ; + +explicit boostrelease ; \ No newline at end of file diff --git a/doc/banded.html b/doc/banded.html deleted file mode 100644 index 6ce82f2df..000000000 --- a/doc/banded.html +++ /dev/null @@ -1,580 +0,0 @@ - - - - - - - - - -Banded Matrix - - -

Banded Matrix

-
-
-

Description

-

The templated class banded_matrix<T, F, A> is -the base container adaptor for banded matrices. For a (m x -n)-dimensional banded matrix with l lower and -u upper diagonals and 0 <= i < m, 0 -<= j < n holds bi, j = -0, if i > j + l or i < j - u. The -storage of banded matrices is packed.

-

Example

-
-#include <boost/numeric/ublas/banded.hpp>
-#include <boost/numeric/ublas/io.hpp>
-
-int main () {
-    using namespace boost::numeric::ublas;
-    banded_matrix<double> m (3, 3, 1, 1);
-    for (signed i = 0; i < signed (m.size1 ()); ++ i)
-        for (signed j = std::max (i - 1, 0); j < std::min (i + 2, signed (m.size2 ())); ++ j)
-            m (i, j) = 3 * i + j;
-    std::cout << m << std::endl;
-}
-
-

Definition

-

Defined in the header banded.hpp.

-

Template parameters

- - - - - - - - - - - - - - - - - - - - - - - -
ParameterDescriptionDefault
TThe type of object stored in the matrix.
FFunctor describing the storage organization. [1]row_major
AThe type of the adapted array. [2]unbounded_array<T>
-

Model of

-

Matrix .

-

Type requirements

-

None, except for those imposed by the requirements of Matrix .

-

Public base classes

-

matrix_container<banded_matrix<T, F, A> ->

-

Members

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MemberDescription
banded_matrix ()Allocates an uninitialized banded_matrix that -holds zero rows of zero elements.
banded_matrix (size_type size1, size_type size2, -size_type lower = 0, size_type upper = 0)Allocates an uninitialized banded_matrix that -holds (lower + 1 + upper) diagonals around the main -diagonal of a matrix with size1 rows of -size2 elements.
banded_matrix (const banded_matrix &m)The copy constructor.
template<class AE>
-banded_matrix (const matrix_expression<AE> -&ae)
The extended copy constructor.
void resize (size_type size1, size_type size2, size_type -lower = 0, size_type upper = 0, bool preserve = true)Reallocates a banded_matrix to hold (lower + -1 + upper) diagonals around the main diagonal of a matrix -with size1 rows of size2 elements. The -existing elements of the banded_matrix are preseved -when specified.
size_type size1 () constReturns the number of rows.
size_type size2 () constReturns the number of columns.
size_type lower () constReturns the number of diagonals below the main diagonal.
size_type upper () constReturns the number of diagonals above the main diagonal.
const_reference operator () (size_type i, size_type j) -constReturns a const reference of the j --th element in the i-th row.
reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
banded_matrix &operator = (const banded_matrix -&m)The assignment operator.
banded_matrix &assign_temporary (banded_matrix -&m)Assigns a temporary. May change the banded matrix -m .
template<class AE>
-banded_matrix &operator = (const matrix_expression<AE> -&ae)
The extended assignment operator.
template<class AE>
-banded_matrix &assign (const matrix_expression<AE> -&ae)
Assigns a matrix expression to the banded matrix. Left and -right hand side of the assignment should be independent.
template<class AE>
-banded_matrix &operator += (const matrix_expression<AE> -&ae)
A computed assignment operator. Adds the matrix expression to -the banded matrix.
template<class AE>
-banded_matrix &plus_assign (const matrix_expression<AE> -&ae)
Adds a matrix expression to the banded matrix. Left and right -hand side of the assignment should be independent.
template<class AE>
-banded_matrix &operator -= (const matrix_expression<AE> -&ae)
A computed assignment operator. Subtracts the matrix expression -from the banded matrix.
template<class AE>
-banded_matrix &minus_assign (const matrix_expression<AE> -&ae)
Subtracts a matrix expression from the banded matrix. Left and -right hand side of the assignment should be independent.
template<class AT>
-banded_matrix &operator *= (const AT &at)
A computed assignment operator. Multiplies the banded matrix -with a scalar.
template<class AT>
-banded_matrix &operator /= (const AT &at)
A computed assignment operator. Divides the banded matrix -through a scalar.
void swap (banded_matrix &m)Swaps the contents of the banded matrices.
void insert (size_type i, size_type j, const_reference -t)Inserts the value t at the j-th -element of the i-th row.
void erase (size_type i, size_type j)Erases the value at the j-th elemenst of the -i-th row.
void clear ()Clears the matrix.
const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the banded_matrix.
const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the banded_matrix.
iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the banded_matrix.
iterator1 end1 ()Returns a iterator1 pointing to the end of the -banded_matrix.
const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the banded_matrix.
const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the banded_matrix.
iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the banded_matrix.
iterator2 end2 ()Returns a iterator2 pointing to the end of the -banded_matrix.
const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed banded_matrix.
const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed banded_matrix.
reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed banded_matrix.
reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed banded_matrix.
const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed banded_matrix.
const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed banded_matrix.
reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed banded_matrix.
reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed banded_matrix.
-

Notes

-

[1] Supported -parameters for the storage organization are row_major -and column_major.

-

[2] Supported -parameters for the adapted array are -unbounded_array<T> , -bounded_array<T> and -std::vector<T> .

-

Banded Adaptor

-

Description

-

The templated class banded_adaptor<M> is a -banded matrix adaptor for other matrices.

-

Example

-
-#include <boost/numeric/ublas/banded.hpp>
-#include <boost/numeric/ublas/io.hpp>
-
-int main () {
-    using namespace boost::numeric::ublas;
-    matrix<double> m (3, 3);
-    banded_adaptor<matrix<double> > ba (m, 1, 1);
-    for (signed i = 0; i < signed (ba.size1 ()); ++ i)
-        for (signed j = std::max (i - 1, 0); j < std::min (i + 2, signed (ba.size2 ())); ++ j)
-            ba (i, j) = 3 * i + j;
-    std::cout << ba << std::endl;
-}
-
-

Definition

-

Defined in the header banded.hpp.

-

Template parameters

- - - - - - - - - - - - - -
ParameterDescriptionDefault
MThe type of the adapted matrix.
-

Model of

-

Matrix Expression -.

-

Type requirements

-

None, except for those imposed by the requirements of Matrix Expression .

-

Public base classes

-

matrix_expression<banded_adaptor<M> ->

-

Members

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MemberDescription
banded_adaptor (matrix_type &data, size_type lower = -0, size_type upper = 0)Constructs a banded_adaptor that holds -(lower + 1 + upper) diagonals around the main diagonal -of a matrix.
banded_adaptor (const banded_adaptor &m)The copy constructor.
template<class AE>
-banded_adaptor (const matrix_expression<AE> -&ae)
The extended copy constructor.
size_type size1 () constReturns the number of rows.
size_type size2 () constReturns the number of columns.
size_type lower () constReturns the number of diagonals below the main diagonal.
size_type upper () constReturns the number of diagonals above the main diagonal.
const_reference operator () (size_type i, size_type j) -constReturns a const reference of the j --th element in the i-th row.
reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
banded_adaptor &operator = (const banded_adaptor -&m)The assignment operator.
banded_adaptor &assign_temporary (banded_adaptor -&m)Assigns a temporary. May change the banded adaptor -m .
template<class AE>
-banded_adaptor &operator = (const matrix_expression<AE> -&ae)
The extended assignment operator.
template<class AE>
-banded_adaptor &assign (const matrix_expression<AE> -&ae)
Assigns a matrix expression to the banded adaptor. Left and -right hand side of the assignment should be independent.
template<class AE>
-banded_adaptor &operator += (const matrix_expression<AE> -&ae)
A computed assignment operator. Adds the matrix expression to -the banded adaptor.
template<class AE>
-banded_adaptor &plus_assign (const matrix_expression<AE> -&ae)
Adds a matrix expression to the banded adaptor. Left and right -hand side of the assignment should be independent.
template<class AE>
-banded_adaptor &operator -= (const matrix_expression<AE> -&ae)
A computed assignment operator. Subtracts the matrix expression -from the banded adaptor.
template<class AE>
-banded_adaptor &minus_assign (const matrix_expression<AE> -&ae)
Subtracts a matrix expression from the banded adaptor. Left and -right hand side of the assignment should be independent.
template<class AT>
-banded_adaptor &operator *= (const AT &at)
A computed assignment operator. Multiplies the banded adaptor -with a scalar.
template<class AT>
-banded_adaptor &operator /= (const AT &at)
A computed assignment operator. Divides the banded adaptor -through a scalar.
void swap (banded_adaptor &m)Swaps the contents of the banded adaptors.
const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the banded_adaptor.
const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the banded_adaptor.
iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the banded_adaptor.
iterator1 end1 ()Returns a iterator1 pointing to the end of the -banded_adaptor.
const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the banded_adaptor.
const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the banded_adaptor.
iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the banded_adaptor.
iterator2 end2 ()Returns a iterator2 pointing to the end of the -banded_adaptor.
const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed banded_adaptor.
const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed banded_adaptor.
reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed banded_adaptor.
reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed banded_adaptor.
const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed banded_adaptor.
const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed banded_adaptor.
reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed banded_adaptor.
reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed banded_adaptor.
-
-

Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
- Use, modification and distribution are 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). -

- - - diff --git a/doc/blas.html b/doc/blas.html deleted file mode 100644 index 07573e835..000000000 --- a/doc/blas.html +++ /dev/null @@ -1,452 +0,0 @@ - - - - - BLAS - - - - - - - - - - - -

Level 3 BLAS

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Functions

template<class M1, class T, class M2, class M3> M1 & boost::numeric::ublas::blas_3::tmm (M1 &m1, const T &t, const M2 &m2, const M3 &m3)
 triangular matrix multiplication

template<class M1, class T, class M2, class C> M1 & boost::numeric::ublas::blas_3::tsm (M1 &m1, const T &t, const M2 &m2, C)
 triangular solve m2 * x = t * m1 in place, m2 is a triangular matrix

template<class M1, class T1, class T2, class M2, class M3> M1 & boost::numeric::ublas::blas_3::gmm (M1 &m1, const T1 &t1, const T2 &t2, const M2 &m2, const M3 &m3)
 general matrix multiplication

template<class M1, class T1, class T2, class M2> M1 & boost::numeric::ublas::blas_3::srk (M1 &m1, const T1 &t1, const T2 &t2, const M2 &m2)
 symmetric rank k update: m1 = t * m1 + t2 * (m2 * m2T)

template<class M1, class T1, class T2, class M2> M1 & boost::numeric::ublas::blas_3::hrk (M1 &m1, const T1 &t1, const T2 &t2, const M2 &m2)
 hermitian rank k update: m1 = t * m1 + t2 * (m2 * m2H)

template<class M1, class T1, class T2, class M2, class M3> M1 & boost::numeric::ublas::blas_3::sr2k (M1 &m1, const T1 &t1, const T2 &t2, const M2 &m2, const M3 &m3)
 generalized symmetric rank k update: m1 = t1 * m1 + t2 * (m2 * m3T) + t2 * (m3 * m2T)

template<class M1, class T1, class T2, class M2, class M3> M1 & boost::numeric::ublas::blas_3::hr2k (M1 &m1, const T1 &t1, const T2 &t2, const M2 &m2, const M3 &m3)
 generalized hermitian rank k update: m1 = t1 * m1 + t2 * (m2 * m3H) + (m3 * (t2 * m2)H)

template<class M, class E1, class E2> BOOST_UBLAS_INLINE M & boost::numeric::ublas::axpy_prod (const matrix_expression< E1 > &e1, const matrix_expression< E2 > &e2, M &m, bool init=true)
 computes M += A X or M = A X in an optimized fashion.

template<class M, class E1, class E2> BOOST_UBLAS_INLINE M & boost::numeric::ublas::opb_prod (const matrix_expression< E1 > &e1, const matrix_expression< E2 > &e2, M &m, bool init=true)
 computes M += A X or M = A X in an optimized fashion.

- -
- -

Function Documentation

- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M1& tmm ( M1 &  m1,
const T &  t,
const M2 &  m2,
const M3 &  m3
) 
-
- - - - - -
-   - -

triangular matrix multiplication

-
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M1& tsm ( M1 &  m1,
const T &  t,
const M2 &  m2,
C 
) 
-
- - - - - -
-   - - -

-triangular solve m2 * x = t * m1 in place, m2 is a triangular matrix -

-
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M1& gmm ( M1 &  m1,
const T1 &  t1,
const T2 &  t2,
const M2 &  m2,
const M3 &  m3
) 
-
- - - - - -
-   - - -

-general matrix multiplication -

-
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M1& srk ( M1 &  m1,
const T1 &  t1,
const T2 &  t2,
const M2 &  m2
) 
-
- - - - - -
-   - - -

-symmetric rank k update: m1 = t * m1 + t2 * (m2 * m2T) -

-
Todo:
use opb_prod()
-
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M1& hrk ( M1 &  m1,
const T1 &  t1,
const T2 &  t2,
const M2 &  m2
) 
-
- - - - - -
-   - - -

-hermitian rank k update: m1 = t * m1 + t2 * (m2 * m2H) -

-
Todo:
use opb_prod()
-
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M1& sr2k ( M1 &  m1,
const T1 &  t1,
const T2 &  t2,
const M2 &  m2,
const M3 &  m3
) 
-
- - - - - -
-   - - -

-generalized symmetric rank k update: m1 = t1 * m1 + t2 * (m2 * m3T) + t2 * (m3 * m2T) -

-
Todo:
use opb_prod()
-
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M1& hr2k ( M1 &  m1,
const T1 &  t1,
const T2 &  t2,
const M2 &  m2,
const M3 &  m3
) 
-
- - - - - -
-   - - -

-generalized hermitian rank k update: m1 = t1 * m1 + t2 * (m2 * m3H) + (m3 * (t2 * m2)H) -

-
Todo:
use opb_prod()
-
- - - -
-

Copyright (©) 2000-2004 Michael Stevens, Mathias Koch, -Joerg Walter, Gunter Winkler
-Use, modification and distribution are 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). -

- - - diff --git a/doc/bounded_array.html b/doc/bounded_array.html deleted file mode 100644 index fea0d7b53..000000000 --- a/doc/bounded_array.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - -Bounded Array; - - -

Bounded Array Storage

-
-

Bounded Array

-

Description

-

The templated class bounded_array<T, N, ALLOC> implements a bounded storage array. The bounded array is similar to a C++ array type in that its maximum size is bounded by N and is allocated on the stack instead of the heap. Similarly a bounded_array requires no secondary storage and ALLOC is only used to specify size_type and difference_type. -

-

When resized bounded_array never reallocated the storage. It is therefore always efficient to resize a bounded_array but the size bound N must not be exceeded.

-

Example

-
-#include <boost/numeric/ublas/storage.hpp>
-
-int main () {
-    using namespace boost::numeric::ublas;
-    bounded_array<double, 3> a (3);
-    for (unsigned i = 0; i < a.size (); ++ i) {
-        a [i] = i;
-        std::cout << a [i] << std::endl;
-    }
-}
-
-

Definition

-

Defined in the header storage.hpp.

-

Template parameters

- - - - - - - - - - - - - - - - - - - - - - - -
ParameterDescriptionDefault
TThe type of object stored in the array.
NThe allocation size of the array.
ALLOCAn STL Allocatorstd::allocator
-

Model of

-

Storage

-

Type requirements

-

None, except for those imposed by the requirements of Storage.

-

Public base classes

-

None.

-

Members

-
    -
  • The description does not describe what the member actually does, this can be looked up -in the corresponding concept documentation, but instead contains a remark on the implementation of the -member inside this model of the concept.
  • -
  • Typography: -
      -
    • Members that are not part of the implemented concepts are in blue.
    • -
    -
  • -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MemberWhere definedDescription
value_typeContainer
pointerContainerDefined as value_type*
const_pointerContainerDefined as const value_type*
referenceContainerDefined as value_type&
const_referenceContainerDefined as const value_type&
size_typeContainerDefined as Alloc::size_type
difference_typeContainerDefined as Alloc::difference_type
iteratorContainerDefined as pointer
const_iteratorContainerDefined as const_pointer
revere_iteratorContainerDefined as std::reverse_iterator<iterator>
const_revere_iteratorContainerDefined as std::reverse_iterator<const_iterator>
bounded_array ()StorageCreates an unbounded_array that holds zero elements.
bounded_array (size_type size)StorageCreates a uninitialized bounded_array that holds size elements. All the elements are default constructed.
bounded_array (size_type size, const T& init)StorageCreates an initialized bounded_array that holds size elements. All the elements are constructed from the init value.
bounded_array (const bounded_array &c)ContainerThe copy constructor.
~bounded_array ()ContainerDeallocates the bounded_array itself.
void resize (size_type size)Storage -Reallocates a bounded_array to hold size elements.
void resize (size_type size, const T& t)Storage -Reallocates a bounded_array to hold size elements.
size_type size () constContainerReturns the size of the bounded_array.
const_reference operator [] (size_type i) constContainerReturns a const reference of the i -th element.
reference operator [] (size_type i)ContainerReturns a reference of the i-th element.
bounded_array &operator = (const bounded_array &a)ContainerThe assignment operator.
bounded_array &assign_temporary (bounded_array &a)Assigns a temporary. May change the array a.
void swap (bounded_array &a)ContainerSwaps the contents of the arrays.
const_iterator begin () constContainerReturns a const_iterator pointing to the beginning of the bounded_array.
const_iterator end () constContainerReturns a const_iterator pointing to the end of the bounded_array.
iterator begin ()ContainerReturns a iterator pointing to the beginning of the bounded_array.
iterator end ()ContainerReturns a iterator pointing to the end of the bounded_array.
const_reverse_iterator rbegin () constReversible ContainerReturns a const_reverse_iterator pointing to the beginning of the reversed bounded_array.
const_reverse_iterator rend () constReversible ContainerReturns a const_reverse_iterator pointing to the end of the reversed bounded_array.
reverse_iterator rbegin ()Reversible ContainerReturns a reverse_iterator pointing to the beginning of the reversed bounded_array.
reverse_iterator rend ()Reversible ContainerReturns a reverse_iterator pointing to the end of the reversed bounded_array.
-
-

- Copyright (©) 2000-2004 Michael Stevens, Mathias Koch, - Joerg Walter, Gunter Winkler
- Use, modification and distribution are 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 - ). -

- - - diff --git a/doc/container_concept.html b/doc/container_concept.html deleted file mode 100644 index 7027e83ec..000000000 --- a/doc/container_concept.html +++ /dev/null @@ -1,629 +0,0 @@ - - - - - - - - - - - - -Container Concepts - - -

Container Concepts

-
-

Vector

-

Description

-

A Vector describes common aspects of dense, packed and sparse -vectors.

-

Refinement of

-

DefaultConstructible, -Vector Expression -[1].

-

Associated types

-

In addition to the types defined by Vector Expression

- - - - - - - - - - - - - -
Public basevector_container<V>V must be derived from this public base type.
Storage arrayV::array_type -Dense Vector ONLY. The type of underlying storage array used to store the elements. The array_type must model the -Storage concept.
-

Notation

- - - - - - - - - - - - - - - - - - - - - - - -
VA type that is a model of Vector
vObjects of type V
n, iObjects of a type convertible to size_type
tObject of a type convertible to value_type
pObject of a type convertible to bool
-

Definitions

-

Valid expressions

-

In addition to the expressions defined in DefaultConstructible, -Vector Expression the following expressions must be valid.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Sizing constructorV v (n) V
Insertv.insert_element (i, t)v is mutable.void
Erasev.erase_element (i)v is mutable.void
Clearv.clear ()v is mutable.void
Resizev.resize (n)
-v.resize (n, p)
v is mutable.void
Storagev.data()v is mutable and Dense.array_type& if v is mutable, const array_type& otherwise
-

Expression semantics

-

Semantics of an expression is defined only where it differs -from, or is not defined in Vector Expression .

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionPreconditionSemanticsPostcondition
Sizing constructorV v (n)n >= 0Allocates a vector ofn elements.v.size () == n.
Element access [2]v[n]0<n>v.size()returns the n-th element in v 
Insertv.insert_element (i, t)0 <= i < v.size ().Inserts an element at v (i) with value t. -The storage requirement of the Vector may be increased.v (i) is equal to t.
Erasev.erase_element (i)0 <= i < v.size ()Destroys the element as v (i) and replaces it with the default -value_type (). -The storage requirement of the Vector may be decreased.v (i) is equal to value_type ().
Clearv.clear () Equivalent to
-for (i = 0; i < v.size (); ++ i)
-  v.erase_element (i);
 
Resizev.resize (n) -
v.resize (n, p)
 Reallocates the vector so that it can hold n -elements.
-Erases or appends elements in order to bring the vector to the prescribed size. Appended elements copies of value_type(). -
-When p == false then existing elements are not preserved and elements will not appended as normal. Instead the vector is in the same state as that after an equivalent sizing constructor.
v.size () == n.
Storagev.data()Returns a reference to the underlying dense storage. 
-

Complexity guarantees

-

The run-time complexity of the sizing constructor is linear in -the vector's size.

-

The run-time complexity of insert_element and erase_element is specific for the -Vector model and it depends on increases/decreases in storage requirements.

-

The run-time complexity of resize is linear in the vector's -size.

-

Invariants

-

Models

-
    -
  • vector, bounded_vector, c_vector
  • -
  • unit_vector, zero_vector, scalar_vector
  • -
  • mapped_vector;, compressed_vector, coordinate_vector
  • -
-

Notes

-

[1] -As a user you need not care about Vector being a refinement of the VectorExpression. Being a refinement of the VectorExpression is only important for the template-expression engine but not the user.

-

[2] -The operator[] is added purely for convenience -and compatibility with the std::vector. In uBLAS however, -generally operator() is used for indexing because this can be -used for both vectors and matrices.

- - -
- - - -

Matrix

-

Description

-

A Matrix describes common aspects of dense, packed and sparse -matrices.

-

Refinement of

-

DefaultConstructible, -Matrix Expression -[1] -.

-

Associated types

-

In addition to the types defined by Matrix Expression

- - - - - - - - - - - - - -
Public basematrix_container<M>M must be derived from this public base type.
Storage arrayM::array_typeDense Matrix ONLY. The type of underlying storage array used to store the elements. The array_type must model -the Storage concept.
-

Notation

- - - - - - - - - - - - - - - - - - - - - - - -
MA type that is a model of Matrix
mObjects of type M
n1, n2, i, jObjects of a type convertible to size_type
tObject of a type convertible to value_type
pObject of a type convertible to bool
-

Definitions

-

Valid expressions

-

In addition to the expressions defined in Matrix Expression the -following expressions must be valid.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Sizing constructorM m (n1, n2) M
Insertm.insert_element (i, j, t)m is mutable.void
Erasem.erase_element (i, j)m is mutable.void
Clearm.clear ()m is mutable.void
Resizem.resize (n1, n2)
-m.resize (n1, n2, p)
m is mutable.void
Storagem.data()m is mutable and Dense.array_type& if m is mutable, const array_type& otherwise
-

Expression semantics

-

Semantics of an expression is defined only where it differs -from, or is not defined in Matrix Expression .

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionPreconditionSemanticsPostcondition
Sizing constructorM m (n1, n2)n1 >= 0 and n2 >= 0Allocates a matrix of n1 rows and n2 -columns.m.size1 () == n1 and m.size2 () == -n2.
Insertm.insert_element (i, j, t)0 <= i < m.size1 (),
-0 <= j < m.size2 ().
Inserts an element at m (i, j) with value t. -The storage requirement of the Matrix may be increased.m (i, j) is equal to t.
Erasem.erase_element (i, j)0 <= i < m.size1 ()and
-0 <= j < m.size2
Destroys the element as m (i, j) and replaces it with the default -value_type (). -The storage requirement of the Matrix may be decreased.m (i, j) is equal to value_type ().
Clearm.clear () Equivalent to
-for (i = 0; i < m.size1 (); ++ i)
-  for (j = 0; j < m.size2 (); ++ j)
-    m.erase_element (i, j);
 
Resizem.resize (n1, n2) -
-m.resize (n1, n2, p) -
 Reallocate the matrix so that it can hold n1 rows -and n2 columns.
-Erases or appends elements in order to bring the matrix to the -prescribed size. Appended elements are value_type() -copies.
-When p == false then existing elements are not preserved and elements will not appended as normal. Instead the matrix is in the same state as that after an equivalent sizing constructor.
m.size1 () == n1 and m.size2 () == n2.
Storagem.data()Returns a reference to the underlying dense storage. 
-

Complexity guarantees

-

The run-time complexity of the sizing constructor is quadratic -in the matrix's size.

-

The run-time complexity of insert_element and erase_element is specific for the -Matrix model and it depends on increases/decreases in storage requirements.

-

The run-time complexity of resize is quadratic in the matrix's -size.

-

Invariants

-

Models

-
    -
  • matrix, bounded_matrix, c_matrix
  • -
  • identity_matrix , zero_matrix , scalar_matrix
  • -
  • triangular_matrix , symmetric_matrix , banded_matrix
  • -
  • mapped_matrix , compressed_matrix , coordinate_matrix
  • -
-

Notes

-

[1] -As a user you need not care about Matrix being a refinement of the MatrixExpression. Being a refinement of the MatrixExpression is only important for the template-expression engine but not the user.

- -
- - - -

Tensor

-

Description

-

A Tensor describes common aspects of dense multidimensional arrays.

-

Refinement of

-

DefaultConstructible, -Tensor Expression -[1] -.

-

Associated types

-

In addition to the types defined by Tensor Expression

- - - - - - - - - - - - - -
Public basetensor_container<tensor_t>tensor_t must be derived from this public base type.
Storage arraytensor_t::array_typeDense tensor ONLY. The type of underlying storage array used to store the elements. The array_type must model -the Storage concept.
-

Notation

- - - - - - - - - - - - - - - - - - - - - - - -
tensor_tA type that is a model of Tensor
tObjects of type tensor_t
n1, n2, np, m1, m2, mq Dimension objects of a type convertible to size_type
i1, i2, ip, j, k Index objects of a type convertible to size_type
vObject of a type convertible to value_type
-

Definitions

-

Valid expressions

-

In addition to the expressions defined in Tensor Expression the -following expressions must be valid.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Sizing constructorT t(n1, n2, ..., np) T
Writet.at(i1, i2, ..., ip)t is mutable.void
Readt.at(i1, i2, ..., ip)t is mutable.v
Cleart.clear ()t is mutable.void
Resizet.resize(m1, m2, ... , mq)t is mutable.void
Storaget.data()t is mutable and dense.pointer if t is mutable, const_pointer otherwise
-

Expression semantics

-

Semantics of an expression is defined only where it differs -from, or is not defined in Tensor Expression .

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionPreconditionSemanticsPostcondition
Sizing constructorT t(n1, n2, ..., np)$n_r \geq 1$ for $1\leq 1 \leq p $Allocates a p-order tensor with dimension extents $n_1,n_2,\dots,n_p$.t.size(r)==nr for $1\leq r \leq p$.
Writet.at(i1,i2,...,ip)=v$0 \leq i_r < n_r$ for $1 \leq r \leq p$.Writes an element at multi-index position $i_1,i_2,\dots,i_p$ with value v.t(i1,i2,...,ip) is equal to v.
Readv=t.at(i1,i2,...,ip)$0 \leq i_r < n_r$ for $1 \leq r \leq p$.Reads the element at multi-index position $(i_1,i2_,\dots,i_p)$ and returns a value v.t(i1,i2,...,ip) is equal to v.
Cleart.clear() Removes all elements from the container. 
Resizet.resize(m1, m2, ..., mq)$m_r \geq 1$ for $1\leq 1 \leq q $Reallocate the matrix so that it can hold $m_1\times m_2\times \cdots \times m_q$ elements.
-Erases or appends elements in order to bring the matrix to the -prescribed size. Appended elements are value_type() -copies.
t.size(r) == mr for $1\leq r \leq q$.
Storagem.data()Returns a reference to the underlying dense storage. 
-

Complexity guarantees

-

The run-time complexity of contructor is linear in the tensor's size $n_1 \times n_2 \times \cdots \times n_p$.

-

The run-time complexity of write() and read() is linear in the order of the tensor.

-

The run-time complexity of resize is at most linear in the tensor's size $m_1 \times m_2 \times \cdots \times n_q$.

-

Invariants

-

Models

-
    -
  • tensor
  • -
- -

Notes

-

[1] -As a user you need not care about Tensor being a refinement of the TensorExpression. Being a refinement of the TensorExpression is only important for the template-expression engine but not the user.

- - - - -
-

-Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
-Copyright (©) 2018 Cem Bassoy
- Use, modification and distribution are 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 - ). -

- - - diff --git a/doc/expression_concept.html b/doc/expression_concept.html deleted file mode 100644 index ffbfd1481..000000000 --- a/doc/expression_concept.html +++ /dev/null @@ -1,1074 +0,0 @@ - - - - - - - - -Expression Concepts - - -

Expression Concepts

-
-

Scalar Expression

-

Description

-

A Scalar Expression is an expression convertible to a scalar -type.

-

Refinement of

-

Default Constructible.

-

Associated types

- - - - - - - - - - - - - -
Public basescaler_expression<S>S must be derived from this public base type.
Value typevalue_typeThe type of the scalar expression.
-

Notation

- - - - - - - -
SA type that is a model of Scalar Expression
-

Definitions

-

Valid expressions

-

In addition to the expressions defined in Default Constructible -the following expressions must be valid.

- - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Evaluationoperator value_type () const value_type
-

Expression semantics

-

Semantics of an expression is defined only where it differs -from, or is not defined in Default Constructible.

- - - - - - - - - - - - - - - - - -
NameExpressionPreconditionSemanticsPostcondition
Evaluationoperator value_type () const   Evaluates the scalar expression. 
-

Complexity guarantees

-

The run-time complexity of the evaluation is specific for the -evaluated scalar expression.

-

Invariants

-

Models

-
    -
  • vector_scalar_unary
  • -
  • vector_scalar_binary
  • -
-

Vector Expression

-

Description

-

A Vector Expression is an expression evaluatable to a vector. -Vector Expression provides an Indexed Bidirectional -Iterator or an Indexed Random Access -Iterator .

-

Refinement of

-

Default Constructible.

-

Associated types

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Public basevector_expression<V>V must be derived from this public base type.
Value typevalue_type -The element type of the vector expression. -
Reference typereference -The return type when accessing an element of a vector expression. -
-Convertable to avalue_type. -
Const reference typeconst_reference -The return type when accessing an element of a constant vector expression. -
-Convertable to avalue_type. -
Size typesize_type -The index type of the vector expression. Am unsigned integral type used to represent size and index values. -
-Can represent any nonnegative value of difference_type. -
Distance typedifference_type -A signed integral type used to represent the distance between two of the vector expression's iterators. -
Const iterator typeconst_iteratorA type of iterator that may be used to examine a vector -expression's elements.
Iterator typeiteratorA type of iterator that may be used to modify a vector -expression's elements.
Const reverse iterator typeconst_reverse_iteratorA Reverse Iterator adaptor whose base iterator type is the -vector expression's const iterator type.
Reverse iterator typereverse_iteratorA Reverse Iterator adaptor whose base iterator type is the -vector expression's iterator type.
-

Notation

- - - - - - - - - - - - - - - - - - - -
VA type that is a model of Vector Expression
v, v1, v2Object of type V
iObject of a type convertible to size_type
tObject of a type convertible to value_type
-

Definitions

-

Valid expressions

-

In addition to the expressions defined in Default Constructible -the following expressions must be valid.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Beginning of rangev.begin () const_iterator
v.begin ()v is mutable.iterator
End of rangev.end () const_iterator
v.end ()v is mutable.iterator
Sizev.size () size_type
Swapv1.swap (v2)v1 and v2 are mutable.void
Beginning of reverse rangev.rbegin () const_reverse_iterator
v.rbegin ()v is mutable.reverse_iterator
End of reverse rangev.rend () const_reverse_iterator
v.rend ()v is mutable.reverse_iterator
Element accessv (i)i is convertible to size_type.Convertible to value_type.
Assignmentv2 = v1v2 is mutable and v1 is convertible -to V.V &
v2.assign (v1)v2 is mutable and v1 is convertible -to V.V &
Computed assignmentv2 += v1v2 is mutable and v1 is convertible -to V.V &
v2.plus_assign (v1)v2 is mutable and v1 is convertible -to V.V &
v2 -= v1v2 is mutable and v1 is convertible -to V.V &
v2.minus_assign (v1)v2 is mutable and v1 is convertible -to V.V &
v *= tv is mutable and t is convertible to -value_type.V &
-

Expression semantics

-

Semantics of an expression is defined only where it differs -from, or is not defined in Default Constructible.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionPreconditionSemanticsPostcondition
Beginning of rangev.begin () Returns an iterator pointing to the first element in the vector -expression.v.begin () is either dereferenceable or -past-the-end. It is past-the-end if and only if v.size () == -0.
End of rangev.end () Returns an iterator pointing one past the last element in the -vector expression.v.end () is past-the-end.
Sizev.size () Returns the size of the vector expression, that is, its number -of elements.v.size () >= 0
Swapv1.swap (v2) Equivalent to swap (v1, v2). 
Beginning of reverse rangev.rbegin () Equivalent to reverse_iterator (v.end ()).v.rbegin () is either dereferenceable or -past-the-end. It is past-the-end if and only if v.size () == -0.
End of reverse rangev.rend () Equivalent to reverse_iterator (v.begin ()).v.rend () is past-the-end.
Element accessv (i)0 <= i < v.size ()Returns the i-th element of the vector -expression. 
Assignmentv2 = v1v1.size () == v2.size ()Assigns every element of the evaluated vector expression -v1 to the corresponding element of v2 -. 
v2.assign (v1)v1.size () == v2.size ()Assigns every element of v1 to the corresponding -element of v2. 
Computed assignmentv2 += v1v1.size () == v2.size ()Adds every element of the evaluated vector expression -v1 to the corresponding element of -v2. 
v2.plus_assign (v1)v1.size () == v2.size ()Adds every element of v1 to the corresponding -element of v2. 
v2 -= v1v1.size () == v2.size ()Subtracts every element of the evaluated vector expression -v1 from the corresponding element of v2 -. 
v2.minus_assign (v1)v1.size () == v2.size ()Subtracts every element of v1 from the -corresponding element of v2. 
v *= t Multiplies every element of v with t -. 
-

Complexity guarantees

-

The run-time complexity of begin () and end -() is specific for the evaluated vector expression, -typically amortized constant time.

-

The run-time complexity of size () is constant -time.

-

The run-time complexity of swap () is specific for -the evaluated vector expression, typically constant time.

-

The run-time complexity of rbegin () and rend -() is specific for the evaluated vector expression, -typically amortized constant time.

-

The run-time complexity of the element access is specific for -the evaluated vector expression, typically amortized constant time -for the dense and logarithmic for the sparse case.

-

The run-time complexity of the arithmetic operations is specific -for the evaluated vector expressions, typically linear in the size -of the expressions.

-

Invariants

- - - - - - - - - - - - - - - - - - - -
Valid rangeFor any vector expression v, [v.begin (), -v.end ()) is a valid range.
CompletenessAn algorithm that iterates through the range [v.begin (), -v.end ()) will pass through every element of v -.
Valid reverse range[v.rbegin (), v.rend ()) is a valid range.
Equivalence of rangesThe distance from v.begin () to v.end -() is the same as the distance from v.rbegin () -to v.rend ().
-

Models

-
    -
  • vector_range;
  • -
  • vector_slice
  • -
  • matrix_row
  • -
  • matrix_column
  • -
  • matrix_vector_range
  • -
  • matrix_vector_slice
  • -
  • vector_unary
  • -
  • vector_binary
  • -
  • vector_binary_scalar1
  • -
  • vector_binary_scalar2
  • -
  • matrix_vector_unary1
  • -
  • matrix_vector_unary2
  • -
  • matrix_vector_binary1
  • -
  • matrix_vector_binary2
  • -
- -

Matrix Expression

-

Description

-

A Matrix Expression is an expression evaluatable to a matrix. -Matrix Expression provides an Indexed -Bidirectional Column/Row Iterator or an Indexed Random -Access Column/Row Iterator .

-

Refinement of

-

Default Constructible.

- -

Associated types

-
immutable types
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Public basematrix_expression<M>M must be derived from this public base type.
Value typevalue_type -The element type of the matrix expression. -
Const reference typeconst_reference -The return type when accessing an element of a constant matrix expression. -
-Convertable to a value_type. -
Size typesize_type -The index type of the matrix expression. Am unsigned integral type used to represent size and index values. -
-Can represent any nonnegative value of difference_type. -
Distance typedifference_type -A signed integral type used to represent the distance between two of the matrix expression's iterators. -
Const iterator typesconst_iterator1A type of column iterator that may be used to examine a matrix -expression's elements.
const_iterator2A type of row iterator that may be used to examine a matrix -expression's elements.
Const reverse iterator typesconst_reverse_iterator1A Reverse Iterator adaptor whose base iterator type is the -matrix expression's const column iterator type.
const_reverse_iterator2A Reverse Iterator adaptor whose base iterator type is the -matrix expression's const row iterator type.
- -
mutable types
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Reference typereference -The return type when accessing an element of a matrix expression. -
-Convertable to a value_type. -
Iterator typesiterator1A type of column iterator that may be used to modify a matrix -expression's elements.
iterator2A type of row iterator that may be used to modify a matrix -expression's elements.
Reverse iterator typesreverse_iterator1A Reverse Iterator adaptor whose base iterator type is the -matrix expression's column iterator type.
reverse_iterator2A Reverse Iterator adaptor whose base iterator type is the -matrix expression's row iterator type.
- - -

Notation

- - - - - - - - - - - - - - - - - - - -
MA type that is a model of Matrix Expression
m, m1, m2Object of type M
i, jObjects of a type convertible to size_type
tObject of a type convertible to value_type
-

Definitions

-

Valid expressions

-

In addition to the expressions defined in Default Constructible -the following expressions must be valid.

- -
immutable expressions
- - - - - - - - - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Sizem.size1 () size_type
m.size2 () size_type
- -
possibly mutable expressions
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Beginning of rangem.begin1 () const_iterator1
m.begin2 () const_iterator2
m.begin1 ()m is mutable. iterator1
m.begin2 ()m is mutable.iterator2
End of rangem.end1 () const_iterator1
m.end2 () const_iterator2
m.end1 ()m is mutable. iterator1
m.end2 ()m is mutable.iterator2
Swapm1.swap (m2)m1 and m2 are mutable. void
Beginning of reverse rangem.rbegin1 () const_reverse_iterator1
m.rbegin2 () const_reverse_iterator2
m.rbegin1 ()m is mutable. reverse_iterator1
m.rbegin2 ()m is mutable.reverse_iterator2
End of reverse rangem.rend1 () const_reverse_iterator1
m.rend2 () const_reverse_iterator2
m.rend1 ()m is mutable.reverse_iterator1
m.rend2 ()m is mutable.reverse_iterator2
Element accessm (i, j)i and j are convertible to -size_type .Convertible to value_type.
Assignmentm2 = m1m2 is mutable and m1 is convertible -to M.M &
m2.assign (m1)m2 is mutable and m1 is convertible -to M.M &
Computed assignmentm2 += m1m2 is mutable and m1 is convertible -to M.M &
m2.plus_assign (m1)m2 is mutable and m1 is convertible -to M.M &
m2 -= m1m2 is mutable and m1 is convertible -to M.M &
m2.minus_assign (m1)m2 is mutable and m1 is convertible -to M.M &
m *= tm is mutable and t is convertible to -value_type.M &
-

Expression semantics

-

Semantics of an expression is defined only where it differs -from, or is not defined in Default Constructible.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionPreconditionSemanticsPostcondition
Beginning of rangem.begin1 () Returns an iterator pointing to the first element in the first -column of a matrix expression.m.begin1 () is either dereferenceable or -past-the-end. It is past-the-end if and only if m.size1 () == -0.
m.begin2 () Returns an iterator pointing to the first element in the first -row of a matrix expression.m.begin2 () is either dereferenceable or -past-the-end. It is past-the-end if and only if m.size2 () == -0.
End of rangem.end1 () Returns an iterator pointing one past the last element in the -matrix expression.m.end1 () is past-the-end.
m.end2 () Returns an iterator pointing one past the last element in the -matrix expression.m.end2 () is past-the-end.
Sizem.size1 () Returns the number of rows of the matrix expression.m.size1 () >= 0
m.size2 () Returns the number of columns of the matrix expression.m.size2 () >= 0
Swapm1.swap (m2) Equivalent to swap (m1, m2). 
Beginning of reverse rangem.rbegin1 () Equivalent to reverse_iterator1 (m.end1 ()).m.rbegin1 () is either dereferenceable or -past-the-end. It is past-the-end if and only if m.size1 () == -0.
m.rbegin2 () Equivalent to reverse_iterator2 (m.end2 ()).m.rbegin2 () is either dereferenceable or -past-the-end. It is past-the-end if and only if m.size2 () == -0.
End of reverse rangem.rend1 () Equivalent to reverse_iterator1 (m.begin1 -()).m.rend1 () is past-the-end.
m.rend2 () Equivalent to reverse_iterator2 (m.begin2 -()).m.rend2 () is past-the-end.
Element accessm (i, j)0 <= i < m.size1 () and 0 <= j < -m.size2 ()Returns the j-th element of the i-th -row of the matrix expression. 
Assignmentm2 = m1m1.size1 () == m2.size1 () and
-m1.size2 () == m2.size2 ()
Assigns every element of the evaluated matrix expression -m1 to the corresponding element of m2 -. 
m2.assign (m1)m1.size1 () == m2.size1 () and
-m1.size2 () == m2.size2 ()
Assigns every element of m1 to the corresponding -element of m2. 
Computed assignmentm2 += m1m1.size1 () == m2.size1 () and
-m1.size2 () == m2.size2 ()
Adds every element of the evaluated matrix expression -m1 to the corresponding element of -m2. 
m2.plus_assign (m1)m1.size1 () == m2.size1 () and
-m1.size2 () == m2.size2 ()
Adds every element of m1 to the corresponding -element of m2. 
m2 -= m1m1.size1 () == m2.size1 () and
-m1.size2 () == m2.size2 ()
Subtracts every element of the evaluated matrix expression -m1 from the corresponding element of m2 -. 
m2.minus_assign (m1)m1.size1 () == m2.size1 () and
-m1.size2 () == m2.size2 ()
Subtracts every element of m1 from the -corresponding element of m2. 
m *= t Multiplies every element of m with t -. 
-

Complexity guarantees

-

The run-time complexity of begin1 (), begin2 -() , end1 () and end2 () is -specific for the evaluated matrix expression.

-

The run-time complexity of size1 () and size2 -() is constant time.

-

The run-time complexity of swap () is specific for -the evaluated matrix expression, typically constant time.

-

The run-time complexity of rbegin1 (), -rbegin2 () , rend1 () and rend2 -() is specific for the evaluated matrix expression.

-

The run-time complexity of the element access is specific for -the evaluated matrix expression, typically amortized constant time -for the dense and logarithmic for the sparse case.

-

The run-time complexity of the arithmetic operations is specific -for the evaluated matrix expressions, typically quadratic in the -size of the proxies.

-

Invariants

- - - - - - - - - - - - - - - - - - - -
Valid rangeFor any matrix expression m, [m.begin1 (), -m.end1 ()) and [m.begin2 (), m.end2 ()) are -valid ranges.
CompletenessAn algorithm that iterates through the range [m.begin1 -(), m.end1 ()) will pass through every row of m -, an algorithm that iterates through the range [m.begin2 (), -m.end2 ()) will pass through every column of m -.
Valid reverse range[m.rbegin1 (), m.rend1 ()) and [m.rbegin2 -(), m.rend2 ()) are valid ranges.
Equivalence of rangesThe distance from m.begin1 () to m.end1 -() is the same as the distance from m.rbegin1 -() to m.rend1 () and the distance from -m.begin2 () to m.end2 () is the same as -the distance from m.rbegin2 () to m.rend2 -().
-

Models

-
    -
  • matrix_range
  • -
  • matrix_slice;
  • -
  • triangular_adaptor
  • -
  • symmetric_adaptor
  • -
  • banded_adaptor
  • -
  • vector_matrix_binary
  • -
  • matrix_unary1
  • -
  • matrix_unary2
  • -
  • matrix_binary
  • -
  • matrix_binary_scalar1
  • -
  • matrix_binary_scalar2
  • -
  • matrix_matrix_binary
  • -
-
-

Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
- Use, modification and distribution are 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 - ). -

- - - diff --git a/doc/hermitian.html b/doc/hermitian.html deleted file mode 100644 index f6a4f62ae..000000000 --- a/doc/hermitian.html +++ /dev/null @@ -1,597 +0,0 @@ - - - - - - - - - -Hermitian Matrix - - -

Hermitian Matrix

-
-

Hermitian Matrix

-

Description

-

The templated class hermitian_matrix<T, F1, F2, -A> is the base container adaptor for hermitian matrices. -For a (n x n )-dimensional hermitian matrix and 0 -<= i < n, 0 <= j < n holds -hi, j = hj, -i-. The storage of hermitian -matrices is packed.

-

Example

-
-#include <boost/numeric/ublas/hermitian.hpp>
-#include <boost/numeric/ublas/io.hpp>
-
-int main () {
-    using namespace boost::numeric::ublas;
-    hermitian_matrix<std::complex<double>, lower> ml (3, 3);
-    for (unsigned i = 0; i < ml.size1 (); ++ i) {
-        for (unsigned j = 0; j < i; ++ j)
-            ml (i, j) = std::complex<double> (3 * i + j, 3 * i + j);
-        ml (i, i) = std::complex<double> (4 * i, 0);
-    }
-    std::cout << ml << std::endl;
-    hermitian_matrix<std::complex<double>, upper> mu (3, 3);
-    for (unsigned i = 0; i < mu.size1 (); ++ i) {
-        mu (i, i) = std::complex<double> (4 * i, 0);
-        for (unsigned j = i + 1; j < mu.size2 (); ++ j)
-            mu (i, j) = std::complex<double> (3 * i + j, 3 * i + j);
-    }
-    std::cout << mu << std::endl;
-}
-
-

Definition

-

Defined in the header hermitian.hpp.

-

Template parameters

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ParameterDescriptionDefault
TThe type of object stored in the matrix.
F1Functor describing the type of the hermitian matrix. [1]lower
F2Functor describing the storage organization. [2]row_major
AThe type of the adapted array. [3]unbounded_array<T>
-

Model of

-

Matrix .

-

Type requirements

-

None, except for those imposed by the requirements of Matrix .

-

Public base classes

-

matrix_container<hermitian_matrix<T, F1, F2, A> ->

-

Members

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MemberDescription
hermitian_matrix ()Allocates an uninitialized hermitian_matrix that -holds zero rows of zero elements.
hermitian_matrix (size_type size)Allocates an uninitialized hermitian_matrix that -holds size rows of size elements.
hermitian_matrix (const hermitian_matrix -&m)The copy constructor.
template<class AE>
-hermitian_matrix (const matrix_expression<AE> -&ae)
The extended copy constructor.
void resize (size_type size, bool preserve = -true)Reallocates a hermitian_matrix to hold -size rows of size elements. The existing -elements of the hermitian_matrix are preseved when -specified.
size_type size1 () constReturns the number of rows.
size_type size2 () constReturns the number of columns.
const_reference operator () (size_type i, size_type j) -constReturns a const reference of the j --th element in the i-th row.
reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
hermitian_matrix &operator = (const hermitian_matrix -&m)The assignment operator.
hermitian_matrix &assign_temporary (hermitian_matrix -&m)Assigns a temporary. May change the hermitian matrix -m .
template<class AE>
-hermitian_matrix &operator = (const matrix_expression<AE> -&ae)
The extended assignment operator.
template<class AE>
-hermitian_matrix &assign (const matrix_expression<AE> -&ae)
Assigns a matrix expression to the hermitian matrix. Left and -right hand side of the assignment should be independent.
template<class AE>
-hermitian_matrix &operator += (const -matrix_expression<AE> &ae)
A computed assignment operator. Adds the matrix expression to -the hermitian matrix.
template<class AE>
-hermitian_matrix &plus_assign (const -matrix_expression<AE> &ae)
Adds a matrix expression to the hermitian matrix. Left and -right hand side of the assignment should be independent.
template<class AE>
-hermitian_matrix &operator -= (const -matrix_expression<AE> &ae)
A computed assignment operator. Subtracts the matrix expression -from the hermitian matrix.
template<class AE>
-hermitian_matrix &minus_assign (const -matrix_expression<AE> &ae)
Subtracts a matrix expression from the hermitian matrix. Left -and right hand side of the assignment should be independent.
template<class AT>
-hermitian_matrix &operator *= (const AT &at)
A computed assignment operator. Multiplies the hermitian matrix -with a scalar.
template<class AT>
-hermitian_matrix &operator /= (const AT &at)
A computed assignment operator. Divides the hermitian matrix -through a scalar.
void swap (hermitian_matrix &m)Swaps the contents of the hermitian matrices.
void insert (size_type i, size_type j, const_reference -t)Inserts the value t at the j-th -element of the i-th row.
void erase (size_type i, size_type j)Erases the value at the j-th elemenst of the -i-th row.
void clear ()Clears the matrix.
const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the hermitian_matrix.
const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the hermitian_matrix.
iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the hermitian_matrix.
iterator1 end1 ()Returns a iterator1 pointing to the end of the -hermitian_matrix.
const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the hermitian_matrix.
const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the hermitian_matrix.
iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the hermitian_matrix.
iterator2 end2 ()Returns a iterator2 pointing to the end of the -hermitian_matrix.
const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed hermitian_matrix.
const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed hermitian_matrix.
reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed hermitian_matrix.
reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed hermitian_matrix.
const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed hermitian_matrix.
const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed hermitian_matrix.
reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed hermitian_matrix.
reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed hermitian_matrix.
-

Notes

-

[1] -Supported parameters for the type of the hermitian matrix are -lower and upper.

-

[2] -Supported parameters for the storage organization are -row_major and column_major.

-

[3] -Supported parameters for the adapted array are -unbounded_array<T> , -bounded_array<T> and -std::vector<T> .

-

Hermitian Adaptor

-

Description

-

The templated class hermitian_adaptor<M, F> -is a hermitian matrix adaptor for other matrices.

-

Example

-
-#include <boost/numeric/ublas/hermitian.hpp>
-#include <boost/numeric/ublas/io.hpp>
-
-int main () {
-    using namespace boost::numeric::ublas;
-    matrix<std::complex<double> > m (3, 3);
-    hermitian_adaptor<matrix<std::complex<double> >, lower> hal (m);
-    for (unsigned i = 0; i < hal.size1 (); ++ i) {
-        for (unsigned j = 0; j < i; ++ j)
-            hal (i, j) = std::complex<double> (3 * i + j, 3 * i + j);
-        hal (i, i) = std::complex<double> (4 * i, 0);
-    }
-    std::cout << hal << std::endl;
-    hermitian_adaptor<matrix<std::complex<double> >, upper> hau (m);
-    for (unsigned i = 0; i < hau.size1 (); ++ i) {
-        hau (i, i) = std::complex<double> (4 * i, 0);
-        for (unsigned j = i + 1; j < hau.size2 (); ++ j)
-            hau (i, j) = std::complex<double> (3 * i + j, 3 * i + j);
-    }
-    std::cout << hau << std::endl;
-}
-
-

Definition

-

Defined in the header hermitian.hpp.

-

Template parameters

- - - - - - - - - - - - - - - - - - -
ParameterDescriptionDefault
MThe type of the adapted matrix.
FFunctor describing the type of the hermitian adaptor. [1]lower
-

Model of

-

Matrix Expression -.

-

Type requirements

-

None, except for those imposed by the requirements of Matrix Expression .

-

Public base classes

-

matrix_expression<hermitian_adaptor<M, F> ->

-

Members

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MemberDescription
hermitian_adaptor (matrix_type &data)Constructs a hermitian_adaptor of a matrix.
hermitian_adaptor (const hermitian_adaptor -&m)The copy constructor.
template<class AE>
-hermitian_adaptor (const matrix_expression<AE> -&ae)
The extended copy constructor.
size_type size1 () constReturns the number of rows.
size_type size2 () constReturns the number of columns.
const_reference operator () (size_type i, size_type j) -constReturns a const reference of the j --th element in the i-th row.
reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
hermitian_adaptor &operator = (const -hermitian_adaptor &m)The assignment operator.
hermitian_adaptor &assign_temporary -(hermitian_adaptor &m)Assigns a temporary. May change the hermitian adaptor -m.
template<class AE>
-hermitian_adaptor &operator = (const -matrix_expression<AE> &ae)
The extended assignment operator.
template<class AE>
-hermitian_adaptor &assign (const matrix_expression<AE> -&ae)
Assigns a matrix expression to the hermitian adaptor. Left and -right hand side of the assignment should be independent.
template<class AE>
-hermitian_adaptor &operator += (const -matrix_expression<AE> &ae)
A computed assignment operator. Adds the matrix expression to -the hermitian adaptor.
template<class AE>
-hermitian_adaptor &plus_assign (const -matrix_expression<AE> &ae)
Adds a matrix expression to the hermitian adaptor. Left and -right hand side of the assignment should be independent.
template<class AE>
-hermitian_adaptor &operator -= (const -matrix_expression<AE> &ae)
A computed assignment operator. Subtracts the matrix expression -from the hermitian adaptor.
template<class AE>
-hermitian_adaptor &minus_assign (const -matrix_expression<AE> &ae)
Subtracts a matrix expression from the hermitian adaptor. Left -and right hand side of the assignment should be independent.
template<class AT>
-hermitian_adaptor &operator *= (const AT &at)
A computed assignment operator. Multiplies the hermitian -adaptor with a scalar.
template<class AT>
-hermitian_adaptor &operator /= (const AT &at)
A computed assignment operator. Divides the hermitian adaptor -through a scalar.
void swap (hermitian_adaptor &m)Swaps the contents of the hermitian adaptors.
const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the hermitian_adaptor.
const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the hermitian_adaptor.
iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the hermitian_adaptor.
iterator1 end1 ()Returns a iterator1 pointing to the end of the -hermitian_adaptor.
const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the hermitian_adaptor.
const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the hermitian_adaptor.
iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the hermitian_adaptor.
iterator2 end2 ()Returns a iterator2 pointing to the end of the -hermitian_adaptor.
const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed hermitian_adaptor.
const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed hermitian_adaptor.
reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed hermitian_adaptor.
reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed hermitian_adaptor.
const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed hermitian_adaptor.
const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed hermitian_adaptor.
reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed hermitian_adaptor.
reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed hermitian_adaptor.
-

Notes

-

[1] -Supported parameters for the type of the hermitian adaptor are -lower and upper.

-
-

Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
- Use, modification and distribution are 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 - ). -

- - - diff --git a/doc/index.html b/doc/index.html deleted file mode 100644 index bedf58133..000000000 --- a/doc/index.html +++ /dev/null @@ -1,432 +0,0 @@ - - - - - - - - - - - -Boost Basic Linear Algebra - - -

logoBasic Linear Algebra Library

-
- -

uBLAS is a C++ template class library that provides BLAS level 1, 2, 3 -functionality for dense, packed and sparse matrices. The design and implementation unify mathematical notation via -operator overloading and efficient code generation via expression templates.

- -

Functionality

- -

uBLAS provides templated C++ classes for dense, unit and sparse vectors, dense, identity, triangular, banded, -symmetric, hermitian and sparse matrices. Views into vectors and matrices can be constructed via ranges, slices, -adaptor classes and indirect arrays. The library covers the usual basic linear algebra operations on vectors and matrices: reductions like -different norms, addition and subtraction of vectors and matrices and multiplication with a scalar, inner and outer -products of vectors, matrix vector and matrix matrix products and triangular solver. The glue between containers, views -and expression templated operations is a mostly STL conforming iterator interface.

- -

Documentation

- - - -

Release notes

-Release notes can be found here. - - -

Known limitations

- -
    -
  • The implementation assumes a linear memory address model.
  • - -
  • Tuning was focussed on dense matrices.
  • -
- -

Further Information

- - - -

Authors and Credits

- -

uBLAS initially was written by Joerg Walter and Mathias Koch. We would like to thank all, which supported and -contributed to the development of this library: David Abrahams, Ed Brey, Fernando Cacciola, Juan Jose Gomez Cadenas, -Beman Dawes, Matt Davies, Bob Fletcher, Kresimir Fresl, Joachim Kessel, Patrick Kowalzick, Toon Knapen, Hendrik Kueck, -John Maddock, Jens Maurer, Alexei Novakov, Gary Powell, Joachim Pyras, Peter Schmitteckert, Jeremy Siek, Markus Steffl, -Michael Stevens, Benedikt Weber, Martin Weiser, Gunter Winkler, Marc Zimmermann, Marco Guazzone, Nasos Iliopoulus, the members of Boost and all others contributors around the world. I promise I will try to add their names to this list.

-

-This library is currently maintained by David Bellot and Stefan Seefeld. - -

Frequently Asked Questions

- -

Q: Should I use uBLAS for new projects?
-A: At the time of writing (09/2012) there are a lot of good matrix libraries available, e.g., -MTL4, -armadillo, -eigen. uBLAS offers a stable, well tested set of vector and -matrix classes, the typical operations for linear algebra and solvers for triangular systems of equations. uBLAS offers -dense, structured and sparse matrices - all using similar interfaces. And finally uBLAS offers good (but not outstanding) -performance. On the other side, the last major improvement of uBLAS was in 2008 and no significant change was committed -since 2009. So one should ask himself some questions to aid the decision: Availability? uBLAS is part of boost -and thus available in many environments. Easy to use? uBLAS is easy to use for simple things, but needs decent -C++ knowledge when you leave the path. Performance? There are faster alternatives. Cutting edge? uBLAS -is more than 10 years old and missed all new stuff from C++11.

- -

Q: I'm running the uBLAS dense vector and matrix benchmarks. Why do I see a significant performance difference -between the native C and library implementations?
-A: uBLAS distinguishes debug mode (size and type conformance checks enabled, expression templates disabled) and release -mode (size and type conformance checks disabled, expression templates enabled). Please check, if the preprocessor -symbol NDEBUG of cassert is defined. NDEBUG enables release mode, which in turn -uses expression templates. You can optionally define BOOST_UBLAS_NDEBUG to disable all bounds, structure -and similar checks of uBLAS.

- -

Q: I've written some uBLAS tests, which try to incorrectly assign different matrix types or overrun vector and -matrix dimensions. Why don't I get a compile time or runtime diagnostic?
-A: uBLAS distinguishes debug mode (size and type conformance checks enabled, expression templates disabled) and release -mode (size and type conformance checks disabled, expression templates enabled). Please check, if the preprocessor -symbol NDEBUG of cassert is defined. NDEBUG disables debug mode, which is needed -to get size and type conformance checks.

- -

Q: I've written some uBLAS benchmarks to measure the performance of matrix chain multiplications like prod (A, -prod (B, C)) and see a significant performance penalty due to the use of expression templates. How can I disable -expression templates?
-A: You do not need to disable expression templates. Please try reintroducing temporaries using either prod -(A, matrix_type (prod (B, C))) or prod (A, -prod<matrix_type > (B, C)).

- -
- -

Copyright (©) 2000-2011 Joerg Walter, Mathias Koch, Gunter Winkler, David Bellot
-Use, modification and distribution are 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 -).

- - - diff --git a/doc/iterator_concept.html b/doc/iterator_concept.html deleted file mode 100644 index c9e4c9951..000000000 --- a/doc/iterator_concept.html +++ /dev/null @@ -1,1168 +0,0 @@ - - - - - - - - - -Iterator Concepts - - -

Iterator Concepts

-
-

An Iterator is a restricted pointer-like object pointing into a -vector or matrix container.

-

Indexed Bidirectional Iterator

-

Description

-

An Indexed Bidirectional Iterator is an iterator of a container -that can be dereferenced, incremented, decremented and carries -index information.

-

Refinement of

-

Assignable, Equality Comparable, Default Constructible.

-

Associated types

- - - - - - - - - - - -
Value typeThe type of the value obtained by dereferencing a Indexed -Bidirectional Iterator
Container typeThe type of the container a Indexed Bidirectional Iterator -points into.
-

Notation

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
IA type that is a model of Indexed Bidirectional Iterator
TThe value type of I
CThe container type of I
it, itt, it1, it2Objects of type I
tObject of type T
cObject of type C
-

Definitions

-

A Indexed Bidirectional Iterator may be mutable, meaning -that the values referred to by objects of that type may be -modified, or constant , meaning that they may not. If an -iterator type is mutable, this implies that its value type is a -model of Assignable; the converse, though, is not necessarily -true.

-

A Indexed Bidirectional Iterator may have a singular -value, meaning that the results of most operations, including -comparison for equality, are undefined. The only operation that is -guaranteed to be supported is assigning a nonsingular iterator to a -singular iterator.

-

A Indexed Bidirectional Iterator may have a -dereferenceable value, meaning that dereferencing it yields -a well-defined value. Dereferenceable iterators are always -nonsingular, but the converse is not true.

-

An Indexed Bidirectional Iterator is past-the-end if it -points beyond the last element of a container. Past-the-end values -are nonsingular and nondereferenceable.

-

Valid expressions

-

In addition to the expressions defined for Assignable, Equality -Comparable and Default Constructible, the following expressions -must be valid.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Default constructorI it  
Dereference*it Convertible to T.
Dereference assignment*it = tI is mutable. 
Member accessit->mT is a type for which t.m is -defined. 
Preincrement++ it I &
Postincrementit ++ I
Predecrement-- it I &
Postdecrementit -- I
Indexit.index () C::size_type
-

Expression Semantics

-

Semantics of an expression is defined only where it differs -from, or is not defined in, Assignable, Equality Comparable and -Default Constructible.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionPreconditionSemanticsPostcondition
Default constructorI it  it is singular.
Dereference*itit is dereferenceable.  
Dereference assignment*it = tSame as for *it. *it is a copy of t.
Member accessit->mit is dereferenceable.Equivalent to (*it).m 
Preincrement++ itit is dereferenceable.it is modified to point to the next element.it is dereferenceable or past-the-end. -
-&it == &++ it
.
-If it1 == it2,
-then ++ it1 == ++ it2.
Postincrementit ++Same as for ++ it.Equivalent to
-{
- I itt = it;
- ++ it;
- return itt;
-}
it is dereferenceable or past-the-end.
Predecrement-- itit is dereferenceable or past-the-end.
-There exists a dereferenceable iterator itt such that -it == ++ itt.
it is modified to point to the previous -element.it is dereferenceable.
-&it = &-- it.
-If it1 == it2,
-then -- it1 == -- it2.
-If it2 is dereferenceable and it1 == -++it2,
-then --it1 == it2.
Postdecrementit --Same as for -- it.Equivalent to
-{
- I itt = it;
- -- it;
- return itt;
-}
it is dereferenceable. 
Indexit.index ()it is dereferenceable.it.index () >= 0
-and
-it.index () < it ().size ()
If it1 == it2,
-then it1.index () == it2.index ().
-If it1 == it2,
-then it1.index () < (++ it2).index -().
-If it1 == it2,
-then it1.index () > (-- it2).index -().
-

Complexity guarantees

-

The complexity of operations on indexed bidirectional iterators -is guaranteed to be amortized constant time.

-

Invariants

- - - - - - - - - - - - - - - -
Identityit1 == it2 if and only if &*it1 == -&*it2.
Symmetry of increment and decrementIf it is dereferenceable, then ++ it; ---it; is a null operation. Similarly, -- it; ++ -it; is a null operation.
Relation between iterator index and container element -operatorIf it is dereferenceable, *it == it () -(it.index ()).
-

Models

-
    -
  • sparse_vector::iterator
  • -
-

Indexed Random Access Iterator

-

Description

-

An Indexed Random Access Iterator is an iterator of a container -that can be dereferenced, moved forward, moved backward and carries -index information.

-

Refinement of

-

LessThanComparable, Indexed Bidirectional -Iterator .

-

Associated types

- - - - - - - - - - - -
Value typeThe type of the value obtained by dereferencing a Indexed -Random Access Iterator
Container typeThe type of the container a Indexed Random Access Iterator -points into.
-

Notation

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
IA type that is a model of Indexed Random Access Iterator
TThe value type of I
CThe container type of I
it, itt, it1, it2Objects of type I
tObject of type T
nObject of type C::difference_type
-

Definitions

-

An Indexed Random Access Iterator it1 is -reachable from an Indexed Random Access Iterator -it2 if, after applying operator ++ to -it2 a finite number of times, it1 == -it2.

-

Valid expressions

-

In addition to the expressions defined for Indexed Bidirectional -Iterator , the following expressions must be valid.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Forward motionit += n I &
Iterator additionit + n I
Backward motioni -= n I &
Iterator subtractionit - n I 
Differenceit1 - it2 C::difference_type
Element operatorit [n] Convertible to T.
Element assignmentit [n] = tI is mutableConvertible to T.
-

Expression Semantics

-

Semantics of an expression is defined only where it differs -from, or is not defined in, Indexed Bidirectional -Iterator .

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionPreconditionSemanticsPostcondition
Forward motionit += nIncluding it itself, there must be n -dereferenceable or past-the-end iterators following or preceding -it, depending on whether n is positive or -negative.If n > 0, equivalent to executing ++ -it n times. If n < 0, -equivalent to executing -- it n times. If -n == 0, this is a null operation.it is dereferenceable or past-the-end.
Iterator additionit + nSame as for i += n.Equivalent to
-{
- I itt = it;
- return itt += n;
-}
Result is dereferenceable or past-the-end.
Backward motionit -= nIncluding it itself, there must be n -dereferenceable or past-the-end iterators preceding or following -it, depending on whether n is positive or -negative.Equivalent to it += (-n).it is dereferenceable or past-the-end.
Iterator subtractionit - nSame as for i -= n.Equivalent to
-{
- I itt = it;
- return itt -= n;
-}
Result is dereferenceable or past-the-end.
Differenceit1 - it2Either it1 is reachable from it2 or -it2 is reachable from it1, or both.Returns a number n such that it1 == it2 + -n 
Element operatorit [n]it + n exists and is dereferenceable.Equivalent to *(it + n) 
Element assignmenti[n] = tSame as for it [n].Equivalent to *(it + n) = t 
-

Complexity guarantees

-

The complexity of operations on indexed random access iterators -is guaranteed to be amortized constant time.

-

Invariants

- - - - - - - - - - - - - - - -
Symmetry of addition and subtractionIf it + n is well-defined, then it += n; it --= n; and (it + n) - n are null operations. -Similarly, if it - n is well-defined, then it -= -n; it += n; and (it - n) + n are null -operations.
Relation between distance and additionIf it1 - it2 is well-defined, then it1 == -it2 + (it1 - it2).
Reachability and distanceIf it1 is reachable from it2, then -it1 - it2 >= 0.
-

Models

-
    -
  • vector::iterator
  • -
-

Indexed Bidirectional Column/Row Iterator

-

Description

-

An Indexed Bidirectional Column/Row Iterator is an iterator of a -container that can be dereferenced, incremented, decremented and -carries index information.

-

Refinement of

-

Assignable, Equality Comparable, Default Constructible.

-

Associated types

- - - - - - - - - - - -
Value typeThe type of the value obtained by dereferencing a Indexed -Bidirectional Column/Row Iterator
Container typeThe type of the container a Indexed Bidirectional Column/Row -Iterator points into.
-

Notation

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
I1A type that is a model of Indexed Bidirectional Column/Row -Iterator
I2A type that is a model of Indexed Bidirectional Row/Column -Iterator
TThe value type of I1 and I2
CThe container type of I1 and I2
it1, it1t, it11, -it12Objects of type I1
it2, it2tObjects of type I2
tObject of type T
cObject of type C
-

Definitions

-

Valid expressions

-

In addition to the expressions defined for Assignable, Equality -Comparable and Default Constructible, the following expressions -must be valid.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Default constructorI1 it  
Dereference*it Convertible to T.
Dereference assignment*it = tI1 is mutable. 
Member accessit->mT is a type for which t.m is -defined. 
Preincrement++ it I1 &
Postincrementit ++ I1
Predecrement-- it I1 &
Postdecrementit -- I1
Row Indexit.index1 () C::size_type
Column Indexit.index2 () C::size_type
Row/Column Beginit.begin () I2
Row/Column Endit.end () I2
Reverse Row/Column Beginit.rbegin () reverse_iterator<I2>
Reverse Row/Column Endit.rend () reverse_iterator<I2>
-

Expression Semantics

-

Semantics of an expression is defined only where it differs -from, or is not defined in, Assignable, Equality Comparable and -Default Constructible.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionPreconditionSemanticsPostcondition
Default constructorI1 it  it is singular.
Dereference*itit is dereferenceable.  
Dereference assignment*it = tSame as for *it. *it is a copy of t.
Member accessit->mit is dereferenceable.Equivalent to (*it).m 
Preincrement++ itit is dereferenceable.it is modified to point to the next element of -the column/row, i.e. for column iterators holds
-it.index1 () < (++ it).index1 () and
-it.index2 () == (++ it).index2 (),
-for row iterators holds
-it.index1 () == (++ it).index1 () and
-it.index2 () < (++ it).index2 ().
it is dereferenceable or past-the-end. -
-&it == &++ it
.
-If it1 == it2,
-then ++ it1 == ++ it2.
Postincrementit ++Same as for ++ it.Equivalent to
-{
- I1 itt = it;
- ++ it;
- return itt;
-}
it is dereferenceable or past-the-end.
Predecrement-- itit is dereferenceable or past-the-end.
-There exists a dereferenceable iterator itt such that -it == ++ itt.
it is modified to point to the previous  -element of the column/row, i.e. for column iterators holds
-it.index1 () > (-- it).index1 () and
-it.index2 () == (-- it).index2 (),
-for row iterators holds
-it.index1 () == (-- it).index1 () and
-it.index2 () > (-- it).index2 ().
it is dereferenceable.
-&it = &-- it.
-If it1 == it2,
-then -- it1 == -- it2.
Postdecrementit --Same as for -- it.Equivalent to
-{
- I1 itt = it;
- -- it;
- return itt;
-}
it is dereferenceable. 
Row Indexit.index1 ()If it is a Row iterator then it must be dereferenceable.it.index1 () >= 0 and
-it.index1 () < it () .size1 ()
If it1 == it2,
-then it1.index1 () == 12.index1 ().
-If it1, it2 are Row Iterators with it1 == it2,
-then it1.index1 () < (++ it2).index1 ().
-and it1.index1 () > (-- it2).index1 ().
Column Indexit.index2 ()If it is a Column iterator then it must be dereferenceable.it.index2 () >= 0 and
-it.index2 () < it () .size2 ()
If it1 == it2,
-then it1.index2 () == it2.index2 () -.
-If it1, it2 are Column Iterators with it1 == i12,
-then it1.index2 () < (++ it2).index2 ().
-end it1.index2 () > (-- it2).index2 ().
Row/Column Beginit.begin ()it is dereferenceable.If it is a Column Iterator,
-then it2 = it.begin () is a Row Iterator
-with it2.index1 () == it.index1 (). -

If it is a Row Iterator,
-then it2 = it.begin () is a Column Iterator
-with it2.index2 () == it.index2 ().

-
 
Row/Column Endit.end ()it is dereferenceable.If it is a Column Iterator,
-then it2 = it.end () is a Row Iterator
-with it2.index1 () == it.index1 (). -

If it is a Row Iterator,
-then it2 = it.end () is a Column Iterator
-with it2.index2 () == it.index2 ().

-
 
Reverse Row/Column Beginit.rbegin ()it is dereferenceable.Equivalent to reverse_iterator<I2> (it.end -()). 
Reverse Row/Column Endit.rend ()it is dereferenceable.Equivalent to reverse_iterator<I2> (it.begin -()). 
-

Complexity guarantees

-

The complexity of operations on indexed bidirectional column/row -iterators is guaranteed to be logarithmic depending on the size of -the container. The complexity of one iterator (depending on the -storage layout) can be lifted to be amortized constant time. The -complexity of the other iterator (depending on the storage layout -and the container) can be lifted to be amortized constant time for -the first row/first column respectively.

-

Invariants

- - - - - - - - - - - - - - - - - - - - - - - -
Identityit1 == it2 if and only if &*it1 == -&*it2.
Symmetry of increment and decrementIf it is dereferenceable, then ++ it; ---it; is a null operation. Similarly, -- it; ++ -it; is a null operation.
Relation between iterator index and container element -operatorIf it is dereferenceable, *it == it () -(it.index1 (), it.index2 ())
Relation between iterator column/row begin and iterator -indexIf it is a Column Iterator -and it2 = it.begin () then it2.index2 () < -it2t.index2 () for all it2t with it2t () -== it2 () and it2t ().index1 () == it2 ().index1 -(). -

If it is a Row Iterator and -it2 = it.begin () then it2.index1 () < -it2t.index1 () for all it2t with it2t () -== it2 () and it2t ().index2 () == it2 ().index2 -().

-
Relation between iterator column/row end and iterator -indexIf it is a Column Iterator -and it2 = it.end () then it2.index2 () > -it2t.index2 () for all it2t with it2t () -== it2 () and it2t ().index1 () == it2 ().index1 -(). -

If it is a Row Iterator and -it2 = it.end () then it2.index1 () > -it2t.index1 () for all it2t with it2t () -== it2 () and it2t ().index2 () == it2 ().index2 -().

-
-

Models

-
    -
  • sparse_matrix::iterator1
  • -
  • sparse_matrix::iterator2
  • -
-

Indexed Random Access Column/Row Iterator

-

Description

-

An Indexed Random Access Column/Row Iterator is an iterator of a -container that can be dereferenced, incremented, decremented and -carries index information.

-

Refinement of

-

Indexed -Bidirectional Column/Row Iterator .

-

Associated types

- - - - - - - - - - - -
Value typeThe type of the value obtained by dereferencing a Indexed -Random Access Column/Row Iterator
Container typeThe type of the container a Indexed Random Access Column/Row -Iterator points into.
-

Notation

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
IA type that is a model of Indexed Random Access Column/Row -Iterator
TThe value type of I
CThe container type of I
it, itt, it1, it2Objects of type I
tObject of type T
cObject of type C
-

Definitions

-

Valid expressions

-

In addition to the expressions defined for Indexed Bidirectional -Column/Row Iterator , the following expressions must be -valid.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionType requirementsReturn type
Forward motionit += n I &
Iterator additionit + n I
Backward motioni -= n I &
Iterator subtractionit - n I 
Differenceit1 - it2 C::difference_type
Element operatorit [n] Convertible to T.
Element assignmentit [n] = tI is mutableConvertible to T.
-

Expression Semantics

-

Semantics of an expression is defined only where it differs -from, or is not defined in, Indexed Bidirectional -Column/Row Iterator .

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExpressionPreconditionSemanticsPostcondition
Forward motionit += nIncluding it itself, there must be n -dereferenceable or past-the-end iterators following or preceding -it, depending on whether n is positive or -negative.If n > 0, equivalent to executing ++ -it n times. If n < 0, -equivalent to executing -- it n times. If -n == 0, this is a null operation.it is dereferenceable or past-the-end.
Iterator additionit + nSame as for i += n.Equivalent to
-{
- I itt = it;
- return itt += n;
-}
Result is dereferenceable or past-the-end.
Backward motionit -= nIncluding it itself, there must be n -dereferenceable or past-the-end iterators preceding or following -it, depending on whether n is positive or -negative.Equivalent to it += (-n).it is dereferenceable or past-the-end.
Iterator subtractionit - nSame as for i -= n.Equivalent to
-{
- I itt = it;
- return itt -= n;
-}
Result is dereferenceable or past-the-end.
Differenceit1 - it2Either it1 is reachable from it2 or -it2 is reachable from it1, or both.Returns a number n such that it1 == it2 + -n 
Element operatorit [n]it + n exists and is dereferenceable.Equivalent to *(it + n) 
Element assignmenti[n] = tSame as for it [n].Equivalent to *(it + n) = t 
-

Complexity guarantees

-

The complexity of operations on indexed random access Column/Row -iterators is guaranteed to be amortized constant time.

-

Invariants

- - - - - - - - - - - - - - - -
Symmetry of addition and subtractionIf it + n is well-defined, then it += n; it --= n; and (it + n) - n are null operations. -Similarly, if it - n is well-defined, then it -= -n; it += n; and (it - n) + n are null -operations.
Relation between distance and additionIf it1 - it2 is well-defined, then it1 == -it2 + (it1 - it2).
Reachability and distanceIf it1 is reachable from it2, then -it1 - it2 >= 0.
-

Models

-
    -
  • matrix::iterator1
  • -
  • matrix::iterator2
  • -
-
-

Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
- Use, modification and distribution are 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 - ). -

- - - diff --git a/doc/js/jquery-1.3.2.min.js b/doc/js/jquery-1.3.2.min.js deleted file mode 100644 index b1ae21d8b..000000000 --- a/doc/js/jquery-1.3.2.min.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * jQuery JavaScript Library v1.3.2 - * http://jquery.com/ - * - * Copyright (c) 2009 John Resig - * Dual licensed under the MIT and GPL licenses. - * http://docs.jquery.com/License - * - * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) - * Revision: 6246 - */ -(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
"]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
","
"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); -/* - * Sizzle CSS Selector Engine - v0.9.3 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); \ No newline at end of file diff --git a/doc/js/jquery.toc-gw.js b/doc/js/jquery.toc-gw.js deleted file mode 100644 index d48dd4be6..000000000 --- a/doc/js/jquery.toc-gw.js +++ /dev/null @@ -1,166 +0,0 @@ -/*! - * jQuery TOC Plugin v1.1.x based on - * samaxesJS JavaScript Library - * http://code.google.com/p/samaxesjs/ - * - * Copyright (c) 2008 samaxes.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * 2009-10-04, guwi17: modified and extended to meet uBLAS' needs - */ - -(function($) { - /* - * The TOC plugin dynamically builds a table of contents from the headings in - * a document and prepends legal-style section numbers to each of the headings. - */ - $.fn.toc = function(options) { - var opts = $.extend({}, $.fn.toc.defaults, options); - - return this.each(function() { - var toc = $(this).append('
    ').children('ul'); - var headers = {h1: 0, h2: 0, h3: 0, h4: 0, h5: 0, h6: 0}; - var index = 0; - var indexes = { - h1: (opts.exclude.match('h1') == null && $('h1').length > 0) ? ++index : 0, - h2: (opts.exclude.match('h2') == null && $('h2').length > 0) ? ++index : 0, - h3: (opts.exclude.match('h3') == null && $('h3').length > 0) ? ++index : 0, - h4: (opts.exclude.match('h4') == null && $('h4').length > 0) ? ++index : 0, - h5: (opts.exclude.match('h5') == null && $('h5').length > 0) ? ++index : 0, - h6: (opts.exclude.match('h6') == null && $('h6').length > 0) ? ++index : 0 - }; - - $(':header').not(opts.exclude).each(function() { - var linkId = ""; - if ($(this).is('h6')) { - checkContainer(headers.h6, toc); - updateNumeration(headers, 'h6'); - $(this).text(addNumeration(headers, 'h6', $(this).text())); - linkId = fixAnchor($(this)); - appendToTOC(toc, indexes.h6, linkId, $(this).text(), headers); - } else if ($(this).is('h5')) { - checkContainer(headers.h5, toc); - updateNumeration(headers, 'h5'); - $(this).text(addNumeration(headers, 'h5', $(this).text())); - linkId = fixAnchor($(this)); - appendToTOC(toc, indexes.h5, linkId, $(this).text(), headers); - } else if ($(this).is('h4')) { - checkContainer(headers.h4, toc); - updateNumeration(headers, 'h4'); - $(this).text(addNumeration(headers, 'h4', $(this).text())); - linkId = fixAnchor($(this)); - appendToTOC(toc, indexes.h4, linkId, $(this).text(), headers); - } else if ($(this).is('h3')) { - checkContainer(headers.h3, toc); - updateNumeration(headers, 'h3'); - $(this).text(addNumeration(headers, 'h3', $(this).text())); - linkId = fixAnchor($(this)); - appendToTOC(toc, indexes.h3, linkId, $(this).text(), headers); - } else if ($(this).is('h2')) { - checkContainer(headers.h2, toc); - updateNumeration(headers, 'h2'); - $(this).text(addNumeration(headers, 'h2', $(this).text())); - linkId = fixAnchor($(this)); - appendToTOC(toc, indexes.h2, linkId, $(this).text(), headers); - } else if ($(this).is('h1')) { - updateNumeration(headers, 'h1'); - $(this).text(addNumeration(headers, 'h1', $(this).text())); - linkId = fixAnchor($(this)); - appendToTOC(toc, indexes.h1, linkId, $(this).text(), headers); - } - }); - }); - }; - - /* - * Checks if the last node is an 'ul' element. - * If not, a new one is created. - */ - function checkContainer(header, toc) { - if (header == 0 && !toc.find(':last').is('ul')) { - toc.find('li:last').append('
      '); - } - }; - - /* - * Updates headers numeration. - */ - function updateNumeration(headers, header) { - $.each(headers, function(i, val) { - if (i == header) { - ++headers[i]; - } else if (i > header) { - headers[i] = 0; - } - }); - }; - - /* - * Prepends the numeration to a heading. - */ - function addNumeration(headers, header, text) { - var numeration = ''; - - $.each(headers, function(i, val) { - if (i <= header && headers[i] > 0) { - numeration += headers[i] + '.'; - } - }); - - return removeFinalDot(numeration) + ' ' + text; - }; - - function removeFinalDot(text) { - return (text||"").replace(/\.$/g, "" ) - } - - function fixAnchor(element) { - // use existing id by default - var linkId = element.attr('id'); - // next, look for an anchor and use its id or name - if ( !linkId ) { - element.find('> a:first').each( function() { - linkId = $(this).attr('id') || $(this).attr('name'); - }); - } - // next, use the text content as last resort - if ( !linkId ) { - linkId = (element.text()||"unknown").replace(/[^a-zA-Z0-9]/g,""); - } - - element.attr('id',linkId); - return linkId; - } - - /* - * Appends a new node to the TOC. - */ - function appendToTOC(toc, index, id, text, headers) { - var parent = toc; - - for (var i = 1; i < index; i++) { - if (parent.find('> li:last > ul').length == 0) { - parent = parent.append('
      • '); - } - parent = parent.find('> li:last > ul'); - } - if (id) { - parent.append('
      • ' + text + '
      • '); - } else { - parent.append('
      • ' + text + '
      • '); - } - }; - - $.fn.toc.defaults = {exclude: 'h1, h5, h6'} -})(jQuery); diff --git a/doc/matrix.html b/doc/matrix.html deleted file mode 100644 index 0342d04a2..000000000 --- a/doc/matrix.html +++ /dev/null @@ -1,768 +0,0 @@ - - - - - - - - - -Matrix - - -

        Matrix

        -
        -

        Matrix

        -

        Description

        -

        The templated class matrix<T, F, A> is the -base container adaptor for dense matrices. For a (m x -n)-dimensional matrix and 0 <= i < m, 0 -<= j < n every element mi, -j is mapped to the (i x n + j)-th element of -the container for row major orientation or the (i + j x -m)-th element of the container for column major -orientation.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i)
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            m (i, j) = 3 * i + j;
        -    std::cout << m << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the matrix.
        FFunctor describing the storage organization. [1]row_major
        AThe type of the Storage array. [2]unbounded_array<T>
        -

        Model of

        -

        Matrix .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix .

        -

        Public base classes

        -

        matrix_container<matrix<T, F, A> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix ()Allocates an uninitialized matrix that holds zero -rows of zero elements.
        matrix (size_type size1, size_type size2)Allocates an uninitialized matrix that holds -size1 rows of size2 elements.
        matrix (const matrix &m)The copy constructor.
        template<class AE>
        -matrix (const matrix_expression<AE> &ae)
        The extended copy constructor.
        void resize (size_type size1, size_type size2, bool -preserve = true)Reallocates a matrix to hold size1 -rows of size2 elements. The existing elements of the -matrix are preseved when specified.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const array_type& data () const
        array_type& data ()
        const_reference operator () (size_type i, size_type j) -constReturns a const reference of the j --th element in the i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        matrix &operator = (const matrix &m)The assignment operator.
        matrix &assign_temporary (matrix &m)Assigns a temporary. May change the matrix m.
        template<class AE>
        -matrix &operator = (const matrix_expression<AE> -&ae)
        The extended assignment operator.
        template<class AE>
        -matrix &assign (const matrix_expression<AE> -&ae)
        Assigns a matrix expression to the matrix. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -matrix &operator += (const matrix_expression<AE> -&ae)
        A computed assignment operator. Adds the matrix expression to -the matrix.
        template<class AE>
        -matrix &plus_assign (const matrix_expression<AE> -&ae)
        Adds a matrix expression to the matrix. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -matrix &operator -= (const matrix_expression<AE> -&ae)
        A computed assignment operator. Subtracts the matrix expression -from the matrix.
        template<class AE>
        -matrix &minus_assign (const matrix_expression<AE> -&ae)
        Subtracts a matrix expression from the matrix. Left and right -hand side of the assignment should be independent.
        template<class AT>
        -matrix &operator *= (const AT &at)
        A computed assignment operator. Multiplies the matrix with a -scalar.
        template<class AT>
        -matrix &operator /= (const AT &at)
        A computed assignment operator. Divides the matrix through a -scalar.
        void swap (matrix &m)Swaps the contents of the matrices.
        void insert_element (size_type i, size_type j, const_reference -t)Inserts the value t at the j-th -element of the i-th row.
        void erase_element (size_type i, size_type j)Erases the value at the j-th element of the -i-th row.
        void clear ()Clears the matrix.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the matrix.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the matrix.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the matrix.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -matrix.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the matrix.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the matrix.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the matrix.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -matrix.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed matrix.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed matrix.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed matrix.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed matrix.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed matrix.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed matrix.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed matrix.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed matrix.
        -

        Notes

        -

        [1] Supported parameters -for the storage organization are row_major and -column_major.

        -

        [2] Common parameters -for the storage array are unbounded_array<T> , -bounded_array<T> and -std::vector<T> .

        -

        Identity Matrix

        -

        Description

        -

        The templated class identity_matrix<T, ALLOC> -represents identity matrices. For a (m x n)-dimensional -identity matrix and 0 <= i < m, 0 <= j < -n holds idi, j = 0, if -i <> j, and idi, i= -1.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    identity_matrix<double> m (3);
        -    std::cout << m << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the matrix.int
        ALLOCAn STL Allocator for size_type and difference_type.std::allocator
        -

        Model of

        -

        Matrix .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of -Matrix .

        -

        Public base classes

        -

        matrix_container<identity_matrix<T> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        identity_matrix ()Constructs an identity_matrix that holds zero rows -of zero elements.
        identity_matrix (size_type size)Constructs an identity_matrix that holds -size rows of size elements.
        identity_matrix (const identity_matrix -&m)The copy constructor.
        void resize (size_type size, bool preserve = -true)Resizes a identity_matrix to hold -size rows of size elements. Therefore the -existing elements of the itendity_matrix are always -preseved.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        identity_matrix &operator = (const identity_matrix -&m)The assignment operator.
        identity_matrix &assign_temporary (identity_matrix -&m)Assigns a temporary. May change the identity matrix -m .
        void swap (identity_matrix &m)Swaps the contents of the identity matrices.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the identity_matrix.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the identity_matrix.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the identity_matrix.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the identity_matrix.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed identity_matrix.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed identity_matrix.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed identity_matrix.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed identity_matrix.
        -

        Zero Matrix

        -

        Description

        -

        The templated class zero_matrix<T, ALLOC> represents -zero matrices. For a (m x n)-dimensional zero matrix and -0 <= i < m, 0 <= j < n holds -zi, j = 0.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    zero_matrix<double> m (3, 3);
        -    std::cout << m << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the matrix.int
        ALLOCAn STL Allocator for size_type and difference_type.std::allocator
        -

        Model of

        -

        Matrix .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of -Matrix .

        -

        Public base classes

        -

        matrix_container<zero_matrix<T> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        zero_matrix ()Constructs a zero_matrix that holds zero rows of -zero elements.
        zero_matrix (size_type size1, size_type -size2)Constructs a zero_matrix that holds -size1 rows of size2 elements.
        zero_matrix (const zero_matrix &m)The copy constructor.
        void resize (size_type size1, size_type size2, bool -preserve = true)Resizes a zero_matrix to hold size1 -rows of size2 elements. Therefore the existing -elements of the zero_matrix are always preseved.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        zero_matrix &operator = (const zero_matrix -&m)The assignment operator.
        zero_matrix &assign_temporary (zero_matrix -&m)Assigns a temporary. May change the zero matrix m -.
        void swap (zero_matrix &m)Swaps the contents of the zero matrices.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the zero_matrix.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the zero_matrix.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the zero_matrix.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the zero_matrix.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed zero_matrix.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed zero_matrix.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed zero_matrix.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed zero_matrix.
        -

        Scalar Matrix

        -

        Description

        -

        The templated class scalar_matrix<T, ALLOC> -represents scalar matrices. For a (m x n)-dimensional -scalar matrix and 0 <= i < m, 0 <= j < -n holds zi, j = s.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    scalar_matrix<double> m (3, 3);
        -    std::cout << m << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the matrix.int
        ALLOCAn STL Allocator for size_type and difference_type.std::allocator
        -

        Model of

        -

        Matrix .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of -Matrix .

        -

        Public base classes

        -

        matrix_container<scalar_matrix<T> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        scalar_matrix ()Constructs a scalar_matrix that holds scalar rows -of zero elements.
        scalar_matrix (size_type size1, size_type size2, const -value_type &value)Constructs a scalar_matrix that holds -size1 rows of size2 elements each of the -specified value.
        scalar_matrix (const scalar_matrix &m)The copy constructor.
        void resize (size_type size1, size_type size2, bool -preserve = true)Resizes a scalar_matrix to hold size1 -rows of size2 elements. Therefore the existing -elements of the scalar_matrix are always -preseved.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        scalar_matrix &operator = (const scalar_matrix -&m)The assignment operator.
        scalar_matrix &assign_temporary (scalar_matrix -&m)Assigns a temporary. May change the scalar matrix -m .
        void swap (scalar_matrix &m)Swaps the contents of the scalar matrices.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the scalar_matrix.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the scalar_matrix.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the scalar_matrix.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the scalar_matrix.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed scalar_matrix.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed scalar_matrix.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed scalar_matrix.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed scalar_matrix.
        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/matrix_expression.html b/doc/matrix_expression.html deleted file mode 100644 index a9798142d..000000000 --- a/doc/matrix_expression.html +++ /dev/null @@ -1,1428 +0,0 @@ - - - - - - - - - -Matrix Expressions - - -

        Matrix Expressions

        -
        -

        Matrix Expression

        -

        Description

        -

        The templated class matrix_expression<E> -is required to be a public base of all classes which model the Matrix Expression concept.

        -

        Definition

        -

        Defined in the header expression_types.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        EThe type of the matrix expression. 
        -

        Model of

        -

        None. Not a Matrix Expression! -

        -

        Type requirements

        -

        None.

        -

        Public base classes

        -

        None.

        -

        Members

        - - - - - - - - - - - - - - - -
        MemberDescription
        const expression_type &operator () () -constReturns a const reference of the expression.
        expression_type &operator () ()Returns a reference of the expression.
        -

        Notes

        -

        The operator[], row, column, range, slice and project functions have been removed. Use the free functions defined in matrix proxy instead.

        -

        Matrix Container

        -

        Description

        -

        The templated class matrix_container<C> -is required to be a public base of all classes which model the Matrix concept. -This includes the class matrix itself.

        -

        Definition

        -

        Defined in the header expression_types.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        EThe type of the matrix expression. 
        -

        Model of

        -

        None. Not a Matrix Expression OR Matrix! -

        -

        Type requirements

        -

        None.

        -

        Public base classes

        -

        matrix_expression<C>

        -

        Members

        - - - - - - - - - - - - - - - -
        MemberDescription
        const container_type &operator () () -constReturns a const reference of the container.
        container_type &operator () ()Returns a reference of the container.
        -

        Matrix References

        -

        Reference

        -

        Description

        -

        The templated class matrix_reference<E> -contains a reference to a matrix expression.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        EThe type of the matrix expression. 
        -

        Model of

        -

        Matrix Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix Expression .

        -

        Public base classes

        -

        matrix_expression<matrix_reference<E> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_reference (expression_type &e)Constructs a constant reference of the expression.
        void resize (size_type size1, size2)Resizes the expression to hold at most size1 rows -of size2 elements.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the expression.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the expression.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the expression.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -expression.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the expression.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the expression.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the expression.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -expression.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed expression.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed expression.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed expression.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed expression.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed expression.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed expression.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed expression.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed expression.
        -

        Matrix Operations

        -

        Unary Operation Description

        -

        Description

        -

        The templated classes matrix_unary1<E, F> and -matrix_unary2<E, F> describe unary matrix -operations.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        EThe type of the matrix expression. 
        FThe type of the operation. 
        -

        Model of

        -

        Matrix Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix Expression .

        -

        Public base classes

        -

        matrix_expression<matrix_unary1<E, F> > -and matrix_expression<matrix_unary2<E, F> -> resp.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_unary1 (const expression_type &e)Constructs a description of the expression.
        matrix_unary2 (const expression_type &e)Constructs a description of the expression.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the expression.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the expression.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the expression.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the expression.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed expression.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed expression.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed expression.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed expression.
        -

        Unary Operations

        -

        Prototypes

        -
        -template<class E, class F>
        -    struct matrix_unary1_traits {
        -        typedef matrix_unary1<typename E::const_closure_type, F> expression_type;
        -        typedef expression_type result_type;
        -     };
        -
        -    // (- m) [i] [j] = - m [i] [j]
        -    template<class E>
        -     typename matrix_unary1_traits<E, scalar_negate<typename E::value_type> >::result_type
        -    operator - (const matrix_expression<E> &e);
        -
        -    // (conj m) [i] [j] = conj (m [i] [j])
        -    template<class E>
        -     typename matrix_unary1_traits<E, scalar_conj<typename E::value_type> >::result_type
        -    conj (const matrix_expression<E> &e);
        -
        -    // (real m) [i] [j] = real (m [i] [j])
        -    template<class E>
        -     typename matrix_unary1_traits<E, scalar_real<typename E::value_type> >::result_type
        -    real (const matrix_expression<E> &e);
        -
        -    // (imag m) [i] [j] = imag (m [i] [j])
        -    template<class E>
        -     typename matrix_unary1_traits<E, scalar_imag<typename E::value_type> >::result_type
        -    imag (const matrix_expression<E> &e);
        -
        -    template<class E, class F>
        -    struct matrix_unary2_traits {
        -        typedef matrix_unary2<typename E::const_closure_type, F> expression_type;
        -        typedef expression_type result_type;
        -     };
        -
        -    // (trans m) [i] [j] = m [j] [i]
        -    template<class E>
        -     typename matrix_unary2_traits<E, scalar_identity<typename E::value_type> >::result_type
        -    trans (const matrix_expression<E> &e);
        -
        -    // (herm m) [i] [j] = conj (m [j] [i])
        -    template<class E>
        -     typename matrix_unary2_traits<E, scalar_conj<typename E::value_type> >::result_type
        -    herm (const matrix_expression<E> &e);
        -
        -

        Description

        -

        operator - computes the additive inverse of a -matrix expression. conj computes the complex conjugate -of a matrix expression. real and imag -compute the real and imaginary parts of a matrix expression. -trans computes the transpose of a matrix expression. -herm computes the hermitian, i.e. the complex -conjugate of the transpose of a matrix expression.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -

        None.

        -

        Complexity

        -

        Quadratic depending from the size of the matrix expression.

        -

        Examples

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<std::complex<double> > m (3, 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i)
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            m (i, j) = std::complex<double> (3 * i + j, 3 * i + j);
        -
        -    std::cout << - m << std::endl;
        -    std::cout << conj (m) << std::endl;
        -    std::cout << real (m) << std::endl;
        -    std::cout << imag (m) << std::endl;
        -    std::cout << trans (m) << std::endl;
        -    std::cout << herm (m) << std::endl;
        -}
        -
        -

        Binary Operation Description

        -

        Description

        -

        The templated class matrix_binary<E1, E2, F> -describes a binary matrix operation.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        E1The type of the first matrix expression.
        E2The type of the second matrix expression.
        FThe type of the operation.
        -

        Model of

        -

        Matrix Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix Expression .

        -

        Public base classes

        -

        matrix_expression<matrix_binary<E1, E2, F> ->.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_binary (const expression1_type &e1, const -expression2_type &e2)Constructs a description of the expression.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the expression.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the expression.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the expression.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the expression.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed expression.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed expression.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed expression.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed expression.
        -

        Binary Operations

        -

        Prototypes

        -
        -template<class E1, class E2, class F>
        -    struct matrix_binary_traits {
        -        typedef matrix_binary<typename E1::const_closure_type,
        -                               typename E2::const_closure_type, F> expression_type;
        -        typedef expression_type result_type;
        -     };
        -
        -    // (m1 + m2) [i] [j] = m1 [i] [j] + m2 [i] [j]
        -    template<class E1, class E2>
        -    typename matrix_binary_traits<E1, E2, scalar_plus<typename E1::value_type,
        -                                                       typename E2::value_type> >::result_type
        -    operator + (const matrix_expression<E1> &e1,
        -                 const matrix_expression<E2> &e2);
        -
        -    // (m1 - m2) [i] [j] = m1 [i] [j] - m2 [i] [j]
        -    template<class E1, class E2>
        -    typename matrix_binary_traits<E1, E2, scalar_minus<typename E1::value_type,
        -                                                        typename E2::value_type> >::result_type
        -    operator - (const matrix_expression<E1> &e1,
        -                 const matrix_expression<E2> &e2);
        -
        -

        Description

        -

        operator + computes the sum of two matrix -expressions. operator - computes the difference of two -matrix expressions.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -
          -
        • e1 ().size1 () == e2 ().size1 ()
        • -
        • e1 ().size2 () == e2 ().size2 ()
        • -
        -

        Complexity

        -

        Quadratic depending from the size of the matrix expressions.

        -

        Examples

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m1 (3, 3), m2 (3, 3);
        -    for (unsigned i = 0; i < std::min (m1.size1 (), m2.size1 ()); ++ i)
        -        for (unsigned j = 0; j < std::min (m1.size2 (), m2.size2 ()); ++ j)
        -            m1 (i, j) = m2 (i, j) = 3 * i + j;
        -
        -    std::cout << m1 + m2 << std::endl;
        -    std::cout << m1 - m2 << std::endl;
        -}
        -
        -

        Scalar Matrix Operation Description

        -

        Description

        -

        The templated classes matrix_binary_scalar1<E1, E2, -F> and matrix_binary_scalar2<E1, E2, -F> describe binary operations between a scalar and a -matrix.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        E1/E2The type of the scalar expression.
        E2/E1The type of the matrix expression.
        FThe type of the operation.
        -

        Model of

        -

        Matrix Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix Expression .

        -

        Public base classes

        -

        matrix_expression<matrix_binary_scalar1<E1, E2, -F> > and -matrix_expression<matrix_binary_scalar2<E1, E2, F> -> resp.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_binary_scalar1 (const expression1_type &e1, -const expression2_type &e2)Constructs a description of the expression.
        matrix_binary_scalar1 (const expression1_type &e1, -const expression2_type &e2)Constructs a description of the expression.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the expression.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the expression.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the expression.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the expression.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed expression.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed expression.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed expression.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed expression.
        -

        Scalar Matrix Operations

        -

        Prototypes

        -
        -template<class T1, class E2, class F>
        -    struct matrix_binary_scalar1_traits {
        -        typedef matrix_binary_scalar1<scalar_const_reference<T1>,
        -                                      typename E2::const_closure_type, F> expression_type;
        -        typedef expression_type result_type;
        -     };
        -
        -    // (t * m) [i] [j] = t * m [i] [j]
        -    template<class T1, class E2>
        -    typename matrix_binary_scalar1_traits<T1, E2, scalar_multiplies<T1, typename E2::value_type> >::result_type
        -    operator * (const T1 &e1,
        -                 const matrix_expression<E2> &e2);
        -
        -    template<class E1, class T2, class F>
        -    struct matrix_binary_scalar2_traits {
        -        typedef matrix_binary_scalar2<typename E1::const_closure_type,
        -                                      scalar_const_reference<T2>, F> expression_type;
        -        typedef expression_type result_type;
        -     };
        -
        -    // (m * t) [i] [j] = m [i] [j] * t
        -    template<class E1, class T2>
        -    typename matrix_binary_scalar2_traits<E1, T2, scalar_multiplies<typename E1::value_type, T2> >::result_type
        -    operator * (const matrix_expression<E1> &e1,
        -                 const T2 &e2);
        -
        -    // (m / t) [i] [j] = m [i] [j] / t
        -    template<class E1, class T2>
        -    typename matrix_binary_scalar2_traits<E1, T2, scalar_divides<typename E1::value_type, T2> >::result_type
        -    operator / (const matrix_expression<E1> &e1,
        -                 const T2 &e2);
        -
        -

        Description

        -

        operator * computes the product of a scalar and a -matrix expression. operator / multiplies the matrix -with the reciprocal of the scalar.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -

        None.

        -

        Complexity

        -

        Quadratic depending from the size of the matrix expression.

        -

        Examples

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i)
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            m (i, j) = 3 * i + j;
        -
        -    std::cout << 2.0 * m << std::endl;
        -    std::cout << m * 2.0 << std::endl;
        -}
        -
        -

        Matrix Vector Operations

        -

        Binary Operation Description

        -

        Description

        -

        The templated classes matrix_vector_binary1<E1, E2, -F> and matrix_vector_binary2<E1, E2, -F> describe binary matrix vector operations.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        E1The type of the matrix or vector expression.
        E2The type of the vector or matrix expression.
        FThe type of the operation.
        -

        Model of

        -

        Vector Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<matrix_vector_binary1<E1, E2, -F> > and -vector_expression<matrix_vector_binary2<E1, E2, F> -> resp.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_vector_binary1 (const expression1_type &e1, -const expression2_type &e2)Constructs a description of the expression.
        matrix_vector_binary2 (const expression1_type &e1, -const expression2_type &e2)Constructs a description of the expression.
        size_type size () constReturns the size of the expression.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the expression.
        const_iterator end () constReturns a const_iterator pointing to the end of -the expression.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed expression.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed expression.
        -

        Binary Operations

        -

        Prototypes

        -
        -template<class T1, class E1, class T2, class E2>
        -    struct matrix_vector_binary1_traits {
        -        typedef row_major_tag dispatch_category;
        -        typedef typename promote_traits<T1, T2>::promote_type promote_type;
        -        typedef matrix_vector_binary1<typename E1::const_closure_type,
        -                                       typename E2::const_closure_type,
        -                                       matrix_vector_prod1<T1, T2, promote_type> > expression_type;
        -        typedef expression_type result_type;
        -     };
        -
        -    template<class E1, class E2>
        -    typename matrix_vector_binary1_traits<typename E1::value_type, E1,
        -                                           typename E2::value_type, E2>::result_type
        -    prod (const matrix_expression<E1> &e1,
        -           const vector_expression<E2> &e2,
        -          row_major_tag);
        -
        -    // Dispatcher
        -    template<class E1, class E2>
        -    typename matrix_vector_binary1_traits<typename E1::value_type, E1,
        -                                           typename E2::value_type, E2>::result_type
        -    prod (const matrix_expression<E1> &e1,
        -           const vector_expression<E2> &e2);
        -
        -    template<class E1, class E2>
        -    typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
        -                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
        -    prec_prod (const matrix_expression<E1> &e1,
        -                const vector_expression<E2> &e2,
        -               row_major_tag);
        -
        -    // Dispatcher
        -    template<class E1, class E2>
        -    typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
        -                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
        -    prec_prod (const matrix_expression<E1> &e1,
        -                const vector_expression<E2> &e2);
        -
        -    template<class V, class E1, class E2>
        -    V
        -    prod (const matrix_expression<E1> &e1,
        -          const vector_expression<E2> &e2);
        -
        -    template<class V, class E1, class E2>
        -    V
        -    prec_prod (const matrix_expression<E1> &e1,
        -               const vector_expression<E2> &e2);
        -
        -    template<class T1, class E1, class T2, class E2>
        -    struct matrix_vector_binary2_traits {
        -        typedef column_major_tag dispatch_category;
        -        typedef typename promote_traits<T1, T2>::promote_type promote_type;
        -        typedef matrix_vector_binary2<typename E1::const_closure_type,
        -                                       typename E2::const_closure_type,
        -                                       matrix_vector_prod2<T1, T2, promote_type> > expression_type;
        -        typedef expression_type result_type;
        -     };
        -
        -    template<class E1, class E2>
        -    typename matrix_vector_binary2_traits<typename E1::value_type, E1,
        -                                           typename E2::value_type, E2>::result_type
        -    prod (const vector_expression<E1> &e1,
        -           const matrix_expression<E2> &e2,
        -          column_major_tag);
        -
        -    // Dispatcher
        -    template<class E1, class E2>
        -    typename matrix_vector_binary2_traits<typename E1::value_type, E1,
        -                                           typename E2::value_type, E2>::result_type
        -    prod (const vector_expression<E1> &e1,
        -           const matrix_expression<E2> &e2);
        -
        -    template<class E1, class E2>
        -    typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
        -                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
        -    prec_prod (const vector_expression<E1> &e1,
        -                const matrix_expression<E2> &e2,
        -               column_major_tag);
        -
        -    // Dispatcher
        -    template<class E1, class E2>
        -    typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
        -                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
        -    prec_prod (const vector_expression<E1> &e1,
        -                const matrix_expression<E2> &e2);
        -
        -    template<class V, class E1, class E2>
        -    V
        -    prod (const vector_expression<E1> &e1,
        -          const matrix_expression<E2> &e2);
        -
        -    template<class V, class E1, class E2>
        -    V
        -    prec_prod (const vector_expression<E1> &e1,
        -               const matrix_expression<E2> &e2);
        -
        -

        Description

        -

        prod computes the product of the matrix and the -vector expression. prec_prod computes the double -precision product of the matrix and the vector expression.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -
          -
        • e1 ().size2 () == e2 ().size ()
        • -
        • e1 ().size () == e2 ().size1 ()
        • -
        -

        Complexity

        -

        Quadratic depending from the size of the matrix expression.

        -

        Examples

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    vector<double> v (3);
        -    for (unsigned i = 0; i < std::min (m.size1 (), v.size ()); ++ i) {
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            m (i, j) = 3 * i + j;
        -        v (i) = i;
        -    }
        -
        -    std::cout << prod (m, v) << std::endl;
        -    std::cout << prod (v, m) << std::endl;
        -}
        -
        -

        Triangular Solver

        -

        Prototypes

        -
        -template<class E1, class E2>
        -    struct matrix_vector_solve_traits {
        -        typedef typename promote_traits<typename E1::value_type, typename E2::value_type>::promote_type promote_type;
        -        typedef vector<promote_type> result_type;
        -    };
        -
        -    template<class E1, class E2>
        -    void inplace_solve (const matrix_expression<E1> &e1,
        -                         E2 &e2,
        -                        lower_tag,
        -                        vector_tag);
        -    template<class E1, class E2>
        -    void inplace_solve (const matrix_expression<E1> &e1,
        -                         E2 &e2,
        -                        upper_tag,
        -                        vector_tag);
        -    template<class E1, class E2>
        -    void inplace_solve (const matrix_expression<E1> &e1,
        -                         E2 &e2,
        -                        unit_lower_tag,
        -                        vector_tag);
        -    template<class E1, class E2>
        -    void inplace_solve (const matrix_expression<E1> &e1,
        -                         E2 &e2,
        -                        unit_upper_tag,
        -                        vector_tag);
        -
        -    template<class E1, class E2, class C>
        -    typename matrix_vector_solve_traits<E1, E2>::result_type
        -    solve (const matrix_expression<E1> &e1,
        -            const vector_expression<E2> &e2,
        -           C);
        -
        -    template<class E1, class E2>
        -    void inplace_solve (E1 &e1,
        -                        const matrix_expression<E2> &e2,
        -                         vector_tag,
        -                         lower_tag);
        -    template<class E1, class E2>
        -    void inplace_solve (E1 &e1,
        -                        const matrix_expression<E2> &e2,
        -                         vector_tag,
        -                         upper_tag);
        -    template<class E1, class E2>
        -    void inplace_solve (E1 &e1,
        -                        const matrix_expression<E2> &e2,
        -                         vector_tag,
        -                         unit_lower_tag);
        -    template<class E1, class E2>
        -    void inplace_solve (E1 &e1,
        -                        const matrix_expression<E2> &e2,
        -                         vector_tag,
        -                         unit_upper_tag);
        -
        -    template<class E1, class E2, class C>
        -    typename matrix_vector_solve_traits<E1, E2>::result_type
        -    solve (const vector_expression<E1> &e1,
        -            const matrix_expression<E2> &e2,
        -           C);
        -
        -

        Description

        -

        solve solves a linear equation for lower or upper -(unit) triangular matrices.

        -

        Definition

        -

        Defined in the header triangular.hpp.

        -

        Type requirements

        - -

        Preconditions

        -
          -
        • e1 ().size1 () == e1 ().size2 ()
        • -
        • e1 ().size2 () == e2 ().size ()
        • -
        • e1 ().size () == e2 ().size1 ()
        • -
        • e2 ().size1 () == e2 ().size2 ()
        • -
        -

        Complexity

        -

        Quadratic depending from the size of the matrix expression.

        -

        Examples

        -
        -#include <boost/numeric/ublas/triangular.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    vector<double> v (3);
        -    for (unsigned i = 0; i < std::min (m.size1 (), v.size ()); ++ i) {
        -        for (unsigned j = 0; j <= i; ++ j)
        -            m (i, j) = 3 * i + j + 1;
        -        v (i) = i;
        -    }
        -
        -    std::cout << solve (m, v, lower_tag ()) << std::endl;
        -    std::cout << solve (v, m, lower_tag ()) << std::endl;
        -}
        -
        -

        Matrix Matrix Operations

        -

        Binary Operation Description

        -

        Description

        -

        The templated class matrix_matrix_binary<E1, E2, -F> describes a binary matrix operation.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        E1The type of the first matrix expression.
        E2The type of the second matrix expression.
        FThe type of the operation.
        -

        Model of

        -

        Matrix Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix Expression .

        -

        Public base classes

        -

        matrix_expression<matrix_matrix_binary<E1, E2, F> -> .

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_matrix_binary (const expression1_type &e1, -const expression2_type &e2)Constructs a description of the expression.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the expression.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the expression.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the expression.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the expression.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed expression.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed expression.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed expression.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed expression.
        -

        Binary Operations

        -

        Prototypes

        -
        -template<class T1, class E1, class T2, class E2>
        -    struct matrix_matrix_binary_traits {
        -        typedef unknown_orientation_tag dispatch_category;
        -        typedef typename promote_traits<T1, T2>::promote_type promote_type;
        -        typedef matrix_matrix_binary<typename E1::const_closure_type,
        -                                     typename E2::const_closure_type,
        -                                     matrix_matrix_prod<T1, T2, promote_type> > expression_type;
        -        typedef expression_type result_type;
        -    };
        -
        -    template<class E1, class E2>
        -    typename matrix_matrix_binary_traits<typename E1::value_type, E1,
        -                                         typename E2::value_type, E2>::result_type
        -    prod (const matrix_expression<E1> &e1,
        -          const matrix_expression<E2> &e2,
        -          unknown_orientation_tag);
        -
        -    // Dispatcher
        -    template<class E1, class E2>
        -    typename matrix_matrix_binary_traits<typename E1::value_type, E1,
        -                                         typename E2::value_type, E2>::result_type
        -    prod (const matrix_expression<E1> &e1,
        -          const matrix_expression<E2> &e2);
        -
        -    template<class E1, class E2>
        -    typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
        -                                         typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
        -    prec_prod (const matrix_expression<E1> &e1,
        -               const matrix_expression<E2> &e2,
        -               unknown_orientation_tag);
        -
        -    // Dispatcher
        -    template<class E1, class E2>
        -    typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
        -                                         typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
        -    prec_prod (const matrix_expression<E1> &e1,
        -               const matrix_expression<E2> &e2);
        -
        -    template<class M, class E1, class E2>
        -    M
        -    prod (const matrix_expression<E1> &e1,
        -          const matrix_expression<E2> &e2);
        -
        -    template<class M, class E1, class E2>
        -    M
        -    prec_prod (const matrix_expression<E1> &e1,
        -               const matrix_expression<E2> &e2);
        -
        -

        Description

        -

        prod computes the product of the matrix -expressions. prec_prod computes the double precision -product of the matrix expressions.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -
          -
        • e1 ().size2 () == e2 ().size1 ()
        • -
        -

        Complexity

        -

        Cubic depending from the size of the matrix expression.

        -

        Examples

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m1 (3, 3), m2 (3, 3);
        -    for (unsigned i = 0; i < std::min (m1.size1 (), m2.size1 ()); ++ i)
        -        for (unsigned j = 0; j < std::min (m1.size2 (), m2.size2 ()); ++ j)
        -            m1 (i, j) = m2 (i, j) = 3 * i + j;
        -
        -    std::cout << prod (m1, m2) << std::endl;
        -}
        -
        -

        Triangular Solvers

        -

        Prototypes

        -
        -template<class E1, class E2>
        -    struct matrix_matrix_solve_traits {
        -        typedef typename promote_traits<typename E1::value_type, typename E2::value_type>::promote_type promote_type;
        -        typedef matrix<promote_type> result_type;
        -    };
        -
        -    template<class E1, class E2>
        -    void inplace_solve (const matrix_expression<E1> &e1,
        -                        E2 &e2,
        -                        lower_tag,
        -                        matrix_tag);
        -    template<class E1, class E2>
        -    void inplace_solve (const matrix_expression<E1> &e1,
        -                        E2 &e2,
        -                        upper_tag,
        -                        matrix_tag);
        -    template<class E1, class E2>
        -    void inplace_solve (const matrix_expression<E1> &e1,
        -                        E2 &e2,
        -                        unit_lower_tag,
        -                        matrix_tag);
        -    template<class E1, class E2>
        -    void inplace_solve (const matrix_expression<E1> &e1,
        -                        E2 &e2,
        -                        unit_upper_tag,
        -                        matrix_tag);
        -
        -    template<class E1, class E2, class C>
        -    typename matrix_matrix_solve_traits<E1, E2>::result_type
        -    solve (const matrix_expression<E1> &e1,
        -           const matrix_expression<E2> &e2,
        -           C);
        -
        -

        Description

        -

        solve solves a linear equation for lower or upper -(unit) triangular matrices.

        -

        Definition

        -

        Defined in the header triangular.hpp.

        -

        Type requirements

        - -

        Preconditions

        -
          -
        • e1 ().size1 () == e1 ().size2 ()
        • -
        • e1 ().size2 () == e2 ().size1 ()
        • -
        -

        Complexity

        -

        Cubic depending from the size of the matrix expressions.

        -

        Examples

        -
        -#include <boost/numeric/ublas/triangular.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m1 (3, 3), m2 (3, 3);
        -    for (unsigned i = 0; i < std::min (m1.size1 (), m2.size1 ()); ++ i)
        -        for (unsigned j = 0; j <= i; ++ j)
        -            m1 (i, j) = m2 (i, j) = 3 * i + j + 1;
        -
        -    std::cout << solve (m1, m2, lower_tag ()) << std::endl;
        -}
        -
        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/matrix_proxy.html b/doc/matrix_proxy.html deleted file mode 100644 index d4b420257..000000000 --- a/doc/matrix_proxy.html +++ /dev/null @@ -1,1428 +0,0 @@ - - - - - - - - - -Matrix Proxies - - -

        Matrix Proxies

        -
        -

        Matrix Row

        -

        Description

        -

        The templated class matrix_row<M> allows -addressing a row of a matrix.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/matrix_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i) {
        -        matrix_row<matrix<double> > mr (m, i);
        -        for (unsigned j = 0; j < mr.size (); ++ j)
        -            mr (j) = 3 * i + j;
        -        std::cout << mr << std::endl;
        -    }
        -}
        -
        -

        Definition

        -

        Defined in the header matrix_proxy.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        MThe type of matrix referenced.
        -

        Model of

        -

        Vector Expression -.

        -

        If the specified row falls outside that of the row index range -of the matrix, then the matrix_row is not a well -formed Vector Expression. That is, access to an element which is -outside of the matrix is undefined.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<matrix_row<M> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_row (matrix_type &data, size_type -i)Constructs a sub vector.
        size_type size () constReturns the size of the sub vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        reference operator () (size_type i)Returns a reference of the i-th element.
        matrix_row &operator = (const matrix_row -&mr)The assignment operator.
        matrix_row &assign_temporary (matrix_row -&mr)Assigns a temporary. May change the matrix row mr -.
        template<class AE>
        -matrix_row &operator = (const vector_expression<AE> -&ae)
        The extended assignment operator.
        template<class AE>
        -matrix_row &assign (const vector_expression<AE> -&ae)
        Assigns a vector expression to the sub vector. Left and right -hand side of the assignment should be independent.
        template<class AE>
        -matrix_row &operator += (const vector_expression<AE> -&ae)
        A computed assignment operator. Adds the vector expression to -the sub vector.
        template<class AE>
        -matrix_row &plus_assign (const vector_expression<AE> -&ae)
        Adds a vector expression to the sub vector. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -matrix_row &operator -= (const vector_expression<AE> -&ae)
        A computed assignment operator. Subtracts the vector expression -from the sub vector.
        template<class AE>
        -matrix_row &minus_assign (const vector_expression<AE> -&ae)
        Subtracts a vector expression from the sub vector. Left and -right hand side of the assignment should be independent.
        template<class AT>
        -matrix_row &operator *= (const AT &at)
        A computed assignment operator. Multiplies the sub vector with -a scalar.
        template<class AT>
        -matrix_row &operator /= (const AT &at)
        A computed assignment operator. Divides the sub vector through -a scalar.
        void swap (matrix_row &mr)Swaps the contents of the sub vectors.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the matrix_row.
        const_iterator end () constReturns a const_iterator pointing to the end of -the matrix_row.
        iterator begin ()Returns a iterator pointing to the beginning of -the matrix_row.
        iterator end ()Returns a iterator pointing to the end of the -matrix_row.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed matrix_row.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed matrix_row.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed matrix_row.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed matrix_row.
        -

        Projections

        -

        Description

        -

        The free row functions support the construction of -matrix rows.

        -

        Prototypes

        -
        
        -    template<class M>
        -    matrix_row<M> row (M &data, std::size_t i);
        -    template<class M>
        -    const matrix_row<const M> row (const M &data, std::size_t i);
        -
        -

        Definition

        -

        Defined in the header matrix_proxy.hpp.

        -

        Type requirements

        - -

        Complexity

        -

        Linear depending from the size of the row.

        -

        Examples

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/matrix_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i) {
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            row (m, i) (j) = 3 * i + j;
        -        std::cout << row (m, i) << std::endl;
        -    }
        -}
        -
        -

        Matrix Column

        -

        Description

        -

        The templated class matrix_column<M> allows -addressing a column of a matrix.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/matrix_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    for (unsigned j = 0; j < m.size2 (); ++ j) {
        -        matrix_column<matrix<double> > mc (m, j);
        -        for (unsigned i = 0; i < mc.size (); ++ i)
        -            mc (i) = 3 * i + j;
        -        std::cout << mc << std::endl;
        -    }
        -}
        -
        -

        Definition

        -

        Defined in the header matrix_proxy.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        MThe type of matrix referenced.
        -

        Model of

        -

        Vector Expression -.

        -

        If the specified column falls outside that of the column index -range of the matrix, then the matrix_column is not a -well formed Vector Expression. That is, access to an element which -is outside of the matrix is undefined.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<matrix_column<M> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_column (matrix_type &data, size_type -j)Constructs a sub vector.
        size_type size () constReturns the size of the sub vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        reference operator () (size_type i)Returns a reference of the i-th element.
        matrix_column &operator = (const matrix_column -&mc)The assignment operator.
        matrix_column &assign_temporary (matrix_column -&mc)Assigns a temporary. May change the matrix column -mc .
        template<class AE>
        -matrix_column &operator = (const vector_expression<AE> -&ae)
        The extended assignment operator.
        template<class AE>
        -matrix_column &assign (const vector_expression<AE> -&ae)
        Assigns a vector expression to the sub vector. Left and right -hand side of the assignment should be independent.
        template<class AE>
        -matrix_column &operator += (const vector_expression<AE> -&ae)
        A computed assignment operator. Adds the vector expression to -the sub vector.
        template<class AE>
        -matrix_column &plus_assign (const vector_expression<AE> -&ae)
        Adds a vector expression to the sub vector. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -matrix_column &operator -= (const vector_expression<AE> -&ae)
        A computed assignment operator. Subtracts the vector expression -from the sub vector.
        template<class AE>
        -matrix_column &minus_assign (const vector_expression<AE> -&ae)
        Subtracts a vector expression from the sub vector. Left and -right hand side of the assignment should be independent.
        template<class AT>
        -matrix_column &operator *= (const AT &at)
        A computed assignment operator. Multiplies the sub vector with -a scalar.
        template<class AT>
        -matrix_column &operator /= (const AT &at)
        A computed assignment operator. Divides the sub vector through -a scalar.
        void swap (matrix_column &mc)Swaps the contents of the sub vectors.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the matrix_column.
        const_iterator end () constReturns a const_iterator pointing to the end of -the matrix_column.
        iterator begin ()Returns a iterator pointing to the beginning of -the matrix_column.
        iterator end ()Returns a iterator pointing to the end of the -matrix_column.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed matrix_column.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed matrix_column.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed matrix_column.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed matrix_column.
        -

        Projections

        -

        Description

        -

        The free column functions support the construction -of matrix columns.

        -

        Prototypes

        -
        
        -    template<class M>
        -    matrix_column<M> column (M &data, std::size_t j);
        -    template<class M>
        -    const matrix_column<const M> column (const M &data, std::size_t j);
        -
        -

        Definition

        -

        Defined in the header matrix_proxy.hpp.

        -

        Type requirements

        - -

        Complexity

        -

        Linear depending from the size of the column.

        -

        Examples

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/matrix_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    for (unsigned j = 0; j < m.size2 (); ++ j) {
        -        for (unsigned i = 0; i < m.size1 (); ++ i)
        -            column (m, j) (i) = 3 * i + j;
        -        std::cout << column (m, j) << std::endl;
        -    }
        -}
        -
        -

        Vector Range

        -

        Description

        -

        The templated class matrix_vector_range<M> -allows addressing a sub vector of a matrix.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/matrix_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i)
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            m (i, j) = 3 * i + j;
        -
        -    matrix_vector_range<matrix<double> > mvr (m, range (0, 3), range (0, 3));
        -    std::cout << mvr << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix_proxy.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        MThe type of matrix referenced.
        -

        Model of

        -

        Vector Expression -.

        -

        If the specified ranges fall outside that of the index range of -the matrix, then the matrix_vector_range is not a well -formed Vector Expression. That is, access to an element which is -outside of the matrix is undefined.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<matrix_vector_range<M> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_vector_range (matrix_type &data,
        -const range &r1, const range &r2)
        Constructs a sub vector.
        size_type size () constReturns the size of the sub vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        reference operator () (size_type i)Returns a reference of the i-th element.
        matrix_vector_range &operator = (const -matrix_vector_range &mvr)The assignment operator.
        matrix_vector_range &assign_temporary -(matrix_vector_range &mvr)Assigns a temporary. May change the matrix vector range -mvr.
        template<class AE>
        -matrix_vector_range &operator = (const -vector_expression<AE> &ae)
        The extended assignment operator.
        template<class AE>
        -matrix_vector_range &assign (const vector_expression<AE> -&ae)
        Assigns a vector expression to the sub vector. Left and right -hand side of the assignment should be independent.
        template<class AE>
        -matrix_vector_range &operator += (const -vector_expression<AE> &ae)
        A computed assignment operator. Adds the vector expression to -the sub vector.
        template<class AE>
        -matrix_vector_range &plus_assign (const -vector_expression<AE> &ae)
        Adds a vector expression to the sub vector. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -matrix_vector_range &operator -= (const -vector_expression<AE> &ae)
        A computed assignment operator. Subtracts the vector expression -from the sub vector.
        template<class AE>
        -matrix_vector_range &minus_assign (const -vector_expression<AE> &ae)
        Subtracts a vector expression from the sub vector. Left and -right hand side of the assignment should be independent.
        template<class AT>
        -matrix_vector_range &operator *= (const AT &at)
        A computed assignment operator. Multiplies the sub vector with -a scalar.
        template<class AT>
        -matrix_vector_range &operator /= (const AT &at)
        A computed assignment operator. Divides the sub vector through -a scalar.
        void swap (matrix_vector_range &mvr)Swaps the contents of the sub vectors.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the matrix_vector_range.
        const_iterator end () constReturns a const_iterator pointing to the end of -the matrix_vector_range.
        iterator begin ()Returns a iterator pointing to the beginning of -the matrix_vector_range.
        iterator end ()Returns a iterator pointing to the end of the -matrix_vector_range.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the matrix_vector_range.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed matrix_vector_range.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed matrix_vector_range.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed matrix_vector_range.
        -

        Vector Slice

        -

        Description

        -

        The templated class matrix_vector_slice<M> -allows addressing a sliced sub vector of a matrix.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/matrix_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i)
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            m (i, j) = 3 * i + j;
        -
        -    matrix_vector_slice<matrix<double> > mvs (m, slice (0, 1, 3), slice (0, 1, 3));
        -    std::cout << mvs << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix_proxy.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        MThe type of matrix referenced.
        -

        Model of

        -

        Vector Expression -.

        -

        If the specified slices fall outside that of the index range of -the matrix, then the matrix_vector_slice is not a well -formed Vector Expression. That is, access to an element which is -outside of the matrix is undefined.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<matrix_vector_slice<M> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_vector_slice (matrix_type &data,
        -const slice &s1, const slice &s2)
        Constructs a sub vector.
        size_type size () constReturns the size of the sub vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        reference operator () (size_type i)Returns a reference of the i-th element.
        matrix_vector_slice &operator = (const -matrix_vector_slice &mvs)The assignment operator.
        matrix_vector_slice &assign_temporary -(matrix_vector_slice &mvs)Assigns a temporary. May change the matrix vector slice -vs.
        template<class AE>
        -matrix_vector_slice &operator = (const -vector_expression<AE> &ae)
        The extended assignment operator.
        template<class AE>
        -matrix_vector_slice &assign (const vector_expression<AE> -&ae)
        Assigns a vector expression to the sub vector. Left and right -hand side of the assignment should be independent.
        template<class AE>
        -matrix_vector_slice &operator += (const -vector_expression<AE> &ae)
        A computed assignment operator. Adds the vector expression to -the sub vector.
        template<class AE>
        -matrix_vector_slice &plus_assign (const -vector_expression<AE> &ae)
        Adds a vector expression to the sub vector. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -matrix_vector_slice &operator -= (const -vector_expression<AE> &ae)
        A computed assignment operator. Subtracts the vector expression -from the sub vector.
        template<class AE>
        -matrix_vector_slice &minus_assign (const -vector_expression<AE> &ae)
        Subtracts a vector expression from the sub vector. Left and -right hand side of the assignment should be independent.
        template<class AT>
        -matrix_vector_slice &operator *= (const AT &at)
        A computed assignment operator. Multiplies the sub vector with -a scalar.
        template<class AT>
        -matrix_vector_slice &operator /= (const AT &at)
        A computed assignment operator. Divides the sub vector through -a scalar.
        void swap (matrix_vector_slice &mvs)Swaps the contents of the sub vectors.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the matrix_vector_slice.
        const_iterator end () constReturns a const_iterator pointing to the end of -the matrix_vector_slice.
        iterator begin ()Returns a iterator pointing to the beginning of -the matrix_vector_slice.
        iterator end ()Returns a iterator pointing to the end of the -matrix_vector_slice.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed matrix_vector_slice.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed matrix_vector_slice.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed matrix_vector_slice.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed matrix_vector_slice.
        -

        Matrix Range

        -

        Description

        -

        The templated class matrix_range<M> allows -addressing a sub matrix of a matrix.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/matrix_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    matrix_range<matrix<double> > mr (m, range (0, 3), range (0, 3));
        -    for (unsigned i = 0; i < mr.size1 (); ++ i)
        -        for (unsigned j = 0; j < mr.size2 (); ++ j)
        -            mr (i, j) = 3 * i + j;
        -    std::cout << mr << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix_proxy.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        MThe type of matrix referenced.
        -

        Model of

        -

        Matrix Expression -.

        -

        If the specified ranges fall outside that of the index range of -the matrix, then the matrix_range is not a well formed -Matrix Expression. That is, access to an element which is outside -of the matrix is undefined.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix Expression .

        -

        Public base classes

        -

        matrix_expression<matrix_range<M> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_range (matrix_type &data,
        -const range &r1, const range &r2)
        Constructs a sub matrix.
        size_type start1 () constReturns the index of the first row.
        size_type size1 () constReturns the number of rows.
        size_type start2 () constReturns the index of the first column.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        matrix_range &operator = (const matrix_range -&mr)The assignment operator.
        matrix_range &assign_temporary (matrix_range -&mr)Assigns a temporary. May change the matrix range -mr .
        template<class AE>
        -matrix_range &operator = (const matrix_expression<AE> -&ae)
        The extended assignment operator.
        template<class AE>
        -matrix_range &assign (const matrix_expression<AE> -&ae)
        Assigns a matrix expression to the sub matrix. Left and right -hand side of the assignment should be independent.
        template<class AE>
        -matrix_range &operator += (const matrix_expression<AE> -&ae)
        A computed assignment operator. Adds the matrix expression to -the sub matrix.
        template<class AE>
        -matrix_range &plus_assign (const matrix_expression<AE> -&ae)
        Adds a matrix expression to the sub matrix. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -matrix_range &operator -= (const matrix_expression<AE> -&ae)
        A computed assignment operator. Subtracts the matrix expression -from the sub matrix.
        template<class AE>
        -matrix_range &minus_assign (const matrix_expression<AE> -&ae)
        Subtracts a matrix expression from the sub matrix. Left and -right hand side of the assignment should be independent.
        template<class AT>
        -matrix_range &operator *= (const AT &at)
        A computed assignment operator. Multiplies the sub matrix with -a scalar.
        template<class AT>
        -matrix_range &operator /= (const AT &at)
        A computed assignment operator. Divides the sub matrix through -a scalar.
        void swap (matrix_range &mr)Swaps the contents of the sub matrices.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the matrix_range.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the matrix_range.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the matrix_range.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -matrix_range.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the matrix_range.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the matrix_range.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the matrix_range.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -matrix_range.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed matrix_range.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed matrix_range.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed matrix_range.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed matrix_range.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed matrix_range.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed matrix_range.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed matrix_range.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -reversed the matrix_range.
        -

        Simple Projections

        -

        Description

        -

        The free subrange functions support the construction -of matrix ranges.

        -

        Prototypes

        -
        
        -    template<class M>
        -    matrix_range<M> subrange (M &data,
        -       M::size_type start1, M::size_type stop1, M::size_type start2, M::size_type, stop2);
        -    template<class M>
        -    const matrix_range<const M> subrange (const M &data,
        -       M::size_type start1, M::size_type stop1, M::size_type start2, M::size_type, stop2);
        -
        -

        Generic Projections

        -

        Description

        -

        The free project functions support the construction -of matrix ranges. Existing matrix_range's can be composed with further ranges. The resulting ranges are computed using this existing ranges' compose function.

        -

        Prototypes

        -
        
        -    template<class M>
        -    matrix_range<M> project (M &data, const range &r1, const range &r2);
        -    template<class M>
        -    const matrix_range<const M> project (const M &data, const range &r1, const range &r2);
        -    template<class M>
        -    matrix_range<M> project (matrix_range<M> &data, const range &r1, const range &r2);
        -    template<class M>
        -    const matrix_range<M> project (const matrix_range<M> &data, const range &r1, const range &r2);
        -
        -

        Definition

        -

        Defined in the header matrix_proxy.hpp.

        -

        Type requirements

        - -

        Complexity

        -

        Quadratic depending from the size of the ranges.

        -

        Examples

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/matrix_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i)
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            project (m, range (0, 3), range (0, 3)) (i, j) = 3 * i + j;
        -    std::cout << project (m, range (0, 3), range (0, 3)) << std::endl;
        -}
        -
        -

        Matrix Slice

        -

        Description

        -

        The templated class matrix_slice<M> allows -addressing a sliced sub matrix of a matrix.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/matrix_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    matrix_slice<matrix<double> > ms (m, slice (0, 1, 3), slice (0, 1, 3));
        -    for (unsigned i = 0; i < ms.size1 (); ++ i)
        -        for (unsigned j = 0; j < ms.size2 (); ++ j)
        -            ms (i, j) = 3 * i + j;
        -    std::cout << ms << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix_proxy.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        MThe type of matrix referenced.
        -

        Model of

        -

        Matrix Expression -.

        -

        If the specified slices fall outside that of the index range of -the matrix, then the matrix_slice is not a well formed -Matrix Expression. That is, access to an element which is outside -of the matrix is undefined.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix Expression .

        -

        Public base classes

        -

        matrix_expression<matrix_slice<M> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        matrix_slice (matrix_type &data,
        -const slice &s1, const slice &s2)
        Constructs a sub matrix.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        matrix_slice &operator = (const matrix_slice -&ms)The assignment operator.
        matrix_slice &assign_temporary (matrix_slice -&ms)Assigns a temporary. May change the matrix slice -ms .
        template<class AE>
        -matrix_slice &operator = (const matrix_expression<AE> -&ae)
        The extended assignment operator.
        template<class AE>
        -matrix_slice &assign (const matrix_expression<AE> -&ae)
        Assigns a matrix expression to the sub matrix. Left and right -hand side of the assignment should be independent.
        template<class AE>
        -matrix_slice &operator += (const matrix_expression<AE> -&ae)
        A computed assignment operator. Adds the matrix expression to -the sub matrix.
        template<class AE>
        -matrix_slice &plus_assign (const matrix_expression<AE> -&ae)
        Adds a matrix expression to the sub matrix. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -matrix_slice &operator -= (const matrix_expression<AE> -&ae)
        A computed assignment operator. Subtracts the matrix expression -from the sub matrix.
        template<class AE>
        -matrix_slice &minus_assign (const matrix_expression<AE> -&ae)
        Subtracts a matrix expression from the sub matrix. Left and -right hand side of the assignment should be independent.
        template<class AT>
        -matrix_slice &operator *= (const AT &at)
        A computed assignment operator. Multiplies the sub matrix with -a scalar.
        template<class AT>
        -matrix_slice &operator /= (const AT &at)
        A computed assignment operator. Multiplies the sub matrix -through a scalar.
        void swap (matrix_slice &ms)Swaps the contents of the sub matrices.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the matrix_slice.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the matrix_slice.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the matrix_slice.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -matrix_slice.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the matrix_slice.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the matrix_slice.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the matrix_slice.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -matrix_slice.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed matrix_slice.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed matrix_slice.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed matrix_slice.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed matrix_slice.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed matrix_slice.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed matrix_slice.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed matrix_slice.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed matrix_slice.
        -

        Simple Projections

        -

        Description

        -

        The free subslice functions support the construction -of matrix slices.

        -

        Prototypes

        -
        
        -    template<class M>
        -    matrix_slice<M> subslice (M &data,
        -       M::size_type start1, M::difference_type stride1, M::size_type size1,
        -       M::size_type start2, M::difference_type stride2, M::size_type size2);
        -    template<class M>
        -    const matrix_slice<const M> subslice (const M &data,
        -       M::size_type start1, M::difference_type stride1, M::size_type size1,
        -       M::size_type start2, M::difference_type stride2, M::size_type size2);
        -
        -

        Generic Projections

        -

        Description

        -

        The free project functions support the construction -of matrix slices. Existing matrix_slice's can be composed with further ranges or slices. The resulting slices are computed using this existing slices' compose function.

        -

        Prototypes

        -
        
        -    template<class M>
        -    matrix_slice<M> project (M &data, const slice &s1, const slice &s2);
        -    template<class M>
        -    const matrix_slice<const M> project (const M &data, const slice &s1, const slice &s2);
        -    template<class M>
        -    matrix_slice<M> project (matrix_slice<M> &data, const range &r1, const range &r2);
        -    template<class M>
        -    const matrix_slice<M> project (const matrix_slice<M> &data, const range &r1, const range &r2);
        -    template<class M>
        -    matrix_slice<M> project (matrix_slice<M> &data, const slice &s1, const slice &s2);
        -    template<class M>
        -    const matrix_slice<M> project (const matrix_slice<M> &data, const slice &s1, const slice &s2);
        -
        -

        Definition

        -

        Defined in the header matrix_proxy.hpp.

        -

        Type requirements

        - -

        Complexity

        -

        Quadratic depending from the size of the slices.

        -

        Examples

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/matrix_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i)
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            project (m, slice (0, 1, 3), slice (0, 1, 3)) (i, j) = 3 * i + j;
        -    std::cout << project (m, slice (0, 1, 3), slice (0, 1, 3)) << std::endl;
        -}
        -
        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/matrix_sparse.html b/doc/matrix_sparse.html deleted file mode 100644 index fb77de468..000000000 --- a/doc/matrix_sparse.html +++ /dev/null @@ -1,983 +0,0 @@ - - - - - - - - - -Sparse Matrix - - -

        Sparse Matricies

        -
        -

        Mapped Matrix

        -

        Description

        -

        The templated class mapped_matrix<T, F, A> is -the base container adaptor for sparse matricies using element maps. -For a (m xn)-dimensional sparse matrix and 0 <= i < m, -0 <= j < n the non-zero elements -mi, j are mapped via (i x n + -j) for row major orientation or via (i + j x m) for -column major orientation to consecutive elements of the associative -container, i.e. for elements k = -mi1 -,j1and k + 1 = -mi2 -,j2of the container holds -i1 < -i2 or (i1 -= i2 and -j1 < -j2) with row major orientation or -j1 < -j2 or (j1 -= j2 and -i1 < -i2) with column major -orientation.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix_sparse.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    mapped_matrix<double> m (3, 3, 3 * 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i)
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            m (i, j) = 3 * i + j;
        -    std::cout << m << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix_sparse.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the mapped matrix.
        FFunctor describing the storage organization. [1]row_major
        AThe type of the adapted array. [2]map_std<std::size_t, T>
        -

        Model of

        -

        Matrix .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix .

        -

        Public base classes

        -

        matrix_container<mapped_matrix<T, F, A> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        mapped_matrix ()Allocates a mapped_matrix that holds at most zero -rows of zero elements.
        mapped_matrix (size_type size1, size_type2, size_type non_zeros = 0)Allocates a mapped_matrix that holds at most -size1 rows of size2 elements.
        mapped_matrix (const mapped_matrix &m)The copy constructor.
        template<class AE>
        -mapped_matrix (size_type non_zeros, const -matrix_expression<AE> &ae)
        The extended copy constructor.
        void resize (size_type size1, size_type size2, bool preserve = true)Reallocates a mapped_matrix to hold at most -size1 rows of size2 elements. The -existing elements of the mapped_matrix are preseved -when specified.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        mapped_matrix &operator = (const mapped_matrix -&m)The assignment operator.
        mapped_matrix &assign_temporary (mapped_matrix -&m)Assigns a temporary. May change the mapped matrix -m .
        template<class AE>
        -mapped_matrix &operator = (const matrix_expression<AE> -&ae)
        The extended assignment operator.
        template<class AE>
        -mapped_matrix &assign (const matrix_expression<AE> -&ae)
        Assigns a matrix expression to the mapped matrix. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -mapped_matrix &operator += (const matrix_expression<AE> -&ae)
        A computed assignment operator. Adds the matrix expression to -the mapped matrix.
        template<class AE>
        -mapped_matrix &plus_assign (const matrix_expression<AE> -&ae)
        Adds a matrix expression to the mapped matrix. Left and right -hand side of the assignment should be independent.
        template<class AE>
        -mapped_matrix &operator -= (const matrix_expression<AE> -&ae)
        A computed assignment operator. Subtracts the matrix expression -from the mapped matrix.
        template<class AE>
        -mapped_matrix &minus_assign (const matrix_expression<AE> -&ae)
        Subtracts a matrix expression from the mapped matrix. Left and -right hand side of the assignment should be independent.
        template<class AT>
        -mapped_matrix &operator *= (const AT &at)
        A computed assignment operator. Multiplies the mapped matrix -with a scalar.
        template<class AT>
        -mapped_matrix &operator /= (const AT &at)
        A computed assignment operator. Divides the mapped matrix -through a scalar.
        void swap (mapped_matrix &m)Swaps the contents of the mapped matrices.
        true_refrence insert_element (size_type i, size_type j, const_reference -t)Inserts the value t at the j-th -element of the i-th row. Duplicates elements are not allowed.
        void erase_element (size_type i, size_type j)Erases the value at the j-th element of the -i-th row.
        void clear ()Clears the mapped matrix.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the mapped_matrix.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the mapped_matrix.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the mapped_matrix.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -mapped_matrix.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the mapped_matrix.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the mapped_matrix.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the mapped_matrix.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -mapped_matrix.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed mapped_matrix.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed mapped_matrix.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed mapped_matrix.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed mapped_matrix.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed mapped_matrix.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed mapped_matrix.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed mapped_matrix.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed mapped_matrix.
        -

        Notes

        -

        [1] Supported -parameters for the storage organization are row_major -and column_major.

        -

        [2] Supported -parameters for the adapted array are -map_array<std::size_t, T> and -map_std<std::size_t, T>. The latter is -equivalent to std::map<std::size_t, T>.

        -

        Compressed Matrix

        -

        Description

        -

        The templated class compressed_matrix<T, F, IB, IA, -TA> is the base container adaptor for compressed -matrices. For a (m x n )-dimensional compressed matrix and -0 <= i < m, 0 <= j < n the non-zero -elements mi, j are mapped via (i x -n + j) for row major orientation or via (i + j x m) -for column major orientation to consecutive elements of the index -and value containers, i.e. for elements k = -mi1 -,j1and k + 1 = -mi2 -,j2of the container holds -i1 < -i2 or (i1 -= i2 and -j1 < -j2) with row major orientation or -j1 < -j2 or (j1 -= j2 and -i1 < -i2) with column major -orientation.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix_sparse.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    compressed_matrix<double> m (3, 3, 3 * 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i)
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            m (i, j) = 3 * i + j;
        -    std::cout << m << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix_sparse.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the compressed matrix.
        FFunctor describing the storage organization. [1]row_major
        IBThe index base of the compressed vector. [2]0
        IAThe type of the adapted array for indices. [3]unbounded_array<std::size_t>
        TAThe type of the adapted array for values. [3]unbounded_array<T>
        -

        Model of

        -

        Matrix .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix .

        -

        Public base classes

        -

        matrix_container<compressed_matrix<T, F, IB, IA, -TA> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        compressed_matrix ()Allocates a compressed_matrix that holds at most -zero rows of zero elements.
        compressed_matrix (size_type size1, size_type2, size_type non_zeros = 0)Allocates a compressed_matrix that holds at most -size1 rows of size2 elements.
        compressed_matrix (const compressed_matrix -&m)The copy constructor.
        template<class AE>
        -compressed_matrix (size_type non_zeros, const -matrix_expression<AE> &ae)
        The extended copy constructor.
        void resize (size_type size1, size_type size2, bool preserve = true)Reallocates a compressed_matrix to hold at most -size1 rows of size2 elements. The -existing elements of the compressed_matrix are -preseved when specified.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        compressed_matrix &operator = (const -compressed_matrix &m)The assignment operator.
        compressed_matrix &assign_temporary -(compressed_matrix &m)Assigns a temporary. May change the compressed matrix -m.
        template<class AE>
        -compressed_matrix &operator = (const -matrix_expression<AE> &ae)
        The extended assignment operator.
        template<class AE>
        -compressed_matrix &assign (const matrix_expression<AE> -&ae)
        Assigns a matrix expression to the compressed matrix. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -compressed_matrix &operator += (const -matrix_expression<AE> &ae)
        A computed assignment operator. Adds the matrix expression to -the compressed matrix.
        template<class AE>
        -compressed_matrix &plus_assign (const -matrix_expression<AE> &ae)
        Adds a matrix expression to the compressed matrix. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -compressed_matrix &operator -= (const -matrix_expression<AE> &ae)
        A computed assignment operator. Subtracts the matrix expression -from the compressed matrix.
        template<class AE>
        -compressed_matrix &minus_assign (const -matrix_expression<AE> &ae)
        Subtracts a matrix expression from the compressed matrix. Left -and right hand side of the assignment should be independent.
        template<class AT>
        -compressed_matrix &operator *= (const AT &at)
        A computed assignment operator. Multiplies the compressed -matrix with a scalar.
        template<class AT>
        -compressed_matrix &operator /= (const AT &at)
        A computed assignment operator. Divides the compressed matrix -through a scalar.
        void swap (compressed_matrix &m)Swaps the contents of the compressed matrices.
        true_reference insert_element (size_type i, size_type j, const_reference -t)Inserts the value t at the j-th -element of the i-th row. Duplicates elements are not allowed.
        void erase_element (size_type i, size_type j)Erases the value at the j-th element of the -i-th row.
        void clear ()Clears the compressed matrix.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the compressed_matrix.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the compressed_matrix.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the compressed_matrix.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -compressed_matrix.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the compressed_matrix.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the compressed_matrix.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the compressed_matrix.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -compressed_matrix.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed compressed_matrix.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed compressed_matrix.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed compressed_matrix.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed compressed_matrix.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed compressed_matrix.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed compressed_matrix.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed compressed_matrix.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed compressed_matrix.
        -

        Notes

        -

        [1] -Supported parameters for the storage organization are -row_major and column_major.

        -

        [2] -Supported parameters for the index base are 0 and -1 at least.

        -

        [3] -Supported parameters for the adapted array are -unbounded_array<> , -bounded_array<> and -std::vector<> .

        -

        Coordinate Matrix

        -

        Description

        -

        The templated class coordinate_matrix<T, F, IB, IA, -TA> is the base container adaptor for compressed -matrices. For a (m x n )-dimensional sorted coordinate -matrix and 0 <= i < m, 0 <= j < n the -non-zero elements mi, j are mapped via -(i x n + j) for row major orientation or via (i + j x -m) for column major orientation to consecutive elements of the -index and value containers, i.e. for elements k = -mi1 -,j1and k + 1 = -mi2 -,j2of the container holds -i1 < -i2 or (i1 -= i2 and -j1 < -j2) with row major orientation or -j1 < -j2 or (j1 -= j2 and -i1 < -i2) with column major -orientation.

        -

        Example

        -
        -#include <boost/numeric/ublas/matrix_sparse.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    coordinate_matrix<double> m (3, 3, 3 * 3);
        -    for (unsigned i = 0; i < m.size1 (); ++ i)
        -        for (unsigned j = 0; j < m.size2 (); ++ j)
        -            m (i, j) = 3 * i + j;
        -    std::cout << m << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header matrix_sparse.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the coordinate matrix.
        FFunctor describing the storage organization. [1]row_major
        IBThe index base of the coordinate vector. [2]0
        IAThe type of the adapted array for indices. [3]unbounded_array<std::size_t>
        TAThe type of the adapted array for values. [3]unbounded_array<T>
        -

        Model of

        -

        Matrix .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix .

        -

        Public base classes

        -

        matrix_container<coordinate_matrix<T, F, IB, IA, -TA> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        coordinate_matrix ()Allocates a coordinate_matrix that holds at most -zero rows of zero elements.
        coordinate_matrix (size_type size1, size_type2, size_type non_zeros = 0)Allocates a coordinate_matrix that holds at most -size1 rows of size2 elements.
        coordinate_matrix (const coordinate_matrix -&m)The copy constructor.
        template<class AE>
        -coordinate_matrix (size_type non_zeros, const -matrix_expression<AE> &ae)
        The extended copy constructor.
        void resize (size_type size1, size_type size2, bool preserve = true)Reallocates a coordinate_matrix to hold at most -size1 rows of size2 elements. The -existing elements of the coordinate_matrix are -preseved when specified.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        coordinate_matrix &operator = (const -coordinate_matrix &m)The assignment operator.
        coordinate_matrix &assign_temporary -(coordinate_matrix &m)Assigns a temporary. May change the coordinate matrix -m.
        template<class AE>
        -coordinate_matrix &operator = (const -matrix_expression<AE> &ae)
        The extended assignment operator.
        template<class AE>
        -coordinate_matrix &assign (const matrix_expression<AE> -&ae)
        Assigns a matrix expression to the coordinate matrix. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -coordinate_matrix &operator += (const -matrix_expression<AE> &ae)
        A computed assignment operator. Adds the matrix expression to -the coordinate matrix.
        template<class AE>
        -coordinate_matrix &plus_assign (const -matrix_expression<AE> &ae)
        Adds a matrix expression to the coordinate matrix. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -coordinate_matrix &operator -= (const -matrix_expression<AE> &ae)
        A computed assignment operator. Subtracts the matrix expression -from the coordinate matrix.
        template<class AE>
        -coordinate_matrix &minus_assign (const -matrix_expression<AE> &ae)
        Subtracts a matrix expression from the coordinate matrix. Left -and right hand side of the assignment should be independent.
        template<class AT>
        -coordinate_matrix &operator *= (const AT &at)
        A computed assignment operator. Multiplies the coordinate -matrix with a scalar.
        template<class AT>
        -coordinate_matrix &operator /= (const AT &at)
        A computed assignment operator. Divides the coordinate matrix -through a scalar.
        void swap (coordinate_matrix &m)Swaps the contents of the coordinate matrices.
        true_reference insert_element (size_type i, size_type j, const_reference -t)Inserts the value t at the j-th -element of the i-th row. Duplicates elements are not allowed.
        void append_element (size_type i, size_type j, const_reference t)Appends the value t at the j-th element of the i-th row. -Duplicate elements can be appended to a coordinate_matrix. They are merged into a single -arithmetically summed element by the sort function.
        void erase_element (size_type i, size_type j)Erases the value at the j-th element of the -i-th row.
        void clear ()Clears the coordinate matrix.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the coordinate_matrix.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the coordinate_matrix.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the coordinate_matrix.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -coordinate_matrix.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the coordinate_matrix.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the coordinate_matrix.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the coordinate_matrix.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -coordinate_matrix.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed coordinate_matrix.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed coordinate_matrix.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed coordinate_matrix.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed coordinate_matrix.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed coordinate_matrix.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed coordinate_matrix.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed coordinate_matrix.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed coordinate_matrix.
        -

        Notes

        -

        [1] -Supported parameters for the storage organization are -row_major and column_major.

        -

        [2] -Supported parameters for the index base are 0 and -1 at least.

        -

        [3] -Supported parameters for the adapted array are -unbounded_array<> , -bounded_array<> and -std::vector<> .

        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/operations_overview.html b/doc/operations_overview.html deleted file mode 100644 index 442048e98..000000000 --- a/doc/operations_overview.html +++ /dev/null @@ -1,277 +0,0 @@ - - - - - - - - - - -uBLAS operations overview - - -

        Overview of Tensor, Matrix and Vector Operations

        -
        - -
        -
        Contents:
        -
        Basic Linear Algebra
        -
        Advanced Functions
        -
        Submatrices, Subvectors
        -
        Speed Improvements
        -
        - -

        Definitions

        - - - - - - - - - - - - - - - - -
        X, Y, Z are tensors
        A, B, C are matrices
        u, v, ware vectors
        i, j, kare integer values
        t, t1, t2are scalar values
        r, r1, r2are ranges, e.g. range(0, 3)
        s, s1, s2are slices, e.g. slice(0, 1, 3)
        - -

        Basic Linear Algebra

        - -

        standard operations: addition, subtraction, multiplication by a -scalar

        -
        
        -X = Y + Z; X = Y - Z; X = -Y;
        -C = A + B; C = A - B; C = -A;
        -w = u + v; w = u - v; w = -u;
        -X = t * Y; Y = X * t; X = Y / t;
        -C = t * A; C = A * t; C = A / t;
        -w = t * u; w = u * t; w = u / t;
        -
        - -

        computed assignments

        -
        
        -X += Y; X -= Y; 
        -C += A; C -= A; 
        -w += u; w -= u; 
        -X *= t; X /= t; 
        -C *= t; C /= t; 
        -w *= t; w /= t;
        -
        - -

        inner, outer and other products

        -
        
        -t = inner_prod(u, v);
        -C = outer_prod(u, v);
        -w = prod(A, u); w = prod(u, A); w = prec_prod(A, u); w = prec_prod(u, A);
        -C = prod(A, B); C = prec_prod(A, B);
        -w = element_prod(u, v); w = element_div(u, v);
        -C = element_prod(A, B); C = element_div(A, B);
        -
        - -

        tensor products

        -
        
        -Z = prod(X, v, t);
        -Z = prod(X, A, t);
        -Z = prod(X, Y, p);
        -Z = prod(X, Y, pa, pb);
        -t = inner_prod(X, Y);
        -Z = outer_prod(X, Y);
        -
        - -

        transformations

        -
        
        -w = conj(u); w = real(u); w = imag(u);
        -C = trans(A); C = conj(A); C = herm(A); C = real(A); C = imag(A);
        -Z = trans(X); Z = conj(X); Z = real(X); Z = imag(X);
        -
        - - -

        Advanced functions

        - -

        norms

        - -
        
        -t = norm_inf(v); i = index_norm_inf(v);
        -t = norm_1(v);   t = norm_2(v);
        -t = norm_2_square(v);
        -t = norm_inf(A); i = index_norm_inf(A);
        -t = norm_1(A);   t = norm_frobenius(A); 
        -t = norm(X);
        -
        - -

        products

        - -
        
        -axpy_prod(A, u, w, true);  // w = A * u
        -axpy_prod(A, u, w, false); // w += A * u
        -axpy_prod(u, A, w, true);  // w = trans(A) * u
        -axpy_prod(u, A, w, false); // w += trans(A) * u
        -axpy_prod(A, B, C, true);  // C = A * B
        -axpy_prod(A, B, C, false); // C += A * B
        -
        -

        Note: The last argument (bool init) of -axpy_prod is optional. Currently it defaults to -true, but this may change in the future. Setting the -init to true is equivalent to calling -w.clear() before axpy_prod. -There are some specialisation for products of compressed matrices that give a -large speed up compared to prod.

        -
        
        -w = block_prod<matrix_type, 64> (A, u); // w = A * u
        -w = block_prod<matrix_type, 64> (u, A); // w = trans(A) * u
        -C = block_prod<matrix_type, 64> (A, B); // C = A * B
        -
        -

        Note: The blocksize can be any integer. However, the -actual speed depends very significantly on the combination of blocksize, -CPU and compiler. The function block_prod is designed -for large dense matrices.

        -

        rank-k updates

        -
        
        -opb_prod(A, B, C, true);  // C = A * B
        -opb_prod(A, B, C, false); // C += A * B
        -
        -

        Note: The last argument (bool init) of -opb_prod is optional. Currently it defaults to -true, but this may change in the future. This function -may give a speedup if A has less columns than rows, -because the product is computed as a sum of outer products.

        - -

        Submatrices, Subvectors

        -

        Accessing submatrices and subvectors via proxies using project functions:

        -
        
        -w = project(u, r);         // the subvector of u specifed by the index range r
        -w = project(u, s);         // the subvector of u specifed by the index slice s
        -C = project(A, r1, r2);    // the submatrix of A specified by the two index ranges r1 and r2
        -C = project(A, s1, s2);    // the submatrix of A specified by the two index slices s1 and s2
        -w = row(A, i); w = column(A, j);    // a row or column of matrix as a vector
        -
        -

        Assigning to submatrices and subvectors via proxies using project functions:

        -
        
        -project(u, r) = w;         // assign the subvector of u specifed by the index range r
        -project(u, s) = w;         // assign the subvector of u specifed by the index slice s
        -project(A, r1, r2) = C;    // assign the submatrix of A specified by the two index ranges r1 and r2
        -project(A, s1, s2) = C;    // assign the submatrix of A specified by the two index slices s1 and s2
        -row(A, i) = w; column(A, j) = w;    // a row or column of matrix as a vector
        -
        -

        Note: A range r = range(start, stop) -contains all indices i with start <= i < -stop. A slice is something more general. The slice -s = slice(start, stride, size) contains the indices -start, start+stride, ..., start+(size-1)*stride. The -stride can be 0 or negative! If start >= stop for a range -or size == 0 for a slice then it contains no elements.

        -

        Sub-ranges and sub-slices of vectors and matrices can be created directly with the subrange and sublice functions:

        -
        
        -w = subrange(u, 0, 2);         // the 2 element subvector of u
        -w = subslice(u, 0, 1, 2);      // the 2 element subvector of u
        -C = subrange(A, 0,2, 0,3);     // the 2x3 element submatrix of A
        -C = subslice(A, 0,1,2, 0,1,3); // the 2x3 element submatrix of A
        -subrange(u, 0, 2) = w;         // assign the 2 element subvector of u
        -subslice(u, 0, 1, 2) = w;      // assign the 2 element subvector of u
        -subrange(A, 0,2, 0,3) = C;     // assign the 2x3 element submatrix of A
        -subrange(A, 0,1,2, 0,1,3) = C; // assigne the 2x3 element submatrix of A
        -
        -

        There are to more ways to access some matrix elements as a -vector:

        -
        matrix_vector_range<matrix_type> (A, r1, r2);
        -matrix_vector_slice<matrix_type> (A, s1, s2);
        -
        -

        Note: These matrix proxies take a sequence of elements -of a matrix and allow you to access these as a vector. In -particular matrix_vector_slice can do this in a very -general way. matrix_vector_range is less useful as the -elements must lie along a diagonal.

        -

        Example: To access the first two elements of a sub -column of a matrix we access the row with a slice with stride 1 and -the column with a slice with stride 0 thus:
        -matrix_vector_slice<matrix_type> (A, slice(0,1,2), -slice(0,0,2)); -

        - -

        Speed improvements

        -

        Matrix / Vector assignment

        -

        If you know for sure that the left hand expression and the right -hand expression have no common storage, then assignment has -no aliasing. A more efficient assignment can be specified -in this case:

        -
        noalias(C) = prod(A, B);
        -
        -

        This avoids the creation of a temporary matrix that is required in a normal assignment. -'noalias' assignment requires that the left and right hand side be size conformant.

        - -

        Sparse element access

        -

        The matrix element access function A(i1,i2) or the equivalent vector -element access functions (v(i) or v[i]) usually create 'sparse element proxies' -when applied to a sparse matrix or vector. These proxies allow access to elements -without having to worry about nasty C++ issues where references are invalidated.

        -

        These 'sparse element proxies' can be implemented more efficiently when applied to const -objects. -Sadly in C++ there is no way to distinguish between an element access on the left and right hand side of -an assignment. Most often elements on the right hand side will not be changed and therefore it would -be better to use the const proxies. We can do this by making the matrix or vector -const before accessing it's elements. For example:

        -
        value = const_cast<const VEC>(v)[i];   // VEC is the type of V
        -
        -

        If more then one element needs to be accessed const_iterator's should be used -in preference to iterator's for the same reason. For the more daring 'sparse element proxies' -can be completely turned off in uBLAS by defining the configuration macro BOOST_UBLAS_NO_ELEMENT_PROXIES. -

        - - -

        Controlling the complexity of nested products

        - -

        What is the complexity (the number of add and multiply operations) required to compute the following? -

        -
        - R = prod(A, prod(B,C)); 
        -
        -

        Firstly the complexity depends on matrix size. Also since prod is transitive (not commutative) -the bracket order affects the complexity. -

        -

        uBLAS evaluates expressions without matrix or vector temporaries and honours -the bracketing structure. However avoiding temporaries for nested product unnecessarly increases the complexity. -Conversly by explictly using temporary matrices the complexity of a nested product can be reduced. -

        -

        uBLAS provides 3 alternative syntaxes for this purpose: -

        -
        - temp_type T = prod(B,C); R = prod(A,T);   // Preferable if T is preallocated
        -
        -
        - prod(A, temp_type(prod(B,C));
        -
        -
        - prod(A, prod<temp_type>(B,C));
        -
        -

        The 'temp_type' is important. Given A,B,C are all of the same type. Say -matrix<float>, the choice is easy. However if the value_type is mixed (int with float or double) -or the matrix type is mixed (sparse with symmetric) the best solution is not so obvious. It is up to you! It -depends on numerical properties of A and the result of the prod(B,C). -

        - -
        -

        Copyright (©) 2000-2007 Joerg Walter, Mathias Koch, Gunter -Winkler, Michael Stevens
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/options.html b/doc/options.html deleted file mode 100644 index 2b9e6f231..000000000 --- a/doc/options.html +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - - - - - - -Boost Basic Linear Algebra - Configuration Options - - -

        logoBoost Basic Linear Algebra - Configuration Options

        -
        - - - -

        NDEBUG

        - -

        Make sure you define NDEBUG The only way uBLAS -knows you want a release configuration is to check if you have defined -NDEBUG. If you don't it assumes you want a debug configuration and -adds a lot of very useful runtime check. However these are very slow! -

        - - -

        BOOST_UBLAS_MOVE_SEMANTICS

        - -

        The patch and description was provided by Nasos Iliopoulos.

        - -

        An immediate effect of this option is the elimination of the need -for noalias in types vector<T> and matrix<T>, -when assigned to the same type. This option doesn't have an effect on -bounded and c types. Although it is rare, not all compilers support copy -elision (that allows for move semantics), so a test must be performed to -make sure that there is a benefit when it is enabled. A small -demonstration and test can be found in -test_move_semantics.cpp

        - -

        -In the test -example two tests are defined, one for vectors and one for -matrices. The aim of this example is to print the pointers of the -storage of each of the containers, before and after the assignment to -a temporary object. When move semantics are enabled, the -vector<T> and matrix<T> storage is moved -from the temporary and no copy is performed. -

        - -

        -If move semantics are supported by your compiler you will get an output like the following: -

        -
        -matrix<double> --------------------------------------------------------------------
        -Temporary pointer r: 0x94790c0
        -Pointer (must be equal to temp. pointer if move semantics are enabled) : 0x94790c0
        -
        - -

        Notes:

        -
          -
        • It should be no surprise to see matrices and vectors been passed -by VALUE, the compiler takes care and either moves (if the underlying -code does not modify the object), or copies (if the underlying code -modifies the object). -
        • -
        • There might be some space for some improvements (like clearing the -data, before swaping) -
        • -
        • Move semantics don't eliminate temporaries. They rather move their -storage around so no copies are performed. -
        • -
        • MSVC does no implement Named Return Value Optimization in debug -mode. So if you build in debug with this compiler you might get different behaviour than a release build. -
        • -
        • Enabling move semantics is done via #define BOOST_UBLAS_MOVE_SEMANTICS. -
        • -
        • There is plenty of room for optimizations when c++0x standard is -out, taking advantage of rvalue references. (I have a sweet vector -implementation using that). -
        • -
        • If you enable move semantics and your compiler does not support -them, the operation will just be as passing by const reference. -
        • -
        - -

        Interesting links

        - - -

        BOOST_UBLAS_CHECK_ENABLE

        - -

        When BOOST_UBLAS_CHECK_ENABLE is defined then all index and -parameter checks are enabled. This is enabled in debug mode and -disabled in release mode. -

        - -

        BOOST_UBLAS_TYPE_CHECK

        - -

        When BOOST_UBLAS_TYPE_CHECK is enabled then all possibly expensive -structure checks are enabled. If this is not desireable then use -#define BOOST_UBLAS_TYPE_CHECK 0 before including any uBLAS -header. The define BOOST_UBLAS_TYPE_CHECK_EPSILON can be used to -control the acceptable tolerance, see -detail/matrix_assign.hpp for implementation details of this -check. -

        - -

        BOOST_UBLAS_USE_LONG_DOUBLE

        - -

        Enable uBLAS expressions that involve containers of 'long double'

        - -

        BOOST_UBLAS_USE_INTERVAL

        - -

        Enable uBLAS expressions that involve containers of 'boost::numeric::interval' types

        - -

        Configuring uBLAS with Macros

        - -

        Many macro's appear in ublas/config.hpp and elsewhere. Hopefully in the future some of these will disappear! -They fall into 4 groups: -

        -
          -
        • Automatically set by 'boost/numeric/ublas/config.hpp' based on -NDEBUG. Makes the distinction between debug (safe) and release (fast) -mode. Similar to STLport -
            -
          • Release mode (NDEBUG defined) -
              -
            • BOOST_UBLAS_INLINE Compiler dependant definition to control -function inlining.
            • BOOST_UBLAS_USE_FAST_SAME
            -
          • Debug mode -
              -
            • BOOST_UBLAS_CHECK_ENABLE Enable checking of indexs, iterators -and parameters. Prevents out of bound access etc.
            • -BOOST_UBLAS_TYPE_CHECK Enable additional checks for the results of -expressions using non dense types. Picks up runtime error such as the -assignment of a numerically non-symmetric matrix to -symmertic_matrix. Use #define BOOST_UBLAS_TYPE_CHECK 0 to -disable expensive numeric type checks. (Note: "structure check" -would be a much better name.)
            • -BOOST_UBLAS_TYPE_CHECK_EPSILON default: sqrt(epsilon), controls how -large the difference between the expected result and the computed -result may become. Increase this value if you are going to use near -singular or badly scaled matrices. Please, refer to -detail/matrix_assign.hpp for implementation of these type -checks.
          -
        • -
        • Automatically set by 'boost/numeric/ublas/config.hpp' based on -compiler and boost/config.hpp macro's. Augments the compiler -deficiency workarounds already supplied by boost/config.hpp -
            -
          • BOOST_UBLAS_NO_NESTED_CLASS_RELATION A particularly nasty -problem with VC7.1 Requires that uBLAS and the user use begin(it) -rather then it.begin()
          • BOOST_UBLAS_NO_SMART_PROXIES -Disable the automatic propagation of 'constantness' to -proxies. Smart proxies automatically determine if the underling -container they reference is constant or not. They adjust there -definition of iterators and container access to reflect this -constantness.
          -
        • -
        • For use by uBLAS authors to test implementation methods. Preset -in config.hpp -
            -
          • BOOST_UBLAS_USE_INVARIANT_HOISTING
          • -BOOST_UBLAS_USE_INDEXING
          • BOOST_UBLAS_USE_INDEXED_ITERATOR -
          • BOOST_UBLAS_NON_CONFORMANT_PROXIES Gappy containers may -be non-conformant, that is contain elements at different -indices. Assigning between proxies (vector ranges for example) of -these containers is difficult as the LHS may need insert new -elements. This is slow.
          • BOOST_UBLAS_USE_DUFF_DEVICE -Near useless on all platforms (see GCC's -funroll-loops) - -
          -
        • -
        • User options. Can be predefined by user before including any -uBLAS headers. They may also be automatically defined for some -compilers to work around compile bugs. -
            -
          • BOOST_UBLAS_USE_LONG_DOUBLE Enable uBLAS expressions that -involve containers of 'long double'
          • -BOOST_UBLAS_USE_INTERVAL Enable uBLAS expressions that involve -containers of 'boost::numeric::interval' types
          • -BOOST_UBLAS_SIMPLE_ET_DEBUG In order to simplify debugging is is -possible to simplify expression templateso they are restricted to a -single operation - -
          • BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS enable automatic -conversion from proxy class to matrix expression
          • -BOOST_UBLAS_NO_ELEMENT_PROXIES Disables the use of element proxies -for gappy types.
          • The Gappy types (sparse, coordinate, -compressed) store non-zero elements in their own containers. When new -non-zero elements are assigned they must rearrange these -containers. This invalidates references, iterators or pointers to -these elements. This can happen at some surprising times such as the -expression "a [1] = a [0] = 1;". Element proxies guarantee all such -expressions will work as expected. However they bring their own -restrictions and efficiency problems. For example as of Boost 1.30.0 -they prevent the assignment of elements between different types. -
          • -
          • BOOST_UBLAS_REFERENCE_CONST_MEMBER Enable to allow refernces -to be returned to fixed (zero or one) elements of triangular or banded -matrices - -
          • BOOST_UBLAS_NO_EXCEPTIONS Disable the use exceptions of -uBLAS internal checks and error conditions. BOOST_NO_EXCEPTIONS has -same effect. -
          • -
          • BOOST_UBLAS_SINGULAR_CHECK Check the for singularity in triangular solve() functions
          • -
          -
        • -
        - -
        - -
        -

        - - -Last modified: Wed Sep 16 23:16:45 CEST 2009 - -

        -
        - - - diff --git a/doc/overview.html b/doc/overview.html deleted file mode 100644 index 1ce347dc3..000000000 --- a/doc/overview.html +++ /dev/null @@ -1,965 +0,0 @@ - - - - - - - - - - -uBLAS Overview - - -

        logouBLAS Overview

        -
        -

        Rationale

        -

        It would be nice if every kind of numeric software could -be written in C++ without loss of efficiency, but unless something -can be found that achieves this without compromising the C++ type -system it may be preferable to rely on Fortran, assembler or -architecture-specific extensions (Bjarne Stroustrup).

        -

        This C++ library is directed towards scientific computing on the -level of basic linear algebra constructions with matrices and -vectors and their corresponding abstract operations. The primary -design goals were:

        -
          -
        • mathematical notation
        • -
        • efficiency
        • -
        • functionality
        • -
        • compatibility
        • -
        -

        Another intention was to evaluate, if the abstraction penalty -resulting from the use of such matrix and vector classes is -acceptable.

        -

        Resources

        -

        The development of this library was guided by a couple of -similar efforts:

        -
          -
        • BLAS by -Jack Dongarra et al.
        • -
        • Blitz++ by Todd -Veldhuizen
        • -
        • POOMA by Scott -Haney et al.
        • -
        • MTL by Jeremy -Siek et al.
        • -
        -

        BLAS seems to be the most widely used library for basic linear -algebra constructions, so it could be called a de-facto standard. -Its interface is procedural, the individual functions are somewhat -abstracted from simple linear algebra operations. Due to the fact -that is has been implemented using Fortran and its optimizations, -it also seems to be one of the fastest libraries available. As we -decided to design and implement our library in an object-oriented -way, the technical approaches are distinct. However anyone should -be able to express BLAS abstractions in terms of our library -operators and to compare the efficiency of the implementations.

        -

        Blitz++ is an impressive library implemented in C++. Its main -design seems to be oriented towards multidimensional arrays and -their associated operators including tensors. The author of Blitz++ -states, that the library achieves performance on par or better than -corresponding Fortran code due to his implementation technique -using expression templates and template metaprograms. However we -see some reasons, to develop an own design and implementation -approach. We do not know whether anybody tries to implement -traditional linear algebra and other numerical algorithms using -Blitz++. We also presume that even today Blitz++ needs the most -advanced C++ compiler technology due to its implementation idioms. -On the other hand, Blitz++ convinced us, that the use of expression -templates is mandatory to reduce the abstraction penalty to an -acceptable limit.

        -

        POOMA's design goals seem to parallel Blitz++'s in many parts . -It extends Blitz++'s concepts with classes from the domains of -partial differential equations and theoretical physics. The -implementation supports even parallel architectures.

        -

        MTL is another approach supporting basic linear algebra -operations in C++. Its design mainly seems to be influenced by BLAS -and the C++ Standard Template Library. We share the insight that a -linear algebra library has to provide functionality comparable to -BLAS. On the other hand we think, that the concepts of the C++ -standard library have not yet been proven to support numerical -computations as needed. As another difference MTL currently does -not seem to use expression templates. This may result in one of two -consequences: a possible loss of expressiveness or a possible loss -of performance.

        -

        Concepts

        -

        Mathematical Notation

        -

        The usage of mathematical notation may ease the development of -scientific algorithms. So a C++ library implementing basic linear -algebra concepts carefully should overload selected C++ operators -on matrix and vector classes.

        -

        We decided to use operator overloading for the following -primitives:

        - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DescriptionOperator
        Indexing of vectors and matricesvector::operator(size_t i);
        -matrix::operator(size_t i, size_t j);
        Assignment of vectors and matricesvector::operator = (const vector_expression &);
        -vector::operator += (const vector_expression &);
        -vector::operator -= (const vector_expression &);
        -vector::operator *= (const scalar_expression &);
        -matrix::operator = (const matrix_expression &);
        -matrix::operator += (const matrix_expression &);
        -matrix::operator -= (const matrix_expression &);
        -matrix::operator *= (const scalar_expression &);
        Unary operations on vectors and matricesvector_expression operator - (const vector_expression -&);
        -matrix_expression operator - (const matrix_expression -&);
        Binary operations on vectors and matricesvector_expression operator + (const vector_expression -&, const vector_expression &);
        -vector_expression operator - (const vector_expression &, const -vector_expression &);
        -matrix_expression operator + (const matrix_expression &, const -matrix_expression &);
        -matrix_expression operator - (const matrix_expression &, const -matrix_expression &);
        Multiplication of vectors and matrices with a scalarvector_expression operator * (const scalar_expression -&, const vector_expression &);
        -vector_expression operator * (const vector_expression &, const -scalar_expression &);
        -matrix_expression operator * (const scalar_expression &, const -matrix_expression &);
        -matrix_expression operator * (const matrix_expression &, const -scalar_expression &);
        -

        We decided to use no operator overloading for the following -other primitives:

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DescriptionFunction
        Left multiplication of vectors with a matrixvector_expression -prod<vector_type > (const -matrix_expression &, const vector_expression &);
        -vector_expression prod (const matrix_expression &, const -vector_expression &);
        Right multiplication of vectors with a matrixvector_expression -prod<vector_type > (const -vector_expression &, const matrix_expression &);
        -vector_expression prod (const vector_expression &, const -matrix_expression &);
        Multiplication of matricesmatrix_expression -prod<matrix_type > (const -matrix_expression &, const matrix_expression &);
        -matrix_expression prod (const matrix_expression &, const -matrix_expression &);
        Inner product of vectorsscalar_expression inner_prod (const vector_expression -&, const vector_expression &);
        Outer product of vectorsmatrix_expression outer_prod (const vector_expression -&, const vector_expression &);
        Transpose of a matrixmatrix_expression trans (const matrix_expression -&);
        -

        Efficiency

        -

        To achieve the goal of efficiency for numerical computing, one -has to overcome two difficulties in formulating abstractions with -C++, namely temporaries and virtual function calls. Expression -templates solve these problems, but tend to slow down compilation -times.

        -

        Eliminating Temporaries

        -

        Abstract formulas on vectors and matrices normally compose a -couple of unary and binary operations. The conventional way of -evaluating such a formula is first to evaluate every leaf operation -of a composition into a temporary and next to evaluate the -composite resulting in another temporary. This method is expensive -in terms of time especially for small and space especially for -large vectors and matrices. The approach to solve this problem is -to use lazy evaluation as known from modern functional programming -languages. The principle of this approach is to evaluate a complex -expression element wise and to assign it directly to the -target.

        -

        Two interesting and dangerous facts result:

        -

        Aliases

        -

        One may get serious side effects using element wise -evaluation on vectors or matrices. Consider the matrix vector -product x = A x. Evaluation of -A1x and assignment to -x1 changes the right hand side, so -that the evaluation of A2x -returns a wrong result. In this case there are aliases of the elements -xn on both the left and right hand side of the assignment.

        -

        Our solution for this problem is to -evaluate the right hand side of an assignment into a temporary and -then to assign this temporary to the left hand side. To allow -further optimizations, we provide a corresponding member function -for every assignment operator and also a - noalias syntax. -By using this syntax a programmer can confirm, that the left and right hand sides of an -assignment are independent, so that element wise evaluation and -direct assignment to the target is safe.

        -

        Complexity

        -

        The computational complexity may be unexpectedly large under certain -cirumstances. Consider the chained matrix vector product A (B -x). Conventional evaluation of A (B x) is quadratic. -Deferred evaluation of B xi is linear. -As every element B xi is needed -linearly depending of the size, a completely deferred evaluation of -the chained matrix vector product A (B x) is cubic. In -such cases one needs to reintroduce temporaries in the -expression.

        -

        Eliminating Virtual Function Calls

        -

        Lazy expression evaluation normally leads to the definition of a -class hierarchy of terms. This results in the usage of dynamic -polymorphism to access single elements of vectors and matrices, -which is also known to be expensive in terms of time. A solution -was found a couple of years ago independently by David Vandervoorde -and Todd Veldhuizen and is commonly called expression templates. -Expression templates contain lazy evaluation and replace dynamic -polymorphism with static, i.e. compile time polymorphism. -Expression templates heavily depend on the famous Barton-Nackman -trick, also coined 'curiously defined recursive templates' by Jim -Coplien.

        -

        Expression templates form the base of our implementation.

        -

        Compilation times

        -

        It is also a well known fact, that expression templates -challenge currently available compilers. We were able to -significantly reduce the amount of needed expression templates -using the Barton-Nackman trick consequently.

        -

        We also decided to support a dual conventional implementation -(i.e. not using expression templates) with extensive bounds and -type checking of vector and matrix operations to support the -development cycle. Switching from debug mode to release mode is -controlled by the NDEBUG preprocessor symbol of -<cassert>.

        - -

        Functionality

        - -

        Every C++ library supporting linear algebra will be measured -against the long-standing Fortran package BLAS. We now describe how -BLAS calls may be mapped onto our classes.

        - -

        The page Overview of Matrix and Vector Operations -gives a short summary of the most used operations on vectors and -matrices.

        - -

        Blas Level 1

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        BLAS CallMapped Library ExpressionMathematical DescriptionComment
        sasum OR dasumnorm_1 (x)sum |xi|Computes the l1 (sum) norm of a real vector.
        scasum OR dzasumreal (sum (v)) + imag (sum (v))sum re(xi) + sum im(xi)Computes the sum of elements of a complex vector.
        _nrm2norm_2 (x)sqrt (sum -|xi|2 )Computes the l2 (euclidean) norm of a vector.
        i_amaxnorm_inf (x)
        -index_norm_inf (x)
        max |xi|Computes the linf (maximum) norm of a vector.
        -BLAS computes the index of the first element having this -value.
        _dot
        -_dotu
        -_dotc
        inner_prod (x, y)or
        -inner_prod (conj (x), y)
        xT y or
        -xH y
        Computes the inner product of two vectors.
        -BLAS implements certain loop unrollment.
        dsdot
        -sdsdot
        a + prec_inner_prod (x, y)a + xT yComputes the inner product in double precision.
        _copyx = y
        -y.assign (x)
        x <- yCopies one vector to another.
        -BLAS implements certain loop unrollment.
        _swapswap (x, y)x <-> ySwaps two vectors.
        -BLAS implements certain loop unrollment.
        _scal
        -csscal
        -zdscal
        x *= ax <- a xScales a vector.
        -BLAS implements certain loop unrollment.
        _axpyy += a * xy <- a x + yAdds a scaled vector.
        -BLAS implements certain loop unrollment.
        _rot
        -_rotm
        -csrot
        -zdrot
        t.assign (a * x + b * y),
        -y.assign (- b * x + a * y),
        -x.assign (t)
        (x, y) <- (a x + b y, -b x + a y)Applies a plane rotation.
        _rotg
        -_rotmg
         (a, b) <-
        -  (? a / sqrt (a
        2 + -b2),
        -    ? b / sqrt (a
        2 + -b2)) or
        -(1, 0) <- (0, 0)
        Constructs a plane rotation.
        -

        Blas Level 2

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        BLAS CallMapped Library ExpressionMathematical DescriptionComment
        _t_mvx = prod (A, x) or
        -x = prod (trans (A), x)
        or
        -x = prod (herm (A), x)
        x <- A x or
        -x <- A
        T x or
        -x <- A
        H x
        Computes the product of a matrix with a vector.
        _t_svy = solve (A, x, tag) or
        -inplace_solve (A, x, tag) or
        -y = solve (trans (A), x, tag) or
        -inplace_solve (trans (A), x, tag) or
        -y = solve (herm (A), x, tag)or
        -inplace_solve (herm (A), x, tag)
        y <- A-1 x -or
        -x <- A
        -1 x or
        -y <- -A
        T-1 -x or
        -x <- -A
        T-1 -x or
        -y <- -A
        H-1 -x or
        -x <- -A
        H-1 -x
        Solves a system of linear equations with triangular form, i.e. -A is triangular.
        _g_mv
        -_s_mv
        -_h_mv
        y = a * prod (A, x) + b * y or
        -y = a * prod (trans (A), x) + b * y
        or
        -y = a * prod (herm (A), x) + b * y
        y <- a A x + b y or
        -y <- a A
        T x + b y
        -y <- a A
        H x + b y
        Adds the scaled product of a matrix with a vector.
        _g_r
        -_g_ru
        -_g_rc
        A += a * outer_prod (x, y) or
        -A += a * outer_prod (x, conj (y))
        A <- a x yT + A -or
        -A <- a x y
        H + A
        Performs a rank 1 update.
        _s_r
        -_h_r
        A += a * outer_prod (x, x) or
        -A += a * outer_prod (x, conj (x))
        A <- a x xT + A -or
        -A <- a x x
        H + A
        Performs a symmetric or hermitian rank 1 update.
        _s_r2
        -_h_r2
        A += a * outer_prod (x, y) +
        - a * outer_prod (y, x))
        or
        -A += a * outer_prod (x, conj (y)) +
        - conj (a) * outer_prod (y, conj (x)))
        A <- a x yT + a y -xT + A or
        -A <- a x y
        H + -a- y xH + -A
        Performs a symmetric or hermitian rank 2 update.
        -

        Blas Level 3

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        BLAS CallMapped Library ExpressionMathematical DescriptionComment
        _t_mmB = a * prod (A, B) or
        -B = a * prod (trans (A), B) or
        -B = a * prod (A, trans (B)) or
        -B = a * prod (trans (A), trans (B)) or
        -B = a * prod (herm (A), B) or
        -B = a * prod (A, herm (B)) or
        -B = a * prod (herm (A), trans (B)) or
        -B = a * prod (trans (A), herm (B)) or
        -B = a * prod (herm (A), herm (B))
        B <- a op (A) op (B) with
        -  op (X) = X or
        -  op (X) = XT or
        -  op (X) = XH
        Computes the scaled product of two matrices.
        _t_smC = solve (A, B, tag) or
        -inplace_solve (A, B, tag) or
        -C = solve (trans (A), B, tag) or
        -inplace_solve (trans (A), B, tag)
        or
        -C = solve (herm (A), B, tag)
        or
        -inplace_solve (herm (A), B, tag)
        C <- A-1 B -or
        -B <- A
        -1 B or
        -C <- -A
        T-1 -B or
        -B <- A
        -1 B or
        -C <- -A
        H-1 -B or
        -B <- -A
        H-1 -B
        Solves a system of linear equations with triangular form, i.e. -A is triangular.
        _g_mm
        -_s_mm
        -_h_mm
        C = a * prod (A, B) + b * C or
        -C = a * prod (trans (A), B) + b * C or
        -C = a * prod (A, trans (B)) + b * C or
        -C = a * prod (trans (A), trans (B)) + b * C or
        -C = a * prod (herm (A), B) + b * C or
        -C = a * prod (A, herm (B)) + b * C or
        -C = a * prod (herm (A), trans (B)) + b * C or
        -C = a * prod (trans (A), herm (B)) + b * C or
        -C = a * prod (herm (A), herm (B)) + b * C
        C <- a op (A) op (B) + b C with
        -  op (X) = X or
        -  op (X) = XT or
        -  op (X) = XH
        Adds the scaled product of two matrices.
        _s_rk
        -_h_rk
        B = a * prod (A, trans (A)) + b * B or
        -B = a * prod (trans (A), A) + b * B or
        -B = a * prod (A, herm (A)) + b * B or
        -B = a * prod (herm (A), A) + b * B
        B <- a A AT + b B -or
        -B <- a A
        T A + b B or
        -B <- a A AH + b B -or
        -B <- a A
        H A + b B
        Performs a symmetric or hermitian rank k update.
        _s_r2k
        -_h_r2k
        C = a * prod (A, trans (B)) +
        - a * prod (B, trans (A)) + b * C
        or
        -C = a * prod (trans (A), B) +
        - a * prod (trans (B), A) + b * C
        or
        -C = a * prod (A, herm (B)) +
        - conj (a) * prod (B, herm (A)) + b * C
        or
        -C = a * prod (herm (A), B) +
        - conj (a) * prod (herm (B), A) + b * C
        C <- a A BT + a B -AT + b C or
        -C <- a A
        T B + a -BT A + b C or
        -C <- a A B
        H + -a- B AH + -b C or
        -C <- a A
        H B + -a- BH A + -b C
        Performs a symmetric or hermitian rank 2 k -update.
        - -

        Storage Layout

        - -

        uBLAS supports many different storage layouts. The full details can be -found at the Overview of Types. Most types like -vector<double> and matrix<double> are -by default compatible to C arrays, but can also be configured to contain -FORTAN compatible data. -

        - -

        Compatibility

        -

        For compatibility reasons we provide array like indexing for vectors and matrices. For some types (hermitian, sparse etc) this can be expensive for matrices due to the needed temporary proxy objects.

        -

        uBLAS uses STL compatible allocators for the allocation of the storage required for it's containers.

        -

        Benchmark Results

        -

        The following tables contain results of one of our benchmarks. -This benchmark compares a native C implementation ('C array') and -some library based implementations. The safe variants based on the -library assume aliasing, the fast variants do not use temporaries -and are functionally equivalent to the native C implementation. -Besides the generic vector and matrix classes the benchmark -utilizes special classes c_vector and -c_matrix, which are intended to avoid every overhead -through genericity.

        -

        The benchmark program bench1 was compiled with GCC 4.0 and run on an Athlon 64 3000+. Times are scales for reasonable precision by running bench1 100.

        -

        First we comment the results for double vectors and matrices of dimension 3 and 3 x 3, respectively.

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Comment
        inner_prodC array0.61782Some abstraction penalty
        c_vector0.86554
        vector<unbounded_array>1.02467
        vector + vectorC array0.511122Abstraction penalty: factor 2
        c_vector fast1.17489
        vector<unbounded_array> fast1.32433
        c_vector safe2.02283
        vector<unbounded_array> safe6.9582
        outer_prodC array0.59872Some abstraction penalty
        c_matrix, c_vector fast0.88585
        matrix<unbounded_array>, vector<unbounded_array> fast0.90572
        c_matrix, c_vector safe1.66310
        matrix<unbounded_array>, vector<unbounded_array> safe2.95175
        prod (matrix, vector)C array0.64671No significant abstraction penalty
        c_matrix, c_vector fast0.70613
        matrix<unbounded_array>, vector<unbounded_array> fast0.79543
        c_matrix, c_vector safe0.95452
        matrix<unbounded_array>, vector<unbounded_array> safe2.61164
        matrix + matrixC array0.75686No significant abstraction penalty
        c_matrix fast0.99520
        matrix<unbounded_array> fast1.29399
        c_matrix safe1.7303
        matrix<unbounded_array> safe3.14164
        prod (matrix, matrix)C array0.94457No significant abstraction penalty
        c_matrix fast1.17367
        matrix<unbounded_array> fast1.34320
        c_matrix safe1.56275
        matrix<unbounded_array> safe2.06208
        -

        We notice a two fold performance loss for small vectors and matrices: first the general abstraction penalty for using classes, and then a small loss when using the generic vector and matrix classes. The difference w.r.t. alias assumptions is also significant.

        -

        Next we comment the results for double vectors and matrices of -dimension 100 and 100 x 100, respectively.

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        OperationImplementationElapsed [s]MFLOP/sComment
        inner_prodC array0.64889No significant abstraction penalty
        c_vector0.66862
        vector<unbounded_array>0.66862
        vector + vectorC array0.64894No significant abstraction penalty
        c_vector fast0.66867
        vector<unbounded_array> fast0.66867
        c_vector safe1.14501
        vector<unbounded_array> safe1.23465
        outer_prodC array0.501144No significant abstraction penalty
        c_matrix, c_vector fast0.71806
        matrix<unbounded_array>, vector<unbounded_array> fast0.571004
        c_matrix, c_vector safe1.91300
        matrix<unbounded_array>, vector<unbounded_array> safe0.89643
        prod (matrix, vector)C array0.65876No significant abstraction penalty
        c_matrix, c_vector fast0.65876
        matrix<unbounded_array>, vector<unbounded_array> -fast0.66863
        c_matrix, c_vector safe0.66863
        matrix<unbounded_array>, vector<unbounded_array> -safe0.66863
        matrix + matrixC array0.96596No significant abstraction penalty
        c_matrix fast1.21473
        matrix<unbounded_array> fast1.00572
        c_matrix safe2.44235
        matrix<unbounded_array> safe1.30440
        prod (matrix, matrix)C array0.70813No significant abstraction penalty
        c_matrix fast0.73780
        matrix<unbounded_array> fast0.76749
        c_matrix safe0.75759
        matrix<unbounded_array> safe0.76749
        -

        For larger vectors and matrices the general abstraction penalty -for using classes seems to decrease, the small loss when using -generic vector and matrix classes seems to remain. The difference -w.r.t. alias assumptions remains visible, too.

        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/products.html b/doc/products.html deleted file mode 100644 index 563a4b8ce..000000000 --- a/doc/products.html +++ /dev/null @@ -1,318 +0,0 @@ -?xml version="1.0" encoding="UTF-8"?> - - - - Special Products - - - - - - - - - - -

        Special Products

        -
        - -

        Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template<class V, class E1, class E2> BOOST_UBLAS_INLINE V & axpy_prod (const matrix_expression< E1 > &e1, const vector_expression< E2 > &e2, V &v, bool init=true)
         computes v += A x or v = A x in an optimized fashion.

        template<class V, class E1, class E2> BOOST_UBLAS_INLINE V & axpy_prod (const vector_expression< E1 > &e1, const matrix_expression< E2 > &e2, V &v, bool init=true)
         computes v += AT x or v = AT x in an optimized fashion.

        template<class M, class E1, class E2> BOOST_UBLAS_INLINE M & axpy_prod (const matrix_expression< E1 > &e1, const matrix_expression< E2 > &e2, M &m, bool init=true)
         computes M += A X or M = A X in an optimized fashion.

        template<class M, class E1, class E2> BOOST_UBLAS_INLINE M & opb_prod (const matrix_expression< E1 > &e1, const matrix_expression< E2 > &e2, M &m, bool init=true)
         computes M += A X or M = A X in an optimized fashion.

        - -
        - - - - - - -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        BOOST_UBLAS_INLINE V& axpy_prod ( const matrix_expression< E1 > &  e1,
        const vector_expression< E2 > &  e2,
        V &  v,
        bool  init = true
        ) 
        -
        - - - - - -
        -   - - -

        -computes v += A x or v = A x in an optimized fashion. -

        -
        Parameters:
        - - - - - -
        e1 the matrix expression A
        e2 the vector expression x
        v the result vector v
        init a boolean parameter
        -
        -axpy_prod(A, x, v, init) implements the well known axpy-product. Setting init to true is equivalent to call v.clear() before axpy_prod. Currently init defaults to true, but this may change in the future.

        -Up to now there are some specialisation for compressed matrices that give a large speed up compared to prod.

        - - - - - - - -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        BOOST_UBLAS_INLINE V& axpy_prod ( const vector_expression< E1 > &  e1,
        const matrix_expression< E2 > &  e2,
        V &  v,
        bool  init = true
        ) 
        -
        - - - - - -
        -   - - -

        -computes v += AT x or v = AT x in an optimized fashion. -

        -
        Parameters:
        - - - - - -
        e1 the vector expression x
        e2 the matrix expression A
        v the result vector v
        init a boolean parameter
        -
        -axpy_prod(x, A, v, init) implements the well known axpy-product. Setting init to true is equivalent to call v.clear() before axpy_prod. Currently init defaults to true, but this may change in the future.

        -Up to now there are some specialisation for compressed matrices that give a large speed up compared to prod.

        - - - - - - -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        BOOST_UBLAS_INLINE M& axpy_prod ( const matrix_expression< E1 > &  e1,
        const matrix_expression< E2 > &  e2,
        M &  m,
        bool  init = true
        ) 
        -
        - - - - - -
        -   - - -

        -computes M += A X or M = A X in an optimized fashion. -

        -
        Parameters:
        - - - - - -
        e1 the matrix expression A
        e2 the matrix expression X
        m the result matrix M
        init a boolean parameter
        -
        -axpy_prod(A, X, M, init) implements the well known axpy-product. Setting init to true is equivalent to call M.clear() before axpy_prod. Currently init defaults to true, but this may change in the future.

        -Up to now there are no specialisations.

        - - - - - - - -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        BOOST_UBLAS_INLINE M& opb_prod ( const matrix_expression< E1 > &  e1,
        const matrix_expression< E2 > &  e2,
        M &  m,
        bool  init = true
        ) 
        -
        - - - - - -
        -   - - -

        -computes M += A X or M = A X in an optimized fashion. -

        -
        Parameters:
        - - - - - -
        e1 the matrix expression A
        e2 the matrix expression X
        m the result matrix M
        init a boolean parameter
        -
        -opb_prod(A, X, M, init) implements the well known axpy-product. Setting init to true is equivalent to call M.clear() before opb_prod. Currently init defaults to true, but this may change in the future.

        -This function may give a speedup if A has less columns than rows, because the product is computed as a sum of outer products.

        - - - -
        -

        Copyright (©) 2000-2004 Michael Stevens, Mathias Koch, -Joerg Walter, Gunter Winkler
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/range.html b/doc/range.html deleted file mode 100644 index 37213bee9..000000000 --- a/doc/range.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - -Range and slice - - -

        Range and Slice Storage

        -
        -

        Range<SizeType,DistanceType>

        -

        Description

        -

        The class range specifies a range of indicies. The range is a sequence of indices -from a start value to stop value. The indices increase by one and exlude the stop value. -range can therefore be used to specify ranges of elements from vectors and matrices.

        -

        Example

        -
        -#include <boost/numeric/ublas/storage.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    range r (0, 3);
        -    for (unsigned i = 0; i < r.size (); ++ i) {
        -        std::cout << r (i) << std::endl;
        -    }
        -}
        -
        -

        Definition

        -

        Defined in the header storage.hpp.

        -

        Model of

        -

        Reversible Container.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Reversible -Container.

        -

        Public base classes

        -

        None.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        range (size_type start, size_type stop)Constructs a range of indicies from start to stop (excluded) -.
        size_type start () constReturns the beginning of the range.
        size_type size () constReturns the size of the range.
        const_reference operator [] (size_type i) -constReturns the value start + i of the i --th element.
        range compose (const range &r) constReturns the composite range from start + r.start -() to start + r.start () + r.size ().
        bool operator == (const range &r) constTests two ranges for equality.
        bool operator != (const range &r) constTests two ranges for inequality.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the range.
        const_iterator end () constReturns a const_iterator pointing to the end of -the range.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed range.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed range.
        -

        Preconditions

        -
          -
        • start () <= stop ()
        • -
        - -

        Slice<SizeType,DistanceType>

        -

        Description

        -

        The class slice specifies a 'slice' of indicies. Slices are more general -then ranges, the stride allows the sequence of indicies to increase and decrease by the specified amount between element. -slice can therefore be used to specify slices of element from vectors and matrices.

        -

        Example

        -
        -#include <boost/numeric/ublas/storage.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    slice s (0, 1, 3);
        -    for (unsigned i = 0; i < s.size (); ++ i) {
        -        std::cout << s (i) << std::endl;
        -    }
        -}
        -
        -

        Definition

        -

        Defined in the header storage.hpp.

        -

        Model of

        -

        Reversible Container.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Reversible -Container.

        -

        Public base classes

        -

        None.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        slice (size_type start, size_type stride, size_type -size)Constructs a slice start,start+stride,start+2*stride... with -size elements.
        size_type start () constReturns the beginning of the slice.
        size_type stride () constReturns the stride of the slice.
        size_type size () constReturns the size of the slice.
        const_reference operator [] (size_type i) -constReturns the value start + i * stride of the -i-th element.
        slice compose (const range &r) constReturns the composite slice from start + stride * r.start -() to start + stride * (r.start () + r.size ()) -with stride stride.
        slice compose (const slice &s) constReturns the composite slice from start + stride * s.start -() to start + stride * s.stride () * (s.start () + -s.size ()) with stride stride * s.stride () -.
        bool operator == (const slice &s) constTests two slices for equality.
        bool operator != (const slice &s) constTests two slices for inequality.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the slice.
        const_iterator end () constReturns a const_iterator pointing to the end of -the slice.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed slice.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed slice.
        -

        Preconditions

        -
          -
        • None all strides are vaild. However when an index is returned or an iterator is dereferenced its -value must be representable as the size_type.
        • -
        -
        -

        - Copyright (©) 2000-2004 Michael Stevens, Mathias Koch, - Joerg Walter, Gunter Winkler
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/release_notes.html b/doc/release_notes.html deleted file mode 100644 index 806d794dc..000000000 --- a/doc/release_notes.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - -Boost Basic Linear Algebra - Release Notes - - -

        logoBoost Basic Linear Algebra - Release Notes

        - - -
        - -

        Release 1.70.0

        - -

        improvements

        - -
          -
        • Add support for GPU-accelerated operations via Boost.Compute
        • -
        • Add support for a new (arbitrary-rank) tensor type and associated operations.
        • -
        - -

        Release 1.52.0

        - -

        improvements

        - -
          -
        • [4024] improve performance of inplace_solve
        • -
        • [6511] Division by scalar should use enable_if<>
        • -
        • [7297] Make the free functions 'num_columns' and 'num_rows' support the uBLAS traits system and better work with expression types
        • -
        - -

        bug fixes

        - -
          -
        • [7296] fixes and improvements to test utility functions
        • -
        • [7363] fixed coordinate_matrix::sort() for gcc 4.7 and others
        • -
        - -

        Release 1.43.0

        - -

        bug fixes

        - -
          -
        • [3968] fixed coordinate_matrix sort problem on MSVC10 -
        • -
        • [3539] - changed computation of norm_inf for complex types to match - mathematical definition.
          - Note: This might cause a performance drop - because now std::abs(z) is called for each vector element. - The old implementation used std::max(std::abs(real(z)),std::abs(imag(z)). - Further norm_inf and norm_1 will now return - the same values for complex vector. -
        • -
        • [3501] Moved free functions in concepts.hpp into anonymous namespace. -
        • -
        - -

        Release 1.41.1

        - -

        new features

        - -
          -
        • Move semantics of vector/matrix container assignments have been -implemented. They can be enabled by setting -BOOST_UBLAS_MOVE_SEMANTICS. More details are on the preprocessor options page. -
        • -
        • Introduce new free functions. See [3449], -the new tests in libs/numeric/ublas/test and the inline documentation of the files in boost/numeric/ublas/operation/. -
        • -
        - -

        bug fixes

        - -
          -
        • [3293] Fix resizing problem in identity_matrix -
        • -
        • [3499] Add DefaultConstructible to concept checks -
        • -
        - -

        Release 1.40.0 and before

        -
          -
        • Release notes were not available in this form.
        • -
        - -
        -

        Copyright (©) 2000-2009 Joerg Walter, Mathias Koch, Gunter Winkler
        - Use, modification and distribution are 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 - ). -

        - - - - diff --git a/doc/storage_concept.html b/doc/storage_concept.html deleted file mode 100644 index 2f30529e8..000000000 --- a/doc/storage_concept.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - - -Storage concept - - -

        Storage concept

        -
        -

        Storage concept

        -

        Description

        -

        Storage is a variable-size container whose elements are arranged in a strict linear order. -

        Storage extends the STL Container concept with some STL Sequence-like functionality. The main difference with -the Sequence concept however is that the Storage concept does not require default-initialisation of its -elements. -

        Refinement of

        -Random Access Container -and -Default Constructible -

        Associated types

        -No additional types beyond those defined by -Random Access Container -

        Notation

        - - - - - -
        XA type that is model of Storage
        TThe value_type of X
        tAn object of type T
        nobject of type convertible to X::size_type
        -

        Definitions

        -

        Valid expressions

        -In addition to the expressions defined in -Random Access Container, -and -Default Constructible -the following expressions must be valid: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        NameExpressionType requirementsReturn type
        Size constructorX(n)T is DefaultConstructibleX
        Fill constructorX(n,t)X
        Range constructorX(i, j)i and j are Input Iterators whose value type is convertible to T X
        Resizea.resize(n, t)a is mutablevoid
        Resizea.resize(n)a is mutablevoid
        -

        Expression semantics

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        NameExpressionPreconditionSemanticsPostcondition -
        Default-constructorX() -Creates 0 elements. -size()==0
        Size-constructorX(n) -n>=0Creates n elements. Elements are constructed without an initializer. That is -if T is a (possibly cv-qualified) non-POD class type (or array thereof), the object is default -initialized. Otherwise, the object created has indeterminate value. See the sentance -"If new initializer is omitted" in section 5.3.4 paragraph 15 of the ISO C++ standard. -size()==n
        Fill-constructorX(n,t) -n>=0Creates n initialised element with copies of tsize()==n
        Range constructorX(i, j)[i,j) is a valid range.copies the range [i,j) to the storagesize() is equal to the distance from i to j. Each element is a copy of the corresponding element in the range [i,j).
        Resizea.resize(n, t)n <= a.max_size()Modified the container so that it has exactly n elements.
        -The container may be reallocated if its size changes. -Existing element values are preserved, additional elements are copies of t.
        a.size() == n
        Resizea.resize(n)n <= a.max_size()Modified the container so that it has exactly n elements.
        -The container may be reallocated if its size changes. Element values are uninitialised. That is, -each element value may be a previously assigned value or default construced value for T.
        a.size() == n
        -

        Complexity guarantees

        -

        Invariants

        -

        Models

        - -

        Notes

        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - - diff --git a/doc/storage_sparse.html b/doc/storage_sparse.html deleted file mode 100644 index b4899d9b2..000000000 --- a/doc/storage_sparse.html +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - -Sparse Storage - - -

        Sparse Storage

        -
        -

        Default Standard Map

        -

        Description

        -

        The templated class map_std<I, T, ALLOC> provides a -wrapper for the standard library associative container -std::map. The wrapper has one simple purpose. It -allows the definition of a default template parameter (for the -adapted array) when declaring the sparse container types.

        -

        Example

        -
        -#include <boost/numeric/ublas/storage_sparse.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    map_std<int, double> a (3);
        -    for (unsigned i = 0; i < a.size (); ++ i) {
        -        a [i] = i;
        -        std::cout << a [i] << std::endl;
        -    }
        -}
        -
        -

        Definition

        -

        Defined in the header storage_sparse.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        IThe type of index stored in the array.
        TThe type of object stored in the array.
        ALLOCAn STL Allocatorstd::allocator
        -

        Model of

        -

        Reversible Container.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Reversible -Container.

        -

        Public base classes

        -

        std::map

        -

        Map Array

        -

        Description

        -

        The templated class map_array<I, T, ALLOC> implements a std::map like associative container as a sorted array. It therefore some of the Associative Container interface without having the same semantics as an std::map. -

        At any time the map_array has a capacity up to which new element can be inserted. -If insert would cause the size of the map_array to exceeds its capactity then it is reallocated. Iterators and reference are invalidated. -The capacity can be directly control using the reserve member function. -

        -

        Example

        -
        -#include <boost/numeric/ublas/storage_sparse.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    map_array<int, double> a (3);
        -    for (unsigned i = 0; i < a.size (); ++ i) {
        -        a [i] = i;
        -        std::cout << a [i] << std::endl;
        -    }
        -}
        -
        -

        Definition

        -

        Defined in the header storage_sparse.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        IThe type of index stored in the array.
        TThe type of object stored in the array.
        ALLOCAn STL Allocatorstd::allocator
        -

        Model of

        -

        Reversible Container.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Reversible -Container.

        -

        Public base classes

        -

        None.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        map_array (ALLOC &a = ALLOC())Allocates a map_array that holds at most zero -elements.
        map_array (const map_array &c)The copy constructor.
        ~map_array ()Deallocates the map_array itself.
        void reserve (size_type capacity) -Changes themap_array capacity. It can hold at mostcapacity elements without reallocation. The capacity can be reduced such that capacity >= size(). The content of themap_array is preserved.
        size_type size () constReturns the size of the map_array.
        size_type size () constReturns the capacity of the map_array.
        data_reference operator [] (index_type i)Returns a reference of the element that is associated with a -particular index. If the map_array does not already -contain such an element, operator[] inserts the -default T ().
        map_array &operator = (const map_array -&a)The assignment operator.
        map_array &assign_temporary (map_array -&a)Assigns a temporary. May change the array a.
        void swap (map_array &a)Swaps the contents of the arrays.
        std::pair insert (const value_type -&p)Inserts p into the array. The second part of the return value is true -if p was inserted and false if was not inserted because it was aleady -present.
        iterator insert (iterator it, const value_type -&p)Inserts p into the array, using it as -a hint to where it will be inserted.
        void erase (iterator it)Erases the value at it.
        void clear ()Clears the array.
        const_iterator find (index_type i) constFinds an element whose index is i.
        iterator find (index_type i)Finds an element whose index is i.
        const_iterator lower_bound (index_type i) -constFinds the first element whose index is not less than -i .
        iterator lower_bound (index_type i)Finds the first element whose index is not less than -i .
        const_iterator upper_bound (index_type i) -constFinds the first element whose index is greater than -i .
        iterator upper_bound (index_type i)Finds the first element whose index is greater than -i .
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the map_array.
        const_iterator end () constReturns a const_iterator pointing to the end of -the map_array.
        iterator begin ()Returns a iterator pointing to the beginning of -the map_array.
        iterator end ()Returns a iterator pointing to the end of the -map_array.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed map_array.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed map_array.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed map_array.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed map_array.
        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/symmetric.html b/doc/symmetric.html deleted file mode 100644 index c3693bde4..000000000 --- a/doc/symmetric.html +++ /dev/null @@ -1,588 +0,0 @@ - - - - - - - - - -Symmetric Matrix - - -

        Symmetric Matrix

        -
        -

        Symmetric Matrix

        -

        Description

        -

        The templated class symmetric_matrix<T, F1, F2, -A> is the base container adaptor for symmetric matrices. -For a (n x n )-dimensional symmetric matrix and 0 -<= i < n, 0 <= j < n holds -si, j = sj, -i. The storage of symmetric matrices is packed.

        -

        Example

        -
        -#include <boost/numeric/ublas/symmetric.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    symmetric_matrix<double, lower> ml (3, 3);
        -    for (unsigned i = 0; i < ml.size1 (); ++ i)
        -        for (unsigned j = 0; j <= i; ++ j)
        -            ml (i, j) = 3 * i + j;
        -    std::cout << ml << std::endl;
        -    symmetric_matrix<double, upper> mu (3, 3);
        -    for (unsigned i = 0; i < mu.size1 (); ++ i)
        -        for (unsigned j = i; j < mu.size2 (); ++ j)
        -            mu (i, j) = 3 * i + j;
        -    std::cout << mu << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header symmetric.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the matrix.
        F1Functor describing the type of the symmetric matrix. [1]lower
        F2Functor describing the storage organization. [2]row_major
        AThe type of the adapted array. [3]unbounded_array<T>
        -

        Model of

        -

        Matrix .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix .

        -

        Public base classes

        -

        matrix_container<symmetric_matrix<T, F1, F2, A> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        symmetric_matrix (size_type size)Allocates an uninitialized symmetric_matrix that -holds size rows of size elements.
        symmetric_matrix (const symmetric_matrix -&m)The copy constructor.
        template<class AE>
        -symmetric_matrix (const matrix_expression<AE> -&ae)
        The extended copy constructor.
        void resize (size_type size, bool preserve = -true)Reallocates a symmetric_matrix to hold -size rows of size elements. The existing -elements of the symmetric_matrix are preseved when -specified.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns a const reference of the j --th element in the i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        symmetric_matrix &operator = (const symmetric_matrix -&m)The assignment operator.
        symmetric_matrix &assign_temporary (symmetric_matrix -&m)Assigns a temporary. May change the symmetric matrix -m .
        template<class AE>
        -symmetric_matrix &operator = (const matrix_expression<AE> -&ae)
        The extended assignment operator.
        template<class AE>
        -symmetric_matrix &assign (const matrix_expression<AE> -&ae)
        Assigns a matrix expression to the symmetric matrix. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -symmetric_matrix &operator += (const -matrix_expression<AE> &ae)
        A computed assignment operator. Adds the matrix expression to -the symmetric matrix.
        template<class AE>
        -symmetric_matrix &plus_assign (const -matrix_expression<AE> &ae)
        Adds a matrix expression to the symmetric matrix. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -symmetric_matrix &operator -= (const -matrix_expression<AE> &ae)
        A computed assignment operator. Subtracts the matrix expression -from the symmetric matrix.
        template<class AE>
        -symmetric_matrix &minus_assign (const -matrix_expression<AE> &ae)
        Subtracts a matrix expression from the symmetric matrix. Left -and right hand side of the assignment should be independent.
        template<class AT>
        -symmetric_matrix &operator *= (const AT &at)
        A computed assignment operator. Multiplies the symmetric matrix -with a scalar.
        template<class AT>
        -symmetric_matrix &operator /= (const AT &at)
        A computed assignment operator. Divides the symmetric matrix -through a scalar.
        void swap (symmetric_matrix &m)Swaps the contents of the symmetric matrices.
        void insert (size_type i, size_type j, const_reference -t)Inserts the value t at the j-th -element of the i-th row.
        void erase (size_type i, size_type j)Erases the value at the j-th elemenst of the -i-th row.
        void clear ()Clears the matrix.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the symmetric_matrix.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the symmetric_matrix.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the symmetric_matrix.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -symmetric_matrix.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the symmetric_matrix.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the symmetric_matrix.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the symmetric_matrix.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -symmetric_matrix.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed symmetric_matrix.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed symmetric_matrix.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed symmetric_matrix.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed symmetric_matrix.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed symmetric_matrix.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed symmetric_matrix.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed symmetric_matrix.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed symmetric_matrix.
        -

        Notes

        -

        [1] -Supported parameters for the type of the symmetric matrix are -lower and upper.

        -

        [2] -Supported parameters for the storage organization are -row_major and column_major.

        -

        [3] -Supported parameters for the adapted array are -unbounded_array<T> , -bounded_array<T> and -std::vector<T> .

        -

        Symmetric Adaptor

        -

        Description

        -

        The templated class symmetric_adaptor<M, F> -is a symmetric matrix adaptor for other matrices.

        -

        Example

        -
        -#include <boost/numeric/ublas/symmetric.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    symmetric_adaptor<matrix<double>, lower> sal (m);
        -    for (unsigned i = 0; i < sal.size1 (); ++ i)
        -        for (unsigned j = 0; j <= i; ++ j)
        -            sal (i, j) = 3 * i + j;
        -    std::cout << sal << std::endl;
        -    symmetric_adaptor<matrix<double>, upper> sau (m);
        -    for (unsigned i = 0; i < sau.size1 (); ++ i)
        -        for (unsigned j = i; j < sau.size2 (); ++ j)
        -            sau (i, j) = 3 * i + j;
        -    std::cout << sau << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header symmetric.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        MThe type of the adapted matrix.
        FFunctor describing the type of the symmetric adaptor. [1]lower
        -

        Model of

        -

        Matrix Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix Expression .

        -

        Public base classes

        -

        matrix_expression<symmetric_adaptor<M, F> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        symmetric_adaptor ()Constructs a symmetric_adaptor that holds zero -rows of zero elements.
        symmetric_adaptor (matrix_type &data)Constructs a symmetric_adaptor of a matrix.
        symmetric_adaptor (const symmetric_adaptor -&m)The copy constructor.
        template<class AE>
        -symmetric_adaptor (const matrix_expression<AE> -&ae)
        The extended copy constructor.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns a const reference of the j --th element in the i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        symmetric_adaptor &operator = (const -symmetric_adaptor &m)The assignment operator.
        symmetric_adaptor &assign_temporary -(symmetric_adaptor &m)Assigns a temporary. May change the symmetric adaptor -m.
        template<class AE>
        -symmetric_adaptor &operator = (const -matrix_expression<AE> &ae)
        The extended assignment operator.
        template<class AE>
        -symmetric_adaptor &assign (const matrix_expression<AE> -&ae)
        Assigns a matrix expression to the symmetric adaptor. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -symmetric_adaptor &operator += (const -matrix_expression<AE> &ae)
        A computed assignment operator. Adds the matrix expression to -the symmetric adaptor.
        template<class AE>
        -symmetric_adaptor &plus_assign (const -matrix_expression<AE> &ae)
        Adds a matrix expression to the symmetric adaptor. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -symmetric_adaptor &operator -= (const -matrix_expression<AE> &ae)
        A computed assignment operator. Subtracts the matrix expression -from the symmetric adaptor.
        template<class AE>
        -symmetric_adaptor &minus_assign (const -matrix_expression<AE> &ae)
        Subtracts a matrix expression from the symmetric adaptor. Left -and right hand side of the assignment should be independent.
        template<class AT>
        -symmetric_adaptor &operator *= (const AT &at)
        A computed assignment operator. Multiplies the symmetric -adaptor with a scalar.
        template<class AT>
        -symmetric_adaptor &operator /= (const AT &at)
        A computed assignment operator. Divides the symmetric adaptor -through a scalar.
        void swap (symmetric_adaptor &m)Swaps the contents of the symmetric adaptors.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the symmetric_adaptor.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the symmetric_adaptor.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the symmetric_adaptor.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -symmetric_adaptor.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the symmetric_adaptor.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the symmetric_adaptor.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the symmetric_adaptor.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -symmetric_adaptor.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed symmetric_adaptor.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed symmetric_adaptor.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed symmetric_adaptor.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed symmetric_adaptor.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed symmetric_adaptor.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed symmetric_adaptor.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed symmetric_adaptor.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed symmetric_adaptor.
        -

        Notes

        -

        [1] -Supported parameters for the type of the symmetric adaptor are -lower and upper.

        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/tensor.html b/doc/tensor.html deleted file mode 100644 index 8b08a2fb8..000000000 --- a/doc/tensor.html +++ /dev/null @@ -1,652 +0,0 @@ - - - - - - - - - - - - - -Tensor - - -

        Tensor

        -
        -

        Tensor

        -

        Description

        -

        The templated class tensor<value_t,format_t,storage_t> is the base container adaptor for dense tensors. -Every element $t_{i_1,i_2,\dots,i_p}$ of a $p$-order $(n_1 \times n_2 \times \cdots \times n_p)$-dimensional tensor $T$ is mapped to $j$-th element of a one-dimensional container where $j = \sum_{r=1}^p i_r \cdot w_r$ with $1 \leq i_r \leq n_r $ for $1 \leq r \leq p$. -For the first-order orientation $w_1 = 1$ and $w_k = n_{k-1} \cdot w_{k-1}$ for $k > 1$. For last-order orientation $w_p = 1$ and $ w_k = n_{k+1} \cdot w_{k+1}$ for $k < p$. -

        -

        Example

        -
        -#include <boost/numeric/ublas/tensor.hpp>
        -
        -int main () {
        -  using namespace boost::numeric::ublas;
        -  tensor<double> t{4,2,3};
        -  for (auto k = 0ul; k < t.size (2); ++ k)
        -    for (auto j = 0ul; j < t.size (1); ++ j)
        -      for (auto i = 0ul; i < t.size (0); ++ i)
        -        t.at(i,j,k) = 3*i + 2*j + 5*k;
        -        
        -  std::cout << t << std::endl;
        -}
        -
        - -

        Definition

        -

        Defined in the header file tensor/tensor.hpp.

        - -

        Model of

        -

        Tensor

        - -

        Type requirements

        -

        None, except for those imposed by the requirements of Tensor .

        - -

        Public base classes

        -

        tensor_container<tensor<value_t,format_t,storage_t> >

        - -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        value_tThe type of object stored in the tensor.
        format_tStorage organization. [1]first_order
        storage_tThe type of the Storage array. [2]std::vector<value_t>
        - -

        Member types

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Member typeDescription
        value_typeType value_t of the tensor elements.
        layout_typeFormat of the tensor which is either first_order or last_order.
        array_typeSequence container type that stores all tensor elements and is accessible with a single index.
        strides_typeType of the strides vector basic_strides<std::size_t,layout_type> that stores all tensor elements and is accessible with a single index.
        extents_typeType of the dimension extents vector shape that stores all tensor elements and is accessible with a single index.
        size_typeUnsigned integer which is usually std::size_t.
        difference_typeUnsigned integer which is usually std::ptrdiff_t.
        referenceReference type storage_type::reference which is in most cases value_type&.
        const_referenceConstant reference type storage_type::const_reference which is in most cases const value_type&.
        pointerPointer type storage_type::pointer which is in most cases value_type*.
        const_pointerConstant reference type storage_type::const_reference which is in most cases const value_type*.
        iteratorRandomAccessIterator storage_type::iterator.
        const_iteratorConstant RandomAccessIterator storage_type::const_iterator.
        reverse_iteratorReverse RandomAccessIterator storage_type::reverse_iterator.
        const_reverse_iteratorReverse RandomAccessIterator storage_type::const_reverse_iterator.
        matrix_typeType of the matrix matrix<value_type,layout_type,array_type> with which the tensor type interacts.
        vector_typeType of the vector matrix<value_type,layout_type,array_type> with which the tensor type interacts.
        - -

        Alias templates

        - - - - - - - - - - - - - - - - - - -
        Alias templateDescription
        template<class derived_type>
        using tensor_expression_type = detail::tensor_expression<self_type,derived_type>
        Type of tensor_expression where self_type is the tensor type.
        template<class derived_type>
        using matrix_expression_type = matrix_expression<derived_type>
        Type of matrix_expression.
        template<class derived_type>
        using vector_expression_type = vector_expression<derived_type>
        Type of vector_expression.
        - - -

        Member Functions

        - -

        Construction

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Member functionDescription
        tensor ()Constructs an uninitialized tensor that holds zero elements.
        tensor (std::initializer_list<size_type> list) Constructs an uninitialized tensor where list specifies the dimension extents.
        tensor (extents_type const& s) Constructs an uninitialized tensor where -s specifies the dimension extents.
        tensor (extents_type const& e, array_type const& a) Constructs an uninitialized tensor where -e specifies the dimension extents and a the data elements of the tensor.
        tensor (tensor<value_type,other_layout&rt; const& other)Constructs tensor by copying elements from other where the layout is different from this layout type.
        tensor (tensor const& other)Constructs tensor by copying elements from other.
        tensor (tensor && other)Constructs tensor by moving elements from other.
        tensor (matrix_type const& other)Constructs tensor by copying elements from other matrix. The tensor will have the order 2.
        tensor (matrix_type && other)Constructs tensor by moving elements from other matrix. The tensor will have the order 2.
        tensor (vector_type const& other)Constructs tensor by copying elements from other vector. The tensor will have the order 1.
        tensor (vector_type && other)Constructs tensor by moving elements from other vector. The tensor will have the order 1.
        tensor (tensor_expression_type<derived_type> const& expr)Constructs tensor by evaluating the tensor expression expr and copying all elements of the result.
        tensor (matrix_expression_type<derived_type> const& expr)Constructs tensor by evaluating the matrix expression expr and copying all elements of the result.
        tensor (vector_expression_type<derived_type> const& expr)Constructs tensor by evaluating the vector expression expr and copying all elements of the result.
        - - -

        Assignment

        - - - - - - - - - - - - - - - - - - - - - - - -
        Member functionDescription
        tensor& operator=(tensor_expression_type<derived_type> const& expr)Evaluates the tensor expression expr and copyies all elements of the result.
        tensor& operator=(tensor other)Copies or moves elements of other.
        tensor& operator=(const_reference v)Initialiates all elements of a tensor with v.
        - - -

        Capacity

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Member functionDescription
        bool empty() constReturns true if a tensor has zero elements.
        size_type size() constReturns the number of elements of the tensor.
        size_type rank() constReturns the number of dimensions of the tensor.
        size_type order() constReturns the number of dimensions of the tensor.
        strides_type const& strides() constReturns a constant reference to the strides of the tensor.
        extents_type const& extents() constReturns a constant reference to the extents of the tensor.
        - - - -

        Element access

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Member functionDescription
        pointer data()Returns a pointer the first element of the tensor.
        const_pointer data() constReturns a const_pointer the first element of the tensor.
        reference operator[](size_type j)Returns a reference to the j-th element of the storage array of the tensor. Corresponds to the function call tensor::data()+j
        const_reference operator[](size_type j) constReturns a const_reference to the j-th element of the storage array of the tensor. Corresponds to the function call tensor::data()+j.
        template<class ... size_types>
        reference at(size_type i, size_types ... is)
        Returns a reference to the (i,is...)-th element of the tensor where (i,is...) denotes a multi-index with tensor::order() elements. If sizeof...(is)==0, tensor::operator[i] is called.
        template<class ... size_types>
        const_reference at(size_type i, size_types ... is)
        Returns a const_reference to the (i,is...)-th element of the tensor where (i,is...) denotes a multi-index with tensor::order() elements. If sizeof...(is)==0, tensor::operator[i] is called.
        - - - - -

        Proxy Generation

        - - - - - - - - - - - - - - -
        Member functionDescription
        template<std::size_t I, class ... index_types>
        tensor_index operator()(indices::Index<I> p, index_types ... ps)
        Returns a tensor index instance with index objects (p,ps...) for a tensor contraction where sizeof...(ps)+1 must be equal to tensor::order().
        - - -

        Iterators

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Member functionDescription
        const_iterator begin() constReturns a const_iterator pointing to the first element of the tensor.
        const_iterator cbegin() constReturns a const_iterator pointing to the first element of the tensor.
        iterator begin()Returns an iterator pointing to the first element of the tensor.
        const_iterator end() constReturns a const_iterator pointing to the position after the last element of the tensor.
        const_iterator cend() constReturns a const_iterator pointing to the position after the last element of the tensor.
        iterator begin()Returns an iterator pointing to the position after the last element of the tensor.
        - - -

        Modifiers

        - - - - - - - - - - - - - - -
        Member functionDescription
        void reshape(extents_type const& e, value_type v = value_type{})Reshapes the tensor according to the extents e. If e.product() is greater than tensor::size(), the tensor is resized with v.
        - - -

        Notes

        -

        [1] Supported parameters -for the storage organization are first_order and -last_order.

        -

        [2] Common parameters -for the storage array are std::array<N,T> and -std::vector<T>.

        - -
        -

        Copyright (©) 2018 Cem Bassoy
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/tensor/extents.html b/doc/tensor/extents.html deleted file mode 100644 index 5ad9a34b5..000000000 --- a/doc/tensor/extents.html +++ /dev/null @@ -1,250 +0,0 @@ - - - - - - - - - - - -Shape - - -

        Extents

        -
        -

        basic_extents<size_type>

        -

        Description

        -

        The template class basic_extents specifies dimension extents of a tensor instance.

        - -

        Example

        -
        -#include <boost/numeric/ublas/tensor/extents.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    shape s{4,3,2};
        -    for (auto i = 0u; i < s.size(); ++i) {
        -        std::cout << s.at(i) << std::endl;
        -    }
        -}
        -
        -

        Definition

        -

        Defined in the header tensor/extents.hpp.

        - -

        Public base classes

        -

        None.

        - -

        Specialization

        -

        using shape = basic_extents<std::size_t>

        - - -

        Template parameters

        - - - - - - - - - - - -
        ParameterDescription
        size_typeUnsigned integer type.
        - -

        Member types

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Member typeDescription
        value_typeType size_type of the extents.
        size_typeUnsigned integer such as std::size_t.
        referenceReference type which is value_type&.
        const_referenceConstant reference type which is const value_type&.
        pointerPointer type which is value_type*.
        const_pointerConstant reference type which is const value_type*.
        - - - - -

        Member Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Member FunctionDescription
        basic_extents ()Constructs an empty instance of basic_extents.
        basic_extents (std::vector<value_type> const& vector)Constructs an instance copying the content of vector.
        basic_extents (std::vector<value_type> && vector)Constructs an instance moving the content of vector.
        basic_extents (std::initializer_list<value_type> list)Constructs an instance from list.
        basic_extents (const_iterator first, const_iterator last)Constructs an instance from the range specified by [first,last).
        basic_extents (basic_extents const& other)Constructs an instance from other copying its elements.
        basic_extents (basic_extents && other)Constructs an instance from other by moving its elements.
        basic_extents& operator= (basic_extents other)Assigns the elements of other to this instance.
        bool is_scalar() constReturns true if the elements are (1,1,[1,...,1]).
        bool is_vector() constReturns true if the elements are (n,1,[1,...,1]) or (1,n,[1,...,1]) where n>1.
        bool is_matrix() constReturns true if the elements are (m,n,[1,...,1]) where m>1 and n>1.
        bool is_tensor() constReturns true if it is not a scalar, vector or matrix.
        const_pointer data() constReturns a const_pointer to the first element.
        pointer data()Returns a pointer to the first element.
        reference operator[](size_type i)Returns a reference to the i-th element.
        const_reference operator[](size_type i) constReturns a const_reference to the i-th element.
        reference at(size_type i)Returns a reference to the i-th element.
        const_reference at(size_type i) constReturns a const_reference to the i-th element.
        bool empty()Returns true if the container has no elements.
        size_type size() constReturns the number of elements.
        bool valid() constReturns true if size()>1 and all elements are greater than one.
        size_type product() constReturns the multiplication of all entries.
        basic_extents squeeze() constReturns a new instance where entries equal to one are eliminated.
        bool operator==(basic_extents const& b) constReturns true if all elements are equal.
        bool operator!=(basic_extents const& b) constReturns true if some elements are not equal.
        const_iterator begin() constReturns an const_iterator pointing to the first element.
        const_iterator end() constReturns a const_iterator pointing to an element passed the last element.
        std::vector<size_type> base() constReturns a const reference to the private member sequence container holding all elements.
        - - - - -
        -

        -Copyright (©) 2018 Cem Bassoy
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/tensor/strides.html b/doc/tensor/strides.html deleted file mode 100644 index 9af6d839d..000000000 --- a/doc/tensor/strides.html +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - -Strides - - -

        Strides

        -
        -

        basic_strides<size_type, format_type>

        -

        Description

        -

        The template class basic_strides contains weights for a given storage format in order to map multi-indices to scalar memory indices for tensor instances.

        - -

        Example

        -
        -#include <boost/numeric/ublas/tensor/strides.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    auto wf = strides<first_order>(shape{4,3,2});
        -    for (auto i = 0u; i < wf.size(); ++i)
        -        std::cout << wf.at(i) << std::endl;    
        -        // 1,4,12
        -        
        -    auto wl = strides<first_order>(shape{4,3,2});
        -    for (auto i = 0u; i < wl.size(); ++i)
        -        std::cout << wl.at(i) << std::endl;    
        -        // 6,2,1        
        -}
        -
        -

        Definition

        -

        Defined in the header tensor/strides.hpp.

        - -

        Public base classes

        -

        None.

        - -

        Specialization

        -

        template<class format_t>
        using strides = basic_strides<std::size_t,format_t>

        - - -

        Template parameters

        - - - - - - - - - - - -
        ParameterDescription
        size_typeUnsigned integer type.
        - -

        Member types

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Member typeDescription
        value_typeType size_type of the strides.
        size_typeUnsigned integer such as std::size_t.
        referenceReference type which is value_type&.
        const_referenceConstant reference type which is const value_type&.
        pointerPointer type which is value_type*.
        const_pointerConstant pointer type which is const value_type*.
        layout_typeLayout type which can be either boost::numeric::ublas::first_order or boost::numeric::ublas::last_order.
        - - - - -

        Member Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Member FunctionDescription
        basic_strides ()Constructs an empty instance of basic_strides.
        basic_strides (basic_extents<value_type> const& be)Constructs an instance based on the tensor extents specified by be.
        basic_strides (std::vector<value_type> const& v)Constructs an instance copying the content of v.
        basic_strides (std::vector<value_type> && v)Constructs an instance moving the content of v.
        basic_strides (basic_strides const& other)Constructs an instance from other copying its elements.
        basic_strides (basic_strides && other)Constructs an instance from other by moving its elements.
        basic_strides& operator= (basic_strides other)Assigns the elements of other to this instance.
        const_pointer data() constReturns a const_pointer to the first element.
        const_reference operator[](size_type i) constReturns a const_reference to the i-th element.
        const_reference at(size_type i) constReturns a const_reference to the i-th element.
        bool empty()Returns true if the container has no elements.
        size_type size() constReturns the number of elements.
        void clear()Erases all elements.
        bool operator==(basic_strides const& b) constReturns true if all elements are equal.
        bool operator!=(basic_strides const& b) constReturns true if some elements are not equal.
        const_iterator begin() constReturns an const_iterator pointing to the first element.
        const_iterator end() constReturns a const_iterator pointing to an element passed the last element.
        std::vector<size_type> base() constReturns the private member sequence container holding all elements.
        - - - -

        Non-Member Functions

        - - - - - - - - - - - - - - - -
        FunctionDescription
        access(std::vector<size_type> const& i, strides<layout_type> w)Returns relative memory location depending on the multi-index vector i and strides w.
        access(size_type sum, strides<layout_type> w, size_type i, size_types ... is)Returns relative memory location depending on the indices i, is ... and stride vector w (recursive function).
        - - -
        -

        -Copyright (©) 2018 Cem Bassoy
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/tensor/tensor_expression.html b/doc/tensor/tensor_expression.html deleted file mode 100644 index c9e479f8c..000000000 --- a/doc/tensor/tensor_expression.html +++ /dev/null @@ -1,272 +0,0 @@ - - - - - - - - - -Tensor Expressions - - -

        Tensor Expressions

        -
        - - - - -

        Tensor Expression

        -

        Description

        -

        The templated class tensor_expression<T,E> -is required to be a public base of all classes. There is no Tensor Expression concept defined.

        -

        Definition

        -

        Defined in the header tensor/expression.hpp.

        -

        Model of

        -

        None. Not a Tensor Expression! -

        - -

        Type requirements

        -

        None.

        -

        Public base classes

        -

        ublas_expression<E>.

        - -

        Template parameters

        - - - - - - - - - - - - - - - -
        ParameterDescription
        TThe type of the tensor.
        EThe type of the tensor expression.
        - -

        Member types

        - - - - - - - - - - - - - - - - - - - -
        Member typeDescription
        expression_typeType of the derived expression which is E.
        type_categoryTag for categorization which is tensor_tag.
        tensor_typeReference type which is T.
        - -

        Public Member Functions

        - - - - - - - - - - - -
        MemberDescription
        const expression_type &operator()() constReturns a const reference to the derived expression.
        - - -
        -
        - -

        Entrywise Tensor Operations

        - - -

        Binary Tensor Expression

        - -

        Description

        -

        The templated class binary_tensor_expression<T,EL,ER,OP> contains a constant reference to a left and right expression that can be evaluated by using the access operator.

        -

        Definition

        -

        Defined in the header tensor/expression.hpp.

        -

        Model of

        -

        Tensor Expression

        - - -

        Type requirements

        -

        None.

        - -

        Public base classes

        -

        tensor_expression<T,binary_tensor_expression<T,EL,ER,OP>>

        - -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescription
        TType of the tensor.
        ELType of the left binary tensor expression.
        ERType of the right binary tensor expression.
        OPType of the binary operation.
        - -

        Member types

        - - - - - - - - - - - - - - - - - - - - - - - -
        Member typeDescription
        expression_type_leftType of the left expression which is EL.
        expression_type_rightType of the right expression which is ER.
        tensor_typeReference type which is T.
        binary_operationType of the binary operation which is OP.
        - -

        Public Member Functions

        - - - - - - - - - - - -
        MemberDescription
        decltype(auto) operator()(std::size_t i) const Returns a const reference to the i-th element of the expression.
        -
        - - - -

        Unary Tensor Expression

        - - -

        Description

        -

        The templated class unary_tensor_expression<T,E,OP> contains a constant reference to an expression that can be evaluated by using the access operator.

        -

        Definition

        -

        Defined in the header tensor/expression.hpp.

        -

        Model of

        -

        Tensor Expression

        - -

        Type requirements

        -

        None.

        - -

        Public base classes

        -

        tensor_expression<T,unary_tensor_expression<T,E,OP>>

        - -

        Template parameters

        - - - - - - - - - - - - - - - - - - - -
        ParameterDescription
        TType of the tensor.
        EType of the unary tensor expression.
        OPType of the unary operation.
        - -

        Member types

        - - - - - - - - - - - - - - - - - - - -
        Member typeDescription
        expression_typeType of the expression which is E.
        tensor_typeReference type which is T.
        unary_operationType of the unary operation which is OP.
        - -

        Public Member Functions

        - - - - - - - - - - - -
        MemberDescription
        decltype(auto) operator()(std::size_t i) const Returns a const reference to the i-th element of the expression.
        - -
        -

        Copyright (©) 2018 Cem Bassoy
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/tensor/tensor_index.html b/doc/tensor/tensor_index.html deleted file mode 100644 index 1e4ec4cd7..000000000 --- a/doc/tensor/tensor_index.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - - - - - - - - -Shape - - -

        Tensor Index

        -
        -

        tensor_index<value_t, storage_t, array_t, N>

        -

        Description

        -

        The template class tensor_index decorates the tensor template class with indices for tensor contraction.

        - -

        Example

        -
        -#include <boost/numeric/ublas/tensor/einstein.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    shape s{4,3,2};
        -    for (auto i = 0u; i < s.size(); ++i) {
        -        std::cout << s.at(i) << std::endl;
        -    }
        -}
        -
        -

        Definition

        -

        Defined in the header tensor/tensor_einstein.hpp.

        - -

        Public base classes

        -

        None.

        - - - -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescription
        value_tThe type of object stored in the tensor.
        format_tStorage organization of the tensor.
        storage_tThe type of the storage array of the tensor.
        NNumber of indices provided.
        - - - - - -
        -

        -Copyright (©) 2018 Cem Bassoy
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/triangular.html b/doc/triangular.html deleted file mode 100644 index 865e1912b..000000000 --- a/doc/triangular.html +++ /dev/null @@ -1,602 +0,0 @@ - - - - - - - - - -Triangular Matrix - - -

        Triangular Matrix

        -
        -

        Triangular Matrix

        -

        Description

        -

        The templated class triangular_matrix<T, F1, F2, -A> is the base container adaptor for triangular matrices. -For a (n x n )-dimensional lower triangular matrix and -0 <= i < n,0 <= j < n holds -ti, j = 0 , if i > -j. If furthermore holds ti, i= 1 -the matrix is called unit lower triangular. For a (n x n -)-dimensional lower triangular matrix and 0 <= i < -n,0 <= j < n holds ti, -j = 0 , if i < j. If furthermore -holds ti, i= 1 the matrix is called -unit lower triangular. The storage of triangular matrices is -packed.

        -

        Example

        -
        -#include <boost/numeric/ublas/triangular.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    triangular_matrix<double, lower> ml (3, 3);
        -    for (unsigned i = 0; i < ml.size1 (); ++ i)
        -        for (unsigned j = 0; j <= i; ++ j)
        -            ml (i, j) = 3 * i + j;
        -    std::cout << ml << std::endl;
        -    triangular_matrix<double, upper> mu (3, 3);
        -    for (unsigned i = 0; i < mu.size1 (); ++ i)
        -        for (unsigned j = i; j < mu.size2 (); ++ j)
        -            mu (i, j) = 3 * i + j;
        -    std::cout << mu << std::endl;
        -}
        -
        -

        Please read the full triangular example for more details.

        - -

        Definition

        -

        Defined in the header triangular.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the matrix.
        F1Functor describing the type of the triangular matrix. [1]lower
        F2Functor describing the storage organization. [2]row_major
        AThe type of the adapted array. [3]unbounded_array<T>
        -

        Model of

        -

        Matrix .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix .

        -

        Public base classes

        -

        matrix_container<triangular_matrix<T, F1, F2, A> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        triangular_matrix ()Allocates an uninitialized triangular_matrix that -holds zero rows of zero elements.
        triangular_matrix (size_type size1, size_type -size2)Allocates an uninitialized triangular_matrix that -holds size1 rows of size2 elements.
        triangular_matrix (const triangular_matrix -&m)The copy constructor.
        template<class AE>
        -triangular_matrix (const matrix_expression<AE> -&ae)
        The extended copy constructor.
        void resize (size_type size1, size_type size2, bool -preserve = true)Reallocates a triangular_matrix to hold -size1 rows of size2 elements. The -existing elements of the triangular_matrix are -preseved when specified.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns a const reference of the j --th element in the i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        triangular_matrix &operator = (const -triangular_matrix &m)The assignment operator.
        triangular_matrix &assign_temporary -(triangular_matrix &m)Assigns a temporary. May change the triangular matrix -m.
        template<class AE>
        -triangular_matrix &operator = (const -matrix_expression<AE> &ae)
        The extended assignment operator.
        template<class AE>
        -triangular_matrix &assign (const matrix_expression<AE> -&ae)
        Assigns a matrix expression to the triangular matrix. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -triangular_matrix &operator += (const -matrix_expression<AE> &ae)
        A computed assignment operator. Adds the matrix expression to -the triangular matrix.
        template<class AE>
        -triangular_matrix &plus_assign (const -matrix_expression<AE> &ae)
        Adds a matrix expression to the triangular matrix. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -triangular_matrix &operator -= (const -matrix_expression<AE> &ae)
        A computed assignment operator. Subtracts the matrix expression -from the triangular matrix.
        template<class AE>
        -triangular_matrix &minus_assign (const -matrix_expression<AE> &ae)
        Subtracts a matrix expression from the triangular matrix. Left -and right hand side of the assignment should be independent.
        template<class AT>
        -triangular_matrix &operator *= (const AT &at)
        A computed assignment operator. Multiplies the triangular -matrix with a scalar.
        template<class AT>
        -triangular_matrix &operator /= (const AT &at)
        A computed assignment operator. Divides the triangular matrix -through a scalar.
        void swap (triangular_matrix &m)Swaps the contents of the triangular matrices.
        void insert (size_type i, size_type j, const_reference -t)Inserts the value t at the j-th -element of the i-th row.
        void erase (size_type i, size_type j)Erases the value at the j-th elemenst of the -i-th row.
        void clear ()Clears the matrix.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the triangular_matrix.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the triangular_matrix.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the triangular_matrix.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -triangular_matrix.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the triangular_matrix.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the triangular_matrix.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the triangular_matrix.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -triangular_matrix.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed triangular_matrix.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed triangular_matrix.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed triangular_matrix.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed triangular_matrix.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed triangular_matrix.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed triangular_matrix.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed triangular_matrix.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed triangular_matrix.
        -

        Notes

        -

        [1] -Supported parameters for the type of the triangular matrix are -lower , unit_lower, upper -and unit_upper .

        -

        [2] -Supported parameters for the storage organization are -row_major and column_major.

        -

        [3] -Supported parameters for the adapted array are -unbounded_array<T> , -bounded_array<T> and -std::vector<T> .

        -

        Triangular Adaptor

        -

        Description

        -

        The templated class triangular_adaptor<M, F> -is a triangular matrix adaptor for other matrices.

        -

        Example

        -
        -#include <boost/numeric/ublas/triangular.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    matrix<double> m (3, 3);
        -    triangular_adaptor<matrix<double>, lower> tal (m);
        -    for (unsigned i = 0; i < tal.size1 (); ++ i)
        -        for (unsigned j = 0; j <= i; ++ j)
        -            tal (i, j) = 3 * i + j;
        -    std::cout << tal << std::endl;
        -    triangular_adaptor<matrix<double>, upper> tau (m);
        -    for (unsigned i = 0; i < tau.size1 (); ++ i)
        -        for (unsigned j = i; j < tau.size2 (); ++ j)
        -            tau (i, j) = 3 * i + j;
        -    std::cout << tau << std::endl;
        -}
        -
        -

        Please read the full triangular example for more details.

        - -

        Definition

        -

        Defined in the header triangular.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        MThe type of the adapted matrix.
        FFunctor describing the type of the triangular adaptor. [1]lower
        -

        Model of

        -

        Matrix Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix Expression .

        -

        Public base classes

        -

        matrix_expression<triangular_adaptor<M, F> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        triangular_adaptor (matrix_type &data)Constructs a triangular_adaptor of a matrix.
        triangular_adaptor (const triangular_adaptor -&m)The copy constructor.
        template<class AE>
        -triangular_adaptor (const matrix_expression<AE> -&ae)
        The extended copy constructor.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns a const reference of the j --th element in the i-th row.
        reference operator () (size_type i, size_type -j)Returns a reference of the j-th element in the -i-th row.
        triangular_adaptor &operator = (const -triangular_adaptor &m)The assignment operator.
        triangular_adaptor &assign_temporary -(triangular_adaptor &m)Assigns a temporary. May change the triangular adaptor -m.
        template<class AE>
        -triangular_adaptor &operator = (const -matrix_expression<AE> &ae)
        The extended assignment operator.
        template<class AE>
        -triangular_adaptor &assign (const matrix_expression<AE> -&ae)
        Assigns a matrix expression to the triangular adaptor. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -triangular_adaptor &operator += (const -matrix_expression<AE> &ae)
        A computed assignment operator. Adds the matrix expression to -the triangular adaptor.
        template<class AE>
        -triangular_adaptor &plus_assign (const -matrix_expression<AE> &ae)
        Adds a matrix expression to the triangular adaptor. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -triangular_adaptor &operator -= (const -matrix_expression<AE> &ae)
        A computed assignment operator. Subtracts the matrix expression -from the triangular adaptor.
        template<class AE>
        -triangular_adaptor &minus_assign (const -matrix_expression<AE> &ae)
        Subtracts a matrix expression from the triangular adaptor. Left -and right hand side of the assignment should be independent.
        template<class AT>
        -triangular_adaptor &operator *= (const AT &at)
        A computed assignment operator. Multiplies the triangular -adaptor with a scalar.
        template<class AT>
        -triangular_adaptor &operator /= (const AT &at)
        A computed assignment operator. Divides the triangular adaptor -through a scalar.
        void swap (triangular_adaptor &m)Swaps the contents of the triangular adaptors.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the triangular_adaptor.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the triangular_adaptor.
        iterator1 begin1 ()Returns a iterator1 pointing to the beginning of -the triangular_adaptor.
        iterator1 end1 ()Returns a iterator1 pointing to the end of the -triangular_adaptor.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the triangular_adaptor.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the triangular_adaptor.
        iterator2 begin2 ()Returns a iterator2 pointing to the beginning of -the triangular_adaptor.
        iterator2 end2 ()Returns a iterator2 pointing to the end of the -triangular_adaptor.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed triangular_adaptor.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed triangular_adaptor.
        reverse_iterator1 rbegin1 ()Returns a reverse_iterator1 pointing to the -beginning of the reversed triangular_adaptor.
        reverse_iterator1 rend1 ()Returns a reverse_iterator1 pointing to the end of -the reversed triangular_adaptor.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed triangular_adaptor.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed triangular_adaptor.
        reverse_iterator2 rbegin2 ()Returns a reverse_iterator2 pointing to the -beginning of the reversed triangular_adaptor.
        reverse_iterator2 rend2 ()Returns a reverse_iterator2 pointing to the end of -the reversed triangular_adaptor.
        -

        Notes

        -

        [1] -Supported parameters for the type of the triangular adaptor are -lower , unit_lower, upper -and unit_upper .

        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/types_overview.html b/doc/types_overview.html deleted file mode 100644 index 770a139bd..000000000 --- a/doc/types_overview.html +++ /dev/null @@ -1,608 +0,0 @@ - - - - - - - - - -Types Overview - - -

        Overview of Tensor, Matrix- and Vector Types

        -
        - -
        -
        Contents:
        -
        Vectors
        -
        Vector Proxies
        -
        Matrices
        -
        Matrix Proxies
        -
        Tensors
        -
        Special Storage Layouts
        -
        - - -

        Notation

        - - - - - - - - - - - - - - - - - - - - - -
        Tis the data type. For general linear algebra operations this will be a real type e.g. double, ...
        Fis the orientation type, either -row_major or column_major for matrices and first_order or last_order for tensors
        A, IA, TA is an array storage type, e.g. std::vector, -bounded_array, unbounded_array, ...
        TRIis a triangular functor: lower, -unit_lower, strict_lower, upper, unit_upper, -strict_upper
        M, N, Kare unsigned integer sizes -(std::size_t)
        IBis an index base -(std::size_t)
        VECis any vector type
        MAT is any matrix type
        TEN is any tensor type
        [...]denote optional arguments - for more details -look at the section "storage layout".
        - -

        Vectors

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DefinitionDescription
        vector<T [, A]>
           v(size);
        a dense vector of values of type T of variable -size. A storage type A can be specified -which defaults to unbounded_array. -Elements are constructed by A, which need not initialise their value.
        bounded_vector<T, N>
           v;
        a dense vector of values of type T of variable size but with maximum -N. The default constructor creates v -with size N. -Elements are constructed by the storage type bounded_array, which need not initialise their value.
        c_vector<T, M>
           v(size);
        a dense vector of values of type T with the given size. -The data is stored as an ordinary C++ array T -data_[M]
        zero_vector<T>
           v(size);
        the zero vector of type T with the given -size.
        unit_vector<T>
           v(size, index);
        the unit vector of type T with the given size. The -vector is zero other then a single specified element. -
        index should be less than size.
        mapped_vector<T [, S]>
           v(size);
        a sparse vector of values of type T of variable -size. The sparse storage type S can be std::map<size_t, -T> or map_array<size_t, T>.
        compressed_vector<T [,IB, IA, TA]>
           v(size);
        a sparse vector of values of type T of variable -size. The non zero values are stored as two seperate arrays - an -index array and a value array. The index array is always sorted and -there is at most one entry for each index.
        coordinate_vector<T [,IB, IA, TA]>
           v(size);
        a sparse vector of values of type T of variable -size. The non zero values are stored as two seperate arrays - an -index array and a value array. The arrays may be out of order with -multiple entries for each vector element. If there are multiple -values for the same index the sum of these values is the real -value.
        -

        Note: the default types are defined in -boost/numeric/ublas/fwd.hpp.

        - -

        Vector Proxies

        - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DefinitionDescription
        vector_range<VEC>
           vr(v, range);
        a vector referencing a continuous subvector of elements of -vector v containing all elements specified by -range.
        vector_slice<VEC>
           vs(v, slice);
        a vector referencing a non continuous subvector of elements of -vector v containing all elements specified by -slice.
        matrix_row<MAT>
           vr(m, index);
        a vector referencing the index-th row of matrix -m
        matrix_column<MAT>
           vc(m, index);
        a vector referencing the index-th column of matrix -m
        - -

        Matrices

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DefinitionDescription
        matrix<T [, F, A]>
           m(size1, size2);
        a dense matrix of values of type T of variable -size. A storage type A can be specified -which defaults to unbounded_array. -The orientation functor F defaults to -row_major. -Elements are constructed by A, which need not initialise their value.
        bounded_matrix<T, M, N [, F]>
           m;
        a dense matrix of type T with variable size with maximum M-by-N. The orientation functor F -defaults to row_major. The default constructor creates -m with size M-by-N. -Elements are constructed by the storage type bounded_array, which need not initialise their value.
        c_matrix<T, M, N>
           m(size1, size2);
        a dense matrix of values of type T with the given size. -The data is stored as an ordinary C++ array T -data_[N][M]
        vector_of_vector<T [, F, A]>
           m(size1, -size2);
        a dense matrix of values of type T with the given size. -The data is stored as a vector of vectors. The orientation -F defaults to row_major. The storage -type S defaults to -unbounded_array<unbounded_array<T> >
        zero_matrix<T>
           m(size1, size2);
        a zero matrix of type T with the given size.
        identity_matrix<T>
           m(size1, size2);
        an identity matrix of type T with the given size. -The values are v(i,j) = (i==j)?T(1):T().
        scalar_matrix<T>
           m(size1, size2, -value);
        a matrix of type T with the given size that has the -value value everywhere.
        triangular_matrix<T [, TRI, F, A]>
           -m(size);
        a triangular matrix of values of type T of -variable size. Only the nonzero elements are stored in the given -order F. ("triangular packed storage") The triangular -type F defaults to lower, the orientation -type F defaults to row_major.
        banded_matrix<T [, F, A]>
           m(size1, size2, n_lower, -n_upper);
        a banded matrix of values of type T of variable -size with n_lower sub diagonals and -n_upper super diagonals. Only the nonzero elements are -stored in the given order F. ("packed storage")
        symmetric_matrix<T [, TRI, F, A]>
           -m(size);
        a symmetric matrix of values of type T of -variable size. Only the given triangular matrix is stored in the -given order F.
        hermitian_matrix<T [, TRI, F, A]>
           -m(size);
        a hermitian matrix of values of type T of -variable size. Only the given triangular matrix is stored using -the order F.
        mapped_matrix<T, [F, S]>
           m(size1, size2 [, -non_zeros]);
        a sparse matrix of values of type T of variable -size. The sparse storage type S can be either std::map<size_t, -std::map<size_t, T> > or -map_array<size_t, map_array<size_t, -T> >.
        sparse_vector_of_sparse_vector<T, [F, C]>
           m(size1, -size2 [, non_zeros]);
        a sparse matrix of values of type T of variable -size.
        compressed_matrix<T, [F, IB, IA, TA]>
           m(size1, -size2 [, non_zeros]);
        a sparse matrix of values of type T of variable -size. The values are stored in compressed row/column storage.
        coordinate_matrix<T, [F, IB, IA, TA]>
           m(size1, -size2 [, non_zeros]);
        a sparse matrix of values of type T of variable -size. The values are stored in 3 parallel array as triples (i, j, -value). More than one value for each pair of indices is possible, -the real value is the sum of all.
        generalized_vector_of_vector<T, F, A>
           m(size1, -size2 [, non_zeros]);
        a sparse matrix of values of type T of variable -size. The values are stored as a vector of sparse vectors, e.g. -generalized_vector_of_vector<double, row_major, -unbounded_array<coordinate_vector<double> > >
        -

        Note: the default types are defined in -boost/numeric/ublas/fwd.hpp.

        - -

        Matrix Proxies

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DefinitionDescription
        triangular_adaptor<MAT, TRI>
           ta(m);
        a triangular matrix referencing a selection of elements of the -matrix m.
        symmetric_adaptor<MAT, TRI>
           sa(m);
        a symmetric matrix referencing a selection of elements of the -matrix m.
        hermitian_adaptor<MAT, TRI>
           ha(m);
        a hermitian matrix referencing a selection of elements of the -matrix m.
        banded_adaptor<MAT>
           ba(m, n_lower, -n_upper);
        a banded matrix referencing a selection of elements of the -matrix m.
        matrix_range<MAT, TRI>
           mr(m, range1, -range2);
        a matrix referencing a submatrix of elements in the matrix -m.
        matrix_slice<MAT, TRI>
           ms(m, slice1, -slice2);
        a matrix referencing a non continues submatrix of elements in -the matrix m.
        - - - -

        Tensors

        - - - - - - - - - - - - - - -
        DefinitionDescription
        tensor<T [, F, A]>
           t(size1, size2, ... );
        a dense matrix of values of type T of variable -size. A storage type A can be specified -which defaults to std::vector<T>. -The orientation type F defaults to -first_order. -Elements are constructed by A, which need not initialise their value.
        - - - - -

        Special Storage Layouts

        - - -

        The library supports conventional dense, packed and basic sparse -vector and matrix storage layouts. The description of the most -common constructions of vectors and matrices comes next.

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        ConstructionComment
        vector<T,
        - std::vector<T> >
        -  v (size)
        a dense vector, storage is provided by a standard -vector.
        -The storage layout usually is BLAS compliant.
        vector<T,
        - unbounded_array<T> >
        -  v (size)
        a dense vector, storage is provided by a heap-based -array.
        -The storage layout usually is BLAS compliant.
        vector<T,
        - bounded_array<T, N> >
        -  v (size)
        a dense vector, storage is provided by a stack-based -array.
        -The storage layout usually is BLAS compliant.
        mapped_vector<T,
        - std::map<std::size_t, T> >
        -  v (size, non_zeros)
        a sparse vector, storage is provided by a standard -map.
        mapped_vector<T,
        - map_array<std::size_t, T> >
        -  v (size, non_zeros)
        a sparse vector, storage is provided by a map -array.
        matrix<T,
        - row_major,
        - std::vector<T> >
        -  m (size1, size2)
        a dense matrix, orientation is row major, storage is -provided by a standard vector.
        matrix<T,
        - column_major,
        - std::vector<T> >
        -  m (size1, size2)
        a dense matrix, orientation is column major, storage -is provided by a standard vector.
        -The storage layout usually is BLAS compliant.
        matrix<T,
        - row_major,
        - unbounded_array<T> >
        -  m (size1, size2)
        a dense matrix, orientation is row major, storage is -provided by a heap-based array.
        matrix<T,
        - column_major,
        - unbounded_array<T> >
        -  m (size1, size2)
        a dense matrix, orientation is column major, storage -is provided by a heap-based array.
        -The storage layout usually is BLAS compliant.
        matrix<T,
        - row_major,
        - bounded_array<T, N1 * N2> >
        -  m (size1, size2)
        a dense matrix, orientation is row major, storage is -provided by a stack-based array.
        matrix<T,
        - column_major,
        - bounded_array<T, N1 * N2> >
        -  m (size1, size2)
        a dense matrix, orientation is column major, storage -is provided by a stack-based array.
        -The storage layout usually is BLAS compliant.
        triangular_matrix<T,
        - row_major, F, A>
        -  m (size)
        a packed triangular matrix, orientation is row -major.
        triangular_matrix<T,
        - column_major, F, A>
        -  m (size)
        a packed triangular matrix, orientation is column -major.
        -The storage layout usually is BLAS compliant.
        banded_matrix<T,
        - row_major, A>
        -  m (size1, size2, lower, upper)
        a packed banded matrix, orientation is row -major.
        banded_matrix<T,
        - column_major, A>
        -  m (size1, size2, lower, upper)
        a packed banded matrix, orientation is column -major.
        -The storage layout usually is BLAS compliant.
        symmetric_matrix<T,
        - row_major, F, A>
        -  m (size)
        a packed symmetric matrix, orientation is row -major.
        symmetric_matrix<T,
        - column_major, F, A>
        -  m (size)
        a packed symmetric matrix, orientation is column -major.
        -The storage layout usually is BLAS compliant.
        hermitian_matrix<T,
        - row_major, F, A>
        -  m (size)
        a packed hermitian matrix, orientation is row -major.
        hermitian_matrix<T,
        - column_major, F, A>
        -  m (size)
        a packed hermitian matrix, orientation is column -major.
        -The storage layout usually is BLAS compliant.
        mapped_matrix<T,
        - row_major,
        - std::map<std::size_t, T> >
        -  m (size1, size2, non_zeros)
        a sparse matrix, orientation is row major, storage -is provided by a standard map.
        mapped_matrix<T,
        - column_major,
        - std::map<std::size_t, T> >
        -  m (size1, size2, non_zeros)
        a sparse matrix, orientation is column major, -storage is provided by a standard map.
        mapped_matrix<T,
        - row_major,
        - map_array<std::size_t, T> >
        -  m (size1, size2, non_zeros)
        a sparse matrix, orientation is row major, storage -is provided by a map array.
        mapped_matrix<T,
        - column_major,
        - map_array<std::size_t, T> >
        -  m (size1, size2, non_zeros)
        a sparse matrix, orientation is column major, -storage is provided by a map array.
        compressed_matrix<T,
        - row_major>
        -  m (size1, size2, non_zeros)
        a compressed matrix, orientation is row major.
        -The storage layout usually is BLAS compliant.
        compressed_matrix<T,
        - column_major>
        -  m (size1, size2, non_zeros)
        a compressed matrix, orientation is column -major.
        -The storage layout usually is BLAS compliant.
        coordinate_matrix<T,
        - row_major>
        -  m (size1, size2, non_zeros)
        a coordinate matrix, orientation is row major.
        -The storage layout usually is BLAS compliant.
        coordinate_matrix<T,
        - column_major>
        -  m (size1, size2, non_zeros)
        a coordinate matrix, orientation is column -major.
        -The storage layout usually is BLAS compliant.
        - -
        -

        Copyright (©) 2000-2004 Joerg Walter, Mathias Koch, Gunter -Winkler, Michael Stevens
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/ublas-docinfo-footer.html b/doc/ublas-docinfo-footer.html new file mode 100644 index 000000000..20c80d424 --- /dev/null +++ b/doc/ublas-docinfo-footer.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/doc/ublas.adoc b/doc/ublas.adoc new file mode 100644 index 000000000..94dac0c92 --- /dev/null +++ b/doc/ublas.adoc @@ -0,0 +1,86 @@ +//// +Copyright 2021 Shikhar Vashistha + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +//// + +# Boost.Ublas: The Boost Ublas Library +:toc: left +:toclevels: 2 +:idprefix: +:listing-caption: Code Example +:docinfo: private-footer + +:leveloffset: +1 + +include::ublas/overview.adoc[] + +include::ublas/index.adoc[] + +include::ublas/vector.adoc[] + +include::ublas/vector_sparse.adoc[] + +include::ublas/vector_proxy.adoc[] + +include::ublas/vector_expression.adoc[] + +include::ublas/matrix.adoc[] + +include::ublas/triangular.adoc[] + +include::ublas/symmetric.adoc[] + +include::ublas/hermitian.adoc[] + +include::ublas/banded.adoc[] + +include::ublas/matrix_sparse.adoc[] + +include::ublas/matrix_proxy.adoc[] + +include::ublas/matrix_expression.adoc[] + +include::ublas/tensor.adoc[] + +include::ublas/tensor/tensor_expression.adoc[] + +include::ublas/unbounded_array.adoc[] + +include::ublas/bounded_array.adoc[] + +include::ublas/range.adoc[] + +include::ublas/tensor/extents.adoc[] + +include::ublas/tensor/strides.adoc[] + +include::ublas/tensor/tensor_expression.adoc[] + +include::ublas/tensor/tensor_index.adoc[] + +include::ublas/storage_sparse.adoc[] + +include::ublas/products.adoc[] + +include::ublas/blas.adoc[] + +include::ublas/container_concept.adoc[] + +include::ublas/expression_concept.adoc[] + +include::ublas/storage_concept.adoc[] + +include::ublas/iterator_concept.adoc[] + +:leveloffset: -1 + +[appendix] +## Copyright and License + +This documentation is + +* Copyright 2021 Shikhar Vashistha + +and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0]. diff --git a/doc/ublas.css b/doc/ublas.css deleted file mode 100644 index 1531be7f5..000000000 --- a/doc/ublas.css +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2000-2009 Michael Stevens, Mathias Koch, - * Joerg Walter, Gunter Winkler. - * - * Use, modification and distribution are 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). - */ -table { - border-width: medium; - background-color: #F8F8F8; - margin: 1em; -} - -td { - padding-left: 0.5em; - padding-right: 0.5em; -} - -th { - text-align: left; -} - -pre.screen { - border: 1px solid #DCDCDC; - display: block; - font-size: 9pt; - margin: 1pc 4% 0; - padding: 0.5pc; -} - -p.credit { - font-style: italic; -} - -@media print { - div.toc { display: none; } -} - -div.toc { - margin: 10px; - padding: 3px; -} - -div#toc ul { - list-style: none; - margin: 1px; - padding-left: 1em; - margin-bottom: 0.25em; -} - -div#toc ul li ul { - margin-bottom: 0.25em; -} - -div#toc ul li ul li ul { - margin-bottom: 0.25em; -} \ No newline at end of file diff --git a/doc/ublas/banded.adoc b/doc/ublas/banded.adoc new file mode 100644 index 000000000..a48e003e1 --- /dev/null +++ b/doc/ublas/banded.adoc @@ -0,0 +1,394 @@ +== Banded Matrix + +[[toc]] + +=== [#banded_matrix]#Banded Matrix# + +==== Description + +The templated class `banded_matrix` is the base container +adaptor for banded matrices. For a _(m x n_)-dimensional banded matrix +with _l_ lower and _u_ upper diagonals and _0 < = i < m_, _0 < = j < n_ +holds __b__~_i,j_~ = _0_, if _i > j + l_ or _i < j - u_. The storage of +banded matrices is packed. + +==== Example + +[source, cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + banded_matrix m (3, 3, 1, 1); + for (signed i = 0; i < signed (m.size1 ()); ++ i) + for (signed j = std::max (i - 1, 0); j < std::min (i + 2, signed (m.size2 ())); ++ j) + m (i, j) = 3 * i + j; + std::cout << m << std::endl; +} +.... + +==== Definition + +Defined in the header banded.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the matrix. | + +|`F` |Functor describing the storage organization. +link:#banded_matrix_1[[1]] |`row_major` + +|`A` |The type of the adapted array. link:#banded_matrix_2[[2]] +|`unbounded_array` +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`banded_matrix ()` |Allocates an uninitialized `banded_matrix` that +holds zero rows of zero elements. + +|`banded_matrix (size_type size1, size_type size2, size_type lower = 0, size_type upper = 0)` +|Allocates an uninitialized `banded_matrix` that holds +`(lower + 1 + upper)` diagonals around the main diagonal of a matrix +with `size1` rows of `size2` elements. + +|`banded_matrix (const banded_matrix &m)` |The copy constructor. + +|`template banded_matrix (const matrix_expression &ae)` +|The extended copy constructor. + +|`void resize (size_type size1, size_type size2, size_type lower = 0, size_type upper = 0, bool preserve = true)` +|Reallocates a `banded_matrix` to hold `(lower + 1 + upper)` diagonals +around the main diagonal of a matrix with `size1` rows of `size2` +elements. The existing elements of the `banded_matrix` are preseved when +specified. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`size_type lower () const` |Returns the number of diagonals below the +main diagonal. + +|`size_type upper () const` |Returns the number of diagonals above the +main diagonal. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +a `const` reference of the `j` -th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`banded_matrix &operator = (const banded_matrix &m)` |The assignment +operator. + +|`banded_matrix &assign_temporary (banded_matrix &m)` |Assigns a +temporary. May change the banded matrix `m` . + +|`template banded_matrix &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template banded_matrix &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the banded matrix. Left and right hand +side of the assignment should be independent. + +|`template banded_matrix &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +banded matrix. + +|`template banded_matrix &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the banded matrix. Left and right hand side +of the assignment should be independent. + +|`template banded_matrix &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the banded matrix. + +|`template banded_matrix &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the banded matrix. Left and right +hand side of the assignment should be independent. + +|`template banded_matrix &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the banded matrix with a +scalar. + +|`template banded_matrix &operator /= (const AT &at)` |A +computed assignment operator. Divides the banded matrix through a +scalar. + +|`void swap (banded_matrix &m)` |Swaps the contents of the banded +matrices. + +|`void insert (size_type i, size_type j, const_reference t)` |Inserts +the value `t` at the `j`-th element of the `i`-th row. + +|`void erase (size_type i, size_type j)` |Erases the value at the `j`-th +elemenst of the `i`-th row. + +|`void clear ()` |Clears the matrix. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `banded_matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `banded_matrix`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `banded_matrix`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`banded_matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `banded_matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `banded_matrix`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `banded_matrix`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`banded_matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`banded_matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`banded_matrix`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `banded_matrix`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `banded_matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`banded_matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`banded_matrix`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `banded_matrix`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `banded_matrix`. +|=== + +==== Notes + +[#banded_matrix_1]#[1]# Supported parameters for the storage +organization are `row_major` and `column_major`. + +[#banded_matrix_2]#[2]# Supported parameters for the adapted array are +`unbounded_array` , `bounded_array` and `std::vector` . + +=== [#banded_adaptor]#Banded Adaptor# + +==== Description + +The templated class `banded_adaptor` is a banded matrix adaptor for +other matrices. + +==== Example + +[source, cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + banded_adaptor > ba (m, 1, 1); + for (signed i = 0; i < signed (ba.size1 ()); ++ i) + for (signed j = std::max (i - 1, 0); j < std::min (i + 2, signed (ba.size2 ())); ++ j) + ba (i, j) = 3 * i + j; + std::cout << ba << std::endl; +} +.... + +==== Definition + +Defined in the header banded.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`M` |The type of the adapted matrix. | +|=== + +==== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +==== Public base classes + +`matrix_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`banded_adaptor (matrix_type &data, size_type lower = 0, size_type upper = 0)` +|Constructs a `banded_adaptor` that holds `(lower + 1 + upper)` +diagonals around the main diagonal of a matrix. + +|`banded_adaptor (const banded_adaptor &m)` |The copy constructor. + +|`template banded_adaptor (const matrix_expression &ae)` +|The extended copy constructor. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`size_type lower () const` |Returns the number of diagonals below the +main diagonal. + +|`size_type upper () const` |Returns the number of diagonals above the +main diagonal. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +a `const` reference of the `j` -th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`banded_adaptor &operator = (const banded_adaptor &m)` |The assignment +operator. + +|`banded_adaptor &assign_temporary (banded_adaptor &m)` |Assigns a +temporary. May change the banded adaptor `m` . + +|`template banded_adaptor &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template banded_adaptor &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the banded adaptor. Left and right hand +side of the assignment should be independent. + +|`template banded_adaptor &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +banded adaptor. + +|`template banded_adaptor &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the banded adaptor. Left and right hand +side of the assignment should be independent. + +|`template banded_adaptor &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the banded adaptor. + +|`template banded_adaptor &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the banded adaptor. Left and right +hand side of the assignment should be independent. + +|`template banded_adaptor &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the banded adaptor with a +scalar. + +|`template banded_adaptor &operator /= (const AT &at)` |A +computed assignment operator. Divides the banded adaptor through a +scalar. + +|`void swap (banded_adaptor &m)` |Swaps the contents of the banded +adaptors. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `banded_adaptor`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `banded_adaptor`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `banded_adaptor`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`banded_adaptor`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `banded_adaptor`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `banded_adaptor`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `banded_adaptor`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`banded_adaptor`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`banded_adaptor`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`banded_adaptor`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `banded_adaptor`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `banded_adaptor`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`banded_adaptor`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`banded_adaptor`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `banded_adaptor`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `banded_adaptor`. +|=== + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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). \ No newline at end of file diff --git a/doc/ublas/blas.adoc b/doc/ublas/blas.adoc new file mode 100644 index 000000000..13b54bc2b --- /dev/null +++ b/doc/ublas/blas.adoc @@ -0,0 +1,230 @@ +== Level 3 BLAS + +[[toc]] + +''''' + +=== Functions +[width="100%",cols="100%",] +|=== + +|template M1 & link:#blas_1[boost::numeric::ublas::blas_3::tmm] (M1 &m1, const T &t, +const M2 &m2, const M3 &m3) triangular matrix multiplication + + +|template M1 & link:#blas_2[boost::numeric::ublas::blas_3::tsm] (M1 &m1, const T &t, +const M2 &m2, C) triangular solve _m2_ * _x_ = _t_ * _m1_ in place, _m2_ is a +triangular matrix + +|template M1 & link:#blas_3[boost::numeric::ublas::blas_3::gmm] (M1 &m1, const T1 &t1, +const T2 &t2, const M2 &m2, const M3 &m3) general matrix multiplication + +|template M1 & link:#blas_4[boost::numeric::ublas::blas_3::srk] (M1 &m1, const T1 &t1, +const T2 &t2, const M2 &m2) symmetric rank k update: _m1_ = _t_ * _m1_ + _t2_ * (_m2_ * _m2^T^_) + +|template M1 & link:#blas_5[boost::numeric::ublas::blas_3::hrk] (M1 &m1, const T1 &t1, +const T2 &t2, const M2 &m2) hermitian rank k update: _m1_ = _t_ * _m1_ + _t2_ * (_m2_ * _m2^H^_) + + +|template M1 & link:#blas_6[boost::numeric::ublas::blas_3::sr2k] (M1 &m1, const T1 &t1, +const T2 &t2, const M2 &m2, const M3 &m3) generalized symmetric rank k update: _m1_ = _t1_ * _m1_ + _t2_ * +(_m2_ * _m3^T^_) + _t2_ * (_m3_ * _m2^T^_) + +|template M1 & link:#blas_7[boost::numeric::ublas::blas_3::hr2k] (M1 &m1, const T1 &t1, +const T2 &t2, const M2 &m2, const M3 &m3) generalized hermitian rank k update: _m1_ = _t1_ * _m1_ + _t2_ * +(_m2_ * _m3^H^_) + (_m3_ * (_t2_ * _m2_)^H^) + +|template BOOST_UBLAS_INLINE M & link:products.adoc#product_3[boost::numeric::ublas::axpy_prod] (const +matrix_expression< E1 > &e1, const matrix_expression< E2 > &e2, M &m, +bool init=true) computes `M += A X` or `M = A X` in an optimized fashion. + +|template BOOST_UBLAS_INLINE M & link:products.adoc#product_4[boost::numeric::ublas::opb_prod] (const +matrix_expression< E1 > &e1, const matrix_expression< E2 > &e2, M &m, +bool init=true) computes `M += A X` or `M = A X` in an optimized fashion. +|=== + +''''' + +=== Function Documentation + +[#blas_1]#1.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!M1& tmm !(  !M1 &  !_m1_, +! ! !const T &  !_t_, +! ! !const M2 &  !_m2_, +! ! !const M3 &  !_m3_ +! !)  ! ! +!=== + +|=== + +[cols=",",] +|=== +|  |triangular matrix multiplication +|=== + +[#blas_2]#2.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!M1& tsm !(  !M1 &  !_m1_, +! ! !const T &  !_t_, +! ! !const M2 &  !_m2_, +! ! !C  ! +! !)  ! ! +!=== + +|=== + +[cols=",",] +|=== +|  |triangular solve _m2_ * _x_ = _t_ * _m1_ in place, _m2_ is a +triangular matrix +|=== + +[#blas_3]#3.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!M1& gmm !(  !M1 &  !_m1_, +! ! !const T1 &  !_t1_, +! ! !const T2 &  !_t2_, +! ! !const M2 &  !_m2_, +! ! !const M3 &  !_m3_ +! !)  ! ! +!=== + +|=== + +[cols=",",] +|=== +|  |general matrix multiplication +|=== + +[#blas_4]#4.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!M1& srk !(  !M1 &  !_m1_, +! ! !const T1 &  !_t1_, +! ! !const T2 &  !_t2_, +! ! !const M2 &  !_m2_ +! !)  ! ! +!=== + +|=== + +[width="100%",cols="50%,50%",] +|=== +|  a| +symmetric rank k update: _m1_ = _t_ * _m1_ + _t2_ * (_m2_ * _m2^T^_) + +*Todo:*:: + use opb_prod() + +|=== + +[#blas_5]#5.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!M1& hrk !(  !M1 &  !_m1_, +! ! !const T1 &  !_t1_, +! ! !const T2 &  !_t2_, +! ! !const M2 &  !_m2_ +! !)  ! ! +!=== + +|=== + +[width="100%",cols="50%,50%",] +|=== +|  a| +hermitian rank k update: _m1_ = _t_ * _m1_ + _t2_ * (_m2_ * _m2^H^_) + +*Todo:*:: + use opb_prod() + +|=== + +[#blas_6]#6.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!M1& sr2k !(  !M1 &  !_m1_, +! ! !const T1 &  !_t1_, +! ! !const T2 &  !_t2_, +! ! !const M2 &  !_m2_, +! ! !const M3 &  !_m3_ +! !)  ! ! +!=== + +|=== + +[width="100%",cols="50%,50%",] +|=== +|  a| +generalized symmetric rank k update: _m1_ = _t1_ * _m1_ + _t2_ * (_m2_ * +_m3^T^_) + _t2_ * (_m3_ * _m2^T^_) + +*Todo:*:: + use opb_prod() + +|=== + +[#blas_7]#7.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!M1& hr2k !(  !M1 &  !_m1_, +! ! !const T1 &  !_t1_, +! ! !const T2 &  !_t2_, +! ! !const M2 &  !_m2_, +! ! !const M3 &  !_m3_ +! !)  ! ! +!=== + +|=== + +[width="100%",cols="50%,50%",] +|=== +|  a| +generalized hermitian rank k update: _m1_ = _t1_ * _m1_ + _t2_ * (_m2_ * +_m3^H^_) + (_m3_ * (_t2_ * _m2_)^H^) + +*Todo:*:: + use opb_prod() + +|=== + +''''' + +Copyright (©) 2000-2004 Michael Stevens, Mathias Koch, Joerg Walter, +Gunter Winkler + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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). diff --git a/doc/ublas/bounded_array.adoc b/doc/ublas/bounded_array.adoc new file mode 100644 index 000000000..37ce3cd20 --- /dev/null +++ b/doc/ublas/bounded_array.adoc @@ -0,0 +1,146 @@ +== Bounded Array Storage + +[[toc]] + +=== [#bounded_array]#Bounded Array# + +==== Description + +The templated class `bounded_array` implements a bounded +storage array. The bounded array is similar to a C++ array type in that +its maximum size is bounded by N and is allocated on the stack instead +of the heap. Similarly a `bounded_array` requires no secondary storage +and ALLOC is only used to specify `size_type` and `difference_type`. + +When resized `bounded_array` never reallocated the storage. It is +therefore always efficient to resize a `bounded_array` but the size +bound N must not be exceeded. + +==== Example + +[source, cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + bounded_array a (3); + for (unsigned i = 0; i < a.size (); ++ i) { + a [i] = i; + std::cout << a [i] << std::endl; + } +} +.... + +==== Definition + +Defined in the header storage.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`T` |The type of object stored in the array. | +|`N` |The allocation size of the array. | +|`ALLOC` |An STL Allocator |std::allocator +|=== + +==== Model of + +link:storage_concept.html[Storage] + +==== Type requirements + +None, except for those imposed by the requirements of Storage. + +==== Public base classes + +None. + +==== Members + +* The description does not describe what the member actually does, this +can be looked up in the corresponding concept documentation, but instead +contains a remark on the implementation of the member inside this model +of the concept. +* Typography: +** Members that are not part of the implemented concepts are in blue. + +[cols=",,",] +|=== +|Member |Where defined |Description + +|`value_type`| https://www.boost.org/sgi/stl/Container.html[Container] | + +|`pointer` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `value_type*` + +|`const_pointer` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `const value_type*` + +|`reference` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `value_type&` + +|`const_reference` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `const value_type&` + +|`size_type` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `Alloc::size_type` + +|`difference_type` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `Alloc::difference_type` + +|`iterator` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `pointer` + +|`const_iterator` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `const_pointer` + +|`revere_iterator` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `std::reverse_iterator` + +|`const_revere_iterator` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `std::reverse_iterator` + +|`bounded_array ()` |link:storage_concept.html[Storage] |Creates an `unbounded_array` that holds *zero* elements. + +|`bounded_array (size_type size)` |link:storage_concept.html[Storage] |Creates a uninitialized `bounded_array` that holds `size` elements. All the elements are default constructed. + +|`bounded_array (size_type size, const T& init)` |link:storage_concept.html[Storage] |Creates an initialized `bounded_array` that holds `size` elements. All the elements are constructed from the `init` value. + +|`bounded_array (const bounded_array &c)` |https://www.boost.org/sgi/stl/Container.html[Container] |The copy constructor. + +|`~bounded_array ()` |https://www.boost.org/sgi/stl/Container.html[Container] |Deallocates the `bounded_array` itself. + +|`void resize (size_type size)` |link:storage_concept.html[Storage] |Reallocates a `bounded_array` to hold `size` elements. + +|`void resize (size_type size, const T& t)` |link:storage_concept.html[Storage] |Reallocates a `bounded_array` to hold `size` elements. + +|`size_type size () const` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns the size of the `bounded_array`. + +|`const_reference operator [] (size_type i) const` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a `const` reference of the `i` -th element. + +|`reference operator [] (size_type i)` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a reference of the `i`-th element. + +|`bounded_array &operator = (const bounded_array &a)` |https://www.boost.org/sgi/stl/Container.html[Container] |The assignment operator. + +|`bounded_array &assign_temporary (bounded_array &a)` | |Assigns a temporary. May change the array `a`. + +|`void swap (bounded_array &a)` |https://www.boost.org/sgi/stl/Container.html[Container] |Swaps the contents of the arrays. + +|`const_iterator begin () const` |https://www.boost.org/sgi/stl/Container.html[Container]| Returns a `const_iterator` pointing to the beginning of the `bounded_array`. + +|`const_iterator end () const` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a `const_iterator` pointing to the end of the `bounded_array`. + +|`iterator begin ()` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a `iterator` pointing to the beginning of the `bounded_array`. + +|`iterator end ()` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a `iterator` pointing to the end of the `bounded_array`. + +|`const_reverse_iterator rbegin () const` |https://www.boost.org/sgi/stl/ReversibleContainer.html[Reversible Container] |Returns a `const_reverse_iterator` pointing to the beginning of the reversed `bounded_array`. + +|`const_reverse_iterator rend () const` |https://www.boost.org/sgi/stl/ReversibleContainer.html[Reversible Container] |Returns a `const_reverse_iterator` pointing to the end of the reversed `bounded_array`. + +|`reverse_iterator rbegin ()` |https://www.boost.org/sgi/stl/ReversibleContainer.html[Reversible Container] |Returns a `reverse_iterator` pointing to the beginning of the reversed `bounded_array`. + +|`reverse_iterator rend ()` |https://www.boost.org/sgi/stl/ReversibleContainer.html[Reversible Container] |Returns a `reverse_iterator` pointing to the end of the reversed `bounded_array`. + +|=== +''''' + +Copyright (©) 2000-2004 Michael Stevens, Mathias Koch, Joerg Walter, +Gunter Winkler + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/container_concept.adoc b/doc/ublas/container_concept.adoc new file mode 100644 index 000000000..1c03e729a --- /dev/null +++ b/doc/ublas/container_concept.adoc @@ -0,0 +1,395 @@ +== Container Concepts + +[[toc]] + +=== [#vector]#Vector# + +==== Description + +A Vector describes common aspects of dense, packed and sparse vectors. + +==== Refinement of + +https://www.boost.org/sgi/stl/DefaultConstructible.html[DefaultConstructible], +link:expression_concept.html#vector_expression[Vector Expression] +link:#vector_expression_note[[1]]. + +==== Associated types + +In addition to the types defined by +link:expression_concept.adoc#vector_expression[Vector Expression] + +[cols=",,",] +|=== +|Public base |vector_container |V must be derived from this public +base type. + +|Storage array |V::array_type |Dense Vector ONLY. The type of underlying +storage array used to store the elements. The array_type must model the +link:storage_concept.adoc[*Storage*] concept. +|=== + +==== Notation + +[cols=",",] +|=== +|`V` |A type that is a model of Vector +|`v` |Objects of type `V` +|`n, i` |Objects of a type convertible to `size_type` +|`t` |Object of a type convertible to `value_type` +|`p` |Object of a type convertible to `bool` +|=== + +==== Definitions + +==== Valid expressions + +In addition to the expressions defined in +https://www.boost.org/sgi/stl/DefaultConstructible.html[DefaultConstructible], +link:expression_concept.adoc#vector_expression[Vector Expression] the +following expressions must be valid. + +[width="100%",cols="25%,25%,25%,25%",] +|=== +|Name |Expression |Type requirements |Return type + +|Sizing constructor |`V v (n)` |  |`V` + +|Insert |`v.insert_element (i, t)` |`v` is mutable. |`void` + +|Erase |`v.erase_element (i)` |`v` is mutable. |`void` + +|Clear |`v.clear ()` |`v` is mutable. |`void` + +|Resize |`v.resize (n)` + +`v.resize (n, p)` |`v` is mutable. |`void` + +|Storage |`v.data()` |`v` is mutable and Dense. |`array_type&` if `v` is +mutable, `const array_type&` otherwise +|=== + +==== Expression semantics + +Semantics of an expression is defined only where it differs from, or is +not defined in link:expression_concept.adoc#vector_expression[Vector +Expression] . + +[width="100%",cols=",,,,",options="header",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition +|Sizing constructor |`V v (n)` |`n >= 0` |Allocates a vector of `n` +elements. |`v.size () == n`. + +|Element access link:#element_access_note[[2]] |`v[n]` |`0v.size()` +|returns the n-th element in v |  + +|Insert |`v.insert_element (i, t)` |`0 < = i < v.size ()`. |Inserts an +element at `v (i)` with value `t`. The storage requirement of the Vector +may be increased. |`v (i)` is equal to `t`. + +|Erase |`v.erase_element (i)` |`0 < = i < v.size ()` |Destroys the +element as `v (i)` and replaces it with the default `value_type ()`. The +storage requirement of the Vector may be decreased. |`v (i)` is equal to +`value_type ()`. + +|Clear |`v.clear ()` |  |Equivalent to + +`for (i = 0; i < v.size (); ++ i)` + +  `v.erase_element (i);` |  + +|Resize |`v.resize (n) v.resize (n, p)` |  |Reallocates the vector so +that it can hold `n` elements. + +Erases or appends elements in order to bring the vector to the +prescribed size. Appended elements copies of `value_type()`. + +When `p == false` then existing elements are not preserved and elements +will not appended as normal. Instead the vector is in the same state as +that after an equivalent sizing constructor. |`v.size () == n`. + +|Storage |`v.data()` | |Returns a reference to the underlying dense +storage. |  +|=== + +==== Complexity guarantees + +The run-time complexity of the sizing constructor is linear in the +vector's size. + +The run-time complexity of insert_element and erase_element is specific +for the Vector model and it depends on increases/decreases in storage +requirements. + +The run-time complexity of resize is linear in the vector's size. + +==== Invariants + +==== Models + +* `vector`, `bounded_vector`, `c_vector` +* `unit_vector`, `zero_vector`, `scalar_vector` +* `mapped_vector;`, `compressed_vector`, `coordinate_vector` + +==== Notes + +[#vector_expression_note]#[1]# As a user you need not care about Vector +being a refinement of the VectorExpression. Being a refinement of the +VectorExpression is only important for the template-expression engine +but not the user. + +[#element_access_note]#[2]# The `operator[]` is added purely for +convenience and compatibility with the `std::vector`. In uBLAS however, +generally `operator()` is used for indexing because this can be used for +both vectors and matrices. + +''''' + +=== [#matrix]#Matrix# + +==== Description + +A Matrix describes common aspects of dense, packed and sparse matrices. + +==== Refinement of + +https://www.boost.org/sgi/stl/DefaultConstructible.html[DefaultConstructible], +link:expression_concept.adoc#matrix_expression[Matrix Expression] +link:#matrix_expression_note[[1]] . + +==== Associated types + +In addition to the types defined by +link:expression_concept.adoc#matrix_expression[Matrix Expression] + +[cols=",,",] +|=== +|Public base |matrix_container |M must be derived from this public +base type. + +|Storage array |M::array_type |Dense Matrix ONLY. The type of underlying +storage array used to store the elements. The array_type must model the +link:storage_concept.adoc[*Storage*] concept. +|=== + +==== Notation + +[cols=",",] +|=== +|`M` |A type that is a model of Matrix +|`m` |Objects of type `M` +|`n1, n2, i, j` |Objects of a type convertible to `size_type` +|`t` |Object of a type convertible to `value_type` +|`p` |Object of a type convertible to `bool` +|=== + +==== Definitions + +==== Valid expressions + +In addition to the expressions defined in +link:expression_concept.adoc#matrix_expression[Matrix Expression] the +following expressions must be valid. + +[width="100%",cols="25%,25%,25%,25%",] +|=== +|Name |Expression |Type requirements |Return type + +|Sizing constructor |`M m (n1, n2)` |  |`M` + +|Insert |`m.insert_element (i, j, t)` |`m` is mutable. |`void` + +|Erase |`m.erase_element (i, j)` |`m` is mutable. |`void` + +|Clear |`m.clear ()` |`m` is mutable. |`void` + +|Resize |`m.resize (n1, n2)` + +`m.resize (n1, n2, p)` |`m` is mutable. |`void` + +|Storage |`m.data()` |`m` is mutable and Dense. |`array_type&` if `m` is +mutable, `const array_type&` otherwise +|=== + +==== Expression semantics + +Semantics of an expression is defined only where it differs from, or is +not defined in link:expression_concept.adoc#matrix_expression[Matrix +Expression] . + +[width="100%",cols=",,,,",options="header",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition + +|Sizing constructor |`M m (n1, n2)` |`n1 >= 0` and `n2 >= 0` |Allocates a matrix of `n1` rows and `n2` columns. |`m.size1 () == n1` and `m.size2 () == n2`. + +|Insert |`m.insert_element (i, j, t)` |`0 < = i < m.size1 ()`, + `0 < = j < m.size2 ()`. |Inserts an element at `m (i, j)` with value `t`. The storage requirement of the Matrix may be increased. `m (i, j)` is equal to `t`. |`m(i,j)` is equal to `t`. + +|Erase |`m.erase_element (i, j)` |`0 <= i < m.size1 ()`and ` 0 <= j < m.size2` |Destroys the element as `m (i, j)` and replaces it with the default `value_type ()`. The storage requirement of the Matrix may be decreased. |`m (i, j)` is equal to `value_type ()`. + +|Clear |`m.clear ()` | |Equivalent to + +`for (i = 0; i < m.size1 (); ++ i) + +  for (j = 0; j < m.size2 (); ++ j) + +    m.erase_element (i, j);` | + +|Resize |`m.resize (n1, n2) m.resize (n1, n2, p)` | |Reallocate the matrix so that it can hold `n1` rows and `n2` columns. + +Erases or appends elements in order to bring the matrix to the +prescribed size. Appended elements are `value_type()` copies. + +When `p == false` then existing elements are not preserved and elements +will not appended as normal. Instead the matrix is in the same state as +that after an equivalent sizing constructor. |`m.size1 () == n1` and `m.size2 () == n2`. + +|Storage |`m.data()` | |Returns a reference to the underlying dense storage. | + +|=== +  + +==== Complexity guarantees + +The run-time complexity of the sizing constructor is quadratic in the +matrix's size. + +The run-time complexity of insert_element and erase_element is specific +for the Matrix model and it depends on increases/decreases in storage +requirements. + +The run-time complexity of resize is quadratic in the matrix's size. + +==== Invariants + +==== Models + +* `matrix`, `bounded_matrix`, `c_matrix` +* `identity_matrix` , `zero_matrix` , `scalar_matrix` +* `triangular_matrix` , `symmetric_matrix` , `banded_matrix` +* `mapped_matrix` , `compressed_matrix` , `coordinate_matrix` + +==== Notes + +[#matrix_expression_note]#[1]# As a user you need not care about Matrix +being a refinement of the MatrixExpression. Being a refinement of the +MatrixExpression is only important for the template-expression engine +but not the user. + +''''' + +=== [#tensor]#Tensor# + +==== Description + +A Tensor describes common aspects of dense multidimensional arrays. + +==== Refinement of + +https://www.boost.org/sgi/stl/DefaultConstructible.html[DefaultConstructible], +link:expression_concept.adoc#tensor_expression[Tensor Expression] +link:#tensor_expression_note[[1]] . + +==== Associated types + +In addition to the types defined by +link:expression_concept.adoc#tensor_expression[Tensor Expression] + +[cols=",,",] +|=== +|Public base |`tensor_container` |`tensor_t` must be derived +from this public base type. + +|Storage array |`tensor_t::array_type` |Dense tensor ONLY. The type of +underlying storage array used to store the elements. The array_type must +model the link:storage_concept.adoc[*Storage*] concept. +|=== + +==== Notation + +[cols=",",] +|=== +|`tensor_t` |A type that is a model of Tensor + +|`t` |Objects of type `tensor_t` + +|`n1, n2, np, m1, m2, mq ` |Dimension objects of a type convertible to +`size_type` + +|`i1, i2, ip, j, k ` |Index objects of a type convertible to `size_type` + +|`v` |Object of a type convertible to `value_type` +|=== + +==== Definitions + +==== Valid expressions + +In addition to the expressions defined in +link:expression_concept.adoc#tensor_expression[Tensor Expression] the +following expressions must be valid. + +[cols=",,,",] +|=== +|Name |Expression |Type requirements |Return type + +|Sizing constructor |`T t(n1, n2, ..., np)` |  |`T` + +|Write |`t.at(i1, i2, ..., ip)` |`t` is mutable. |`void` + +|Read |`t.at(i1, i2, ..., ip)` |`t` is mutable. |`v` + +|Clear |`t.clear ()` |`t` is mutable. |`void` + +|Resize |`t.resize(m1, m2, ... , mq)` |`t` is mutable. |`void` + +|Storage |`t.data()` |`t` is mutable and dense. |`pointer` if `t` is +mutable, `const_pointer` otherwise +|=== + +==== Expression semantics + +Semantics of an expression is defined only where it differs from, or is +not defined in link:expression_concept.adoc#tensor_expression[Tensor +Expression] . + +[width="100%",cols=",,,,",options="header",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition + +|Sizing constructor |`T t(n1, n2, ..., np)` |`__n__~_r_~` > =1 for 1< = 1 < = p |Allocates a `p` -order tensor with dimension extents `__n__~_1_~, __n__~_2_~, .... __n__~_p_~`. |`t.size(r)==nr` for 1 < = r < = p. + +|Write |`t.at(i1,i2,...,ip)=v` |0 < = `__i__~_r_~` < `__n__~_r_~` for 1 < = r < = p. |Writes an element at multi-index position `__i__~_1_~, __i__~_2_~, ... __i__~_p_~` with value `v`. |`t(i1,i2,...,ip)` is equal to `v`. + +|Read |`v=t.at(i1,i2,...,ip)` |0 < = `__i__~_r_~` < `__n__~_r_~` for 1 < = r < = p. |Reads the element at multi-index position `__i__~_1_~, __i__~_2_~, ... __i__~_p_~` and returns a value `v`. |`t(i1,i2,...,ip)` is equal to `v`. + +|Clear |`t.clear()` | |Removes all elements from the container. | + +|Resize |`t.resize(m1, m2, ..., mq)` |`__m__~_r_~` > = 1 for 1 < = 1 < = q |Reallocate the matrix so that it can hold `__m__~_1_~ x __m__~_2_~ x ... __m__~_q_~` elements. + Erases or appends elements in order to bring the matrix to the prescribed size. Appended elements are `value_type()` copies. |`t.size(r) == mr` for 1 < = r < = q. + +|Storage |`m.data()` | |Returns a reference to the underlying dense storage.| | + +|=== + +==== Complexity guarantees + +The run-time complexity of contructor is linear in the tensor's size +`__n__~_1_~ x __n__~_2_~ x ... __n__~_p_~`. + +The run-time complexity of `write()` and `read()` is linear in the order +of the tensor. + +The run-time complexity of resize is at most linear in the tensor's size +`__m__~_1_~ x __m__~_2_~ x ... __n__~_q_~`. + +==== Invariants + +==== Models + +* `tensor` + +==== Notes + +[#tensor_expression_note]#[1]# As a user you need not care about Tensor +being a refinement of the TensorExpression. Being a refinement of the +TensorExpression is only important for the template-expression engine +but not the user. + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2018 Cem Bassoy + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/expression_concept.adoc b/doc/ublas/expression_concept.adoc new file mode 100644 index 000000000..3270e48ce --- /dev/null +++ b/doc/ublas/expression_concept.adoc @@ -0,0 +1,604 @@ +== Expression Concepts + +[[toc]] + +=== [#scalar_expression]#Scalar Expression# + +==== Description + +A Scalar Expression is an expression convertible to a scalar type. + +==== Refinement of + +Default Constructible. + +==== Associated types + +[cols=",,",] +|=== +|Public base |scaler_expression |S must be derived from this public +base type. + +|Value type |`value_type` |The type of the scalar expression. +|=== + +==== Notation + +[cols=",",] +|=== +|`S` |A type that is a model of Scalar Expression +|=== + +==== Definitions + +==== Valid expressions + +In addition to the expressions defined in Default Constructible the +following expressions must be valid. + +[cols=",,,",] +|=== +|Name |Expression |Type requirements |Return type +|Evaluation |`operator value_type () const` |  |`value_type` +|=== + +==== Expression semantics + +Semantics of an expression is defined only where it differs from, or is +not defined in Default Constructible. + +[cols=",,,,",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition + +|Evaluation |`operator value_type () const` |  |  Evaluates the scalar +expression. |  +|=== + +==== Complexity guarantees + +The run-time complexity of the evaluation is specific for the evaluated +scalar expression. + +==== Invariants + +==== Models + +* `vector_scalar_unary` +* `vector_scalar_binary` + +=== [#vector_expression]#Vector Expression# + +==== Description + +A Vector Expression is an expression evaluatable to a vector. Vector +Expression provides an +link:iterator_concept.html#indexed_bidirectional_iterator[Indexed +Bidirectional Iterator] or an +link:iterator_concept.html#indexed_random_access_iterator[Indexed Random +Access Iterator] . + +==== Refinement of + +Default Constructible. + +==== Associated types + +[width="100%",cols="34%,33%,33%",] +|=== +|Public base |vector_expression |V must be derived from this public +base type. + +|Value type |`value_type` |The element type of the vector expression. + +|Reference type |`reference` |The return type when accessing an element +of a vector expression. + +Convertable to a`value_type`. + +|Const reference type |`const_reference` |The return type when accessing +an element of a constant vector expression. + +Convertable to a`value_type`. + +|Size type |`size_type` |The index type of the vector expression. Am +unsigned integral type used to represent size and index values. + +Can represent any nonnegative value of `difference_type`. + +|Distance type |`difference_type` |A signed integral type used to +represent the distance between two of the vector expression's iterators. + +|Const iterator type |`const_iterator` |A type of iterator that may be +used to examine a vector expression's elements. + +|Iterator type |`iterator` |A type of iterator that may be used to +modify a vector expression's elements. + +|Const reverse iterator type |`const_reverse_iterator` |A Reverse +Iterator adaptor whose base iterator type is the vector expression's +const iterator type. + +|Reverse iterator type |`reverse_iterator` |A Reverse Iterator adaptor +whose base iterator type is the vector expression's iterator type. +|=== + +==== Notation + +[cols=",",] +|=== +|`V` |A type that is a model of Vector Expression +|`v, v1, v2` |Object of type `V` +|`i` |Object of a type convertible to `size_type` +|`t` |Object of a type convertible to `value_type` +|=== + +==== Definitions + +==== Valid expressions + +In addition to the expressions defined in Default Constructible the +following expressions must be valid. + +[cols=",,,",] +|=== +|Name |Expression |Type requirements |Return type + +|Beginning of range |`v.begin ()` |  |`const_iterator` + +| |`v.begin ()` |`v` is mutable. |`iterator` + +|End of range |`v.end ()` |  |`const_iterator` + +| |`v.end ()` |`v` is mutable. |`iterator` + +|Size |`v.size ()` |  |`size_type` + +|Swap |`v1.swap (v2)` |`v1` and `v2` are mutable. |`void` + +|Beginning of reverse range |`v.rbegin ()` |  |`const_reverse_iterator` + +| |`v.rbegin ()` |`v` is mutable. |`reverse_iterator` + +|End of reverse range |`v.rend ()` |  |`const_reverse_iterator` + +| |`v.rend ()` |`v` is mutable. |`reverse_iterator` + +|Element access |`v (i)` |`i` is convertible to `size_type`. +|Convertible to `value_type`. + +|Assignment |`v2 = v1` |`v2` is mutable and `v1` is convertible to `V`. +|`V &` + +| |`v2.assign (v1)` |`v2` is mutable and `v1` is convertible to `V`. +|`V &` + +|Computed assignment |`v2 += v1` |`v2` is mutable and `v1` is +convertible to `V`. |`V &` + +| |`v2.plus_assign (v1)` |`v2` is mutable and `v1` is convertible to +`V`. |`V &` + +| |`v2 -= v1` |`v2` is mutable and `v1` is convertible to `V`. |`V &` + +| |`v2.minus_assign (v1)` |`v2` is mutable and `v1` is convertible to +`V`. |`V &` + +| |`v *= t` |`v` is mutable and `t` is convertible to `value_type`. +|`V &` +|=== + +==== Expression semantics + +Semantics of an expression is defined only where it differs from, or is +not defined in Default Constructible. + +[cols=",,,,",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition + +|Beginning of range |`v.begin ()` |  |Returns an iterator pointing to +the first element in the vector expression. |`v.begin ()` is either +dereferenceable or past-the-end. It is past-the-end if and only if +`v.size () == 0`. + +|End of range |`v.end ()` |  |Returns an iterator pointing one past the +last element in the vector expression. |`v.end ()` is past-the-end. + +|Size |`v.size ()` |  |Returns the size of the vector expression, that +is, its number of elements. |`v.size () >= 0` + +|Swap |`v1.swap (v2)` |  |Equivalent to `swap (v1, v2)`. |  + +|Beginning of reverse range |`v.rbegin ()` |  |Equivalent to +`reverse_iterator (v.end ())`. |`v.rbegin ()` is either dereferenceable +or past-the-end. It is past-the-end if and only if `v.size () == 0`. + +|End of reverse range |`v.rend ()` |  |Equivalent to +`reverse_iterator (v.begin ())`. |`v.rend ()` is past-the-end. + +|Element access |`v (i)` |`0 <= i < v.size ()` |Returns the `i`-th +element of the vector expression. |  + +|Assignment |`v2 = v1` |`v1.size () == v2.size ()` |Assigns every +element of the evaluated vector expression `v1` to the corresponding +element of `v2` . |  + +| |`v2.assign (v1)` |`v1.size () == v2.size ()` |Assigns every element +of `v1` to the corresponding element of `v2`. |  + +|Computed assignment |`v2 += v1` |`v1.size () == v2.size ()` |Adds every +element of the evaluated vector expression `v1` to the corresponding +element of `v2`. |  + +| |`v2.plus_assign (v1)` |`v1.size () == v2.size ()` |Adds every element +of `v1` to the corresponding element of `v2`. |  + +| |`v2 -= v1` |`v1.size () == v2.size ()` |Subtracts every element of +the evaluated vector expression `v1` from the corresponding element of +`v2` . |  + +| |`v2.minus_assign (v1)` |`v1.size () == v2.size ()` |Subtracts every +element of `v1` from the corresponding element of `v2`. |  + +| |`v *= t` |  |Multiplies every element of `v` with `t` . |  +|=== + +==== Complexity guarantees + +The run-time complexity of `begin ()` and `end ()` is specific for the +evaluated vector expression, typically amortized constant time. + +The run-time complexity of `size ()` is constant time. + +The run-time complexity of `swap ()` is specific for the evaluated +vector expression, typically constant time. + +The run-time complexity of `rbegin ()` and `rend ()` is specific for the +evaluated vector expression, typically amortized constant time. + +The run-time complexity of the element access is specific for the +evaluated vector expression, typically amortized constant time for the +dense and logarithmic for the sparse case. + +The run-time complexity of the arithmetic operations is specific for the +evaluated vector expressions, typically linear in the size of the +expressions. + +==== Invariants + +[cols=",",] +|=== +|Valid range |For any vector expression `v`, `[v.begin (), v.end ())` is +a valid range. + +|Completeness |An algorithm that iterates through the range +`[v.begin (), v.end ())` will pass through every element of `v` . + +|Valid reverse range |`[v.rbegin (), v.rend ())` is a valid range. + +|Equivalence of ranges |The distance from `v.begin ()` to `v.end ()` is +the same as the distance from `v.rbegin ()` to `v.rend ()`. +|=== + +==== Models + +* `vector_range;` +* `vector_slice` +* `matrix_row` +* `matrix_column` +* `matrix_vector_range` +* `matrix_vector_slice` +* `vector_unary` +* `vector_binary` +* `vector_binary_scalar1` +* `vector_binary_scalar2` +* `matrix_vector_unary1` +* `matrix_vector_unary2` +* `matrix_vector_binary1` +* `matrix_vector_binary2` + +=== [#matrix_expression]#Matrix Expression# + +==== Description + +A Matrix Expression is an expression evaluatable to a matrix. Matrix +Expression provides an +link:iterator_concept.html#indexed_bidirectional_cr_iterator[Indexed +Bidirectional Column/Row Iterator] or an +link:iterator_concept.html#indexed_random_access_cr_iterator[Indexed +Random Access Column/Row Iterator] . + +==== Refinement of + +Default Constructible. + +==== Associated types + +===== immutable types + +[width="100%",cols="34%,33%,33%",] +|=== +|Public base |`matrix_expression` |M must be derived from this public +base type. + +|Value type |`value_type` |The element type of the matrix expression. + +|Const reference type |`const_reference` |The return type when accessing +an element of a constant matrix expression. + +Convertable to a `value_type`. + +|Size type |`size_type` |The index type of the matrix expression. Am +unsigned integral type used to represent size and index values. + +Can represent any nonnegative value of `difference_type`. + +|Distance type |`difference_type` |A signed integral type used to +represent the distance between two of the matrix expression's iterators. + +|Const iterator types |`const_iterator1` |A type of column iterator that +may be used to examine a matrix expression's elements. + +| |`const_iterator2` |A type of row iterator that may be used to examine +a matrix expression's elements. + +|Const reverse iterator types |`const_reverse_iterator1` |A Reverse +Iterator adaptor whose base iterator type is the matrix expression's +const column iterator type. + +| |`const_reverse_iterator2` |A Reverse Iterator adaptor whose base +iterator type is the matrix expression's const row iterator type. +|=== + +===== mutable types + +[width="100%",cols="34%,33%,33%",] +|=== +|Reference type |`reference` |The return type when accessing an element +of a matrix expression. + +Convertable to a `value_type`. + +|Iterator types |`iterator1` |A type of column iterator that may be used +to modify a matrix expression's elements. + +| |`iterator2` |A type of row iterator that may be used to modify a +matrix expression's elements. + +|Reverse iterator types |`reverse_iterator1` |A Reverse Iterator adaptor +whose base iterator type is the matrix expression's column iterator +type. + +| |`reverse_iterator2` |A Reverse Iterator adaptor whose base iterator +type is the matrix expression's row iterator type. +|=== + +==== Notation + +[cols=",",] +|=== +|`M` |A type that is a model of Matrix Expression +|`m, m1, m2` |Object of type `M` +|`i, j` |Objects of a type convertible to `size_type` +|`t` |Object of a type convertible to `value_type` +|=== + +==== Definitions + +==== Valid expressions + +In addition to the expressions defined in Default Constructible the +following expressions must be valid. + +===== immutable expressions + +[cols=",,,",options="header",] +|=== +|Name |Expression |Type requirements |Return type +|Size |`m.size1 ()` |  |`size_type` +| |`m.size2 ()` |  |`size_type` +|=== + +===== possibly mutable expressions + +[cols=",,,",] +|=== +|Name |Expression |Type requirements |Return type + +|Beginning of range |`m.begin1 ()` |  |`const_iterator1` + +| |`m.begin2 ()` |  |`const_iterator2` + +| |`m.begin1 ()` |`m` is mutable.  |`iterator1` + +| |`m.begin2 ()` |`m` is mutable. |`iterator2` + +|End of range |`m.end1 ()` |  |`const_iterator1` + +| |`m.end2 ()` |  |`const_iterator2` + +| |`m.end1 ()` |`m` is mutable.  |`iterator1` + +| |`m.end2 ()` |`m` is mutable. |`iterator2` + +|Swap |`m1.swap (m2)` |`m1` and `m2` are mutable.  |`void` + +|Beginning of reverse range |`m.rbegin1 ()` |  +|`const_reverse_iterator1` + +| |`m.rbegin2 ()` |  |`const_reverse_iterator2` + +| |`m.rbegin1 ()` |`m` is mutable.  |`reverse_iterator1` + +| |`m.rbegin2 ()` |`m` is mutable. |`reverse_iterator2` + +|End of reverse range |`m.rend1 ()` |  |`const_reverse_iterator1` + +| |`m.rend2 ()` |  |`const_reverse_iterator2` + +| |`m.rend1 ()` |`m` is mutable. |`reverse_iterator1` + +| |`m.rend2 ()` |`m` is mutable. |`reverse_iterator2` + +|Element access |`m (i, j)` |`i` and `j` are convertible to `size_type` +. |Convertible to `value_type`. + +|Assignment |`m2 = m1` |`m2` is mutable and `m1` is convertible to `M`. +|`M &` + +| |`m2.assign (m1)` |`m2` is mutable and `m1` is convertible to `M`. +|`M &` + +|Computed assignment |`m2 += m1` |`m2` is mutable and `m1` is +convertible to `M`. |`M &` + +| |`m2.plus_assign (m1)` |`m2` is mutable and `m1` is convertible to +`M`. |`M &` + +| |`m2 -= m1` |`m2` is mutable and `m1` is convertible to `M`. |`M &` + +| |`m2.minus_assign (m1)` |`m2` is mutable and `m1` is convertible to +`M`. |`M &` + +| |`m *= t` |`m` is mutable and `t` is convertible to `value_type`. +|`M &` +|=== + +==== Expression semantics + +Semantics of an expression is defined only where it differs from, or is +not defined in Default Constructible. + +[cols=",,,,",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition + +|Beginning of range |`m.begin1 ()` |  |Returns an iterator pointing to +the first element in the first column of a matrix expression. +|`m.begin1 ()` is either dereferenceable or past-the-end. It is +past-the-end if and only if `m.size1 () == 0`. + +| |`m.begin2 ()` |  |Returns an iterator pointing to the first element +in the first row of a matrix expression. |`m.begin2 ()` is either +dereferenceable or past-the-end. It is past-the-end if and only if +`m.size2 () == 0`. + +|End of range |`m.end1 ()` |  |Returns an iterator pointing one past the +last element in the matrix expression. |`m.end1 ()` is past-the-end. + +| |`m.end2 ()` |  |Returns an iterator pointing one past the last +element in the matrix expression. |`m.end2 ()` is past-the-end. + +|Size |`m.size1 ()` |  |Returns the number of rows of the matrix +expression. |`m.size1 () >= 0` + +| |`m.size2 ()` |  |Returns the number of columns of the matrix +expression. |`m.size2 () >= 0` + +|Swap |`m1.swap (m2)` |  |Equivalent to `swap (m1, m2)`. |  + +|Beginning of reverse range |`m.rbegin1 ()` |  |Equivalent to +`reverse_iterator1 (m.end1 ())`. |`m.rbegin1 ()` is either +dereferenceable or past-the-end. It is past-the-end if and only if +`m.size1 () == 0`. + +| |`m.rbegin2 ()` |  |Equivalent to `reverse_iterator2 (m.end2 ())`. +|`m.rbegin2 ()` is either dereferenceable or past-the-end. It is +past-the-end if and only if `m.size2 () == 0`. + +|End of reverse range |`m.rend1 ()` |  |Equivalent to +`reverse_iterator1 (m.begin1 ())`. |`m.rend1 ()` is past-the-end. + +| |`m.rend2 ()` |  |Equivalent to `reverse_iterator2 (m.begin2 ())`. +|`m.rend2 ()` is past-the-end. + +|Element access |`m (i, j)` |`0 <= i < m.size1 ()` and +`0 <= j < m.size2 ()` |Returns the `j`-th element of the `i`-th row of +the matrix expression. |  + +|Assignment |`m2 = m1` |`m1.size1 () == m2.size1 ()` and +` m1.size2 () == m2.size2 ()` |Assigns every element of the evaluated +matrix expression `m1` to the corresponding element of `m2` . |  + +| |`m2.assign (m1)` |`m1.size1 () == m2.size1 ()` and +` m1.size2 () == m2.size2 ()` |Assigns every element of `m1` to the +corresponding element of `m2`. |  + +|Computed assignment |`m2 += m1` |`m1.size1 () == m2.size1 ()` and +` m1.size2 () == m2.size2 ()` |Adds every element of the evaluated +matrix expression `m1` to the corresponding element of `m2`. |  + +| |`m2.plus_assign (m1)` |`m1.size1 () == m2.size1 ()` and +` m1.size2 () == m2.size2 ()` |Adds every element of `m1` to the +corresponding element of `m2`. |  + +| |`m2 -= m1` |`m1.size1 () == m2.size1 ()` and +` m1.size2 () == m2.size2 ()` |Subtracts every element of the evaluated +matrix expression `m1` from the corresponding element of `m2` . |  + +| |`m2.minus_assign (m1)` |`m1.size1 () == m2.size1 ()` and +` m1.size2 () == m2.size2 ()` |Subtracts every element of `m1` from the +corresponding element of `m2`. |  + +| |`m *= t` |  |Multiplies every element of `m` with `t` . |  +|=== + +==== Complexity guarantees + +The run-time complexity of `begin1 ()`, `begin2 ()` , `end1 ()` and +`end2 ()` is specific for the evaluated matrix expression. + +The run-time complexity of `size1 ()` and `size2 ()` is constant time. + +The run-time complexity of `swap ()` is specific for the evaluated +matrix expression, typically constant time. + +The run-time complexity of `rbegin1 ()`, `rbegin2 ()` , `rend1 ()` and +`rend2 ()` is specific for the evaluated matrix expression. + +The run-time complexity of the element access is specific for the +evaluated matrix expression, typically amortized constant time for the +dense and logarithmic for the sparse case. + +The run-time complexity of the arithmetic operations is specific for the +evaluated matrix expressions, typically quadratic in the size of the +proxies. + +==== Invariants + +[cols=",",] +|=== +|Valid range |For any matrix expression `m`, `[m.begin1 (), m.end1 ())` +and `[m.begin2 (), m.end2 ())` are valid ranges. + +|Completeness |An algorithm that iterates through the range +`[m.begin1 (), m.end1 ())` will pass through every row of `m` , an +algorithm that iterates through the range `[m.begin2 (), m.end2 ())` +will pass through every column of `m` . + +|Valid reverse range |`[m.rbegin1 (), m.rend1 ())` and +`[m.rbegin2 (), m.rend2 ())` are valid ranges. + +|Equivalence of ranges |The distance from `m.begin1 ()` to `m.end1 ()` +is the same as the distance from `m.rbegin1 ()` to `m.rend1 ()` and the +distance from `m.begin2 ()` to `m.end2 ()` is the same as the distance +from `m.rbegin2 ()` to `m.rend2 ()`. +|=== + +==== Models + +* `matrix_range` +* `matrix_slice;` +* `triangular_adaptor` +* `symmetric_adaptor` +* `banded_adaptor` +* `vector_matrix_binary` +* `matrix_unary1` +* `matrix_unary2` +* `matrix_binary` +* `matrix_binary_scalar1` +* `matrix_binary_scalar2` +* `matrix_matrix_binary` + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/hermitian.adoc b/doc/ublas/hermitian.adoc new file mode 100644 index 000000000..4634816cd --- /dev/null +++ b/doc/ublas/hermitian.adoc @@ -0,0 +1,409 @@ +== Hermitian Matrix + +[[toc]] + +=== [#hermitian_matrix]#Hermitian Matrix# + +==== Description + +The templated class `hermitian_matrix` is the base +container adaptor for hermitian matrices. For a _(n x n_ )-dimensional +hermitian matrix and _0 < = i < n_, _0 < = j < n_ holds __h__~_i,j_~= +__h__~_j,i_~^_-_^. The storage of hermitian matrices is packed. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + hermitian_matrix, lower> ml (3, 3); + for (unsigned i = 0; i < ml.size1 (); ++ i) { + for (unsigned j = 0; j < i; ++ j) + ml (i, j) = std::complex (3 * i + j, 3 * i + j); + ml (i, i) = std::complex (4 * i, 0); + } + std::cout << ml << std::endl; + hermitian_matrix, upper> mu (3, 3); + for (unsigned i = 0; i < mu.size1 (); ++ i) { + mu (i, i) = std::complex (4 * i, 0); + for (unsigned j = i + 1; j < mu.size2 (); ++ j) + mu (i, j) = std::complex (3 * i + j, 3 * i + j); + } + std::cout << mu << std::endl; +} +.... + +==== Definition + +Defined in the header hermitian.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the matrix. | + +|`F1` |Functor describing the type of the hermitian matrix. +link:#hermitian_matrix_1[[1]] |`lower` + +|`F2` |Functor describing the storage organization. +link:#hermitian_matrix_2[[2]] |`row_major` + +|`A` |The type of the adapted array. link:#hermitian_matrix_3[[3]] +|`unbounded_array` +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`hermitian_matrix ()` |Allocates an uninitialized `hermitian_matrix` +that holds zero rows of zero elements. + +|`hermitian_matrix (size_type size)` |Allocates an uninitialized +`hermitian_matrix` that holds `size` rows of `size` elements. + +|`hermitian_matrix (const hermitian_matrix &m)` |The copy constructor. + +|`template hermitian_matrix (const matrix_expression &ae)` +|The extended copy constructor. + +|`void resize (size_type size, bool preserve = true)` |Reallocates a +`hermitian_matrix` to hold `size` rows of `size` elements. The existing +elements of the `hermitian_matrix` are preseved when specified. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +a `const` reference of the `j` -th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`hermitian_matrix &operator = (const hermitian_matrix &m)` |The +assignment operator. + +|`hermitian_matrix &assign_temporary (hermitian_matrix &m)` |Assigns a +temporary. May change the hermitian matrix `m` . + +|`template hermitian_matrix &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template hermitian_matrix &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the hermitian matrix. Left and right +hand side of the assignment should be independent. + +|`template hermitian_matrix &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +hermitian matrix. + +|`template hermitian_matrix &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the hermitian matrix. Left and right hand +side of the assignment should be independent. + +|`template hermitian_matrix &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the hermitian matrix. + +|`template hermitian_matrix &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the hermitian matrix. Left and right +hand side of the assignment should be independent. + +|`template hermitian_matrix &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the hermitian matrix with a +scalar. + +|`template hermitian_matrix &operator /= (const AT &at)` |A +computed assignment operator. Divides the hermitian matrix through a +scalar. + +|`void swap (hermitian_matrix &m)` |Swaps the contents of the hermitian +matrices. + +|`void insert (size_type i, size_type j, const_reference t)` |Inserts +the value `t` at the `j`-th element of the `i`-th row. + +|`void erase (size_type i, size_type j)` |Erases the value at the `j`-th +elemenst of the `i`-th row. + +|`void clear ()` |Clears the matrix. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `hermitian_matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `hermitian_matrix`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `hermitian_matrix`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`hermitian_matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `hermitian_matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `hermitian_matrix`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `hermitian_matrix`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`hermitian_matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`hermitian_matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`hermitian_matrix`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `hermitian_matrix`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `hermitian_matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`hermitian_matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`hermitian_matrix`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `hermitian_matrix`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `hermitian_matrix`. +|=== + +==== Notes + +[#hermitian_matrix_1]#[1]# Supported parameters for the type of the +hermitian matrix are `lower` and `upper`. + +[#hermitian_matrix_2]#[2]# Supported parameters for the storage +organization are `row_major` and `column_major`. + +[#hermitian_matrix_3]#[3]# Supported parameters for the adapted array +are `unbounded_array` , `bounded_array` and `std::vector` . + +=== [#hermitian_adaptor]#Hermitian Adaptor# + +==== Description + +The templated class `hermitian_adaptor` is a hermitian matrix +adaptor for other matrices. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix > m (3, 3); + hermitian_adaptor >, lower> hal (m); + for (unsigned i = 0; i < hal.size1 (); ++ i) { + for (unsigned j = 0; j < i; ++ j) + hal (i, j) = std::complex (3 * i + j, 3 * i + j); + hal (i, i) = std::complex (4 * i, 0); + } + std::cout << hal << std::endl; + hermitian_adaptor >, upper> hau (m); + for (unsigned i = 0; i < hau.size1 (); ++ i) { + hau (i, i) = std::complex (4 * i, 0); + for (unsigned j = i + 1; j < hau.size2 (); ++ j) + hau (i, j) = std::complex (3 * i + j, 3 * i + j); + } + std::cout << hau << std::endl; +} +.... + +==== Definition + +Defined in the header hermitian.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`M` |The type of the adapted matrix. | + +|`F` |Functor describing the type of the hermitian adaptor. +link:#hermitian_adaptor_1[[1]] |`lower` +|=== + +==== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +==== Public base classes + +`matrix_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`hermitian_adaptor (matrix_type &data)` |Constructs a +`hermitian_adaptor` of a matrix. + +|`hermitian_adaptor (const hermitian_adaptor &m)` |The copy constructor. + +|`template hermitian_adaptor (const matrix_expression &ae)` +|The extended copy constructor. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +a `const` reference of the `j` -th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`hermitian_adaptor &operator = (const hermitian_adaptor &m)` |The +assignment operator. + +|`hermitian_adaptor &assign_temporary (hermitian_adaptor &m)` |Assigns a +temporary. May change the hermitian adaptor `m`. + +|`template hermitian_adaptor &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template hermitian_adaptor &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the hermitian adaptor. Left and right +hand side of the assignment should be independent. + +|`template hermitian_adaptor &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +hermitian adaptor. + +|`template hermitian_adaptor &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the hermitian adaptor. Left and right hand +side of the assignment should be independent. + +|`template hermitian_adaptor &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the hermitian adaptor. + +|`template hermitian_adaptor &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the hermitian adaptor. Left and +right hand side of the assignment should be independent. + +|`template hermitian_adaptor &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the hermitian adaptor with a +scalar. + +|`template hermitian_adaptor &operator /= (const AT &at)` |A +computed assignment operator. Divides the hermitian adaptor through a +scalar. + +|`void swap (hermitian_adaptor &m)` |Swaps the contents of the hermitian +adaptors. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `hermitian_adaptor`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `hermitian_adaptor`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `hermitian_adaptor`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`hermitian_adaptor`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `hermitian_adaptor`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `hermitian_adaptor`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `hermitian_adaptor`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`hermitian_adaptor`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`hermitian_adaptor`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`hermitian_adaptor`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `hermitian_adaptor`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `hermitian_adaptor`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`hermitian_adaptor`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`hermitian_adaptor`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `hermitian_adaptor`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `hermitian_adaptor`. +|=== + +==== Notes + +[#hermitian_adaptor_1]#[1]# Supported parameters for the type of the +hermitian adaptor are `lower` and `upper`. + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/index.adoc b/doc/ublas/index.adoc new file mode 100644 index 000000000..be89ef3c8 --- /dev/null +++ b/doc/ublas/index.adoc @@ -0,0 +1,230 @@ +//// +Copyright 2021 Shikhar Vashistha +Copyright 2021 Cem Bassoy + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +//// + +# Boost.Ublas: The Boost Ublas Library +:toc: left +:toclevels: 2 +:idprefix: +:listing-caption: Code Example +:docinfo: private-footer + +== Basic Linear and Multilinear Algebra Library + +[[toc]] + +uBLAS is a C++ template class library that provides http://www.netlib.org/blas[BLAS] level 1, 2, 3 functionality for dense, packed and sparse matrices. +The design and implementation unify mathematical notation via operator overloading and efficient code generation via expression templates. +Since 2018, uBLAS also supports basic operations for multilinear algebra operations such as the outer and inner product of higher-order tensors. +The goal of the new tensor extension is to provide basic operations that simplify the implementation of e.g. machine learning and quantum computing algorithms. + + +=== Functionality + +uBLAS provides templated C++ classes for dense, unit and sparse vectors, dense, identity, triangular, banded, symmetric, hermitian and sparse matrices. +Views into vectors and matrices can be constructed via ranges, slices, adaptor classes and indirect arrays. +The library covers the usual basic linear and multilinear algebra operations on vectors, matrices and tensors: +reductions like different norms, addition and subtraction of vectors and matrices and multiplication with a scalar, inner and outer products of vectors, matrix vector and matrix matrix products and triangular solver. +Similar operations are also provided for the tensor type. +The glue between containers, views and expression templated operations is a mostly https://en.wikipedia.org/wiki/Standard_Template_Library[STL] conforming iterator interface. + + + +=== Documentation + +* link:overview.html[Overview] +** link:overview.html#rationale[Rationale] +** link:overview.html#functionality[Functionality] +** link:types_overview.html[Overview of Tensor, Matrix- and Vector +Types] +** link:operations_overview.html[Overview of Tensor, Matrix and Vector +Operations] +** link:#further_information[Effective uBLAS and further information] +** link:options.html[Macros and Preprocessor Options] +* link:vector.html[Vector] +** link:vector.html#vector[Vector] +** link:vector.html#unit_vector[Unit Vector] +** link:vector.html#zero_vector[Zero Vector] +** link:vector.html#scalar_vector[Scalar Vector] +* link:vector_sparse.html[Sparse Vector] +** link:vector_sparse.html#mapped_vector[Mapped Vector] +** link:vector_sparse.html#compressed_vector[Compressed Vector] +** link:vector_sparse.html#coordinate_vector[Coordinate Vector] +* link:vector_proxy.html[Vector Proxies] +** link:vector_proxy.html#vector_range[Vector Range] +** link:vector_proxy.html#vector_slice[Vector Slice] +* link:vector_expression.html[Vector Expressions] +** link:vector_expression.html#vector_expression[Vector Expression] +** link:vector_expression.html#vector_references[Vector References] +** link:vector_expression.html#vector_operations[Vector Operations] +** link:vector_expression.html#vector_reductions[Vector Reductions] +* link:matrix.html[Matrix] +** link:matrix.html#matrix[Matrix] +** link:matrix.html#identity_matrix[Identity Matrix] +** link:matrix.html#zero_matrix[Zero Matrix] +** link:matrix.html#scalar_matrix[Scalar Matrix] +* link:triangular.html[Triangular Matrix] +** link:triangular.html#triangular_matrix[Triangular Matrix] +** link:triangular.html#triangular_adaptor[Triangular Adaptor] +* link:symmetric.html[Symmetric Matrix] +** link:symmetric.html#symmetric_matrix[Symmetric Matrix] +** link:symmetric.html#symmetric_adaptor[Symmetric Adaptor] +* link:hermitian.html[Hermitian Matrix] +** link:hermitian.html#hermitian_matrix[Hermitian Matrix] +** link:hermitian.html#hermitian_adaptor[Hermitian Adaptor] +* link:banded.html[Banded Matrix] +** link:banded.html#banded_matrix[Banded Matrix] +** link:banded.html#banded_adaptor[Banded Adaptor] +* link:matrix_sparse.html[Sparse Matrix] +** link:matrix_sparse.html#mapped_matrix[Mapped Matrix] +** link:matrix_sparse.html#compressed_matrix[Compressed Matrix] +** link:matrix_sparse.html#coordinate_matrix[Coordinate Matrix] +* link:matrix_proxy.html[Matrix Proxies] +** link:matrix_proxy.html#matrix_row[Matrix Row] +** link:matrix_proxy.html#matrix_column[Matrix Column] +** link:matrix_proxy.html#vector_range[Vector Range] +** link:matrix_proxy.html#vector_slice[Vector Slice] +** link:matrix_proxy.html#matrix_range[Matrix Range] +** link:matrix_proxy.html#matrix_slice[Matrix Slice] +* link:matrix_expression.html[Matrix Expressions] +** link:matrix_expression.html#matrix_expression[Matrix Expression] +** link:matrix_expression.html#matrix_references[Matrix References] +** link:matrix_expression.html#matrix_operations[Matrix Operations] +** link:matrix_expression.html#matrix_vector_operations[Matrix Vector +Operations] +** link:matrix_expression.html#matrix_matrix_operations[Matrix Matrix +Operations] +* link:tensor.html[Tensor] +** link:tensor.html#tensor[Tensor] +* link:tensor/tensor_expression.html[Tensor Expressions] +** link:tensor/tensor_expression.html#tensor_expression[Tensor +Expression] +** link:tensor/tensor_expression.html#binary_tensor_expression[Binary +Tensor Expression] +** link:tensor/tensor_expression.html#unary_tensor_expression[Unary +Tensor Expression] +* Storage and special containers +** link:unbounded_array.html[Unbounded Array] +** link:bounded_array.html[Bounded Array] +** link:range.html#range[Range] +** link:range.html#slice[Slice] +** link:tensor/extents.html#extents[Extents] +** link:tensor/strides.html#strides[Strides] +* link:storage_sparse.html[Sparse Storage] +** link:storage_sparse.html#map_std[Default Standard Map] +** link:storage_sparse.html#map_array[Map Array] +* Operations & Functions +** link:products.html[Special Products] +** link:blas.html[BLAS] +* uBLAS Concept definitions +** link:container_concept.html[Container Concepts] +*** link:container_concept.html#vector[Vector] +*** link:container_concept.html#matrix[Matrix] +*** link:container_concept.html#tensor[Tensor] +** link:expression_concept.html[Expression Concepts] +*** link:expression_concept.html#scalar_expression[Scalar Expression] +*** link:expression_concept.html#vector_expression[Vector Expression] +*** link:expression_concept.html#matrix_expression[Matrix Expression] +** link:storage_concept.html[Storage Concept] +** link:iterator_concept.html[Iterator Concepts] +*** link:iterator_concept.html#indexed_bidirectional_iterator[Indexed +Bidirectional Iterator] +*** link:iterator_concept.html#indexed_random_access_iterator[Indexed +Random Access Iterator] +*** link:iterator_concept.html#indexed_bidirectional_cr_iterator[Indexed +Bidirectional Column/Row Iterator] +*** link:iterator_concept.html#indexed_random_access_cr_iterator[Indexed +Random Access Column/Row Iterator] + +=== Release notes + +Release notes can be found link:release_notes.html[here]. +[further_information] + +=== Known limitations + +* The implementation assumes a linear memory address model. +* Tuning was focussed on dense matrices. + +=== Further Information + +* https://lists.boost.org/mailman/listinfo.cgi/ublas[uBLAS mailing list] +* https://github.com/boostorg/ublas/wiki[uBLAS wiki] +* https://github.com/boostorg/ublas[Code] + +==== Authors and Credits + +uBLAS initially was written by Joerg Walter and Mathias Koch. +We would like thank all contributors who has supported this library. +Amongst many contributors around the world, David Abrahams, Ed Brey, Fernando Cacciola, Juan Jose Gomez Cadenas, Beman Dawes, Matt Davies, Bob Fletcher, Kresimir Fresl, Joachim Kessel, Patrick Kowalzick, Toon Knapen, Hendrik Kueck, John Maddock, Jens Maurer, Alexei Novakov, Gary Powell, Joachim Pyras, Peter Schmitteckert, Jeremy Siek, Markus Steffl, Michael Stevens, Benedikt Weber, Martin Weiser, Gunter Winkler, Marc Zimmermann, Marco Guazzone, Nasos Iliopoulus and the members of http://www.boost.org[Boost] had a great impact and contribution helping the library to grow and mature. + +Starting with the https://github.com/BoostGSoC18/tensor/wiki[GSoC 2018 project], uBlas has been extended by a flexible tensor data type and basic tensor operations supporting general tensor contractions and the Einstein notation. +The goal of the new tensor extension is to support the implementation of algorithms for e.g. machine learning and quantum computing applications. +The initial implementation of this extension is written by Cem Bassoy. +Contributors of the uBLAS extension are Amit Singh, Ashar Khan, Stefan Seefeld, Cem Bassoy and the members of http://www.boost.org[Boost]. + +This library is currently maintained by David Bellot, Cem Bassoy and Stefan Seefeld. + +=== Frequently Asked Questions + +Q: Should I use uBLAS for new projects? + +A: At the time of writing (09/2012) there are a lot of good matrix +libraries available, e.g., http://www.simunova.com[MTL4], +http://arma.sourceforge.net[armadillo], +http://eigen.tuxfamily.org[eigen]. uBLAS offers a stable, well tested +set of vector and matrix classes, the typical operations for linear +algebra and solvers for triangular systems of equations. uBLAS offers +dense, structured and sparse matrices - all using similar interfaces. +And finally uBLAS offers good (but not outstanding) performance. On the +other side, the last major improvement of uBLAS was in 2008 and no +significant change was committed since 2009. So one should ask himself +some questions to aid the decision: _Availability?_ uBLAS is part of +boost and thus available in many environments. _Easy to use?_ uBLAS is +easy to use for simple things, but needs decent C++ knowledge when you +leave the path. _Performance?_ There are faster alternatives. _Cutting +edge?_ uBLAS is more than 10 years old and missed all new stuff from +C++11. + +Q: I'm running the uBLAS dense vector and matrix benchmarks. Why do I +see a significant performance difference between the native C and +library implementations? + +A: uBLAS distinguishes debug mode (size and type conformance checks +enabled, expression templates disabled) and release mode (size and type +conformance checks disabled, expression templates enabled). Please +check, if the preprocessor symbol `NDEBUG` of `cassert` is defined. +`NDEBUG` enables release mode, which in turn uses expression templates. +You can optionally define `BOOST_UBLAS_NDEBUG` to disable all bounds, +structure and similar checks of uBLAS. + +Q: I've written some uBLAS tests, which try to incorrectly assign +different matrix types or overrun vector and matrix dimensions. Why +don't I get a compile time or runtime diagnostic? + +A: uBLAS distinguishes debug mode (size and type conformance checks +enabled, expression templates disabled) and release mode (size and type +conformance checks disabled, expression templates enabled). Please +check, if the preprocessor symbol `NDEBUG` of `cassert` is defined. +`NDEBUG` disables debug mode, which is needed to get size and type +conformance checks. + +Q: I've written some uBLAS benchmarks to measure the performance of +matrix chain multiplications like `prod (A, prod (B, C))` and see a +significant performance penalty due to the use of expression templates. +How can I disable expression templates? + +A: You do not need to disable expression templates. Please try +reintroducing temporaries using either `prod (A,` `matrix_type` +`(prod (B, C)))` or `prod (A, prod<``matrix_type` `> (B, C))`. + +''''' + +Copyright (©) 2000-2011 Joerg Walter, Mathias Koch, Gunter Winkler, +David Bellot + +Copyright (©) 2021 Shikhar Vashistha + +Copyright (©) 2021 Cem Bassoy + +Use, modification and distribution are 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 ). + diff --git a/doc/ublas/iterator_concept.adoc b/doc/ublas/iterator_concept.adoc new file mode 100644 index 000000000..f89b4ba2e --- /dev/null +++ b/doc/ublas/iterator_concept.adoc @@ -0,0 +1,639 @@ +== Iterator Concepts + +[[toc]] + +An Iterator is a restricted pointer-like object pointing into a vector +or matrix container. + +=== [#indexed_bidirectional_iterator]#Indexed Bidirectional Iterator# + +==== Description + +An Indexed Bidirectional Iterator is an iterator of a container that can +be dereferenced, incremented, decremented and carries index information. + +==== Refinement of + +Assignable, Equality Comparable, Default Constructible. + +==== Associated types + +[cols=",",] +|=== +|Value type |The type of the value obtained by dereferencing a Indexed +Bidirectional Iterator + +|Container type |The type of the container a Indexed Bidirectional +Iterator points into. +|=== + +==== Notation + +[cols=",",] +|=== +|`I` |A type that is a model of Indexed Bidirectional Iterator +|`T` |The value type of `I` +|`C` |The container type of `I` +|`it`, `itt, it1`, `it2` |Objects of type `I` +|`t` |Object of type `T` +|`c` |Object of type `C` +|=== + +==== Definitions + +A Indexed Bidirectional Iterator may be _mutable_, meaning that the +values referred to by objects of that type may be modified, or +_constant_ , meaning that they may not. If an iterator type is mutable, +this implies that its value type is a model of Assignable; the converse, +though, is not necessarily true. + +A Indexed Bidirectional Iterator may have a _singular_ value, meaning +that the results of most operations, including comparison for equality, +are undefined. The only operation that is guaranteed to be supported is +assigning a nonsingular iterator to a singular iterator. + +A Indexed Bidirectional Iterator may have a _dereferenceable_ value, +meaning that dereferencing it yields a well-defined value. +Dereferenceable iterators are always nonsingular, but the converse is +not true. + +An Indexed Bidirectional Iterator is _past-the-end_ if it points beyond +the last element of a container. Past-the-end values are nonsingular and +nondereferenceable. + +==== Valid expressions + +In addition to the expressions defined for Assignable, Equality +Comparable and Default Constructible, the following expressions must be +valid. + +[cols=",,,",] +|=== +|Name |Expression |Type requirements |Return type +|Default constructor |`I it` |  |  +|Dereference |`*it` |  |Convertible to `T`. +|Dereference assignment |`*it = t` |`I` is mutable. |  +|Member access |`it->m` |`T` is a type for which `t.m` is defined. |  +|Preincrement |`++ it` |  |`I &` +|Postincrement |`it ++` |  |`I` +|Predecrement |`-- it` |  |`I &` +|Postdecrement |`it --` |  |`I` +|Index |`it.index ()` |  |`C::size_type` +|=== + +==== Expression Semantics + +Semantics of an expression is defined only where it differs from, or is +not defined in, Assignable, Equality Comparable and Default +Constructible. + +[width="100%",cols="20%,20%,20%,20%,20%",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition + +|Default constructor |`I it` |  |  |`it` is singular. + +|Dereference |`*it` |`it` is dereferenceable. |  |  + +|Dereference assignment |`*it = t` |Same as for `*it`. |  |`*it` is a +copy of t. + +|Member access |`it->m` |`it` is dereferenceable. |Equivalent to +`(*it).m` |  + +|Preincrement |`++ it` |`it` is dereferenceable. |`it` is modified to +point to the next element. |`it` is dereferenceable or past-the-end. +` &it == &++ it`. + +If `it1 == it2`, + +then `++ it1 == ++ it2`. + +|Postincrement |`it ++` |Same as for `++ it`. |Equivalent to + +`{  I itt = it;  ++ it;  return itt; }` |`it` is dereferenceable or +past-the-end. + +|Predecrement |`-- it` |`it` is dereferenceable or past-the-end. + +There exists a dereferenceable iterator `itt` such that `it == ++ itt`. +|`it` is modified to point to the previous element. |`it` is +dereferenceable. + +`&it = &-- it`. + +If `it1 == it2`, + +then `-- it1 == -- it2`. + +If `it2` is dereferenceable and `it1 == ++it2`, + +then `--it1 == it2`. + +|Postdecrement |`it --` |Same as for -- `it`. |Equivalent to + +`{  I itt = it;  -- it;  return itt; }` |`it` is dereferenceable.  + +|Index |`it.index ()` |`it` is dereferenceable. |`it.index () >= 0` + +and + +`it.index () < it ().size ()` |If `it1 == it2`, + +then `it1.index () == it2.index ()`. + +If `it1 == it2`, + +then `it1.index () < (++ it2).index ()`. + +If `it1 == it2`, + +then `it1.index () > (-- it2).index ()`. +|=== + +==== Complexity guarantees + +The complexity of operations on indexed bidirectional iterators is +guaranteed to be amortized constant time. + +==== Invariants + +[cols=",",] +|=== +|Identity |`it1 == it2` if and only if `&*it1 == &*it2`. + +|Symmetry of increment and decrement |If `it` is dereferenceable, then +`++ it; --it;` is a null operation. Similarly, `-- it; ++ it;` is a null +operation. + +|Relation between iterator index and container element operator |If `it` +is dereferenceable, `*it == it () (it.index ())`. +|=== + +==== Models + +* `sparse_vector::iterator` + +=== [#indexed_random_access_iterator]#Indexed Random Access Iterator# + +==== Description + +An Indexed Random Access Iterator is an iterator of a container that can +be dereferenced, moved forward, moved backward and carries index +information. + +==== Refinement of + +LessThanComparable, link:#indexed_bidirectional_iterator[Indexed +Bidirectional Iterator] . + +==== Associated types + +[cols=",",] +|=== +|Value type |The type of the value obtained by dereferencing a Indexed +Random Access Iterator + +|Container type |The type of the container a Indexed Random Access +Iterator points into. +|=== + +==== Notation + +[cols=",",] +|=== +|`I` |A type that is a model of Indexed Random Access Iterator +|`T` |The value type of `I` +|`C` |The container type of `I` +|`it`, `itt, it1`, `it2` |Objects of type `I` +|`t` |Object of type `T` +|`n` |Object of type `C::difference_type` +|=== + +==== Definitions + +An Indexed Random Access Iterator `it1` is _reachable_ from an Indexed +Random Access Iterator `it2` if, after applying `operator ++` to `it2` a +finite number of times, `it1 == it2`. + +==== Valid expressions + +In addition to the expressions defined for +link:#indexed_bidirectional_iterator[Indexed Bidirectional Iterator] , +the following expressions must be valid. + +[cols=",,,",] +|=== +|Name |Expression |Type requirements |Return type +|Forward motion |`it += n` |  |`I &` +|Iterator addition |`it + n` |  |`I` +|Backward motion |`i -= n` |  |`I &` +|Iterator subtraction |`it - n` |  |`I`  +|Difference |`it1 - it2` |  |`C::difference_type` +|Element operator |`it [n]` |  |Convertible to `T`. +|Element assignment |`it [n] = t` |`I` is mutable |Convertible to `T`. +|=== + +==== Expression Semantics + +Semantics of an expression is defined only where it differs from, or is +not defined in, link:#indexed_bidirectional_iterator[Indexed +Bidirectional Iterator] . + +[width="100%",cols="20%,20%,20%,20%,20%",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition + +|Forward motion |`it += n` |Including `it` itself, there must be `n` +dereferenceable or past-the-end iterators following or preceding `it`, +depending on whether `n` is positive or negative. |If `n > 0`, +equivalent to executing `++ it` `n` times. If `n < 0`, equivalent to +executing `-- it` `n` times. If `n == 0`, this is a null operation. +|`it` is dereferenceable or past-the-end. + +|Iterator addition |`it + n` |Same as for `i += n`. |Equivalent to + +`{  I itt = it;  return itt += n; }` |Result is dereferenceable or +past-the-end. + +|Backward motion |`it -= n` |Including `it` itself, there must be `n` +dereferenceable or past-the-end iterators preceding or following `it`, +depending on whether `n` is positive or negative. |Equivalent to +`it += (-n)`. |`it` is dereferenceable or past-the-end. + +|Iterator subtraction |`it - n` |Same as for `i -= n`. |Equivalent to + +`{  I itt = it;  return itt -= n; }` |Result is dereferenceable or +past-the-end. + +|Difference |`it1 - it2` |Either `it1` is reachable from `it2` or `it2` +is reachable from `it1`, or both. |Returns a number `n` such that +`it1 == it2 + n` |  + +|Element operator |`it [n]` |`it + n` exists and is dereferenceable. +|Equivalent to `*(it + n)` |  + +|Element assignment |`i[n] = t` |Same as for `it [n]`. |Equivalent to +`*(it + n) = t` |  +|=== + +==== Complexity guarantees + +The complexity of operations on indexed random access iterators is +guaranteed to be amortized constant time. + +==== Invariants + +[cols=",",] +|=== +|Symmetry of addition and subtraction |If `it + n` is well-defined, then +`it += n; it -= n;` and `(it + n) - n` are null operations. Similarly, +if `it - n` is well-defined, then `it -= n; it += n;` and `(it - n) + n` +are null operations. + +|Relation between distance and addition |If `it1 - it2` is well-defined, +then `it1 == it2 + (it1 - it2)`. + +|Reachability and distance |If `it1` is reachable from `it2`, then +`it1 - it2 >= 0`. +|=== + +==== Models + +* `vector::iterator` + +=== [#indexed_bidirectional_cr_iterator]#Indexed Bidirectional Column/Row Iterator# + +==== Description + +An Indexed Bidirectional Column/Row Iterator is an iterator of a +container that can be dereferenced, incremented, decremented and carries +index information. + +==== Refinement of + +Assignable, Equality Comparable, Default Constructible. + +==== Associated types + +[cols=",",] +|=== +|Value type |The type of the value obtained by dereferencing a Indexed +Bidirectional Column/Row Iterator + +|Container type |The type of the container a Indexed Bidirectional +Column/Row Iterator points into. +|=== + +==== Notation + +[cols=",",] +|=== +|`I1` |A type that is a model of Indexed Bidirectional Column/Row +Iterator + +|`I2` |A type that is a model of Indexed Bidirectional Row/Column +Iterator + +|`T` |The value type of `I1` and `I2` + +|`C` |The container type of `I1` and `I2` + +|`it1`, `it1t, it11`, `it12` |Objects of type `I1` + +|`it2`, `it2t` |Objects of type `I2` + +|`t` |Object of type `T` + +|`c` |Object of type `C` +|=== + +==== Definitions + +==== Valid expressions + +In addition to the expressions defined for Assignable, Equality +Comparable and Default Constructible, the following expressions must be +valid. + +[cols=",,,",] +|=== +|Name |Expression |Type requirements |Return type +|Default constructor |`I1 it` |  |  +|Dereference |`*it` |  |Convertible to `T`. +|Dereference assignment |`*it = t` |`I1` is mutable. |  +|Member access |`it->m` |`T` is a type for which `t.m` is defined. |  +|Preincrement |`++ it` |  |`I1 &` +|Postincrement |`it ++` |  |`I1` +|Predecrement |`-- it` |  |`I1 &` +|Postdecrement |`it --` |  |`I1` +|Row Index |`it.index1 ()` |  |`C::size_type` +|Column Index |`it.index2 ()` |  |`C::size_type` +|Row/Column Begin |`it.begin ()` |  |`I2` +|Row/Column End |`it.end ()` |  |`I2` +|Reverse Row/Column Begin |`it.rbegin ()` |  |`reverse_iterator` +|Reverse Row/Column End |`it.rend ()` |  |`reverse_iterator` +|=== + +==== Expression Semantics + +Semantics of an expression is defined only where it differs from, or is +not defined in, Assignable, Equality Comparable and Default +Constructible. + +[width="100%",cols="20%,20%,20%,20%,20%",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition + +|Default constructor |`I1 it` |  |  |`it` is singular. + +|Dereference |`*it` |`it` is dereferenceable. |  |  + +|Dereference assignment |`*it = t` |Same as for `*it`. |  |`*it` is a +copy of t. + +|Member access |`it->m` |`it` is dereferenceable. |Equivalent to +`(*it).m` |  + +|Preincrement |`++ it` |`it` is dereferenceable. |`it` is modified to +point to the next element of the column/row, i.e. for column iterators +holds + +`it.index1 () < (++ it).index1 ()` and + +`it.index2 () == (++ it).index2 ()`, + +for row iterators holds + +`it.index1 () == (++ it).index1 ()` and + +`it.index2 () < (++ it).index2 ()`. + |`it` is dereferenceable or +past-the-end. ` &it == &++ it`. + +If `it1 == it2`, + +then `++ it1 == ++ it2`. + +|Postincrement |`it ++` |Same as for `++ it`. |Equivalent to + +`{  I1 itt = it;  ++ it;  return itt; }` |`it` is dereferenceable or +past-the-end. + +|Predecrement |`-- it` |`it` is dereferenceable or past-the-end. + +There exists a dereferenceable iterator `itt` such that `it == ++ itt`. +|`it` is modified to point to the previous  element of the column/row, +i.e. for column iterators holds + +`it.index1 () > (-- it).index1 ()` and + +`it.index2 () == (-- it).index2 ()`, + +for row iterators holds + +`it.index1 () == (-- it).index1 ()` and + +`it.index2 () > (-- it).index2 ()`. |`it` is dereferenceable. + +`&it = &-- it`. + +If `it1 == it2`, + +then `-- it1 == -- it2`. + +|Postdecrement |`it --` |Same as for -- `it`. |Equivalent to + +`{  I1 itt = it;  -- it;  return itt; }` |`it` is dereferenceable.  + +|Row Index |`it.index1 ()` |If `it` is a Row iterator then `it` must be +dereferenceable. |`it.index1 () >= 0` and + +`it.index1 () < it () .size1 ()` |If `it1 == it2`, + +then `it1.index1 () == 12.index1 ()`. + +If `it1`, `it2` are Row Iterators with `it1 == it2`, + +then `it1.index1 () < (++ it2`).`index1 ()`. + +and `it1.index1 () > (-- it2`).`index1 ()`. + +|Column Index |`it.index2 ()` |If `it` is a Column iterator then `it` +must be dereferenceable. |`it.index2 () >= 0` and + +`it.index2 () < it () .size2 ()` |If `it1 == it2`, + +then `it1.index2 () == it2`.`index2 ()` . + +If `it1`, `it2` are Column Iterators with `it1 == i12`, + +then `it1.index2 () < (++ it2`).`index2 ()`. + +end `it1.index2 () > (-- it2`).`index2 ()`. + +|Row/Column Begin |`it.begin ()` |`it` is dereferenceable. a| +If `it` is a Column Iterator, + +then `it2 = it.begin ()` is a Row Iterator + +with `it2.index1 () == it.index1 ()`. + +If `it` is a Row Iterator, + +then `it2 = it.begin ()` is a Column Iterator + +with `it2.index2 () == it.index2 ()`. + +|  + +|Row/Column End |`it.end ()` |`it` is dereferenceable. a| +If `it` is a Column Iterator, + +then `it2 = it.end ()` is a Row Iterator + +with `it2.index1 () == it.index1 ()`. + +If `it` is a Row Iterator, + +then `it2 = it.end ()` is a Column Iterator + +with `it2.index2 () == it.index2 ()`. + +|  + +|Reverse Row/Column Begin |`it.rbegin ()` |`it` is dereferenceable. +|Equivalent to `reverse_iterator (it.end ())`. |  + +|Reverse Row/Column End |`it.rend ()` |`it` is dereferenceable. +|Equivalent to `reverse_iterator (it.begin ())`. |  +|=== + +==== Complexity guarantees + +The complexity of operations on indexed bidirectional column/row +iterators is guaranteed to be logarithmic depending on the size of the +container. The complexity of one iterator (depending on the storage +layout) can be lifted to be amortized constant time. The complexity of +the other iterator (depending on the storage layout and the container) +can be lifted to be amortized constant time for the first row/first +column respectively. + +==== Invariants + +[width="100%",cols="50%,50%",] +|=== +|Identity |`it1 == it2` if and only if `&*it1 == &*it2`. + +|Symmetry of increment and decrement |If `it` is dereferenceable, then +`++ it; --it;` is a null operation. Similarly, `-- it; ++ it;` is a null +operation. + +|Relation between iterator index and container element operator |If `it` +is dereferenceable, `*it == it () (it.index1 (), it.index2 ())` + +|Relation between iterator column/row begin and iterator index a| +If `it` is a Column Iterator and `it2 = it.begin ()` then +`it2.index2 () < it2t.index2 ()` for all `it2t` with `it2t () == it2 ()` +and `it2t ().index1 () == it2 ().index1 ()`. + +If `it` is a Row Iterator and `it2 = it.begin ()` then +`it2.index1 () < it2t.index1 ()` for all `it2t` with `it2t () == it2 ()` +and `it2t ().index2 () == it2 ().index2 ()`. + +|Relation between iterator column/row end and iterator index a| +If `it` is a Column Iterator and `it2 = it.end ()` then +`it2.index2 () > it2t.index2 ()` for all `it2t` with `it2t () == it2 ()` +and `it2t ().index1 () == it2 ().index1 ()`. + +If `it` is a Row Iterator and `it2 = it.end ()` then +`it2.index1 () > it2t.index1 ()` for all `it2t` with `it2t () == it2 ()` +and `it2t ().index2 () == it2 ().index2 ()`. + +|=== + +==== Models + +* `sparse_matrix::iterator1` +* `sparse_matrix::iterator2` + +=== [#indexed_random_access_cr_iterator]#Indexed Random Access Column/Row Iterator# + +==== Description + +An Indexed Random Access Column/Row Iterator is an iterator of a +container that can be dereferenced, incremented, decremented and carries +index information. + +==== Refinement of + +link:#indexed_bidirectional_cr_iterator[Indexed Bidirectional Column/Row +Iterator] . + +==== Associated types + +[cols=",",] +|=== +|Value type |The type of the value obtained by dereferencing a Indexed +Random Access Column/Row Iterator + +|Container type |The type of the container a Indexed Random Access +Column/Row Iterator points into. +|=== + +==== Notation + +[cols=",",] +|=== +|`I` |A type that is a model of Indexed Random Access Column/Row +Iterator + +|`T` |The value type of `I` + +|`C` |The container type of `I` + +|`it`, `itt, it1`, `it2` |Objects of type `I` + +|`t` |Object of type `T` + +|`c` |Object of type `C` +|=== + +==== Definitions + +==== Valid expressions + +In addition to the expressions defined for +link:#indexed_bidirectional_cr_iterator[Indexed Bidirectional Column/Row +Iterator] , the following expressions must be valid. + +[cols=",,,",] +|=== +|Name |Expression |Type requirements |Return type +|Forward motion |`it += n` |  |`I &` +|Iterator addition |`it + n` |  |`I` +|Backward motion |`i -= n` |  |`I &` +|Iterator subtraction |`it - n` |  |`I`  +|Difference |`it1 - it2` |  |`C::difference_type` +|Element operator |`it [n]` |  |Convertible to `T`. +|Element assignment |`it [n] = t` |`I` is mutable |Convertible to `T`. +|=== + +==== Expression Semantics + +Semantics of an expression is defined only where it differs from, or is +not defined in, link:#indexed_bidirectional_cr_iterator[Indexed +Bidirectional Column/Row Iterator] . + +[width="100%",cols="20%,20%,20%,20%,20%",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition + +|Forward motion |`it += n` |Including `it` itself, there must be `n` +dereferenceable or past-the-end iterators following or preceding `it`, +depending on whether `n` is positive or negative. |If `n > 0`, +equivalent to executing `++ it` `n` times. If `n < 0`, equivalent to +executing `-- it` `n` times. If `n == 0`, this is a null operation. +|`it` is dereferenceable or past-the-end. + +|Iterator addition |`it + n` |Same as for `i += n`. |Equivalent to + +`{  I itt = it;  return itt += n; }` |Result is dereferenceable or +past-the-end. + +|Backward motion |`it -= n` |Including `it` itself, there must be `n` +dereferenceable or past-the-end iterators preceding or following `it`, +depending on whether `n` is positive or negative. |Equivalent to +`it += (-n)`. |`it` is dereferenceable or past-the-end. + +|Iterator subtraction |`it - n` |Same as for `i -= n`. |Equivalent to + +`{  I itt = it;  return itt -= n; }` |Result is dereferenceable or +past-the-end. + +|Difference |`it1 - it2` |Either `it1` is reachable from `it2` or `it2` +is reachable from `it1`, or both. |Returns a number `n` such that +`it1 == it2 + n` |  + +|Element operator |`it [n]` |`it + n` exists and is dereferenceable. +|Equivalent to `*(it + n)` |  + +|Element assignment |`i[n] = t` |Same as for `it [n]`. |Equivalent to +`*(it + n) = t` |  +|=== + +==== Complexity guarantees + +The complexity of operations on indexed random access Column/Row +iterators is guaranteed to be amortized constant time. + +==== Invariants + +[cols=",",] +|=== +|Symmetry of addition and subtraction |If `it + n` is well-defined, then +`it += n; it -= n;` and `(it + n) - n` are null operations. Similarly, +if `it - n` is well-defined, then `it -= n; it += n;` and `(it - n) + n` +are null operations. + +|Relation between distance and addition |If `it1 - it2` is well-defined, +then `it1 == it2 + (it1 - it2)`. + +|Reachability and distance |If `it1` is reachable from `it2`, then +`it1 - it2 >= 0`. +|=== + +==== Models + +* `matrix::iterator1` +* `matrix::iterator2` + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/matrix.adoc b/doc/ublas/matrix.adoc new file mode 100644 index 000000000..e369e4b5d --- /dev/null +++ b/doc/ublas/matrix.adoc @@ -0,0 +1,552 @@ +== Matrix + +[[toc]] + +=== [#matrix]#Matrix# + +==== Description + +The templated class `matrix` is the base container adaptor for +dense matrices. For a _(m x n_)-dimensional matrix and _0 <= i < m_, _0 +<= j < n_ every element __m__~_i,j_~ is mapped to the __(i x n +j)-__th element of the container for row major orientation or the __(i+ +j x m)-__th element of the container for column major orientation. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + for (unsigned i = 0; i < m.size1 (); ++ i) + for (unsigned j = 0; j < m.size2 (); ++ j) + m (i, j) = 3 * i + j; + std::cout << m << std::endl; +} +.... + +==== Definition + +Defined in the header matrix.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the matrix. | + +|`F` |Functor describing the storage organization. link:#matrix_1[[1]] +|`row_major` + +|`A` |The type of the link:storage_concept.html[Storage] array. +link:#matrix_2[[2]] |`unbounded_array` +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix ()` |Allocates an uninitialized `matrix` that holds zero rows +of zero elements. + +|`matrix (size_type size1, size_type size2)` |Allocates an uninitialized +`matrix` that holds `size1` rows of `size2` elements. + +|`matrix (const matrix &m)` |The copy constructor. + +|`template matrix (const matrix_expression &ae)` |The +extended copy constructor. + +|`void resize (size_type size1, size_type size2, bool preserve = true)` +|Reallocates a `matrix` to hold `size1` rows of `size2` elements. The +existing elements of the `matrix` are preseved when specified. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const array_type& data () const` | + +|`array_type& data ()` | + +|`const_reference operator () (size_type i, size_type j) const` |Returns +a `const` reference of the `j` -th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`matrix &operator = (const matrix &m)` |The assignment operator. + +|`matrix &assign_temporary (matrix &m)` |Assigns a temporary. May change +the matrix `m`. + +|`template matrix &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template matrix &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the matrix. Left and right hand side of +the assignment should be independent. + +|`template matrix &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +matrix. + +|`template matrix &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the matrix. Left and right hand side of the +assignment should be independent. + +|`template matrix &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the matrix. + +|`template matrix &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the matrix. Left and right hand side +of the assignment should be independent. + +|`template matrix &operator *= (const AT &at)` |A computed +assignment operator. Multiplies the matrix with a scalar. + +|`template matrix &operator /= (const AT &at)` |A computed +assignment operator. Divides the matrix through a scalar. + +|`void swap (matrix &m)` |Swaps the contents of the matrices. + +|`void insert_element (size_type i, size_type j, const_reference t)` +|Inserts the value `t` at the `j`-th element of the `i`-th row. + +|`void erase_element (size_type i, size_type j)` |Erases the value at +the `j`-th element of the `i`-th row. + +|`void clear ()` |Clears the matrix. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `matrix`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `matrix`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `matrix`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `matrix`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed `matrix`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `matrix`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed `matrix`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `matrix`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `matrix`. +|=== + +==== Notes + +[#matrix_1]#[1]# Supported parameters for the storage organization are +`row_major` and `column_major`. + +[#matrix_2]#[2]# Common parameters for the storage array are +`unbounded_array` , `bounded_array` and `std::vector` . + +=== [#identity_matrix]#Identity Matrix# + +==== Description + +The templated class `identity_matrix` represents identity +matrices. For a _(m x n_)-dimensional identity matrix and _0 <= i < m_, +_0 <= j < n_ holds __id__~_i,j_~ = 0, if _i <> j_, and __id__~_i,i_~ . + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + identity_matrix m (3); + std::cout << m << std::endl; +} +.... + +==== Definition + +Defined in the header matrix.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the matrix. |`int` + +|`ALLOC` |An STL Allocator for size_type and difference_type. +|std::allocator +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`identity_matrix ()` |Constructs an `identity_matrix` that holds zero +rows of zero elements. + +|`identity_matrix (size_type size)` |Constructs an `identity_matrix` +that holds `size` rows of `size` elements. + +|`identity_matrix (const identity_matrix &m)` |The copy constructor. + +|`void resize (size_type size, bool preserve = true)` |Resizes a +`identity_matrix` to hold `size` rows of `size` elements. Therefore the +existing elements of the `itendity_matrix` are always preseved. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`identity_matrix &operator = (const identity_matrix &m)` |The +assignment operator. + +|`identity_matrix &assign_temporary (identity_matrix &m)` |Assigns a +temporary. May change the identity matrix `m` . + +|`void swap (identity_matrix &m)` |Swaps the contents of the identity +matrices. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `identity_matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `identity_matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `identity_matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `identity_matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`identity_matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`identity_matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`identity_matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`identity_matrix`. +|=== + +=== [#zero_matrix]#Zero Matrix# + +==== Description + +The templated class `zero_matrix` represents zero matrices. +For a _(m x n_)-dimensional zero matrix and _0 <= i < m_, _0 <= j < n_ +holds __z__~_i,j_~ = 0. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + zero_matrix m (3, 3); + std::cout << m << std::endl; +} +.... + +==== Definition + +Defined in the header matrix.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the matrix. |`int` + +|`ALLOC` |An STL Allocator for size_type and difference_type. +|std::allocator +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`zero_matrix ()` |Constructs a `zero_matrix` that holds zero rows of +zero elements. + +|`zero_matrix (size_type size1, size_type size2)` |Constructs a +`zero_matrix` that holds `size1` rows of `size2` elements. + +|`zero_matrix (const zero_matrix &m)` |The copy constructor. + +|`void resize (size_type size1, size_type size2, bool preserve = true)` +|Resizes a `zero_matrix` to hold `size1` rows of `size2` elements. +Therefore the existing elements of the `zero_matrix` are always +preseved. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`zero_matrix &operator = (const zero_matrix &m)` |The assignment +operator. + +|`zero_matrix &assign_temporary (zero_matrix &m)` |Assigns a temporary. +May change the zero matrix `m` . + +|`void swap (zero_matrix &m)` |Swaps the contents of the zero matrices. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `zero_matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `zero_matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `zero_matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `zero_matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`zero_matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`zero_matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`zero_matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`zero_matrix`. +|=== + +=== [#scalar_matrix]#Scalar Matrix# + +==== Description + +The templated class `scalar_matrix` represents scalar +matrices. For a _(m x n_)-dimensional scalar matrix and _0 <= i < m_, _0 +<= j < n_ holds __z__~_i,j_~ = s. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + scalar_matrix m (3, 3); + std::cout << m << std::endl; +} +.... + +==== Definition + +Defined in the header matrix.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the matrix. |`int` + +|`ALLOC` |An STL Allocator for size_type and difference_type. +|std::allocator +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`scalar_matrix ()` |Constructs a `scalar_matrix` that holds scalar rows +of zero elements. + +|`scalar_matrix (size_type size1, size_type size2, const value_type &value)` +|Constructs a `scalar_matrix` that holds `size1` rows of `size2` +elements each of the specified value. + +|`scalar_matrix (const scalar_matrix &m)` |The copy constructor. + +|`void resize (size_type size1, size_type size2, bool preserve = true)` +|Resizes a `scalar_matrix` to hold `size1` rows of `size2` elements. +Therefore the existing elements of the `scalar_matrix` are always +preseved. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`scalar_matrix &operator = (const scalar_matrix &m)` |The assignment +operator. + +|`scalar_matrix &assign_temporary (scalar_matrix &m)` |Assigns a +temporary. May change the scalar matrix `m` . + +|`void swap (scalar_matrix &m)` |Swaps the contents of the scalar +matrices. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `scalar_matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `scalar_matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `scalar_matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `scalar_matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`scalar_matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`scalar_matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`scalar_matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`scalar_matrix`. +|=== + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/matrix_expression.adoc b/doc/ublas/matrix_expression.adoc new file mode 100644 index 000000000..942100d65 --- /dev/null +++ b/doc/ublas/matrix_expression.adoc @@ -0,0 +1,1313 @@ +== Matrix Expressions + +[[toc]] + +=== [#matrix_expression]#Matrix Expression# + +==== Description + +The templated class `matrix_expression` is required to be a public +base of all classes which model the Matrix Expression concept. + +==== Definition + +Defined in the header expression_types.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E` |The type of the matrix expression. |  +|=== + +==== Model of + +None. [underline]#Not a Matrix Expression# + +==== Type requirements + +None. + +==== Public base classes + +None. + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`const expression_type &operator () () const` |Returns a `const` +reference of the expression. + +|`expression_type &operator () ()` |Returns a reference of the +expression. +|=== + +==== Notes + +The `operator[]`, `row`, `column`, `range`, `slice` and `project` +functions have been removed. Use the free functions defined in +link:matrix_proxy.html[matrix proxy] instead. + +=== [#matrix_container]#Matrix Container# + +==== Description + +The templated class `matrix_container` is required to be a public +base of all classes which model the Matrix concept. This includes the +class `matrix` itself. + +==== Definition + +Defined in the header expression_types.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E` |The type of the matrix expression. |  +|=== + +==== Model of + +None. [underline]#Not a Matrix Expression OR Matrix# + +==== Type requirements + +None. + +==== Public base classes + +`matrix_expression` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`const container_type &operator () () const` |Returns a `const` +reference of the container. + +|`container_type &operator () ()` |Returns a reference of the container. +|=== + +=== [#matrix_references]#Matrix References# + +==== Reference + +===== Description + +The templated class `matrix_reference` contains a reference to a +matrix expression. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E` |The type of the matrix expression. |  +|=== + +===== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Public base classes + +`matrix_expression >` + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_reference (expression_type &e)` |Constructs a constant +reference of the expression. + +|`void resize (size_type size1, size2)` |Resizes the expression to hold +at most `size1` rows of `size2` elements. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the expression. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the expression. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the expression. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +expression. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the expression. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the expression. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the expression. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +expression. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +expression. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed expression. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed expression. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +expression. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed expression. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed expression. +|=== + +=== [#matrix_operations]#Matrix Operations# + +==== Unary Operation Description + +===== Description + +The templated classes `matrix_unary1` and `matrix_unary2` +describe unary matrix operations. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E` |The type of the matrix expression. |  +|`F` |The type of the operation. |  +|=== + +===== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Public base classes + +`matrix_expression >` and +`matrix_expression >` resp. + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_unary1 (const expression_type &e)` |Constructs a description of +the expression. + +|`matrix_unary2 (const expression_type &e)` |Constructs a description of +the expression. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the expression. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the expression. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the expression. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the expression. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +expression. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +expression. +|=== + +==== Unary Operations + +===== Prototypes + +[source, cpp] +.... +template + struct matrix_unary1_traits { + typedef matrix_unary1 expression_type; + typedef expression_type result_type; + }; + + // (- m) [i] [j] = - m [i] [j] + template + typename matrix_unary1_traits >::result_type + operator - (const matrix_expression &e); + + // (conj m) [i] [j] = conj (m [i] [j]) + template + typename matrix_unary1_traits >::result_type + conj (const matrix_expression &e); + + // (real m) [i] [j] = real (m [i] [j]) + template + typename matrix_unary1_traits >::result_type + real (const matrix_expression &e); + + // (imag m) [i] [j] = imag (m [i] [j]) + template + typename matrix_unary1_traits >::result_type + imag (const matrix_expression &e); + + template + struct matrix_unary2_traits { + typedef matrix_unary2 expression_type; + typedef expression_type result_type; + }; + + // (trans m) [i] [j] = m [j] [i] + template + typename matrix_unary2_traits >::result_type + trans (const matrix_expression &e); + + // (herm m) [i] [j] = conj (m [j] [i]) + template + typename matrix_unary2_traits >::result_type + herm (const matrix_expression &e); +.... + +===== Description + +`operator -` computes the additive inverse of a matrix expression. +`conj` computes the complex conjugate of a matrix expression. `real` and +`imag` compute the real and imaginary parts of a matrix expression. +`trans` computes the transpose of a matrix expression. `herm` computes +the hermitian, i.e. the complex conjugate of the transpose of a matrix +expression. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Type requirements + +* `E` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Preconditions + +None. + +===== Complexity + +Quadratic depending from the size of the matrix expression. + +===== Examples + +[source, cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix > m (3, 3); + for (unsigned i = 0; i < m.size1 (); ++ i) + for (unsigned j = 0; j < m.size2 (); ++ j) + m (i, j) = std::complex (3 * i + j, 3 * i + j); + + std::cout << - m << std::endl; + std::cout << conj (m) << std::endl; + std::cout << real (m) << std::endl; + std::cout << imag (m) << std::endl; + std::cout << trans (m) << std::endl; + std::cout << herm (m) << std::endl; +} +.... + +==== Binary Operation Description + +===== Description + +The templated class `matrix_binary` describes a binary matrix +operation. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E1` |The type of the first matrix expression. | +|`E2` |The type of the second matrix expression. | +|`F` |The type of the operation. | +|=== + +===== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Public base classes + +`matrix_expression >`. + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_binary (const expression1_type &e1, const expression2_type &e2)` +|Constructs a description of the expression. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the expression. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the expression. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the expression. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the expression. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +expression. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +expression. +|=== + +==== Binary Operations + +===== Prototypes + +[source, cpp] +.... +template + struct matrix_binary_traits { + typedef matrix_binary expression_type; + typedef expression_type result_type; + }; + + // (m1 + m2) [i] [j] = m1 [i] [j] + m2 [i] [j] + template + typename matrix_binary_traits >::result_type + operator + (const matrix_expression &e1, + const matrix_expression &e2); + + // (m1 - m2) [i] [j] = m1 [i] [j] - m2 [i] [j] + template + typename matrix_binary_traits >::result_type + operator - (const matrix_expression &e1, + const matrix_expression &e2); +.... + +===== Description + +`operator +` computes the sum of two matrix expressions. `operator -` +computes the difference of two matrix expressions. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Type requirements + +* `E1` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . +* `E2` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Preconditions + +* `e1 ().size1 () == e2 ().size1 ()` +* `e1 ().size2 () == e2 ().size2 ()` + +===== Complexity + +Quadratic depending from the size of the matrix expressions. + +===== Examples + +[source, cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m1 (3, 3), m2 (3, 3); + for (unsigned i = 0; i < std::min (m1.size1 (), m2.size1 ()); ++ i) + for (unsigned j = 0; j < std::min (m1.size2 (), m2.size2 ()); ++ j) + m1 (i, j) = m2 (i, j) = 3 * i + j; + + std::cout << m1 + m2 << std::endl; + std::cout << m1 - m2 << std::endl; +} +.... + +==== Scalar Matrix Operation Description + +===== Description + +The templated classes `matrix_binary_scalar1` and +`matrix_binary_scalar2` describe binary operations between a +scalar and a matrix. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E1/E2` |The type of the scalar expression. | +|`E2/E1` |The type of the matrix expression. | +|`F` |The type of the operation. | +|=== + +===== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Public base classes + +`matrix_expression >` and +`matrix_expression >` resp. + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_binary_scalar1 (const expression1_type &e1, const expression2_type &e2)` +|Constructs a description of the expression. + +|`matrix_binary_scalar1 (const expression1_type &e1, const expression2_type &e2)` +|Constructs a description of the expression. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the expression. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the expression. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the expression. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the expression. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +expression. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +expression. +|=== + +==== Scalar Matrix Operations + +===== Prototypes + +[source, cpp] +.... +template + struct matrix_binary_scalar1_traits { + typedef matrix_binary_scalar1, + typename E2::const_closure_type, F> expression_type; + typedef expression_type result_type; + }; + + // (t * m) [i] [j] = t * m [i] [j] + template + typename matrix_binary_scalar1_traits >::result_type + operator * (const T1 &e1, + const matrix_expression &e2); + + template + struct matrix_binary_scalar2_traits { + typedef matrix_binary_scalar2, F> expression_type; + typedef expression_type result_type; + }; + + // (m * t) [i] [j] = m [i] [j] * t + template + typename matrix_binary_scalar2_traits >::result_type + operator * (const matrix_expression &e1, + const T2 &e2); + + // (m / t) [i] [j] = m [i] [j] / t + template + typename matrix_binary_scalar2_traits >::result_type + operator / (const matrix_expression &e1, + const T2 &e2); +.... + +===== Description + +`operator *` computes the product of a scalar and a matrix expression. +`operator /` multiplies the matrix with the reciprocal of the scalar. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Type requirements + +* `T1/T2` is a model of +link:expression_concept.html#scalar_expression[Scalar Expression] . +* `E2/E1` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Preconditions + +None. + +===== Complexity + +Quadratic depending from the size of the matrix expression. + +===== Examples + +[source, cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + for (unsigned i = 0; i < m.size1 (); ++ i) + for (unsigned j = 0; j < m.size2 (); ++ j) + m (i, j) = 3 * i + j; + + std::cout << 2.0 * m << std::endl; + std::cout << m * 2.0 << std::endl; +} +.... + +=== [#matrix_vector_operations]#Matrix Vector Operations# + +==== Binary Operation Description + +===== Description + +The templated classes `matrix_vector_binary1` and +`matrix_vector_binary2` describe binary matrix vector +operations. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E1` |The type of the matrix or vector expression. | +|`E2` |The type of the vector or matrix expression. | +|`F` |The type of the operation. | +|=== + +===== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Public base classes + +`vector_expression >` and +`vector_expression >` resp. + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_vector_binary1 (const expression1_type &e1, const expression2_type &e2)` +|Constructs a description of the expression. + +|`matrix_vector_binary2 (const expression1_type &e1, const expression2_type &e2)` +|Constructs a description of the expression. + +|`size_type size () const` |Returns the size of the expression. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the expression. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the expression. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed expression. +|=== + +==== Binary Operations + +===== Prototypes + +[source, cpp] +.... +template + struct matrix_vector_binary1_traits { + typedef row_major_tag dispatch_category; + typedef typename promote_traits::promote_type promote_type; + typedef matrix_vector_binary1 > expression_type; + typedef expression_type result_type; + }; + + template + typename matrix_vector_binary1_traits::result_type + prod (const matrix_expression &e1, + const vector_expression &e2, + row_major_tag); + + // Dispatcher + template + typename matrix_vector_binary1_traits::result_type + prod (const matrix_expression &e1, + const vector_expression &e2); + + template + typename matrix_vector_binary1_traits::precision_type, E1, + typename type_traits::precision_type, E2>::result_type + prec_prod (const matrix_expression &e1, + const vector_expression &e2, + row_major_tag); + + // Dispatcher + template + typename matrix_vector_binary1_traits::precision_type, E1, + typename type_traits::precision_type, E2>::result_type + prec_prod (const matrix_expression &e1, + const vector_expression &e2); + + template + V + prod (const matrix_expression &e1, + const vector_expression &e2); + + template + V + prec_prod (const matrix_expression &e1, + const vector_expression &e2); + + template + struct matrix_vector_binary2_traits { + typedef column_major_tag dispatch_category; + typedef typename promote_traits::promote_type promote_type; + typedef matrix_vector_binary2 > expression_type; + typedef expression_type result_type; + }; + + template + typename matrix_vector_binary2_traits::result_type + prod (const vector_expression &e1, + const matrix_expression &e2, + column_major_tag); + + // Dispatcher + template + typename matrix_vector_binary2_traits::result_type + prod (const vector_expression &e1, + const matrix_expression &e2); + + template + typename matrix_vector_binary2_traits::precision_type, E1, + typename type_traits::precision_type, E2>::result_type + prec_prod (const vector_expression &e1, + const matrix_expression &e2, + column_major_tag); + + // Dispatcher + template + typename matrix_vector_binary2_traits::precision_type, E1, + typename type_traits::precision_type, E2>::result_type + prec_prod (const vector_expression &e1, + const matrix_expression &e2); + + template + V + prod (const vector_expression &e1, + const matrix_expression &e2); + + template + V + prec_prod (const vector_expression &e1, + const matrix_expression &e2); +.... + +===== Description + +`prod` computes the product of the matrix and the vector expression. +`prec_prod` computes the double precision product of the matrix and the +vector expression. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Type requirements + +* `E1` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] or +link:expression_concept.html#vector_expression[Vector Expression] . +* `E2` is a model of +link:expression_concept.html#vector_expression[Vector Expression] or +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Preconditions + +* `e1 ().size2 () == e2 ().size ()` +* `e1 ().size () == e2 ().size1 ()` + +===== Complexity + +Quadratic depending from the size of the matrix expression. + +===== Examples + +[source, cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + vector v (3); + for (unsigned i = 0; i < std::min (m.size1 (), v.size ()); ++ i) { + for (unsigned j = 0; j < m.size2 (); ++ j) + m (i, j) = 3 * i + j; + v (i) = i; + } + + std::cout << prod (m, v) << std::endl; + std::cout << prod (v, m) << std::endl; +} +.... + +==== Triangular Solver + +===== Prototypes + +[source, cpp] +.... +template + struct matrix_vector_solve_traits { + typedef typename promote_traits::promote_type promote_type; + typedef vector result_type; + }; + + template + void inplace_solve (const matrix_expression &e1, + E2 &e2, + lower_tag, + vector_tag); + template + void inplace_solve (const matrix_expression &e1, + E2 &e2, + upper_tag, + vector_tag); + template + void inplace_solve (const matrix_expression &e1, + E2 &e2, + unit_lower_tag, + vector_tag); + template + void inplace_solve (const matrix_expression &e1, + E2 &e2, + unit_upper_tag, + vector_tag); + + template + typename matrix_vector_solve_traits::result_type + solve (const matrix_expression &e1, + const vector_expression &e2, + C); + + template + void inplace_solve (E1 &e1, + const matrix_expression &e2, + vector_tag, + lower_tag); + template + void inplace_solve (E1 &e1, + const matrix_expression &e2, + vector_tag, + upper_tag); + template + void inplace_solve (E1 &e1, + const matrix_expression &e2, + vector_tag, + unit_lower_tag); + template + void inplace_solve (E1 &e1, + const matrix_expression &e2, + vector_tag, + unit_upper_tag); + + template + typename matrix_vector_solve_traits::result_type + solve (const vector_expression &e1, + const matrix_expression &e2, + C); +.... + +===== Description + +`solve` solves a linear equation for lower or upper (unit) triangular +matrices. + +===== Definition + +Defined in the header triangular.hpp. + +===== Type requirements + +* `E1` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] or +link:expression_concept.html#vector_expression[Vector Expression] . +* `E2` is a model of +link:expression_concept.html#vector_expression[Vector Expression] or +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Preconditions + +* `e1 ().size1 () == e1 ().size2 ()` +* `e1 ().size2 () == e2 ().size ()` +* `e1 ().size () == e2 ().size1 ()` +* `e2 ().size1 () == e2 ().size2 ()` + +===== Complexity + +Quadratic depending from the size of the matrix expression. + +===== Examples + +[source, cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + vector v (3); + for (unsigned i = 0; i < std::min (m.size1 (), v.size ()); ++ i) { + for (unsigned j = 0; j <= i; ++ j) + m (i, j) = 3 * i + j + 1; + v (i) = i; + } + + std::cout << solve (m, v, lower_tag ()) << std::endl; + std::cout << solve (v, m, lower_tag ()) << std::endl; +} +.... + +=== [#matrix_matrix_operations]#Matrix Matrix Operations# + +==== Binary Operation Description + +===== Description + +The templated class `matrix_matrix_binary` describes a binary +matrix operation. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E1` |The type of the first matrix expression. | +|`E2` |The type of the second matrix expression. | +|`F` |The type of the operation. | +|=== + +===== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Public base classes + +`matrix_expression >` . + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_matrix_binary (const expression1_type &e1, const expression2_type &e2)` +|Constructs a description of the expression. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the expression. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the expression. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the expression. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the expression. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +expression. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +expression. +|=== + +==== Binary Operations + +===== Prototypes + +[source, cpp] +.... +template + struct matrix_matrix_binary_traits { + typedef unknown_orientation_tag dispatch_category; + typedef typename promote_traits::promote_type promote_type; + typedef matrix_matrix_binary > expression_type; + typedef expression_type result_type; + }; + + template + typename matrix_matrix_binary_traits::result_type + prod (const matrix_expression &e1, + const matrix_expression &e2, + unknown_orientation_tag); + + // Dispatcher + template + typename matrix_matrix_binary_traits::result_type + prod (const matrix_expression &e1, + const matrix_expression &e2); + + template + typename matrix_matrix_binary_traits::precision_type, E1, + typename type_traits::precision_type, E2>::result_type + prec_prod (const matrix_expression &e1, + const matrix_expression &e2, + unknown_orientation_tag); + + // Dispatcher + template + typename matrix_matrix_binary_traits::precision_type, E1, + typename type_traits::precision_type, E2>::result_type + prec_prod (const matrix_expression &e1, + const matrix_expression &e2); + + template + M + prod (const matrix_expression &e1, + const matrix_expression &e2); + + template + M + prec_prod (const matrix_expression &e1, + const matrix_expression &e2); +.... + +===== Description + +`prod` computes the product of the matrix expressions. `prec_prod` +computes the double precision product of the matrix expressions. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Type requirements + +* `E1` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . +* `E2` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Preconditions + +* `e1 ().size2 () == e2 ().size1 ()` + +===== Complexity + +Cubic depending from the size of the matrix expression. + +===== Examples + +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m1 (3, 3), m2 (3, 3); + for (unsigned i = 0; i < std::min (m1.size1 (), m2.size1 ()); ++ i) + for (unsigned j = 0; j < std::min (m1.size2 (), m2.size2 ()); ++ j) + m1 (i, j) = m2 (i, j) = 3 * i + j; + + std::cout << prod (m1, m2) << std::endl; +} +.... + +==== Triangular Solvers + +===== Prototypes + +[source, cpp] +.... +template + struct matrix_matrix_solve_traits { + typedef typename promote_traits::promote_type promote_type; + typedef matrix result_type; + }; + + template + void inplace_solve (const matrix_expression &e1, + E2 &e2, + lower_tag, + matrix_tag); + template + void inplace_solve (const matrix_expression &e1, + E2 &e2, + upper_tag, + matrix_tag); + template + void inplace_solve (const matrix_expression &e1, + E2 &e2, + unit_lower_tag, + matrix_tag); + template + void inplace_solve (const matrix_expression &e1, + E2 &e2, + unit_upper_tag, + matrix_tag); + + template + typename matrix_matrix_solve_traits::result_type + solve (const matrix_expression &e1, + const matrix_expression &e2, + C); +.... + +===== Description + +`solve` solves a linear equation for lower or upper (unit) triangular +matrices. + +===== Definition + +Defined in the header triangular.hpp. + +===== Type requirements + +* `E1` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . +* `E2` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Preconditions + +* `e1 ().size1 () == e1 ().size2 ()` +* `e1 ().size2 () == e2 ().size1 ()` + +===== Complexity + +Cubic depending from the size of the matrix expressions. + +===== Examples + +[source, cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m1 (3, 3), m2 (3, 3); + for (unsigned i = 0; i < std::min (m1.size1 (), m2.size1 ()); ++ i) + for (unsigned j = 0; j <= i; ++ j) + m1 (i, j) = m2 (i, j) = 3 * i + j + 1; + + std::cout << solve (m1, m2, lower_tag ()) << std::endl; +} +.... + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/matrix_proxy.adoc b/doc/ublas/matrix_proxy.adoc new file mode 100644 index 000000000..0b02e54eb --- /dev/null +++ b/doc/ublas/matrix_proxy.adoc @@ -0,0 +1,1144 @@ +== Matrix Proxies + +[[toc]] + +=== [#matrix_row]#Matrix Row# + +==== Description + +The templated class `matrix_row` allows addressing a row of a matrix. + +==== Example + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + for (unsigned i = 0; i < m.size1 (); ++ i) { + matrix_row > mr (m, i); + for (unsigned j = 0; j < mr.size (); ++ j) + mr (j) = 3 * i + j; + std::cout << mr << std::endl; + } +} +.... + +==== Definition + +Defined in the header matrix_proxy.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`M` |The type of matrix referenced. | +|=== + +==== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +If the specified row falls outside that of the row index range of the +matrix, then the `matrix_row` is not a well formed Vector Expression. +That is, access to an element which is outside of the matrix is +_undefined_. + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +==== Public base classes + +`vector_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_row (matrix_type &data, size_type i)` |Constructs a sub vector. + +|`size_type size () const` |Returns the size of the sub vector. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator () (size_type i)` |Returns a reference of the +`i`-th element. + +|`matrix_row &operator = (const matrix_row &mr)` |The assignment +operator. + +|`matrix_row &assign_temporary (matrix_row &mr)` |Assigns a temporary. +May change the matrix row `mr` . + +|`template matrix_row &operator = (const vector_expression &ae)` +|The extended assignment operator. + +|`template matrix_row &assign (const vector_expression &ae)` +|Assigns a vector expression to the sub vector. Left and right hand side +of the assignment should be independent. + +|`template matrix_row &operator += (const vector_expression &ae)` +|A computed assignment operator. Adds the vector expression to the sub +vector. + +|`template matrix_row &plus_assign (const vector_expression &ae)` +|Adds a vector expression to the sub vector. Left and right hand side of +the assignment should be independent. + +|`template matrix_row &operator -= (const vector_expression &ae)` +|A computed assignment operator. Subtracts the vector expression from +the sub vector. + +|`template matrix_row &minus_assign (const vector_expression &ae)` +|Subtracts a vector expression from the sub vector. Left and right hand +side of the assignment should be independent. + +|`template matrix_row &operator *= (const AT &at)` |A computed +assignment operator. Multiplies the sub vector with a scalar. + +|`template matrix_row &operator /= (const AT &at)` |A computed +assignment operator. Divides the sub vector through a scalar. + +|`void swap (matrix_row &mr)` |Swaps the contents of the sub vectors. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `matrix_row`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `matrix_row`. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the `matrix_row`. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +`matrix_row`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`matrix_row`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`matrix_row`. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed `matrix_row`. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed `matrix_row`. +|=== + +==== Projections + +===== Description + +The free `row` functions support the construction of matrix rows. + +===== Prototypes + +[source,cpp] +.... + template + matrix_row row (M &data, std::size_t i); + template + const matrix_row row (const M &data, std::size_t i); +.... + +===== Definition + +Defined in the header matrix_proxy.hpp. + +===== Type requirements + +* `M` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Complexity + +Linear depending from the size of the row. + +===== Examples + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + for (unsigned i = 0; i < m.size1 (); ++ i) { + for (unsigned j = 0; j < m.size2 (); ++ j) + row (m, i) (j) = 3 * i + j; + std::cout << row (m, i) << std::endl; + } +} +.... + +=== [#matrix_column]#Matrix Column# + +==== Description + +The templated class `matrix_column` allows addressing a column of a +matrix. + +==== Example + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + for (unsigned j = 0; j < m.size2 (); ++ j) { + matrix_column > mc (m, j); + for (unsigned i = 0; i < mc.size (); ++ i) + mc (i) = 3 * i + j; + std::cout << mc << std::endl; + } +} +.... + +==== Definition + +Defined in the header matrix_proxy.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`M` |The type of matrix referenced. | +|=== + +==== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +If the specified column falls outside that of the column index range of +the matrix, then the `matrix_column` is not a well formed Vector +Expression. That is, access to an element which is outside of the matrix +is _undefined_. + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +==== Public base classes + +`vector_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_column (matrix_type &data, size_type j)` |Constructs a sub +vector. + +|`size_type size () const` |Returns the size of the sub vector. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator () (size_type i)` |Returns a reference of the +`i`-th element. + +|`matrix_column &operator = (const matrix_column &mc)` |The assignment +operator. + +|`matrix_column &assign_temporary (matrix_column &mc)` |Assigns a +temporary. May change the matrix column `mc` . + +|`template matrix_column &operator = (const vector_expression &ae)` +|The extended assignment operator. + +|`template matrix_column &assign (const vector_expression &ae)` +|Assigns a vector expression to the sub vector. Left and right hand side +of the assignment should be independent. + +|`template matrix_column &operator += (const vector_expression &ae)` +|A computed assignment operator. Adds the vector expression to the sub +vector. + +|`template matrix_column &plus_assign (const vector_expression &ae)` +|Adds a vector expression to the sub vector. Left and right hand side of +the assignment should be independent. + +|`template matrix_column &operator -= (const vector_expression &ae)` +|A computed assignment operator. Subtracts the vector expression from +the sub vector. + +|`template matrix_column &minus_assign (const vector_expression &ae)` +|Subtracts a vector expression from the sub vector. Left and right hand +side of the assignment should be independent. + +|`template matrix_column &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the sub vector with a scalar. + +|`template matrix_column &operator /= (const AT &at)` |A +computed assignment operator. Divides the sub vector through a scalar. + +|`void swap (matrix_column &mc)` |Swaps the contents of the sub vectors. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `matrix_column`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `matrix_column`. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the `matrix_column`. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +`matrix_column`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`matrix_column`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`matrix_column`. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed `matrix_column`. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed `matrix_column`. +|=== + +==== Projections + +===== Description + +The free `column` functions support the construction of matrix columns. + +===== Prototypes + +[source,cpp] +.... + template + matrix_column column (M &data, std::size_t j); + template + const matrix_column column (const M &data, std::size_t j); +.... + +===== Definition + +Defined in the header matrix_proxy.hpp. + +===== Type requirements + +* `M` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Complexity + +Linear depending from the size of the column. + +===== Examples + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + for (unsigned j = 0; j < m.size2 (); ++ j) { + for (unsigned i = 0; i < m.size1 (); ++ i) + column (m, j) (i) = 3 * i + j; + std::cout << column (m, j) << std::endl; + } +} +.... + +=== [#vector_range]#Vector Range# + +==== Description + +The templated class `matrix_vector_range` allows addressing a sub +vector of a matrix. + +==== Example + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + for (unsigned i = 0; i < m.size1 (); ++ i) + for (unsigned j = 0; j < m.size2 (); ++ j) + m (i, j) = 3 * i + j; + + matrix_vector_range > mvr (m, range (0, 3), range (0, 3)); + std::cout << mvr << std::endl; +} +.... + +==== Definition + +Defined in the header matrix_proxy.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`M` |The type of matrix referenced. | +|=== + +==== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +If the specified ranges fall outside that of the index range of the +matrix, then the `matrix_vector_range` is not a well formed Vector +Expression. That is, access to an element which is outside of the matrix +is _undefined_. + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +==== Public base classes + +`vector_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_vector_range (matrix_type &data, const range &r1, const range &r2)` +|Constructs a sub vector. + +|`size_type size () const` |Returns the size of the sub vector. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator () (size_type i)` |Returns a reference of the +`i`-th element. + +|`matrix_vector_range &operator = (const matrix_vector_range &mvr)` |The +assignment operator. + +|`matrix_vector_range &assign_temporary (matrix_vector_range &mvr)` +|Assigns a temporary. May change the matrix vector range `mvr`. + +|`template matrix_vector_range &operator = (const vector_expression &ae)` +|The extended assignment operator. + +|`template matrix_vector_range &assign (const vector_expression &ae)` +|Assigns a vector expression to the sub vector. Left and right hand side +of the assignment should be independent. + +|`template matrix_vector_range &operator += (const vector_expression &ae)` +|A computed assignment operator. Adds the vector expression to the sub +vector. + +|`template matrix_vector_range &plus_assign (const vector_expression &ae)` +|Adds a vector expression to the sub vector. Left and right hand side of +the assignment should be independent. + +|`template matrix_vector_range &operator -= (const vector_expression &ae)` +|A computed assignment operator. Subtracts the vector expression from +the sub vector. + +|`template matrix_vector_range &minus_assign (const vector_expression &ae)` +|Subtracts a vector expression from the sub vector. Left and right hand +side of the assignment should be independent. + +|`template matrix_vector_range &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the sub vector with a scalar. + +|`template matrix_vector_range &operator /= (const AT &at)` |A +computed assignment operator. Divides the sub vector through a scalar. + +|`void swap (matrix_vector_range &mvr)` |Swaps the contents of the sub +vectors. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `matrix_vector_range`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `matrix_vector_range`. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the `matrix_vector_range`. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +`matrix_vector_range`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the +`matrix_vector_range`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`matrix_vector_range`. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed `matrix_vector_range`. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed `matrix_vector_range`. +|=== + +=== [#vector_slice]#Vector Slice# + +==== Description + +The templated class `matrix_vector_slice` allows addressing a sliced +sub vector of a matrix. + +==== Example + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + for (unsigned i = 0; i < m.size1 (); ++ i) + for (unsigned j = 0; j < m.size2 (); ++ j) + m (i, j) = 3 * i + j; + + matrix_vector_slice > mvs (m, slice (0, 1, 3), slice (0, 1, 3)); + std::cout << mvs << std::endl; +} +.... + +==== Definition + +Defined in the header matrix_proxy.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`M` |The type of matrix referenced. | +|=== + +==== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +If the specified slices fall outside that of the index range of the +matrix, then the `matrix_vector_slice` is not a well formed Vector +Expression. That is, access to an element which is outside of the matrix +is _undefined_. + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +==== Public base classes + +`vector_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_vector_slice (matrix_type &data, const slice &s1, const slice &s2)` +|Constructs a sub vector. + +|`size_type size () const` |Returns the size of the sub vector. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator () (size_type i)` |Returns a reference of the +`i`-th element. + +|`matrix_vector_slice &operator = (const matrix_vector_slice &mvs)` |The +assignment operator. + +|`matrix_vector_slice &assign_temporary (matrix_vector_slice &mvs)` +|Assigns a temporary. May change the matrix vector slice `vs`. + +|`template matrix_vector_slice &operator = (const vector_expression &ae)` +|The extended assignment operator. + +|`template matrix_vector_slice &assign (const vector_expression &ae)` +|Assigns a vector expression to the sub vector. Left and right hand side +of the assignment should be independent. + +|`template matrix_vector_slice &operator += (const vector_expression &ae)` +|A computed assignment operator. Adds the vector expression to the sub +vector. + +|`template matrix_vector_slice &plus_assign (const vector_expression &ae)` +|Adds a vector expression to the sub vector. Left and right hand side of +the assignment should be independent. + +|`template matrix_vector_slice &operator -= (const vector_expression &ae)` +|A computed assignment operator. Subtracts the vector expression from +the sub vector. + +|`template matrix_vector_slice &minus_assign (const vector_expression &ae)` +|Subtracts a vector expression from the sub vector. Left and right hand +side of the assignment should be independent. + +|`template matrix_vector_slice &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the sub vector with a scalar. + +|`template matrix_vector_slice &operator /= (const AT &at)` |A +computed assignment operator. Divides the sub vector through a scalar. + +|`void swap (matrix_vector_slice &mvs)` |Swaps the contents of the sub +vectors. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `matrix_vector_slice`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `matrix_vector_slice`. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the `matrix_vector_slice`. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +`matrix_vector_slice`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`matrix_vector_slice`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`matrix_vector_slice`. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed `matrix_vector_slice`. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed `matrix_vector_slice`. +|=== + +=== [#matrix_range]#Matrix Range# + +==== Description + +The templated class `matrix_range` allows addressing a sub matrix of +a matrix. + +==== Example + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + matrix_range > mr (m, range (0, 3), range (0, 3)); + for (unsigned i = 0; i < mr.size1 (); ++ i) + for (unsigned j = 0; j < mr.size2 (); ++ j) + mr (i, j) = 3 * i + j; + std::cout << mr << std::endl; +} +.... + +==== Definition + +Defined in the header matrix_proxy.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`M` |The type of matrix referenced. | +|=== + +==== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +If the specified ranges fall outside that of the index range of the +matrix, then the `matrix_range` is not a well formed Matrix Expression. +That is, access to an element which is outside of the matrix is +_undefined_. + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +==== Public base classes + +`matrix_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_range (matrix_type &data, const range &r1, const range &r2)` +|Constructs a sub matrix. + +|`size_type start1 () const` |Returns the index of the first row. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type start2 () const` |Returns the index of the first column. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`matrix_range &operator = (const matrix_range &mr)` |The assignment +operator. + +|`matrix_range &assign_temporary (matrix_range &mr)` |Assigns a +temporary. May change the matrix range `mr` . + +|`template matrix_range &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template matrix_range &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the sub matrix. Left and right hand side +of the assignment should be independent. + +|`template matrix_range &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the sub +matrix. + +|`template matrix_range &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the sub matrix. Left and right hand side of +the assignment should be independent. + +|`template matrix_range &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the sub matrix. + +|`template matrix_range &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the sub matrix. Left and right hand +side of the assignment should be independent. + +|`template matrix_range &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the sub matrix with a scalar. + +|`template matrix_range &operator /= (const AT &at)` |A +computed assignment operator. Divides the sub matrix through a scalar. + +|`void swap (matrix_range &mr)` |Swaps the contents of the sub matrices. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `matrix_range`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `matrix_range`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `matrix_range`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`matrix_range`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `matrix_range`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `matrix_range`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `matrix_range`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`matrix_range`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`matrix_range`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`matrix_range`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `matrix_range`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `matrix_range`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`matrix_range`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`matrix_range`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `matrix_range`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of reversed the `matrix_range`. +|=== + +==== Simple Projections + +===== Description + +The free `subrange` functions support the construction of matrix ranges. + +===== Prototypes + +[source,cpp] +.... + template + matrix_range subrange (M &data, + M::size_type start1, M::size_type stop1, M::size_type start2, M::size_type, stop2); + template + const matrix_range subrange (const M &data, + M::size_type start1, M::size_type stop1, M::size_type start2, M::size_type, stop2); +.... + +==== Generic Projections + +===== Description + +The free `project` functions support the construction of matrix ranges. +Existing `matrix_range`'s can be composed with further ranges. The +resulting ranges are computed using this existing ranges' `compose` +function. + +===== Prototypes + +[source,cpp] +.... + template + matrix_range project (M &data, const range &r1, const range &r2); + template + const matrix_range project (const M &data, const range &r1, const range &r2); + template + matrix_range project (matrix_range &data, const range &r1, const range &r2); + template + const matrix_range project (const matrix_range &data, const range &r1, const range &r2); +.... + +===== Definition + +Defined in the header matrix_proxy.hpp. + +===== Type requirements + +* `M` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Complexity + +Quadratic depending from the size of the ranges. + +===== Examples + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + for (unsigned i = 0; i < m.size1 (); ++ i) + for (unsigned j = 0; j < m.size2 (); ++ j) + project (m, range (0, 3), range (0, 3)) (i, j) = 3 * i + j; + std::cout << project (m, range (0, 3), range (0, 3)) << std::endl; +} +.... + +=== [#matrix_slice]#Matrix Slice# + +==== Description + +The templated class `matrix_slice` allows addressing a sliced sub +matrix of a matrix. + +==== Example + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + matrix_slice > ms (m, slice (0, 1, 3), slice (0, 1, 3)); + for (unsigned i = 0; i < ms.size1 (); ++ i) + for (unsigned j = 0; j < ms.size2 (); ++ j) + ms (i, j) = 3 * i + j; + std::cout << ms << std::endl; +} +.... + +==== Definition + +Defined in the header matrix_proxy.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`M` |The type of matrix referenced. | +|=== + +==== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +If the specified slices fall outside that of the index range of the +matrix, then the `matrix_slice` is not a well formed Matrix Expression. +That is, access to an element which is outside of the matrix is +_undefined_. + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +==== Public base classes + +`matrix_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`matrix_slice (matrix_type &data, const slice &s1, const slice &s2)` +|Constructs a sub matrix. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`matrix_slice &operator = (const matrix_slice &ms)` |The assignment +operator. + +|`matrix_slice &assign_temporary (matrix_slice &ms)` |Assigns a +temporary. May change the matrix slice `ms` . + +|`template matrix_slice &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template matrix_slice &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the sub matrix. Left and right hand side +of the assignment should be independent. + +|`template matrix_slice &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the sub +matrix. + +|`template matrix_slice &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the sub matrix. Left and right hand side of +the assignment should be independent. + +|`template matrix_slice &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the sub matrix. + +|`template matrix_slice &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the sub matrix. Left and right hand +side of the assignment should be independent. + +|`template matrix_slice &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the sub matrix with a scalar. + +|`template matrix_slice &operator /= (const AT &at)` |A +computed assignment operator. Multiplies the sub matrix through a +scalar. + +|`void swap (matrix_slice &ms)` |Swaps the contents of the sub matrices. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `matrix_slice`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `matrix_slice`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `matrix_slice`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`matrix_slice`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `matrix_slice`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `matrix_slice`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `matrix_slice`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`matrix_slice`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`matrix_slice`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`matrix_slice`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `matrix_slice`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `matrix_slice`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`matrix_slice`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`matrix_slice`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `matrix_slice`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `matrix_slice`. +|=== + +==== Simple Projections + +===== Description + +The free `subslice` functions support the construction of matrix slices. + +===== Prototypes + +[source,cpp] +.... + template + matrix_slice subslice (M &data, + M::size_type start1, M::difference_type stride1, M::size_type size1, + M::size_type start2, M::difference_type stride2, M::size_type size2); + template + const matrix_slice subslice (const M &data, + M::size_type start1, M::difference_type stride1, M::size_type size1, + M::size_type start2, M::difference_type stride2, M::size_type size2); +.... + +==== Generic Projections + +===== Description + +The free `project` functions support the construction of matrix slices. +Existing `matrix_slice` 's can be composed with further ranges or slices. +The resulting slices are computed using this existing slices' `compose` +function. + +===== Prototypes + +[source,cpp] +.... + template + matrix_slice project (M &data, const slice &s1, const slice &s2); + template + const matrix_slice project (const M &data, const slice &s1, const slice &s2); + template + matrix_slice project (matrix_slice &data, const range &r1, const range &r2); + template + const matrix_slice project (const matrix_slice &data, const range &r1, const range &r2); + template + matrix_slice project (matrix_slice &data, const slice &s1, const slice &s2); + template + const matrix_slice project (const matrix_slice &data, const slice &s1, const slice &s2); +.... + +===== Definition + +Defined in the header matrix_proxy.hpp. + +===== Type requirements + +* `M` is a model of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Complexity + +Quadratic depending from the size of the slices. + +===== Examples + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + for (unsigned i = 0; i < m.size1 (); ++ i) + for (unsigned j = 0; j < m.size2 (); ++ j) + project (m, slice (0, 1, 3), slice (0, 1, 3)) (i, j) = 3 * i + j; + std::cout << project (m, slice (0, 1, 3), slice (0, 1, 3)) << std::endl; +} +.... + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/matrix_sparse.adoc b/doc/ublas/matrix_sparse.adoc new file mode 100644 index 000000000..945b7f676 --- /dev/null +++ b/doc/ublas/matrix_sparse.adoc @@ -0,0 +1,660 @@ +== Sparse Matricies + +[[toc]] + +=== [#mapped_matrix]#Mapped Matrix# + +==== Description + +The templated class `mapped_matrix` is the base container +adaptor for sparse matricies using element maps. For a _(m +xn_)-dimensional sparse matrix and _0 < = i < m_, _0 < = j < n_ the +non-zero elements __h__~_i,j_~ are mapped via _(i x n + j)_ for row +major orientation or via _(i + j x m)_ for column major orientation to +consecutive elements of the associative container, i.e. for elements _k_ += __m__~_i1,j1_~ and __k + 1 = __m__~_i2,j2_~ +of the container holds __i__~_1_~ __< i__~_2_~ or +__(i__~_1_~ __= i__~_2_~ and __j__~_1_~ __< j__~_2_~_)_ with row major +orientation or __j__~_1_~ __< j__~_2_~ or __(j__~_1_~ __= j__~_2_~ and +__i__~_1_~ __< __i__~_2_~) with column major orientation. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + mapped_matrix m (3, 3, 3 * 3); + for (unsigned i = 0; i < m.size1 (); ++ i) + for (unsigned j = 0; j < m.size2 (); ++ j) + m (i, j) = 3 * i + j; + std::cout << m << std::endl; +} +.... + +==== Definition + +Defined in the header matrix_sparse.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the mapped matrix. | + +|`F` |Functor describing the storage organization. +link:#mapped_matrix_1[[1]] |`row_major` + +|`A` |The type of the adapted array. link:#mapped_matrix_2[[2]] +|`map_std` +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`mapped_matrix ()` |Allocates a `mapped_matrix` that holds at most zero +rows of zero elements. + +|`mapped_matrix (size_type size1, size_type2, size_type non_zeros = 0)` +|Allocates a `mapped_matrix` that holds at most `size1` rows of `size2` +elements. + +|`mapped_matrix (const mapped_matrix &m)` |The copy constructor. + +|`template mapped_matrix (size_type non_zeros, const matrix_expression &ae)` +|The extended copy constructor. + +|`void resize (size_type size1, size_type size2, bool preserve = true)` +|Reallocates a `mapped_matrix` to hold at most `size1` rows of `size2` +elements. The existing elements of the `mapped_matrix` are preseved when +specified. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`mapped_matrix &operator = (const mapped_matrix &m)` |The assignment +operator. + +|`mapped_matrix &assign_temporary (mapped_matrix &m)` |Assigns a +temporary. May change the mapped matrix `m` . + +|`template mapped_matrix &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template mapped_matrix &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the mapped matrix. Left and right hand +side of the assignment should be independent. + +|`template mapped_matrix &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +mapped matrix. + +|`template mapped_matrix &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the mapped matrix. Left and right hand side +of the assignment should be independent. + +|`template mapped_matrix &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the mapped matrix. + +|`template mapped_matrix &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the mapped matrix. Left and right +hand side of the assignment should be independent. + +|`template mapped_matrix &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the mapped matrix with a +scalar. + +|`template mapped_matrix &operator /= (const AT &at)` |A +computed assignment operator. Divides the mapped matrix through a +scalar. + +|`void swap (mapped_matrix &m)` |Swaps the contents of the mapped +matrices. + +|`true_refrence insert_element (size_type i, size_type j, const_reference t)` +|Inserts the value `t` at the `j`-th element of the `i`-th row. +Duplicates elements are not allowed. + +|`void erase_element (size_type i, size_type j)` |Erases the value at +the `j`-th element of the `i`-th row. + +|`void clear ()` |Clears the mapped matrix. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `mapped_matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `mapped_matrix`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `mapped_matrix`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`mapped_matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `mapped_matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `mapped_matrix`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `mapped_matrix`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`mapped_matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`mapped_matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`mapped_matrix`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `mapped_matrix`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `mapped_matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`mapped_matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`mapped_matrix`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `mapped_matrix`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `mapped_matrix`. +|=== + +==== Notes + +[#mapped_matrix_1]#[1]# Supported parameters for the storage +organization are `row_major` and `column_major`. + +[#mapped_matrix_2]#[2]# Supported parameters for the adapted array are +`map_array` and `map_std`. The latter is +equivalent to `std::map`. + +=== [#compressed_matrix]#Compressed Matrix# + +==== Description + +The templated class `compressed_matrix` is the base +container adaptor for compressed matrices. For a _(m x n_ )-dimensional +compressed matrix and _0 < = i < m_, _0 < = j < n_ the non-zero elements +__m__~_i,j_~ are mapped via _(i x n + j)_ for row major orientation or +via _(i + j x m)_ for column major orientation to consecutive elements +of the index and value containers, i.e. for elements _k_ = +__m__~_i1,j1_~and __k + 1 = __m__~_i2,j2_~ +of the container holds __i__~_1_~ __< i__~_2_~ or +__(i__~_1_~ __= i__~_2_~ and __j__~_1_~ __< j__~_2_~_)_ with row major +orientation or __j__~_1_~ __< j__~_2_~ or __(j__~_1_~ __= j__~_2_~ and +__i__~_1_~ __< i__~_2_~_)_ with column major orientation. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + compressed_matrix m (3, 3, 3 * 3); + for (unsigned i = 0; i < m.size1 (); ++ i) + for (unsigned j = 0; j < m.size2 (); ++ j) + m (i, j) = 3 * i + j; + std::cout << m << std::endl; +} +.... + +==== Definition + +Defined in the header matrix_sparse.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the compressed matrix. | + +|`F` |Functor describing the storage organization. +link:#compressed_matrix_1[[1]] |`row_major` + +|`IB` |The index base of the compressed vector. +link:#compressed_matrix_2[[2]] |`0` + +|`IA` |The type of the adapted array for indices. +link:#compressed_matrix_3[[3]] |`unbounded_array` + +|`TA` |The type of the adapted array for values. +link:#compressed_matrix_3[[3]] |`unbounded_array` +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`compressed_matrix ()` |Allocates a `compressed_matrix` that holds at +most zero rows of zero elements. + +|`compressed_matrix (size_type size1, size_type2, size_type non_zeros = 0)` +|Allocates a `compressed_matrix` that holds at most `size1` rows of +`size2` elements. + +|`compressed_matrix (const compressed_matrix &m)` |The copy constructor. + +|`template compressed_matrix (size_type non_zeros, const matrix_expression &ae)` +|The extended copy constructor. + +|`void resize (size_type size1, size_type size2, bool preserve = true)` +|Reallocates a `compressed_matrix` to hold at most `size1` rows of +`size2` elements. The existing elements of the `compressed_matrix` are +preseved when specified. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`compressed_matrix &operator = (const compressed_matrix &m)` |The +assignment operator. + +|`compressed_matrix &assign_temporary (compressed_matrix &m)` |Assigns a +temporary. May change the compressed matrix `m`. + +|`template compressed_matrix &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template compressed_matrix &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the compressed matrix. Left and right +hand side of the assignment should be independent. + +|`template compressed_matrix &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +compressed matrix. + +|`template compressed_matrix &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the compressed matrix. Left and right hand +side of the assignment should be independent. + +|`template compressed_matrix &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the compressed matrix. + +|`template compressed_matrix &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the compressed matrix. Left and +right hand side of the assignment should be independent. + +|`template compressed_matrix &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the compressed matrix with a +scalar. + +|`template compressed_matrix &operator /= (const AT &at)` |A +computed assignment operator. Divides the compressed matrix through a +scalar. + +|`void swap (compressed_matrix &m)` |Swaps the contents of the +compressed matrices. + +|`true_reference insert_element (size_type i, size_type j, const_reference t)` +|Inserts the value `t` at the `j`-th element of the `i`-th row. +Duplicates elements are not allowed. + +|`void erase_element (size_type i, size_type j)` |Erases the value at +the `j`-th element of the `i`-th row. + +|`void clear ()` |Clears the compressed matrix. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `compressed_matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `compressed_matrix`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `compressed_matrix`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`compressed_matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `compressed_matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `compressed_matrix`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `compressed_matrix`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`compressed_matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`compressed_matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`compressed_matrix`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `compressed_matrix`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `compressed_matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`compressed_matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`compressed_matrix`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `compressed_matrix`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `compressed_matrix`. +|=== + +==== Notes + +[#compressed_matrix_1]#[1]# Supported parameters for the storage +organization are `row_major` and `column_major`. + +[#compressed_matrix_2]#[2]# Supported parameters for the index base are +`0` and `1` at least. + +[#compressed_matrix_3]#[3]# Supported parameters for the adapted array +are `unbounded_array<>` , `bounded_array<>` and `std::vector<>` . + +=== [#coordinate_matrix]#Coordinate Matrix# + +==== Description + +The templated class `coordinate_matrix` is the base +container adaptor for compressed matrices. For a _(m x n_ )-dimensional +sorted coordinate matrix and _0 < = i < m_, _0 < = j < n_ the non-zero +elements __m__~_i,j_~ are mapped via _(i x n + j)_ for row major +orientation or via _(i + j x m)_ for column major orientation to +consecutive elements of the index and value containers, i.e. for +elements _k_ = __m__~_i1,j1_~ and __k + 1 = +__m__~_i2,j2_~ of the container holds __i__~_1_~ __< +i__~_2_~ or __(i__~_1_~ __= i__~_2_~ and __j__~_1_~ __< j__~_2_~_)_ with +row major orientation or __j__~_1_~ __< j__~_2_~ or __(j__~_1_~ __= +j__~_2_~ and __i__~_1_~ __< i__~_2_~_)_ with column major orientation. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + coordinate_matrix m (3, 3, 3 * 3); + for (unsigned i = 0; i < m.size1 (); ++ i) + for (unsigned j = 0; j < m.size2 (); ++ j) + m (i, j) = 3 * i + j; + std::cout << m << std::endl; +} +.... + +==== Definition + +Defined in the header matrix_sparse.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the coordinate matrix. | + +|`F` |Functor describing the storage organization. +link:#coordinate_matrix_1[[1]] |`row_major` + +|`IB` |The index base of the coordinate vector. +link:#coordinate_matrix_2[[2]] |`0` + +|`IA` |The type of the adapted array for indices. +link:#coordinate_matrix_3[[3]] |`unbounded_array` + +|`TA` |The type of the adapted array for values. +link:#coordinate_matrix_3[[3]] |`unbounded_array` +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`coordinate_matrix ()` |Allocates a `coordinate_matrix` that holds at +most zero rows of zero elements. + +|`coordinate_matrix (size_type size1, size_type2, size_type non_zeros = 0)` +|Allocates a `coordinate_matrix` that holds at most `size1` rows of +`size2` elements. + +|`coordinate_matrix (const coordinate_matrix &m)` |The copy constructor. + +|`template coordinate_matrix (size_type non_zeros, const matrix_expression &ae)` +|The extended copy constructor. + +|`void resize (size_type size1, size_type size2, bool preserve = true)` +|Reallocates a `coordinate_matrix` to hold at most `size1` rows of +`size2` elements. The existing elements of the `coordinate_matrix` are +preseved when specified. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`coordinate_matrix &operator = (const coordinate_matrix &m)` |The +assignment operator. + +|`coordinate_matrix &assign_temporary (coordinate_matrix &m)` |Assigns a +temporary. May change the coordinate matrix `m`. + +|`template coordinate_matrix &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template coordinate_matrix &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the coordinate matrix. Left and right +hand side of the assignment should be independent. + +|`template coordinate_matrix &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +coordinate matrix. + +|`template coordinate_matrix &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the coordinate matrix. Left and right hand +side of the assignment should be independent. + +|`template coordinate_matrix &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the coordinate matrix. + +|`template coordinate_matrix &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the coordinate matrix. Left and +right hand side of the assignment should be independent. + +|`template coordinate_matrix &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the coordinate matrix with a +scalar. + +|`template coordinate_matrix &operator /= (const AT &at)` |A +computed assignment operator. Divides the coordinate matrix through a +scalar. + +|`void swap (coordinate_matrix &m)` |Swaps the contents of the +coordinate matrices. + +|`true_reference insert_element (size_type i, size_type j, const_reference t)` +|Inserts the value `t` at the `j`-th element of the `i`-th row. +Duplicates elements are not allowed. + +|`void append_element (size_type i, size_type j, const_reference t)` +|Appends the value `t` at the `j`-th element of the `i`-th row. +Duplicate elements can be appended to a `coordinate_matrix`. They are +merged into a single arithmetically summed element by the `sort` +function. + +|`void erase_element (size_type i, size_type j)` |Erases the value at +the `j`-th element of the `i`-th row. + +|`void clear ()` |Clears the coordinate matrix. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `coordinate_matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `coordinate_matrix`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `coordinate_matrix`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`coordinate_matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `coordinate_matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `coordinate_matrix`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `coordinate_matrix`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`coordinate_matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`coordinate_matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`coordinate_matrix`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `coordinate_matrix`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `coordinate_matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`coordinate_matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`coordinate_matrix`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `coordinate_matrix`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `coordinate_matrix`. +|=== + +==== Notes + +[#coordinate_matrix_1]#[1]# Supported parameters for the storage +organization are `row_major` and `column_major`. + +[#coordinate_matrix_2]#[2]# Supported parameters for the index base are +`0` and `1` at least. + +[#coordinate_matrix_3]#[3]# Supported parameters for the adapted array +are `unbounded_array<>` , `bounded_array<>` and `std::vector<>` . + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/operations_overview.adoc b/doc/ublas/operations_overview.adoc new file mode 100644 index 000000000..64c107864 --- /dev/null +++ b/doc/ublas/operations_overview.adoc @@ -0,0 +1,283 @@ +== Overview of Tensor, Matrix and Vector Operations + +[[toc]] + +Contents::: + link:#blas[Basic Linear Algebra] + + + link:#advanced[Advanced Functions] + + + link:#sub[Submatrices, Subvectors] + + + link:#speed[Speed Improvements] + +=== Definitions + +[cols=",",] +|=== +|`X, Y, Z` |are tensors +|`A, B, C` |are matrices +|`u, v, w` |are vectors +|`i, j, k` |are integer values +|`t, t1, t2` |are scalar values +|`r, r1, r2` |are link:range.html[ranges], e.g. `range(0, 3)` +|`s, s1, s2` |are link:range.html#slice[slices], e.g. `slice(0, 1, 3)` +|=== + +=== [#blas]#Basic Linear Algebra# + +==== standard operations: addition, subtraction, multiplication by a scalar + +.... +X = Y + Z; X = Y - Z; X = -Y; +C = A + B; C = A - B; C = -A; +w = u + v; w = u - v; w = -u; +X = t * Y; Y = X * t; X = Y / t; +C = t * A; C = A * t; C = A / t; +w = t * u; w = u * t; w = u / t; +.... + +==== computed assignments + +.... +X += Y; X -= Y; +C += A; C -= A; +w += u; w -= u; +X *= t; X /= t; +C *= t; C /= t; +w *= t; w /= t; +.... + +==== inner, outer and other products + +.... +t = inner_prod(u, v); +C = outer_prod(u, v); +w = prod(A, u); w = prod(u, A); w = prec_prod(A, u); w = prec_prod(u, A); +C = prod(A, B); C = prec_prod(A, B); +w = element_prod(u, v); w = element_div(u, v); +C = element_prod(A, B); C = element_div(A, B); +.... + +==== tensor products + +.... +Z = prod(X, v, t); +Z = prod(X, A, t); +Z = prod(X, Y, p); +Z = prod(X, Y, pa, pb); +t = inner_prod(X, Y); +Z = outer_prod(X, Y); +.... + +==== transformations + +.... +w = conj(u); w = real(u); w = imag(u); +C = trans(A); C = conj(A); C = herm(A); C = real(A); C = imag(A); +Z = trans(X); Z = conj(X); Z = real(X); Z = imag(X); +.... + +=== [#advanced]#Advanced functions# + +==== norms + +.... +t = norm_inf(v); i = index_norm_inf(v); +t = norm_1(v); t = norm_2(v); +t = norm_2_square(v); +t = norm_inf(A); i = index_norm_inf(A); +t = norm_1(A); t = norm_frobenius(A); +t = norm(X); +.... + +==== products + +.... +axpy_prod(A, u, w, true); // w = A * u +axpy_prod(A, u, w, false); // w += A * u +axpy_prod(u, A, w, true); // w = trans(A) * u +axpy_prod(u, A, w, false); // w += trans(A) * u +axpy_prod(A, B, C, true); // C = A * B +axpy_prod(A, B, C, false); // C += A * B +.... + +*_Note:_ The last argument (`bool init`) of `axpy_prod` is optional. +Currently it defaults to `true`, but this may change in the future. +Setting the `init` to `true` is equivalent to calling `w.clear()` before +`axpy_prod`. There are some specialisation for products of compressed +matrices that give a large speed up compared to `prod`.* + +.... +w = block_prod (A, u); // w = A * u +w = block_prod (u, A); // w = trans(A) * u +C = block_prod (A, B); // C = A * B +.... + +*_Note:_ The blocksize can be any integer. However, the actual speed +depends very significantly on the combination of blocksize, CPU and +compiler. The function `block_prod` is designed for large dense +matrices.* + +==== rank-k updates + +.... +opb_prod(A, B, C, true); // C = A * B +opb_prod(A, B, C, false); // C += A * B +.... + +*_Note:_ The last argument (`bool init`) of `opb_prod` is optional. +Currently it defaults to `true`, but this may change in the future. This +function may give a speedup if `A` has less columns than rows, because +the product is computed as a sum of outer products.* + +=== [#sub]#Submatrices, Subvectors# + +Accessing submatrices and subvectors via *proxies* using `project` +functions: + +.... +w = project(u, r); // the subvector of u specifed by the index range r +w = project(u, s); // the subvector of u specifed by the index slice s +C = project(A, r1, r2); // the submatrix of A specified by the two index ranges r1 and r2 +C = project(A, s1, s2); // the submatrix of A specified by the two index slices s1 and s2 +w = row(A, i); w = column(A, j); // a row or column of matrix as a vector +.... + +Assigning to submatrices and subvectors via *proxies* using `project` +functions: + +.... +project(u, r) = w; // assign the subvector of u specifed by the index range r +project(u, s) = w; // assign the subvector of u specifed by the index slice s +project(A, r1, r2) = C; // assign the submatrix of A specified by the two index ranges r1 and r2 +project(A, s1, s2) = C; // assign the submatrix of A specified by the two index slices s1 and s2 +row(A, i) = w; column(A, j) = w; // a row or column of matrix as a vector +.... + +*_Note:_ A range `r = range(start, stop)` contains all indices `i` with +`start <= i < stop`. A slice is something more general. The slice +`s = slice(start, stride, size)` contains the indices +`start, start+stride, ..., start+(size-1)*stride`. The stride can be 0 +or negative! If `start >= stop` for a range or `size == 0` for a slice +then it contains no elements.* + +Sub-ranges and sub-slices of vectors and matrices can be created +directly with the `subrange` and `sublice` functions: + +.... +w = subrange(u, 0, 2); // the 2 element subvector of u +w = subslice(u, 0, 1, 2); // the 2 element subvector of u +C = subrange(A, 0,2, 0,3); // the 2x3 element submatrix of A +C = subslice(A, 0,1,2, 0,1,3); // the 2x3 element submatrix of A +subrange(u, 0, 2) = w; // assign the 2 element subvector of u +subslice(u, 0, 1, 2) = w; // assign the 2 element subvector of u +subrange(A, 0,2, 0,3) = C; // assign the 2x3 element submatrix of A +subrange(A, 0,1,2, 0,1,3) = C; // assigne the 2x3 element submatrix of A +.... + +There are to more ways to access some matrix elements as a vector: + +.... +matrix_vector_range (A, r1, r2); +matrix_vector_slice (A, s1, s2); +.... + +*_Note:_ These matrix proxies take a sequence of elements of a matrix and +allow you to access these as a vector. In particular +`matrix_vector_slice` can do this in a very general way. +`matrix_vector_range` is less useful as the elements must lie along a +diagonal.* + +_Example:_ To access the first two elements of a sub column of a matrix +we access the row with a slice with stride 1 and the column with a slice +with stride 0 thus: + +`matrix_vector_slice (A, slice(0,1,2), slice(0,0,2));` + +=== [#speed]#Speed improvements# + +==== [#noalias]#Matrix / Vector assignment# + +If you know for sure that the left hand expression and the right hand +expression have no common storage, then assignment has no _aliasing_. A +more efficient assignment can be specified in this case: + +.... +noalias(C) = prod(A, B); +.... + +This avoids the creation of a temporary matrix that is required in a +normal assignment. 'noalias' assignment requires that the left and right +hand side be size conformant. + +==== Sparse element access + +The matrix element access function `A(i1,i2)` or the equivalent vector +element access functions (`v(i) or v[i]`) usually create 'sparse element +proxies' when applied to a sparse matrix or vector. These _proxies_ +allow access to elements without having to worry about nasty C++ issues +where references are invalidated. + +These 'sparse element proxies' can be implemented more efficiently when +applied to `const` objects. Sadly in C++ there is no way to distinguish +between an element access on the left and right hand side of an +assignment. Most often elements on the right hand side will not be +changed and therefore it would be better to use the `const` proxies. We +can do this by making the matrix or vector `const` before accessing it's +elements. For example: + +.... +value = const_cast(v)[i]; // VEC is the type of V +.... + +If more then one element needs to be accessed `const_iterator` 's should +be used in preference to `iterator` 's for the same reason. For the more +daring 'sparse element proxies' can be completely turned off in uBLAS by +defining the configuration macro `BOOST_UBLAS_NO_ELEMENT_PROXIES`. + +==== Controlling the complexity of nested products + +What is the complexity (the number of add and multiply operations) +required to compute the following? + +.... + R = prod(A, prod(B,C)); +.... + +Firstly the complexity depends on matrix size. Also since prod is +transitive (not commutative) the bracket order affects the complexity. + +uBLAS evaluates expressions without matrix or vector temporaries and +honours the bracketing structure. However avoiding temporaries for +nested product unnecessarly increases the complexity. Conversly by +explictly using temporary matrices the complexity of a nested product +can be reduced. + +uBLAS provides 3 alternative syntaxes for this purpose: + +.... + temp_type T = prod(B,C); R = prod(A,T); // Preferable if T is preallocated +.... + +.... + prod(A, temp_type(prod(B,C)); +.... + +.... + prod(A, prod(B,C)); +.... + +The 'temp_type' is important. Given A,B,C are all of the same type. Say +matrix, the choice is easy. However if the value_type is mixed +(int with float or double) or the matrix type is mixed (sparse with +symmetric) the best solution is not so obvious. It is up to you! It +depends on numerical properties of A and the result of the prod(B,C). + +''''' + +Copyright (©) 2000-2007 Joerg Walter, Mathias Koch, Gunter Winkler, +Michael Stevens + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/options.adoc b/doc/ublas/options.adoc new file mode 100644 index 000000000..a9e26bad9 --- /dev/null +++ b/doc/ublas/options.adoc @@ -0,0 +1,188 @@ +== Boost Basic Linear Algebra - Configuration Options + +[[toc]] + +link:index.html[back to uBLAS home] + +=== NDEBUG + +*Make sure you define NDEBUG* The only way uBLAS knows you want a +release configuration is to check if you have defined NDEBUG. If you +don't it assumes you want a debug configuration and adds a lot of very +useful runtime check. However these are very slow! + +=== BOOST_UBLAS_MOVE_SEMANTICS + +The patch and description was provided by Nasos Iliopoulos. + +An immediate effect of this option is the elimination of the need for +noalias in types vector and matrix, when assigned to the same +type. This option doesn't have an effect on bounded and c types. +Although it is rare, not all compilers support copy elision (that allows +for move semantics), so a test must be performed to make sure that there +is a benefit when it is enabled. A small demonstration and test can be +found in +link:../test/manual/test_move_semantics.cpp[test_move_semantics.cpp] + +In the link:../test/manual/test_move_semantics.cpp[test example] two +tests are defined, one for vectors and one for matrices. The aim of this +example is to print the pointers of the storage of each of the +containers, before and after the assignment to a temporary object. When +move semantics are enabled, the vector and matrix storage is moved +from the temporary and no copy is performed. + +If move semantics are supported by your compiler you will get an output +like the following: + +[source,screen] +---- +matrix -------------------------------------------------------------------- +Temporary pointer r: 0x94790c0 +Pointer (must be equal to temp. pointer if move semantics are enabled) : 0x94790c0 +---- + +Notes: + +* It should be no surprise to see matrices and vectors been passed by +VALUE, the compiler takes care and either moves (if the underlying code +does not modify the object), or copies (if the underlying code modifies +the object). +* There might be some space for some improvements (like clearing the +data, before swaping) +* Move semantics don't eliminate temporaries. They rather move their +storage around so no copies are performed. +* MSVC does no implement Named Return Value Optimization in debug mode. +So if you build in debug with this compiler you might get +https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=483229[different +behaviour] than a release build. +* Enabling move semantics is done via #define +BOOST_UBLAS_MOVE_SEMANTICS. +* There is plenty of room for optimizations when c++0x standard is out, +taking advantage of rvalue references. (I have a sweet vector +implementation using that). +* If you enable move semantics and your compiler does not support them, +the operation will just be as passing by const reference. + +Interesting links + +* http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/[Want +Speed? Pass by Value.] +* http://blogs.msdn.com/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx[Rvalue +References: C++0x Features in VC10, Part 2] +* http://cpp-next.com/archive/2009/09/move-it-with-rvalue-references/[Move +It With Rvalue References] + +=== BOOST_UBLAS_CHECK_ENABLE + +When BOOST_UBLAS_CHECK_ENABLE is defined then all index and parameter +checks are enabled. This is enabled in debug mode and disabled in +release mode. + +=== BOOST_UBLAS_TYPE_CHECK + +When BOOST_UBLAS_TYPE_CHECK is enabled then all possibly expensive +structure checks are enabled. If this is not desireable then use #define +BOOST_UBLAS_TYPE_CHECK 0 before including any uBLAS header. The define +BOOST_UBLAS_TYPE_CHECK_EPSILON can be used to control the acceptable +tolerance, see detail/matrix_assign.hpp for implementation details of +this check. + +=== BOOST_UBLAS_USE_LONG_DOUBLE + +Enable uBLAS expressions that involve containers of 'long double' + +=== BOOST_UBLAS_USE_INTERVAL + +Enable uBLAS expressions that involve containers of +'boost::numeric::interval' types + +=== Configuring uBLAS with Macros + +Many macro's appear in ublas/config.hpp and elsewhere. Hopefully in the +future some of these will disappear! They fall into 4 groups: + +* Automatically set by 'boost/numeric/ublas/config.hpp' based on NDEBUG. +Makes the distinction between debug (safe) and release (fast) mode. +Similar to STLport +** _Release_ mode (NDEBUG defined) +*** BOOST_UBLAS_INLINE _Compiler dependant definition to control +function inlining._ +*** BOOST_UBLAS_USE_FAST_SAME +** _Debug_ mode +*** BOOST_UBLAS_CHECK_ENABLE _Enable checking of indexs, iterators and +parameters. Prevents out of bound access etc._ +*** BOOST_UBLAS_TYPE_CHECK _Enable additional checks for the results of +expressions using non dense types. Picks up runtime error such as the +assignment of a numerically non-symmetric matrix to symmertic_matrix. +Use #define BOOST_UBLAS_TYPE_CHECK 0 to disable expensive numeric type +checks._ (Note: "structure check" would be a much better name.) +*** BOOST_UBLAS_TYPE_CHECK_EPSILON _default: sqrt(epsilon), controls how +large the difference between the expected result and the computed result +may become. Increase this value if you are going to use near singular or +badly scaled matrices. Please, refer to detail/matrix_assign.hpp for +implementation of these type checks._ +* Automatically set by 'boost/numeric/ublas/config.hpp' based on +compiler and boost/config.hpp macro's. Augments the compiler deficiency +workarounds already supplied by boost/config.hpp +** BOOST_UBLAS_NO_NESTED_CLASS_RELATION _A particularly nasty problem +with VC7.1 Requires that uBLAS and the user use begin(it) rather then +it.begin()_ +** BOOST_UBLAS_NO_SMART_PROXIES _Disable the automatic propagation of +'constantness' to proxies. Smart proxies automatically determine if the +underling container they reference is constant or not. They adjust there +definition of iterators and container access to reflect this +constantness._ +* For use by uBLAS authors to test implementation methods. Preset in +config.hpp +** BOOST_UBLAS_USE_INVARIANT_HOISTING +** BOOST_UBLAS_USE_INDEXING +** BOOST_UBLAS_USE_INDEXED_ITERATOR +** BOOST_UBLAS_NON_CONFORMANT_PROXIES _Gappy containers may be +non-conformant, that is contain elements at different indices. Assigning +between proxies (vector ranges for example) of these containers is +difficult as the LHS may need insert new elements. This is slow._ +** BOOST_UBLAS_USE_DUFF_DEVICE _Near useless on all platforms (see GCC's +-funroll-loops)_ +* User options. Can be predefined by user before including any uBLAS +headers. They may also be automatically defined for some compilers to +work around compile bugs. +** BOOST_UBLAS_USE_LONG_DOUBLE _Enable uBLAS expressions that involve +containers of 'long double'_ +** BOOST_UBLAS_USE_INTERVAL _Enable uBLAS expressions that involve +containers of 'boost::numeric::interval' types_ +** BOOST_UBLAS_SIMPLE_ET_DEBUG _In order to simplify debugging is is +possible to simplify expression templateso they are restricted to a +single operation_ +** BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS _enable automatic conversion from +proxy class to matrix expression_ +** BOOST_UBLAS_NO_ELEMENT_PROXIES _Disables the use of element proxies +for gappy types._ +** _The Gappy types (sparse, coordinate, compressed) store non-zero +elements in their own containers. When new non-zero elements are +assigned they must rearrange these containers. This invalidates +references, iterators or pointers to these elements. This can happen at +some surprising times such as the expression "a [1] = a [0] = 1;". +Element proxies guarantee all such expressions will work as expected. +However they bring their own restrictions and efficiency problems. For +example as of Boost 1.30.0 they prevent the assignment of elements +between different types._ +** BOOST_UBLAS_REFERENCE_CONST_MEMBER _Enable to allow refernces to be +returned to fixed (zero or one) elements of triangular or banded +matrices_ +** BOOST_UBLAS_NO_EXCEPTIONS _Disable the use exceptions of uBLAS +internal checks and error conditions. BOOST_NO_EXCEPTIONS has same +effect._ +** BOOST_UBLAS_SINGULAR_CHECK _Check the for singularity in triangular +solve() functions_ + +''''' + +[[copyright]] +Copyright (©) 2000-2009 Joerg Walter, Mathias Koch, Gunter Winkler + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). + +[[revision]] +Last modified: Wed Sep 16 23:16:45 CEST 2009 diff --git a/doc/ublas/overview.adoc b/doc/ublas/overview.adoc new file mode 100644 index 000000000..da86f1dd2 --- /dev/null +++ b/doc/ublas/overview.adoc @@ -0,0 +1,582 @@ +== uBLAS Overview + +[[toc]] + +=== Rationale + +It would be nice if every kind of numeric software could be written in +C++ without loss of efficiency, but unless something can be found that +achieves this without compromising the C++ type system it may be +preferable to rely on Fortran, assembler or architecture-specific +extensions (Bjarne Stroustrup). + +This C++ library is directed towards scientific computing on the level +of basic linear algebra constructions with matrices and vectors and +their corresponding abstract operations. The primary design goals were: + +* mathematical notation +* efficiency +* functionality +* compatibility + +Another intention was to evaluate, if the abstraction penalty resulting +from the use of such matrix and vector classes is acceptable. + +=== Resources + +The development of this library was guided by a couple of similar +efforts: + +* http://www.netlib.org/blas/index.html[BLAS] by Jack Dongarra et al. +* http://www.oonumerics.org/blitz/[Blitz++] by Todd Veldhuizen +* http://acts.nersc.gov/pooma/[POOMA] by Scott Haney et al. +* http://www.lsc.nd.edu/research/mtl/[MTL] by Jeremy Siek et al. + +BLAS seems to be the most widely used library for basic linear algebra +constructions, so it could be called a de-facto standard. Its interface +is procedural, the individual functions are somewhat abstracted from +simple linear algebra operations. Due to the fact that is has been +implemented using Fortran and its optimizations, it also seems to be one +of the fastest libraries available. As we decided to design and +implement our library in an object-oriented way, the technical +approaches are distinct. However anyone should be able to express BLAS +abstractions in terms of our library operators and to compare the +efficiency of the implementations. + +Blitz++ is an impressive library implemented in C++. Its main design +seems to be oriented towards multidimensional arrays and their +associated operators including tensors. The author of Blitz++ states, +that the library achieves performance on par or better than +corresponding Fortran code due to his implementation technique using +expression templates and template metaprograms. However we see some +reasons, to develop an own design and implementation approach. We do not +know whether anybody tries to implement traditional linear algebra and +other numerical algorithms using Blitz++. We also presume that even +today Blitz++ needs the most advanced C++ compiler technology due to its +implementation idioms. On the other hand, Blitz++ convinced us, that the +use of expression templates is mandatory to reduce the abstraction +penalty to an acceptable limit. + +POOMA's design goals seem to parallel Blitz++'s in many parts . It +extends Blitz++'s concepts with classes from the domains of partial +differential equations and theoretical physics. The implementation +supports even parallel architectures. + +MTL is another approach supporting basic linear algebra operations in +C++. Its design mainly seems to be influenced by BLAS and the C++ +Standard Template Library. We share the insight that a linear algebra +library has to provide functionality comparable to BLAS. On the other +hand we think, that the concepts of the C++ standard library have not +yet been proven to support numerical computations as needed. As another +difference MTL currently does not seem to use expression templates. This +may result in one of two consequences: a possible loss of expressiveness +or a possible loss of performance. + +=== Concepts + +==== Mathematical Notation + +The usage of mathematical notation may ease the development of +scientific algorithms. So a C++ library implementing basic linear +algebra concepts carefully should overload selected C++ operators on +matrix and vector classes. + +We decided to use operator overloading for the following primitives: + +[cols="<,<",] +|=== +|Description |Operator + +|Indexing of vectors and matrices +|`vector::operator(size_t i); matrix::operator(size_t i, size_t j);` + +|Assignment of vectors and matrices +|`vector::operator = (const vector_expression &); vector::operator += (const vector_expression &); vector::operator -= (const vector_expression &); vector::operator *= (const scalar_expression &); matrix::operator = (const matrix_expression &); matrix::operator += (const matrix_expression &); matrix::operator -= (const matrix_expression &); matrix::operator *= (const scalar_expression &);` + +|Unary operations on vectors and matrices +|`vector_expression operator - (const vector_expression &); matrix_expression operator - (const matrix_expression &);` + +|Binary operations on vectors and matrices +|`vector_expression operator + (const vector_expression &, const vector_expression &); vector_expression operator - (const vector_expression &, const vector_expression &); matrix_expression operator + (const matrix_expression &, const matrix_expression &); matrix_expression operator - (const matrix_expression &, const matrix_expression &);` + +|Multiplication of vectors and matrices with a scalar +|`vector_expression operator * (const scalar_expression &, const vector_expression &); vector_expression operator * (const vector_expression &, const scalar_expression &); matrix_expression operator * (const scalar_expression &, const matrix_expression &); matrix_expression operator * (const matrix_expression &, const scalar_expression &);` +|=== + +We decided to use no operator overloading for the following other +primitives: + +[cols="<,<",] +|=== +|Description |Function + +|Left multiplication of vectors with a matrix +|`vector_expression prod (const matrix_expression &, const vector_expression &); vector_expression prod (const matrix_expression &, const vector_expression &);` + +|Right multiplication of vectors with a matrix +|`vector_expression prod (const vector_expression &, const matrix_expression &); vector_expression prod (const vector_expression &, const matrix_expression &);` + +|Multiplication of matrices |`matrix_expression prod (const matrix_expression &, const matrix_expression &); matrix_expression prod (const matrix_expression &, const matrix_expression &);` + +|Inner product of vectors +|`scalar_expression inner_prod (const vector_expression &, const vector_expression &);` + +|Outer product of vectors +|`matrix_expression outer_prod (const vector_expression &, const vector_expression &);` + +|Transpose of a matrix +|`matrix_expression trans (const matrix_expression &);` +|=== + +==== Efficiency + +To achieve the goal of efficiency for numerical computing, one has to +overcome two difficulties in formulating abstractions with C++, namely +temporaries and virtual function calls. Expression templates solve these +problems, but tend to slow down compilation times. + +===== Eliminating Temporaries + +Abstract formulas on vectors and matrices normally compose a couple of +unary and binary operations. The conventional way of evaluating such a +formula is first to evaluate every leaf operation of a composition into +a temporary and next to evaluate the composite resulting in another +temporary. This method is expensive in terms of time especially for +small and space especially for large vectors and matrices. The approach +to solve this problem is to use lazy evaluation as known from modern +functional programming languages. The principle of this approach is to +evaluate a complex expression element wise and to assign it directly to +the target. + +Two interesting and dangerous facts result: + +===== Aliases + +One may get serious side effects using element wise evaluation on +vectors or matrices. Consider the matrix vector product _x = A x_. +Evaluation of __A__~_1_~_x_ and assignment to __x__~_1_~ changes the +right hand side, so that the evaluation of __A__~_2_~_x_ returns a wrong +result. In this case there are *aliases* of the elements __x__~_n_~ on +both the left and right hand side of the assignment. + +Our solution for this problem is to evaluate the right hand side of an +assignment into a temporary and then to assign this temporary to the +left hand side. To allow further optimizations, we provide a +corresponding member function for every assignment operator and also a +link:operations_overview.html#noalias[`noalias` syntax.] By using this +syntax a programmer can confirm, that the left and right hand sides of +an assignment are independent, so that element wise evaluation and +direct assignment to the target is safe. + +===== Complexity + +The computational complexity may be unexpectedly large under certain +cirumstances. Consider the chained matrix vector product _A (B x)_. +Conventional evaluation of _A (B x)_ is quadratic. Deferred evaluation +of __B x__~_i_~ is linear. As every element __B x__~_i_~ is needed +linearly depending of the size, a completely deferred evaluation of the +chained matrix vector product _A (B x)_ is cubic. In such cases one +needs to reintroduce temporaries in the expression. + +===== Eliminating Virtual Function Calls + +Lazy expression evaluation normally leads to the definition of a class +hierarchy of terms. This results in the usage of dynamic polymorphism to +access single elements of vectors and matrices, which is also known to +be expensive in terms of time. A solution was found a couple of years +ago independently by David Vandervoorde and Todd Veldhuizen and is +commonly called expression templates. Expression templates contain lazy +evaluation and replace dynamic polymorphism with static, i.e. compile +time polymorphism. Expression templates heavily depend on the famous +Barton-Nackman trick, also coined 'curiously defined recursive +templates' by Jim Coplien. + +Expression templates form the base of our implementation. + +===== Compilation times + +It is also a well known fact, that expression templates challenge +currently available compilers. We were able to significantly reduce the +amount of needed expression templates using the Barton-Nackman trick +consequently. + +We also decided to support a dual conventional implementation (i.e. not +using expression templates) with extensive bounds and type checking of +vector and matrix operations to support the development cycle. Switching +from debug mode to release mode is controlled by the `NDEBUG` +preprocessor symbol of ``. + +Functionality + +Every C++ library supporting linear algebra will be measured against the +long-standing Fortran package BLAS. We now describe how BLAS calls may +be mapped onto our classes. + +The page link:operations_overview.html[Overview of Matrix and Vector +Operations] gives a short summary of the most used operations on vectors +and matrices. + +===== Blas Level 1 + +[width="100%",cols="<25%,<25%,<25%,<25%",] +|=== +|BLAS Call |Mapped Library Expression |Mathematical Description |Comment + +|`sasum` OR `dasum` |`norm_1 (x)` |`sum(mod(x~i~))` |Computes the _l~1~_ +(sum) norm of a real vector. + +|`scasum` OR `dzasum` |`real (sum (v)) + imag (sum (v))` |`_sum +re(x~i~) + sum im(x~i~)_` |Computes the sum of elements of a complex +vector. + +|`_nrm2` |`norm_2 (x)` |`sqrt ((sum(mod(x~i~)^_2_^)))` |Computes the +_l~2~_ (euclidean) norm of a vector. + +|`i_amax` |`norm_inf (x) index_norm_inf (x)` |`max(mod(x~i~))` +|Computes the _l~inf~_ (maximum) norm of a vector. + +BLAS computes the index of the first element having this value. + +|`_dot _dotu _dotc` |`inner_prod (x, y)` or `inner_prod (conj (x), y)` +|__x__^_T_^ _y_ or + +__x__^_H_^ _y_ |Computes the inner product of two vectors. + +BLAS implements certain loop unrollment. + +|`dsdot sdsdot` |`a + prec_inner_prod (x, y)` |__a + x__^_T_^ _y_ +|Computes the inner product in double precision. + +|`_copy` |`x = y y.assign (x)` |_x <- y_ |Copies one vector to +another. + +BLAS implements certain loop unrollment. + +|`_swap` |`swap (x, y)` |_x <--> y_ |Swaps two vectors. + +BLAS implements certain loop unrollment. + +|`_scal csscal zdscal` |`x *= a` |_x <- a x_ |Scales a vector. + +BLAS implements certain loop unrollment. + +|`_axpy` |`y += a * x` |_y <- a x + y_ |Adds a scaled vector. + +BLAS implements certain loop unrollment. + +|`_rot _rotm csrot zdrot` +|`t.assign (a * x + b * y), y.assign (- b * x + a * y), x.assign (t)` +|_(x, y) <- (a x + b y, -b x + a y)_ |Applies a plane rotation. + +|`_rotg _rotmg` |  |__(a, b) <- + +  (? a / sqrt (a__^_2_^ + __b__^_2_^__), + +    ? b / sqrt (a__^_2_^ + __b__^_2_^_))_ or__ + +(1, 0) <- (0, 0)__ |Constructs a plane rotation. +|=== + +===== Blas Level 2 + +[width="100%",cols="<25%,<25%,<25%,<25%",] +|=== +|BLAS Call |Mapped Library Expression |Mathematical Description |Comment + +|`_t_mv` |`x = prod (A, x)` or `x = prod (trans (A), x)` or `x = prod (herm (A), x)` |_x <- A x_ or__ + x <- A__^_T_^ _x_ or__ + x <- A__^_H_^ _x_ |Computes the product of a matrix with a vector. + +|`_t_sv` |`y = solve (A, x, tag)` or + +`inplace_solve (A, x, tag)` or + +`y = solve (trans (A), x, tag)` or + +`inplace_solve (trans (A), x, tag)` or + +`y = solve (herm (A), x, tag)`or + +`inplace_solve (herm (A), x, tag)` |__y <- A__^_-1_^ _x_ or__ + +x <- A__^_-1_^ _x_ or__ + +y <- A^_T_^^_-1_^ _x_ or__ + +x <- A^_T_^^_-1_^ _x_ or__ + +y <- A^_H_^^_-1_^ _x_ or__ + +x <- A^_H_^^_-1_^ _x_ +|Solves a system of linear equations with triangular form, i.e. _A_ is +triangular. + +|`_g_mv _s_mv _h_mv` + +|`y = a * prod (A, x) + b * y` or` y = a * prod (trans (A), x) + b * y` +or` y = a * prod (herm (A), x) + b * y` + +|_y <- a A x + b y_ or__ + +y <- a A__^_T_^ __x + b y + +y <- a A__^_H_^ _x + b y_ + +|Adds the scaled product of a matrix with a vector. + +|`_g_r _g_ru _g_rc` + +|`A += a * outer_prod (x, y)` or` A += a * outer_prod (x, conj (y))` + +|__A <- a x y__^_T_^ _+ A_ or__ + +A <- a x y__^_H_^ _+ A_ + +|Performs a rank _1_ update. + +|`_s_r _h_r` + +|`A += a * outer_prod (x, x)` or` A += a * outer_prod (x, conj (x))` + +|__A <- a x x__^_T_^ _+ A_ or__ + +A <- a x x__^_H_^ _+ A_ + +|Performs a symmetric or hermitian rank _1_ update. + +|`_s_r2 _h_r2` + +|`A += a * outer_prod (x, y) +  a * outer_prod (y, x))` +or` A += a * outer_prod (x, conj (y)) +  conj (a) * outer_prod (y, conj (x)))` + +|__A <- a x y__^_T_^ __+ a y x__^_T_^ _+ A_ or__ + +A <- a x y__^_H_^ __+ a__^_-_^ __y x__^_H_^ _+ A_ + +|Performs a symmetric or hermitian rank _2_ update. + +|=== + +===== Blas Level 3 + +[width="100%",cols="<25%,<25%,<25%,<25%",] +|=== +|BLAS Call |Mapped Library Expression |Mathematical Description |Comment + +|`_t_mm` |`B = a * prod (A, B)` or + +`B = a * prod (trans (A), B)` or + +`B = a * prod (A, trans (B))` or + +`B = a * prod (trans (A), trans (B))` or + +`B = a * prod (herm (A), B)` or + +`B = a * prod (A, herm (B))` or + +`B = a * prod (herm (A), trans (B))` or + +`B = a * prod (trans (A), herm (B))` or + +`B = a * prod (herm (A), herm (B))` |_B <- a op (A) op (B)_ with + +  _op (X) = X_ or + +  __op (X) = X__^_T_^ or + +  __op (X) = X__^_H_^ |Computes the scaled product of two matrices. + +|`_t_sm` |`C = solve (A, B, tag)` or + +`inplace_solve (A, B, tag)` or + +`C = solve (trans (A), B, tag)` or` inplace_solve (trans (A), B, tag)` +or` C = solve (herm (A), B, tag)` or` inplace_solve (herm (A), B, tag)` +|__C <- A__^_-1_^ _B_ or__ + +B <- A__^_-1_^ _B_ or__ + +C <- _A_^_T_^^_-1_^ _B_ or__ + +B <- _A_^_-1_^ _B_ or__ + +C <- _A_^_H_^^_-1_^ _B_ or__ + +B <- _A_^_H_^^_-1_^ _B_ |Solves a system of linear equations with +triangular form, i.e. _A_ is triangular. + +|`_g_mm _s_mm _h_mm` |`C = a * prod (A, B) + b * C` or + +`C = a * prod (trans (A), B) + b * C` or + +`C = a * prod (A, trans (B)) + b * C` or + +`C = a * prod (trans (A), trans (B)) + b * C` or + +`C = a * prod (herm (A), B) + b * C` or + +`C = a * prod (A, herm (B)) + b * C` or + +`C = a * prod (herm (A), trans (B)) + b * C` or + +`C = a * prod (trans (A), herm (B)) + b * C` or + +`C = a * prod (herm (A), herm (B)) + b * C` |_C <- a op (A) op (B) + b +C_ with + +  _op (X) = X_ or + +  __op (X) = X__^_T_^ or + +  __op (X) = X__^_H_^ |Adds the scaled product of two matrices. + +|`_s_rk _h_rk` |`B = a * prod (A, trans (A)) + b * B` or + +`B = a * prod (trans (A), A) + b * B` or + +`B = a * prod (A, herm (A)) + b * B` or + +`B = a * prod (herm (A), A) + b * B` |__B <- a A A__^_T_^ _+ b B_ or__ + +B <- a A__^_T_^ _A + b B_ or + +__B <- a A A__^_H_^ _+ b B_ or__ + +B <- a A__^_H_^ _A + b B_ |Performs a symmetric or hermitian rank _k_ +update. + +|`_s_r2k _h_r2k` +|`C = a * prod (A, trans (B)) +  a * prod (B, trans (A)) + b * C` or + +`C = a * prod (trans (A), B) +  a * prod (trans (B), A) + b * C` or + +`C = a * prod (A, herm (B)) +  conj (a) * prod (B, herm (A)) + b * C` +or + +`C = a * prod (herm (A), B) +  conj (a) * prod (herm (B), A) + b * C` +|__C <- a A B__^_T_^ __+ a B A__^_T_^ _+ b C_ or__ + +C <- a A__^_T_^ __B + a B__^_T_^ _A + b C_ or__ + +C <- a A B__^_H_^ __+ a__^_-_^ __B A__^_H_^ _+ b C_ or__ + +C <- a A__^_H_^ __B + a__^_-_^ __B__^_H_^ _A + b C_ |Performs a +symmetric or hermitian rank _2 k_ update. +|=== + +=== Storage Layout + +uBLAS supports many different storage layouts. The full details can be +found at the link:types_overview.html[Overview of Types]. Most types +like `vector` and `matrix` are by default compatible to +C arrays, but can also be configured to contain FORTAN compatible data. + +=== Compatibility + +For compatibility reasons we provide array like indexing for vectors and +matrices. For some types (hermitian, sparse etc) this can be expensive +for matrices due to the needed temporary proxy objects. + +uBLAS uses STL compatible allocators for the allocation of the storage +required for it's containers. + +=== Benchmark Results + +The following tables contain results of one of our benchmarks. This +benchmark compares a native C implementation ('C array') and some +library based implementations. The safe variants based on the library +assume aliasing, the fast variants do not use temporaries and are +functionally equivalent to the native C implementation. Besides the +generic vector and matrix classes the benchmark utilizes special classes +`c_vector` and `c_matrix`, which are intended to avoid every overhead +through genericity. + +The benchmark program *bench1* was compiled with GCC 4.0 and run on an +Athlon 64 3000+. Times are scales for reasonable precision by running +*bench1 100*. + +First we comment the results for double vectors and matrices of +dimension 3 and 3 x 3, respectively. + +[cols="<,,,,",] +|=== +|Comment | | | | + +|inner_prod |C array |0.61 |782 |Some abstraction penalty + +| |c_vector | |0.86 |554 + +| |vector | |1.02 |467 + +|vector + vector |C array |0.51 |1122 |Abstraction penalty: factor 2 + +| |c_vector fast | |1.17 |489 + +| |vector fast | |1.32 |433 + +| |c_vector safe | |2.02 |283 + +| |vector safe | |6.95 |82 + +|outer_prod |C array |0.59 |872 |Some abstraction penalty + +| |c_matrix, c_vector fast | |0.88 |585 + +| |matrix, vector fast | |0.90 |572 + +| |c_matrix, c_vector safe | |1.66 |310 + +| |matrix, vector safe | |2.95 |175 + +|prod (matrix, vector) |C array |0.64 |671 |No significant abstraction +penalty + +| |c_matrix, c_vector fast | |0.70 |613 + +| |matrix, vector fast | |0.79 |543 + +| |c_matrix, c_vector safe | |0.95 |452 + +| |matrix, vector safe | |2.61 |164 + +|matrix + matrix |C array |0.75 |686 |No significant abstraction penalty + +| |c_matrix fast | |0.99 |520 + +| |matrix fast | |1.29 |399 + +| |c_matrix safe | |1.7 |303 + +| |matrix safe | |3.14 |164 + +|prod (matrix, matrix) |C array |0.94 |457 |No significant abstraction +penalty + +| |c_matrix fast | |1.17 |367 + +| |matrix fast | |1.34 |320 + +| |c_matrix safe | |1.56 |275 + +| |matrix safe | |2.06 |208 +|=== + +We notice a two fold performance loss for small vectors and matrices: +first the general abstraction penalty for using classes, and then a +small loss when using the generic vector and matrix classes. The +difference w.r.t. alias assumptions is also significant. + +Next we comment the results for double vectors and matrices of dimension +100 and 100 x 100, respectively. + +[cols="<,<,<,<,<",] +|=== +|Operation |Implementation |Elapsed [s] |MFLOP/s |Comment + +|inner_prod |C array |0.64 |889 |No significant abstraction penalty + +| |c_vector | |0.66 |862 + +| |vector | |0.66 |862 + +|vector + vector |C array |0.64 |894 |No significant abstraction penalty + +| |c_vector fast | |0.66 |867 + +| |vector fast | |0.66 |867 + +| |c_vector safe | |1.14 |501 + +| |vector safe | |1.23 |465 + +|outer_prod |C array |0.50 |1144 |No significant abstraction penalty + +| |c_matrix, c_vector fast | |0.71 |806 + +| |matrix, vector fast | |0.57 |1004 + +| |c_matrix, c_vector safe | |1.91 |300 + +| |matrix, vector safe | |0.89 |643 + +|prod (matrix, vector) |C array |0.65 |876 |No significant abstraction +penalty + +| |c_matrix, c_vector fast | |0.65 |876 + +| |matrix, vector fast | |0.66 |863 + +| |c_matrix, c_vector safe | |0.66 |863 + +| |matrix, vector safe | |0.66 |863 + +|matrix + matrix |C array |0.96 |596 |No significant abstraction penalty + +| |c_matrix fast | |1.21 |473 + +| |matrix fast | |1.00 |572 + +| |c_matrix safe | |2.44 |235 + +| |matrix safe | |1.30 |440 + +|prod (matrix, matrix) |C array |0.70 |813 |No significant abstraction +penalty + +| |c_matrix fast | |0.73 |780 + +| |matrix fast | |0.76 |749 + +| |c_matrix safe | |0.75 |759 + +| |matrix safe | |0.76 |749 +|=== + +For larger vectors and matrices the general abstraction penalty for +using classes seems to decrease, the small loss when using generic +vector and matrix classes seems to remain. The difference w.r.t. alias +assumptions remains visible, too. + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/products.adoc b/doc/ublas/products.adoc new file mode 100644 index 000000000..5c7af1a59 --- /dev/null +++ b/doc/ublas/products.adoc @@ -0,0 +1,200 @@ +== Special Products + +[[toc]] + +=== Functions + +[width="100%",cols=">50%,50%",] +|=== +|template BOOST_UBLAS_INLINE V & +|link:#product_1[axpy_prod] (const matrix_expression< E1 > &e1, const vector_expression< E2 > &e2, V &v, bool init=true) computes `v += A x` or `v = A x` in an optimized fashion. + +|template BOOST_UBLAS_INLINE V & +|link:#product_2[axpy_prod] (const vector_expression< E1 > &e1, const matrix_expression< E2 > &e2, V &v, bool init=true) computes `v += AT x` or `v = AT x` in an optimized fashion. + +|template BOOST_UBLAS_INLINE M & +|link:#product_3[axpy_prod] (const matrix_expression< E1 > &e1, const matrix_expression< E2 > &e2, M &m, bool init=true) computes `M += A X` or `M = A X` in an optimized fashion. + +|template BOOST_UBLAS_INLINE M & +|link:#product_4[opb_prod] (const matrix_expression< E1 > &e1, const matrix_expression< E2 > &e2, M &m, bool init=true) computes `M += A X` or `M = A X` in an optimized fashion. +|=== + +''''' + +[#product_1]#1.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!BOOST_UBLAS_INLINE V& axpy_prod !( !const matrix_expression< E1 > & +!_e1_, + +! ! !const vector_expression< E2 > & !_e2_, + +! ! !V & !_v_, + +! ! !bool !_init_ = `true` + +! !) ! ! +!=== + +|=== + +[width="100%",cols="50%,50%",] +|=== +| a| +computes `v += A x` or `v = A x` in an optimized fashion. + +*Parameters:*:: + _e1_ the matrix expression `A`, + _e2_ the vector expression `x`, + _v_ the result vector `v`, + _init_ a boolean parameter + + +`axpy_prod(A, x, v, init)` implements the well known axpy-product. +Setting _init_ to `true` is equivalent to call `v.clear()` before +`axpy_prod`. Currently _init_ defaults to `true`, but this may change in +the future. + +Up to now there are some specialisation for compressed matrices that +give a large speed up compared to prod. + +|=== + +[#product_2]#2.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!BOOST_UBLAS_INLINE V& axpy_prod !( !const vector_expression< E1 > & +!_e1_, + +! ! !const matrix_expression< E2 > & !_e2_, + +! ! !V & !_v_, + +! ! !bool !_init_ = `true` + +! !) ! ! +!=== + +|=== + +[width="100%",cols="50%,50%",] +|=== +| a| +computes `v += AT x` or `v = AT x` in an optimized fashion. + +*Parameters:*:: + _e1_ the vector expression `x`, + _e2_ the matrix expression `A`, + _v_ the result vector `v`, + _init_ a boolean parameter + +`axpy_prod(x, A, v, init)` implements the well known axpy-product. +Setting _init_ to `true` is equivalent to call `v.clear()` before +`axpy_prod`. Currently _init_ defaults to `true`, but this may change in +the future. + +Up to now there are some specialisation for compressed matrices that +give a large speed up compared to prod. + +|=== + +[#product_3]#3.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!BOOST_UBLAS_INLINE M& axpy_prod !( !const matrix_expression< E1 > & +!_e1_, + +! ! !const matrix_expression< E2 > & !_e2_, + +! ! !M & !_m_, + +! ! !bool !_init_ = `true` + +! !) ! ! +!=== + +|=== + +[width="100%",cols="50%,50%",] +|=== +| a| +computes `M += A X` or `M = A X` in an optimized fashion. + +*Parameters:*:: + _e1_ !the matrix expression `A`, + _e2_ !the matrix expression `X`, + _m_ !the result matrix `M`, + _init_ !a boolean parameter + + +`axpy_prod(A, X, M, init)` implements the well known axpy-product. +Setting _init_ to `true` is equivalent to call `M.clear()` before +`axpy_prod`. Currently _init_ defaults to `true`, but this may change in +the future. + +Up to now there are no specialisations. + +|=== + +[#product_4]#4.# + +[width="100%",cols="100%",] +|=== +a| +[cols=",,,",] +!=== +!BOOST_UBLAS_INLINE M& opb_prod !( !const matrix_expression< E1 > & +!_e1_, + +! ! !const matrix_expression< E2 > & !_e2_, + +! ! !M & !_m_, + +! ! !bool !_init_ = `true` + +! !) ! ! +!=== + +|=== + +[width="100%",cols="50%,50%",] +|=== +| a| +computes `M += A X` or `M = A X` in an optimized fashion. + +*Parameters:*:: + _e1_ the matrix expression `A` + _e2_ the matrix expression `X` + _m_ the result matrix `M` + _init_ a boolean parameter + +`opb_prod(A, X, M, init)` implements the well known axpy-product. +Setting _init_ to `true` is equivalent to call `M.clear()` before +`opb_prod`. Currently _init_ defaults to `true`, but this may change in +the future. + +This function may give a speedup if `A` has less columns than rows, +because the product is computed as a sum of outer products. + +|=== + +''''' + +Copyright (©) 2000-2004 Michael Stevens, Mathias Koch, Joerg Walter, +Gunter Winkler + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). \ No newline at end of file diff --git a/doc/ublas/range.adoc b/doc/ublas/range.adoc new file mode 100644 index 000000000..ad2e8b869 --- /dev/null +++ b/doc/ublas/range.adoc @@ -0,0 +1,191 @@ +== Range and Slice Storage + +[[toc]] + +=== [#range]#Range# + +==== Description + +The class `range` specifies a range of indicies. The range is a sequence +of indices from a start value to stop value. The indices increase by one +and exlude the stop value. `range` can therefore be used to specify +ranges of elements from vectors and matrices. + +==== Example + +[source, cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + range r (0, 3); + for (unsigned i = 0; i < r.size (); ++ i) { + std::cout << r (i) << std::endl; + } +} +.... + +==== Definition + +Defined in the header storage.hpp. + +==== Model of + +Reversible Container. + +==== Type requirements + +None, except for those imposed by the requirements of Reversible +Container. + +==== Public base classes + +None. + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`range (size_type start, size_type stop)` |Constructs a range of +indicies from `start` to `stop (excluded)` . + +|`size_type start () const` |Returns the beginning of the `range`. + +|`size_type size () const` |Returns the size of the `range`. + +|`const_reference operator [] (size_type i) const` |Returns the value +`start + i` of the `i` -th element. + +|`range compose (const range &r) const` |Returns the composite range +from `start + r.start ()` to `start + r.start () + r.size ()`. + +|`bool operator == (const range &r) const` |Tests two ranges for +equality. + +|`bool operator != (const range &r) const` |Tests two ranges for +inequality. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `range`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `range`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`range`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed `range`. +|=== + +==== Preconditions + +* `start () < = stop ()` + +=== [#slice]#Slice# + +==== Description + +The class `slice` specifies a 'slice' of indicies. Slices are more +general then ranges, the stride allows the sequence of indicies to +increase and decrease by the specified amount between element. `slice` +can therefore be used to specify slices of element from vectors and +matrices. + +==== Example + +[source,cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + slice s (0, 1, 3); + for (unsigned i = 0; i < s.size (); ++ i) { + std::cout << s (i) << std::endl; + } +} +.... + +==== Definition + +Defined in the header storage.hpp. + +==== Model of + +Reversible Container. + +==== Type requirements + +None, except for those imposed by the requirements of Reversible +Container. + +==== Public base classes + +None. + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`slice (size_type start, size_type stride, size_type size)` |Constructs +a slice `start,start+stride,start+2*stride...` with `size` elements. + +|`size_type start () const` |Returns the beginning of the `slice`. + +|`size_type stride () const` |Returns the stride of the `slice`. + +|`size_type size () const` |Returns the size of the `slice`. + +|`const_reference operator [] (size_type i) const` |Returns the value +`start + i * stride` of the `i`-th element. + +|`slice compose (const range &r) const` |Returns the composite slice +from `start + stride * r.start ()` to +`start + stride * (r.start () + r.size ())` with stride `stride`. + +|`slice compose (const slice &s) const` |Returns the composite slice +from `start + stride * s.start ()` to +`start + stride * s.stride () * (s.start () + s.size ())` with stride +`stride * s.stride ()` . + +|`bool operator == (const slice &s) const` |Tests two slices for +equality. + +|`bool operator != (const slice &s) const` |Tests two slices for +inequality. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `slice`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `slice`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`slice`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed `slice`. +|=== + +==== Preconditions + +* None all strides are vaild. However when an index is returned or an +iterator is dereferenced its value must be representable as the +size_type. + +''''' + +Copyright (©) 2000-2004 Michael Stevens, Mathias Koch, Joerg Walter, +Gunter Winkler + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/release_notes.adoc b/doc/ublas/release_notes.adoc new file mode 100644 index 000000000..05fda74bc --- /dev/null +++ b/doc/ublas/release_notes.adoc @@ -0,0 +1,80 @@ +== Boost Basic Linear Algebra - Release Notes + +link:index.html[back to uBLAS home] + +[[toc]] + +=== Release 1.70.0 + +==== improvements + +* Add support for GPU-accelerated operations via +http://boostorg.github.io/compute/[Boost.Compute] +* Add support for a new (arbitrary-rank) tensor type and associated +operations. + +=== Release 1.52.0 + +==== improvements + +* https://svn.boost.org/trac/boost/ticket/4024[[4024]] improve +performance of inplace_solve +* https://svn.boost.org/trac/boost/ticket/6511[[6511]] Division by +scalar should use enable_if<> +* https://svn.boost.org/trac/boost/ticket/7297[[7297]] Make the free +functions 'num_columns' and 'num_rows' support the uBLAS traits system +and better work with expression types + +==== bug fixes + +* https://svn.boost.org/trac/boost/ticket/7296[[7296]] fixes and +improvements to test utility functions +* https://svn.boost.org/trac/boost/ticket/7363[[7363]] fixed +coordinate_matrix::sort() for gcc 4.7 and others + +=== Release 1.43.0 + +==== bug fixes + +* https://svn.boost.org/trac/boost/ticket/3968[[3968]] fixed +coordinate_matrix sort problem on MSVC10 +* https://svn.boost.org/trac/boost/ticket/3539[[3539]] changed +computation of `norm_inf` for complex types to match mathematical +definition. + +*Note:* This might cause a performance drop because now `std::abs(z)` is +called for each vector element. The old implementation used +`std::max(std::abs(real(z)),std::abs(imag(z))`. Further `norm_inf` and +`norm_1` will now return the same values for complex vector. +* https://svn.boost.org/trac/boost/ticket/3501[[3501]] Moved free +functions in `concepts.hpp` into anonymous namespace. + +=== Release 1.41.1 + +==== new features + +* Move semantics of vector/matrix container assignments have been +implemented. They can be enabled by setting BOOST_UBLAS_MOVE_SEMANTICS. +More details are on the link:options.html[preprocessor options page]. +* Introduce new free functions. See +https://svn.boost.org/trac/boost/ticket/3449[[3449]], the new tests in +libs/numeric/ublas/test and the inline documentation of the files in +boost/numeric/ublas/operation/. + +==== bug fixes + +* https://svn.boost.org/trac/boost/ticket/3293[[3293]] Fix resizing +problem in `identity_matrix` +* https://svn.boost.org/trac/boost/ticket/3499[[3499]] Add +DefaultConstructible to concept checks + +=== Release 1.40.0 and before + +* Release notes were not available in this form. + +''''' + +Copyright (©) 2000-2009 Joerg Walter, Mathias Koch, Gunter Winkler + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/samples/Jamfile.v2 b/doc/ublas/samples/Jamfile.v2 similarity index 100% rename from doc/samples/Jamfile.v2 rename to doc/ublas/samples/Jamfile.v2 diff --git a/doc/samples/assignment_examples.cpp b/doc/ublas/samples/assignment_examples.cpp similarity index 100% rename from doc/samples/assignment_examples.cpp rename to doc/ublas/samples/assignment_examples.cpp diff --git a/doc/samples/banded_adaptor.cpp b/doc/ublas/samples/banded_adaptor.cpp similarity index 100% rename from doc/samples/banded_adaptor.cpp rename to doc/ublas/samples/banded_adaptor.cpp diff --git a/doc/samples/banded_matrix.cpp b/doc/ublas/samples/banded_matrix.cpp similarity index 100% rename from doc/samples/banded_matrix.cpp rename to doc/ublas/samples/banded_matrix.cpp diff --git a/doc/samples/bounded_array.cpp b/doc/ublas/samples/bounded_array.cpp similarity index 100% rename from doc/samples/bounded_array.cpp rename to doc/ublas/samples/bounded_array.cpp diff --git a/doc/samples/compressed_matrix.cpp b/doc/ublas/samples/compressed_matrix.cpp similarity index 100% rename from doc/samples/compressed_matrix.cpp rename to doc/ublas/samples/compressed_matrix.cpp diff --git a/doc/samples/compressed_vector.cpp b/doc/ublas/samples/compressed_vector.cpp similarity index 100% rename from doc/samples/compressed_vector.cpp rename to doc/ublas/samples/compressed_vector.cpp diff --git a/doc/samples/coordinate_matrix.cpp b/doc/ublas/samples/coordinate_matrix.cpp similarity index 100% rename from doc/samples/coordinate_matrix.cpp rename to doc/ublas/samples/coordinate_matrix.cpp diff --git a/doc/samples/coordinate_vector.cpp b/doc/ublas/samples/coordinate_vector.cpp similarity index 100% rename from doc/samples/coordinate_vector.cpp rename to doc/ublas/samples/coordinate_vector.cpp diff --git a/doc/samples/ex_triangular.cpp b/doc/ublas/samples/ex_triangular.cpp similarity index 100% rename from doc/samples/ex_triangular.cpp rename to doc/ublas/samples/ex_triangular.cpp diff --git a/doc/samples/hermitian_adaptor.cpp b/doc/ublas/samples/hermitian_adaptor.cpp similarity index 100% rename from doc/samples/hermitian_adaptor.cpp rename to doc/ublas/samples/hermitian_adaptor.cpp diff --git a/doc/samples/hermitian_matrix.cpp b/doc/ublas/samples/hermitian_matrix.cpp similarity index 100% rename from doc/samples/hermitian_matrix.cpp rename to doc/ublas/samples/hermitian_matrix.cpp diff --git a/doc/samples/identity_matrix.cpp b/doc/ublas/samples/identity_matrix.cpp similarity index 100% rename from doc/samples/identity_matrix.cpp rename to doc/ublas/samples/identity_matrix.cpp diff --git a/doc/samples/map_array.cpp b/doc/ublas/samples/map_array.cpp similarity index 100% rename from doc/samples/map_array.cpp rename to doc/ublas/samples/map_array.cpp diff --git a/doc/samples/mapped_matrix.cpp b/doc/ublas/samples/mapped_matrix.cpp similarity index 100% rename from doc/samples/mapped_matrix.cpp rename to doc/ublas/samples/mapped_matrix.cpp diff --git a/doc/samples/mapped_vector.cpp b/doc/ublas/samples/mapped_vector.cpp similarity index 100% rename from doc/samples/mapped_vector.cpp rename to doc/ublas/samples/mapped_vector.cpp diff --git a/doc/samples/matrix.cpp b/doc/ublas/samples/matrix.cpp similarity index 100% rename from doc/samples/matrix.cpp rename to doc/ublas/samples/matrix.cpp diff --git a/doc/samples/matrix_binary.cpp b/doc/ublas/samples/matrix_binary.cpp similarity index 100% rename from doc/samples/matrix_binary.cpp rename to doc/ublas/samples/matrix_binary.cpp diff --git a/doc/samples/matrix_binary_scalar.cpp b/doc/ublas/samples/matrix_binary_scalar.cpp similarity index 100% rename from doc/samples/matrix_binary_scalar.cpp rename to doc/ublas/samples/matrix_binary_scalar.cpp diff --git a/doc/samples/matrix_column.cpp b/doc/ublas/samples/matrix_column.cpp similarity index 100% rename from doc/samples/matrix_column.cpp rename to doc/ublas/samples/matrix_column.cpp diff --git a/doc/samples/matrix_column_project.cpp b/doc/ublas/samples/matrix_column_project.cpp similarity index 100% rename from doc/samples/matrix_column_project.cpp rename to doc/ublas/samples/matrix_column_project.cpp diff --git a/doc/samples/matrix_matrix_binary.cpp b/doc/ublas/samples/matrix_matrix_binary.cpp similarity index 100% rename from doc/samples/matrix_matrix_binary.cpp rename to doc/ublas/samples/matrix_matrix_binary.cpp diff --git a/doc/samples/matrix_matrix_solve.cpp b/doc/ublas/samples/matrix_matrix_solve.cpp similarity index 100% rename from doc/samples/matrix_matrix_solve.cpp rename to doc/ublas/samples/matrix_matrix_solve.cpp diff --git a/doc/samples/matrix_range.cpp b/doc/ublas/samples/matrix_range.cpp similarity index 100% rename from doc/samples/matrix_range.cpp rename to doc/ublas/samples/matrix_range.cpp diff --git a/doc/samples/matrix_range_project.cpp b/doc/ublas/samples/matrix_range_project.cpp similarity index 100% rename from doc/samples/matrix_range_project.cpp rename to doc/ublas/samples/matrix_range_project.cpp diff --git a/doc/samples/matrix_row.cpp b/doc/ublas/samples/matrix_row.cpp similarity index 100% rename from doc/samples/matrix_row.cpp rename to doc/ublas/samples/matrix_row.cpp diff --git a/doc/samples/matrix_row_project.cpp b/doc/ublas/samples/matrix_row_project.cpp similarity index 100% rename from doc/samples/matrix_row_project.cpp rename to doc/ublas/samples/matrix_row_project.cpp diff --git a/doc/samples/matrix_slice.cpp b/doc/ublas/samples/matrix_slice.cpp similarity index 100% rename from doc/samples/matrix_slice.cpp rename to doc/ublas/samples/matrix_slice.cpp diff --git a/doc/samples/matrix_slice_project.cpp b/doc/ublas/samples/matrix_slice_project.cpp similarity index 100% rename from doc/samples/matrix_slice_project.cpp rename to doc/ublas/samples/matrix_slice_project.cpp diff --git a/doc/samples/matrix_unary.cpp b/doc/ublas/samples/matrix_unary.cpp similarity index 100% rename from doc/samples/matrix_unary.cpp rename to doc/ublas/samples/matrix_unary.cpp diff --git a/doc/samples/matrix_vector_binary.cpp b/doc/ublas/samples/matrix_vector_binary.cpp similarity index 100% rename from doc/samples/matrix_vector_binary.cpp rename to doc/ublas/samples/matrix_vector_binary.cpp diff --git a/doc/samples/matrix_vector_range.cpp b/doc/ublas/samples/matrix_vector_range.cpp similarity index 100% rename from doc/samples/matrix_vector_range.cpp rename to doc/ublas/samples/matrix_vector_range.cpp diff --git a/doc/samples/matrix_vector_slice.cpp b/doc/ublas/samples/matrix_vector_slice.cpp similarity index 100% rename from doc/samples/matrix_vector_slice.cpp rename to doc/ublas/samples/matrix_vector_slice.cpp diff --git a/doc/samples/matrix_vector_solve.cpp b/doc/ublas/samples/matrix_vector_solve.cpp similarity index 100% rename from doc/samples/matrix_vector_solve.cpp rename to doc/ublas/samples/matrix_vector_solve.cpp diff --git a/doc/samples/range.cpp b/doc/ublas/samples/range.cpp similarity index 100% rename from doc/samples/range.cpp rename to doc/ublas/samples/range.cpp diff --git a/doc/samples/slice.cpp b/doc/ublas/samples/slice.cpp similarity index 100% rename from doc/samples/slice.cpp rename to doc/ublas/samples/slice.cpp diff --git a/doc/samples/symmetric_adaptor.cpp b/doc/ublas/samples/symmetric_adaptor.cpp similarity index 100% rename from doc/samples/symmetric_adaptor.cpp rename to doc/ublas/samples/symmetric_adaptor.cpp diff --git a/doc/samples/symmetric_matrix.cpp b/doc/ublas/samples/symmetric_matrix.cpp similarity index 100% rename from doc/samples/symmetric_matrix.cpp rename to doc/ublas/samples/symmetric_matrix.cpp diff --git a/doc/samples/triangular_adaptor.cpp b/doc/ublas/samples/triangular_adaptor.cpp similarity index 100% rename from doc/samples/triangular_adaptor.cpp rename to doc/ublas/samples/triangular_adaptor.cpp diff --git a/doc/samples/triangular_matrix.cpp b/doc/ublas/samples/triangular_matrix.cpp similarity index 100% rename from doc/samples/triangular_matrix.cpp rename to doc/ublas/samples/triangular_matrix.cpp diff --git a/doc/samples/unbounded_array.cpp b/doc/ublas/samples/unbounded_array.cpp similarity index 100% rename from doc/samples/unbounded_array.cpp rename to doc/ublas/samples/unbounded_array.cpp diff --git a/doc/samples/unit_vector.cpp b/doc/ublas/samples/unit_vector.cpp similarity index 100% rename from doc/samples/unit_vector.cpp rename to doc/ublas/samples/unit_vector.cpp diff --git a/doc/samples/vector.cpp b/doc/ublas/samples/vector.cpp similarity index 100% rename from doc/samples/vector.cpp rename to doc/ublas/samples/vector.cpp diff --git a/doc/samples/vector_binary.cpp b/doc/ublas/samples/vector_binary.cpp similarity index 100% rename from doc/samples/vector_binary.cpp rename to doc/ublas/samples/vector_binary.cpp diff --git a/doc/samples/vector_binary_outer.cpp b/doc/ublas/samples/vector_binary_outer.cpp similarity index 100% rename from doc/samples/vector_binary_outer.cpp rename to doc/ublas/samples/vector_binary_outer.cpp diff --git a/doc/samples/vector_binary_redux.cpp b/doc/ublas/samples/vector_binary_redux.cpp similarity index 100% rename from doc/samples/vector_binary_redux.cpp rename to doc/ublas/samples/vector_binary_redux.cpp diff --git a/doc/samples/vector_binary_scalar.cpp b/doc/ublas/samples/vector_binary_scalar.cpp similarity index 100% rename from doc/samples/vector_binary_scalar.cpp rename to doc/ublas/samples/vector_binary_scalar.cpp diff --git a/doc/samples/vector_range.cpp b/doc/ublas/samples/vector_range.cpp similarity index 100% rename from doc/samples/vector_range.cpp rename to doc/ublas/samples/vector_range.cpp diff --git a/doc/samples/vector_range_project.cpp b/doc/ublas/samples/vector_range_project.cpp similarity index 100% rename from doc/samples/vector_range_project.cpp rename to doc/ublas/samples/vector_range_project.cpp diff --git a/doc/samples/vector_slice.cpp b/doc/ublas/samples/vector_slice.cpp similarity index 100% rename from doc/samples/vector_slice.cpp rename to doc/ublas/samples/vector_slice.cpp diff --git a/doc/samples/vector_slice_project.cpp b/doc/ublas/samples/vector_slice_project.cpp similarity index 100% rename from doc/samples/vector_slice_project.cpp rename to doc/ublas/samples/vector_slice_project.cpp diff --git a/doc/samples/vector_unary.cpp b/doc/ublas/samples/vector_unary.cpp similarity index 100% rename from doc/samples/vector_unary.cpp rename to doc/ublas/samples/vector_unary.cpp diff --git a/doc/samples/vector_unary_redux.cpp b/doc/ublas/samples/vector_unary_redux.cpp similarity index 100% rename from doc/samples/vector_unary_redux.cpp rename to doc/ublas/samples/vector_unary_redux.cpp diff --git a/doc/samples/zero_matrix.cpp b/doc/ublas/samples/zero_matrix.cpp similarity index 100% rename from doc/samples/zero_matrix.cpp rename to doc/ublas/samples/zero_matrix.cpp diff --git a/doc/samples/zero_vector.cpp b/doc/ublas/samples/zero_vector.cpp similarity index 100% rename from doc/samples/zero_vector.cpp rename to doc/ublas/samples/zero_vector.cpp diff --git a/doc/ublas/storage_concept.adoc b/doc/ublas/storage_concept.adoc new file mode 100644 index 000000000..dc85bc83c --- /dev/null +++ b/doc/ublas/storage_concept.adoc @@ -0,0 +1,109 @@ +== Storage concept + +[[toc]] + +=== [#range]#Storage concept# + +==== Description + +Storage is a variable-size container whose elements are arranged in a +strict linear order. + +Storage extends the STL Container concept with some STL Sequence-like +functionality. The main difference with the Sequence concept however is +that the Storage concept does not require default-initialisation of its +elements. + +==== Refinement of + +http://www.boost.org/sgi/stl/RandomAccessContainer.html[Random Access +Container] and +http://www.boost.org/sgi/stl/DefaultConstructible.html[Default +Constructible] + +==== Associated types + +No additional types beyond those defined by +http://www.boost.org/sgi/stl/RandomAccessContainer.html[Random Access +Container] + +==== Notation + +[cols=",",] +|=== +|X |A type that is model of Storage +|T |The value_type of X +|t |An object of type T +|n |object of type convertible to X::size_type +|=== + +==== Definitions + +==== Valid expressions + +In addition to the expressions defined in +http://www.boost.org/sgi/stl/RandomAccessContainer.html[Random Access +Container], and +http://www.boost.org/sgi/stl/DefaultConstructible.html[Default +Constructible] the following expressions must be valid: + +[cols=",,,",options="header",] +|=== +|Name |Expression |Type requirements |Return type +|Size constructor |X(n) |T is +http://www.boost.org/sgi/stl/DefaultConstructible.html[DefaultConstructible] +|X + +|Fill constructor |X(n,t) | |X + +|Range constructor |X(i, j) |i and j are +http://www.boost.org/sgi/stl/InputIterator.html[Input Iterators] whose +value type is convertible to T |X + +|Resize |a.resize(n, t) |a is mutable |void + +|Resize |a.resize(n) |a is mutable |void +|=== + +==== Expression semantics + +[cols=",,,,",options="header",] +|=== +|Name |Expression |Precondition |Semantics |Postcondition + +|Default-constructor |X() | |Creates 0 elements |size()==0 + +|Size-constructor |X(n) |n>=0 |Creates n elements. Elements are constructed without an initializer. +That is if T is a (possibly cv-qualified) non-POD class type (or array +thereof), the object is default initialized. Otherwise, the object +created has indeterminate value. See the sentance "If new initializer is +omitted" in section 5.3.4 paragraph 15 of the ISO C++ standard. |size()==n + +|Fill-constructor |X(n,t) |n>=0 |Creates n initialised element with copies of `t` |size()==n + +|Range constructor |X(i, j) |[i,j) is a valid range. |copies the range [i,j) to the storage |size() is equal to the distance from i to j. Each element is a copy of the corresponding element in the range [i,j). + +|Resize |a.resize(n, t) |n <= a.max_size() |Modified the container so that it has exactly n elements. + The container may be reallocated if its size changes. Existing element values are preserved, additional elements are copies of `t`. |a.size() == n + +|Resize |a.resize(n) |n <= a.max_size() |Modified the container so that it has exactly n elements. + The container may be reallocated if its size changes. Element values are uninitialised. That is, each element value may be a previously assigned value or default construced value for `T`. |a.size() == n + +|=== + +===== Complexity guarantees + +===== Invariants + +===== Models + +* link:unbounded_array.html[unbounded_array] +* link:bounded_array.html[bounded_array] + +===== Notes + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/storage_sparse.adoc b/doc/ublas/storage_sparse.adoc new file mode 100644 index 000000000..884dac190 --- /dev/null +++ b/doc/ublas/storage_sparse.adoc @@ -0,0 +1,210 @@ +== Sparse Storage + +[[toc]] + +=== [#map_std]#Default Standard Map# + +==== Description + +The templated class `map_std` provides a wrapper for the +standard library associative container `std::map`. The wrapper has one +simple purpose. It allows the definition of a default template parameter +(for the adapted array) when declaring the sparse container types. + +==== Example + +[source, cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + map_std a (3); + for (unsigned i = 0; i < a.size (); ++ i) { + a [i] = i; + std::cout << a [i] << std::endl; + } +} +.... + +==== Definition + +Defined in the header storage_sparse.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`I` |The type of index stored in the array. | +|`T` |The type of object stored in the array. | +|`ALLOC` |An STL Allocator |std::allocator +|=== + +==== Model of + +Reversible Container. + +==== Type requirements + +None, except for those imposed by the requirements of Reversible +Container. + +==== Public base classes + +std::map + +=== [#map_array]#Map Array# + +==== Description + +The templated class `map_array` implements a `std::map` +like associative container as a sorted array. It therefore some of the +Associative Container interface without having the same semantics as an +std::map. + +At any time the `map_array` has a capacity up to which new element can +be inserted. If `insert` would cause the size of the `map_array` to +exceeds its capactity then it is *reallocated*. Iterators and reference +are invalidated. The capacity can be directly control using the +`reserve` member function. + +==== Example + +[source, cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + map_array a (3); + for (unsigned i = 0; i < a.size (); ++ i) { + a [i] = i; + std::cout << a [i] << std::endl; + } +} +.... + +==== Definition + +Defined in the header storage_sparse.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`I` |The type of index stored in the array. | +|`T` |The type of object stored in the array. | +|`ALLOC` |An STL Allocator |std::allocator +|=== + +==== Model of + +Reversible Container. + +==== Type requirements + +None, except for those imposed by the requirements of Reversible +Container. + +==== Public base classes + +None. + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`map_array (ALLOC &a = ALLOC())` |Allocates a `map_array` that holds at +most zero elements. + +|`map_array (const map_array &c)` |The copy constructor. + +|`~map_array ()` |Deallocates the `map_array` itself. + +|`void reserve (size_type capacity)` |Changes the`map_array` capacity. +It can hold at most`capacity` elements without reallocation. The +capacity can be reduced such that `capacity >= size()`. The content of +the`map_array` is preserved. + +|`size_type size () const` |Returns the size of the `map_array`. + +|`size_type size () const` |Returns the capacity of the `map_array`. + +|`data_reference operator [] (index_type i)` |Returns a reference of the +element that is associated with a particular index. If the `map_array` +does not already contain such an element, `operator[]` inserts the +default `T ()`. + +|`map_array &operator = (const map_array &a)` |The assignment operator. + +|`map_array &assign_temporary (map_array &a)` |Assigns a temporary. May +change the array `a`. + +|`void swap (map_array &a)` |Swaps the contents of the arrays. + +|`std::pair insert (const value_type &p)` |Inserts `p` into the array. +The second part of the return value is `true` if `p` was inserted and +`false` if was not inserted because it was aleady present. + +|`iterator insert (iterator it, const value_type &p)` |Inserts `p` into +the array, using `it` as a hint to where it will be inserted. + +|`void erase (iterator it)` |Erases the value at `it`. + +|`void clear ()` |Clears the array. + +|`const_iterator find (index_type i) const` |Finds an element whose +index is `i`. + +|`iterator find (index_type i)` |Finds an element whose index is `i`. + +|`const_iterator lower_bound (index_type i) const` |Finds the first +element whose index is not less than `i` . + +|`iterator lower_bound (index_type i)` |Finds the first element whose +index is not less than `i` . + +|`const_iterator upper_bound (index_type i) const` |Finds the first +element whose index is greater than `i` . + +|`iterator upper_bound (index_type i)` |Finds the first element whose +index is greater than `i` . + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `map_array`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `map_array`. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the `map_array`. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +`map_array`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`map_array`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`map_array`. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed `map_array`. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed `map_array`. +|=== + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/symmetric.adoc b/doc/ublas/symmetric.adoc new file mode 100644 index 000000000..ddab2c6f8 --- /dev/null +++ b/doc/ublas/symmetric.adoc @@ -0,0 +1,401 @@ +== Symmetric Matrix + +[[toc]] + +=== [#symmetric_matrix]#Symmetric Matrix# + +==== Description + +The templated class `symmetric_matrix` is the base +container adaptor for symmetric matrices. For a _(n x n_ )-dimensional +symmetric matrix and _0 < = i < n_, _0 < = j < n_ holds __s__~_i,j_~= +__s__~_j,i_~. The storage of symmetric matrices is packed. + +==== Example + +[source, cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + symmetric_matrix ml (3, 3); + for (unsigned i = 0; i < ml.size1 (); ++ i) + for (unsigned j = 0; j <= i; ++ j) + ml (i, j) = 3 * i + j; + std::cout << ml << std::endl; + symmetric_matrix mu (3, 3); + for (unsigned i = 0; i < mu.size1 (); ++ i) + for (unsigned j = i; j < mu.size2 (); ++ j) + mu (i, j) = 3 * i + j; + std::cout << mu << std::endl; +} +.... + +==== Definition + +Defined in the header symmetric.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the matrix. | + +|`F1` |Functor describing the type of the symmetric matrix. +link:#symmetric_matrix_1[[1]] |`lower` + +|`F2` |Functor describing the storage organization. +link:#symmetric_matrix_2[[2]] |`row_major` + +|`A` |The type of the adapted array. link:#symmetric_matrix_3[[3]] +|`unbounded_array` +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`symmetric_matrix (size_type size)` |Allocates an uninitialized +`symmetric_matrix` that holds `size` rows of `size` elements. + +|`symmetric_matrix (const symmetric_matrix &m)` |The copy constructor. + +|`template symmetric_matrix (const matrix_expression &ae)` +|The extended copy constructor. + +|`void resize (size_type size, bool preserve = true)` |Reallocates a +`symmetric_matrix` to hold `size` rows of `size` elements. The existing +elements of the `symmetric_matrix` are preseved when specified. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +a `const` reference of the `j` -th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`symmetric_matrix &operator = (const symmetric_matrix &m)` |The +assignment operator. + +|`symmetric_matrix &assign_temporary (symmetric_matrix &m)` |Assigns a +temporary. May change the symmetric matrix `m` . + +|`template symmetric_matrix &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template symmetric_matrix &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the symmetric matrix. Left and right +hand side of the assignment should be independent. + +|`template symmetric_matrix &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +symmetric matrix. + +|`template symmetric_matrix &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the symmetric matrix. Left and right hand +side of the assignment should be independent. + +|`template symmetric_matrix &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the symmetric matrix. + +|`template symmetric_matrix &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the symmetric matrix. Left and right +hand side of the assignment should be independent. + +|`template symmetric_matrix &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the symmetric matrix with a +scalar. + +|`template symmetric_matrix &operator /= (const AT &at)` |A +computed assignment operator. Divides the symmetric matrix through a +scalar. + +|`void swap (symmetric_matrix &m)` |Swaps the contents of the symmetric +matrices. + +|`void insert (size_type i, size_type j, const_reference t)` |Inserts +the value `t` at the `j`-th element of the `i`-th row. + +|`void erase (size_type i, size_type j)` |Erases the value at the `j`-th +elemenst of the `i`-th row. + +|`void clear ()` |Clears the matrix. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `symmetric_matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `symmetric_matrix`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `symmetric_matrix`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`symmetric_matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `symmetric_matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `symmetric_matrix`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `symmetric_matrix`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`symmetric_matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`symmetric_matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`symmetric_matrix`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `symmetric_matrix`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `symmetric_matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`symmetric_matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`symmetric_matrix`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `symmetric_matrix`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `symmetric_matrix`. +|=== + +==== Notes + +[#symmetric_matrix_1]#[1]# Supported parameters for the type of the +symmetric matrix are `lower` and `upper`. + +[#symmetric_matrix_2]#[2]# Supported parameters for the storage +organization are `row_major` and `column_major`. + +[#symmetric_matrix_3]#[3]# Supported parameters for the adapted array +are `unbounded_array` , `bounded_array` and `std::vector` . + +=== [#symmetric_adaptor]#Symmetric Adaptor# + +==== Description + +The templated class `symmetric_adaptor` is a symmetric matrix +adaptor for other matrices. + +==== Example + +[source, cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + symmetric_adaptor, lower> sal (m); + for (unsigned i = 0; i < sal.size1 (); ++ i) + for (unsigned j = 0; j <= i; ++ j) + sal (i, j) = 3 * i + j; + std::cout << sal << std::endl; + symmetric_adaptor, upper> sau (m); + for (unsigned i = 0; i < sau.size1 (); ++ i) + for (unsigned j = i; j < sau.size2 (); ++ j) + sau (i, j) = 3 * i + j; + std::cout << sau << std::endl; +} +.... + +==== Definition + +Defined in the header symmetric.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`M` |The type of the adapted matrix. | + +|`F` |Functor describing the type of the symmetric adaptor. +link:#symmetric_adaptor_1[[1]] |`lower` +|=== + +==== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +==== Public base classes + +`matrix_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`symmetric_adaptor ()` |Constructs a `symmetric_adaptor` that holds +zero rows of zero elements. + +|`symmetric_adaptor (matrix_type &data)` |Constructs a +`symmetric_adaptor` of a matrix. + +|`symmetric_adaptor (const symmetric_adaptor &m)` |The copy constructor. + +|`template symmetric_adaptor (const matrix_expression &ae)` +|The extended copy constructor. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +a `const` reference of the `j` -th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`symmetric_adaptor &operator = (const symmetric_adaptor &m)` |The +assignment operator. + +|`symmetric_adaptor &assign_temporary (symmetric_adaptor &m)` |Assigns a +temporary. May change the symmetric adaptor `m`. + +|`template symmetric_adaptor &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template symmetric_adaptor &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the symmetric adaptor. Left and right +hand side of the assignment should be independent. + +|`template symmetric_adaptor &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +symmetric adaptor. + +|`template symmetric_adaptor &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the symmetric adaptor. Left and right hand +side of the assignment should be independent. + +|`template symmetric_adaptor &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the symmetric adaptor. + +|`template symmetric_adaptor &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the symmetric adaptor. Left and +right hand side of the assignment should be independent. + +|`template symmetric_adaptor &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the symmetric adaptor with a +scalar. + +|`template symmetric_adaptor &operator /= (const AT &at)` |A +computed assignment operator. Divides the symmetric adaptor through a +scalar. + +|`void swap (symmetric_adaptor &m)` |Swaps the contents of the symmetric +adaptors. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `symmetric_adaptor`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `symmetric_adaptor`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `symmetric_adaptor`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`symmetric_adaptor`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `symmetric_adaptor`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `symmetric_adaptor`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `symmetric_adaptor`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`symmetric_adaptor`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`symmetric_adaptor`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`symmetric_adaptor`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `symmetric_adaptor`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `symmetric_adaptor`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`symmetric_adaptor`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`symmetric_adaptor`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `symmetric_adaptor`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `symmetric_adaptor`. +|=== + +==== Notes + +[#symmetric_adaptor_1]#[1]# Supported parameters for the type of the +symmetric adaptor are `lower` and `upper`. + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/tensor.adoc b/doc/ublas/tensor.adoc new file mode 100644 index 000000000..43d0656bf --- /dev/null +++ b/doc/ublas/tensor.adoc @@ -0,0 +1,351 @@ +== Tensor + +[[toc]] + +. Tensor + +.. link:#tensor_1[Description] + +.. link:#tensor_2[Example] + +.. link:#tensor_3[Definition] + +.. link:#tensor_4[Model of] + +.. link:#tensor_5[Type requirements] + +.. link:#tensor_6[Public base classes] + +.. link:#tensor_7[Template parameters] + +.. link:#tensor_8[Member types] + +.. link:#tensor_9[Alias templates] + + +.. link:#tensor_10[Member Functions] + +... link:#tensor_11[Construction] + +... link:#tensor_12[Assignment] + +... link:#tensor_13[Capacity] + +... link:#tensor_14[Element access] + +... link:#tensor_15[Proxy Generation] + +... link:#tensor_16[Iterators] + +... link:#tensor_17[Modifiers] + +... link:#tensor_18[Notes] + + +==== a. [#tensor_1]#Description# + + +The templated class `tensor` is the base +container adaptor for dense tensors. Every element +$(t_/ i_1, i_2, \dots, i_p)$ of a $p$-order $(n_1 \times n_2 \times \cdots +\times n_p)$-dimensional tensor $T$ is mapped to $j$-th element of a +one-dimensional container where $(j = \sum_ /{r=1}^p i_r \cdot w_r)$ with +$1 \leq i_r \leq n_r $ for $1 \leq r \leq p$. For the first-order +orientation $w_1 = 1$ and $(w_k = n_{k-1} \cdot w_{k-1})$ for $k > 1$. +For last-order orientation $w_p = 1$ and $(w_k = n_/{k+1} \cdot w_/{k+1})$ for $k < p$. + +==== b. [#tensor_2]#Example# + +[source,cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + tensor t{4,2,3}; + for (auto k = 0ul; k < t.size (2); ++ k) + for (auto j = 0ul; j < t.size (1); ++ j) + for (auto i = 0ul; i < t.size (0); ++ i) + t.at(i,j,k) = 3*i + 2*j + 5*k; + + std::cout << t << std::endl; +} +.... + +==== c. [#tensor_3]#Definition# + +Defined in the header file `tensor/tensor.hpp`. + +==== d. [#tensor_4]#Model of# + +link:container_concept.html#tensor[Tensor] + +==== e. [#tensor_5]#Type requirements# + +None, except for those imposed by the requirements of +link:container_concept.html#tensor[Tensor] . + +==== f. [#tensor_6]#Public base classes# + +`tensor_container >` + +==== g. [#tensor_7]#Template parameters# + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`value_t` |The type of object stored in the tensor. | + +|`format_t` |Storage organization. link:#tensor_1[[1]] |`first_order` + +|`storage_t` |The type of the Storage array. link:#tensor_2[[2]] +|`std::vector` +|=== + +==== h. [#tensor_8]#Member types# + +[cols=",",] +|=== +|Member type |Description + +|`value_type` |Type `value_t` of the tensor elements. + +|`layout_type` |Format of the tensor which is either `first_order` or +`last_order`. + +|`array_type` |Sequence container type that stores all tensor elements +and is accessible with a single index. + +|`strides_type` |Type of the strides vector +`basic_strides` that stores all tensor elements +and is accessible with a single index. + +|`extents_type` |Type of the dimension extents vector `shape` that +stores all tensor elements and is accessible with a single index. + +|`size_type` |Unsigned integer which is usually `std::size_t`. + +|`difference_type` |Unsigned integer which is usually `std::ptrdiff_t`. + +|`reference` |Reference type `storage_type::reference` which is in most +cases `value_type&`. + +|`const_reference` |Constant reference type +`storage_type::const_reference` which is in most cases +`const value_type&`. + +|`pointer` |Pointer type `storage_type::pointer` which is in most cases +`value_type*`. + +|`const_pointer` |Constant reference type +`storage_type::const_reference` which is in most cases +`const value_type*`. + +|`iterator` |RandomAccessIterator `storage_type::iterator`. + +|`const_iterator` |Constant RandomAccessIterator +`storage_type::const_iterator`. + +|`reverse_iterator` |Reverse RandomAccessIterator +`storage_type::reverse_iterator`. + +|`const_reverse_iterator` |Reverse RandomAccessIterator +`storage_type::const_reverse_iterator`. + +|`matrix_type` |Type of the matrix +`matrix` with which the tensor type +interacts. + +|`vector_type` |Type of the vector +`matrix` with which the tensor type +interacts. +|=== + +==== i. [#tensor_9]#Alias templates# + +[cols=",",] +|=== +|Alias template |Description + +|`template using tensor_expression_type = detail::tensor_expression` |Type of link:tensor/tensor_expression.html#tensor_expression[tensor_expression] where `self_type` is the `tensor` type. + +|`template using matrix_expression_type = matrix_expression` |Type of link:matrix_expression.html#matrix_expression[matrix_expression]. + +|`template using vector_expression_type = vector_expression` |Type of link:vector_expression.html#vector_expression[vector_expression]. +|=== + +==== j. [#tensor_10]#Member Functions# + +===== i. [#tensor_11]#Construction# + +[cols=",",] +|=== +|Member function |Description + +|`tensor ()` |Constructs an uninitialized `tensor` that holds zero +elements. + +|`tensor (std::initializer_list list)` |Constructs an +uninitialized `tensor` where `list` specifies the dimension +link:tensor/extents.html[extents]. + +|`tensor (extents_type const& s)` |Constructs an uninitialized +`tensor` where `s` specifies the dimension +link:tensor/extents.html[extents]. + +|`tensor (extents_type const& e, array_type const& a)` |Constructs an +uninitialized `tensor` where `e` specifies the dimension +link:tensor/extents.html[extents] and `a` the data elements of the +tensor. + +|`tensor (tensor const& expr)` |Constructs +tensor by evaluating the link:tensor/tensor_expression.html[tensor +expression] `expr` and copying all elements of the result. + +|`tensor (matrix_expression_type const& expr)` |Constructs +tensor by evaluating the link:matrix_expression.html[matrix expression] +`expr` and copying all elements of the result. + +|`tensor (vector_expression_type const& expr)` |Constructs +tensor by evaluating the link:vector_expression.html[vector expression] +`expr` and copying all elements of the result. +|=== + +===== ii. [#tensor_12]#Assignment# + +[cols=",",] +|=== +|Member function |Description + +|`tensor& operator=(tensor_expression_type const& expr)` +|Evaluates the link:tensor/tensor_expression.html[tensor expression] +`expr` and copyies all elements of the result. + +|`tensor& operator=(tensor other)` |Copies or moves elements of `other`. + +|`tensor& operator=(const_reference v)` |Initialiates all elements of a +tensor with `v`. +|=== + +===== iii. [#tensor_13]#Capacity# + +[cols=",",] +|=== +|Member function |Description + +|`bool empty() const` |Returns true if a tensor has zero elements. + +|`size_type size() const` |Returns the number of elements of the tensor. + +|`size_type rank() const` |Returns the number of dimensions of the +tensor. + +|`size_type order() const` |Returns the number of dimensions of the +tensor. + +|`strides_type const& strides() const` |Returns a constant reference to +the link:tensor/strides.html[strides] of the tensor. + +|`extents_type const& extents() const` |Returns a constant reference to +the link:tensor/extents.html[extents] of the tensor. +|=== + +===== iv. [#tensor_14]#Element access# + +[cols=",",] +|=== +|Member function |Description + +|`pointer data()` |Returns a `pointer` the first element of the tensor. + +|`const_pointer data() const` |Returns a `const_pointer` the first +element of the tensor. + +|`reference operator[](size_type j)` |Returns a `reference` to the +`j`-th element of the storage array of the tensor. Corresponds to the +function call `tensor::data()+j` + +|`const_reference operator[](size_type j) const` |Returns a +`const_reference` to the `j`-th element of the storage array of the +tensor. Corresponds to the function call `tensor::data()+j`. + +|`template reference at(size_type i, size_types ... is)` +|Returns a `reference` to the `(i,is...)`-th element of the tensor where +` (i,is...)` denotes a multi-index with `tensor::order()` elements. If +`sizeof...(is)==0`, `tensor::operator[i]` is called. + +|`template const_reference at(size_type i, size_types ... is)` +|Returns a `const_reference` to the `(i,is...)`-th element of the tensor +where ` (i,is...)` denotes a multi-index with `tensor::order()` +elements. If `sizeof...(is)==0`, `tensor::operator[i]` is called. +|=== + +===== v. [#tensor_15]#Proxy Generation# + +[cols=",",] +|=== +|Member function |Description + +|`template tensor_index operator()(indices::Index p, index_types ... ps)` +|Returns a link:tensor/tensor_index.html[tensor index] instance with +index objects `(p,ps...)` for a tensor contraction where +`sizeof...(ps)+1` must be equal to `tensor::order()`. +|=== + +===== vi. [#tensor_16]#Iterators# + +[cols=",",] +|=== +|Member function |Description + +|`const_iterator begin() const` |Returns a const_iterator pointing to +the first element of the tensor. + +|`const_iterator cbegin() const` |Returns a const_iterator pointing to +the first element of the tensor. + +|`iterator begin()` |Returns an iterator pointing to the first element +of the tensor. + +|`const_iterator end() const` |Returns a const_iterator pointing to the +position after the last element of the tensor. + +|`const_iterator cend() const` |Returns a const_iterator pointing to the +position after the last element of the tensor. + +|`iterator begin()` |Returns an iterator pointing to the position after +the last element of the tensor. +|=== + +===== vii. [#tensor_17]#Modifiers# + +[cols=",",] +|=== +|Member function |Description + +|`void reshape(extents_type const& e, value_type v = value_type{})` +|Reshapes the tensor according to the extents `e`. If `e.product()` is +greater than `tensor::size()`, the tensor is resized with `v`. +|=== + +===== viii. [#tensor_18]#Notes# + +[#tensor_1]#[1]# Supported parameters for the storage organization are +`first_order` and `last_order`. + +[#tensor_2]#[2]# Common parameters for the storage array are +`std::array` and `std::vector`. + +''''' + +Copyright (©) 2018 Cem Bassoy + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). \ No newline at end of file diff --git a/doc/ublas/tensor/extents.adoc b/doc/ublas/tensor/extents.adoc new file mode 100644 index 000000000..618edb554 --- /dev/null +++ b/doc/ublas/tensor/extents.adoc @@ -0,0 +1,136 @@ +== Extents + +[[toc]] + +=== [#extents]#basic_extents# + +==== Description + +The template class `basic_extents` specifies dimension extents of a +link:../tensor.html#tensor[tensor] instance. + +==== Example + +[source, cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + shape s{4,3,2}; + for (auto i = 0u; i < s.size(); ++i) { + std::cout << s.at(i) << std::endl; + } +} +.... + +==== Definition + +Defined in the header tensor/extents.hpp. + +==== Public base classes + +None. + +==== Specialization + +`using shape = basic_extents` + +==== Template parameters + +[cols=",",] +|=== +|Parameter |Description +|`size_type` |Unsigned integer type. +|=== + +==== Member types + +[cols=",",] +|=== +|Member type |Description + +|`value_type` |Type `size_type` of the extents. + +|`size_type` |Unsigned integer such as `std::size_t`. + +|`reference` |Reference type which is `value_type&`. + +|`const_reference` |Constant reference type which is +`const value_type&`. + +|`pointer` |Pointer type which is `value_type*`. + +|`const_pointer` |Constant reference type which is `const value_type*`. +|=== + +==== Member Functions +[cols=",",] +|=== +|Member Function |Description + +|`basic_extents ()` |Constructs an empty instance of `basic_extents`. + +|`basic_extents (std::vector const& vector)` |Constructs an instance copying the content of `vector`. + +|`basic_extents (std::vector && vector)` |Constructs an instance moving the content of `vector`. + +|`basic_extents (std::initializer_list list)` |Constructs an instance from `list`. + +|`basic_extents (const_iterator first, const_iterator last)` |Constructs an instance from the range specified by `[first`,`last)`. + +|`basic_extents (basic_extents const& other)` |Constructs an instance from `other` copying its elements. + +|`basic_extents (basic_extents && other)` |Constructs an instance from `other` by moving its elements. + +|`basic_extents& operator= (basic_extents other)` |Assigns the elements of `other` to this instance. + +|`bool is_scalar() const` |Returns true if the elements are `(1,1,[1,...,1])`. + +|`bool is_vector() const` |Returns true if the elements are `(n,1,[1,...,1])` or `(1,n,[1,...,1])` where `n>1`. + +|`bool is_matrix() const` |Returns true if the elements are `(m,n,[1,...,1])` where `m>1` and +`n>1`. + +|`bool is_tensor() const` |Returns true if it is not a scalar, vector or matrix. + +|`const_pointer data() const` |Returns a `const_pointer` to the first element. + +|`pointer data()` |Returns a `pointer` to the first element. + +|`reference operator[](size_type i)` |Returns a `reference` to the `i`-th element. + +|`const_reference operator[](size_type i) const` |Returns a `const_reference` to the `i`-th element. + +|`reference at(size_type i)` |Returns a `reference` to the `i`-th element. + +|`const_reference at(size_type i) const` |Returns a `const_reference` to the `i`-th element. + +|`bool empty()` |Returns true if the container has no elements. + +|`size_type size() const` |Returns the number of elements. + +|`bool valid() const` |Returns true if size()>1 and all elements are greater than one. + +|`size_type product() const` |Returns the multiplication of all entries. + +|`basic_extents squeeze() const` |Returns a new instance where entries equal to one are eliminated. + +|`bool operator==(basic_extents const& b) const` |Returns true if all elements are equal. + +|`bool operator!=(basic_extents const& b) const` |Returns true if some elements are not equal. + +|`const_iterator begin() const` |Returns an `const_iterator pointing to the first element.` + +|`const_iterator end() const` |Returns a `const_iterator` pointing to an element passed the last element. + +|`std::vector base() const` |Returns a const reference to the private member sequence container holding all elements. + +|=== +''''' + +Copyright (©) 2018 Cem Bassoy + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/tensor/strides.adoc b/doc/ublas/tensor/strides.adoc new file mode 100644 index 000000000..1386a46db --- /dev/null +++ b/doc/ublas/tensor/strides.adoc @@ -0,0 +1,155 @@ +== Strides + +[[toc]] + +=== [#extents]#basic_strides# + +==== Description + +The template class `basic_strides` contains weights for a given storage +format in order to map multi-indices to scalar memory indices for +link:../tensor.html#tensor[tensor] instances. + +==== Example + +[source, cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + auto wf = strides(shape{4,3,2}); + for (auto i = 0u; i < wf.size(); ++i) + std::cout << wf.at(i) << std::endl; + // 1,4,12 + + auto wl = strides(shape{4,3,2}); + for (auto i = 0u; i < wl.size(); ++i) + std::cout << wl.at(i) << std::endl; + // 6,2,1 +} +.... + +==== Definition + +Defined in the header tensor/strides.hpp. + +==== Public base classes + +None. + +==== Specialization + +`templateusing strides = basic_strides` + +==== Template parameters + +[cols=",",] +|=== +|Parameter |Description +|`size_type` |Unsigned integer type. +|=== + +==== Member types + +[cols=",",] +|=== +|Member type |Description + +|`value_type` |Type `size_type` of the strides. + +|`size_type` |Unsigned integer such as `std::size_t`. + +|`reference` |Reference type which is `value_type&`. + +|`const_reference` |Constant reference type which is +`const value_type&`. + +|`pointer` |Pointer type which is `value_type*`. + +|`const_pointer` |Constant pointer type which is `const value_type*`. + +|`layout_type` |Layout type which can be either +`boost::numeric::ublas::first_order` or +`boost::numeric::ublas::last_order`. +|=== + +==== Member Functions + +[cols=",",] +|=== +|Member Function |Description + +|`basic_strides ()` |Constructs an empty instance of `basic_strides`. + +|`basic_strides (basic_extents const& be)` |Constructs an +instance based on the tensor extents specified by `be`. + +|`basic_strides (std::vector const& v)` |Constructs an +instance copying the content of `v`. + +|`basic_strides (std::vector && v)` |Constructs an instance +moving the content of `v`. + +|`basic_strides (basic_strides const& other)` |Constructs an instance +from `other` copying its elements. + +|`basic_strides (basic_strides && other)` |Constructs an instance from +`other` by moving its elements. + +|`basic_strides& operator= (basic_strides other)` |Assigns the elements +of `other` to this instance. + +|`const_pointer data() const` |Returns a `const_pointer` to the first +element. + +|`const_reference operator[](size_type i) const` |Returns a +`const_reference` to the `i`-th element. + +|`const_reference at(size_type i) const` |Returns a `const_reference` to +the `i`-th element. + +|`bool empty()` |Returns true if the container has no elements. + +|`size_type size() const` |Returns the number of elements. + +|`void clear()` |Erases all elements. + +|`bool operator==(basic_strides const& b) const` |Returns true if all +elements are equal. + +|`bool operator!=(basic_strides const& b) const` |Returns true if some +elements are not equal. + +|`const_iterator begin() const` |Returns an `const_iterator` pointing to +the first element. + +|`const_iterator end() const` |Returns a `const_iterator` pointing to an +element passed the last element. + +|`std::vector base() const` |Returns the private member +sequence container holding all elements. +|=== + +==== Non-Member Functions + +[cols=",",] +|=== +|Function |Description + +|`access(std::vector const& i, strides w)` +|Returns relative memory location depending on the multi-index vector +`i` and strides `w`. + +|`access(size_type sum, strides w, size_type i, size_types ... is)` +|Returns relative memory location depending on the indices `i`, +`is ...` and stride vector `w` (recursive function). +|=== + +''''' + +Copyright (©) 2018 Cem Bassoy + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/tensor/tensor_expression.adoc b/doc/ublas/tensor/tensor_expression.adoc new file mode 100644 index 000000000..7971dcc24 --- /dev/null +++ b/doc/ublas/tensor/tensor_expression.adoc @@ -0,0 +1,175 @@ +== Tensor Expressions + +[[toc]] + +=== [#tensor_expression]#Tensor Expression# + +==== Description + +The templated class `tensor_expression` is required to be a public +base of all classes. There is no Tensor Expression concept defined. + +==== Definition + +Defined in the header tensor/expression.hpp. + +==== Model of + +None. +++Not a Tensor Expression+++! + +==== Type requirements + +None. + +==== Public base classes + +`ublas_expression`. + +==== Template parameters + +[cols=",",] +|=== +|Parameter |Description +|`T` |The type of the tensor. +|`E` |The type of the tensor expression. +|=== + +==== Member types + +[cols=",",] +|=== +|Member type |Description +|`expression_type` |Type of the derived expression which is `E`. +|`type_category` |Tag for categorization which is `tensor_tag`. +|`tensor_type` |Reference type which is `T`. +|=== + +==== Public Member Functions + +[cols=",",] +|=== +|Member |Description + +|`const expression_type &operator()() const` |Returns a `const` +reference to the derived expression. +|=== + +=== [#entrywise_tensor_operations]#Entrywise Tensor Operations# + +==== [#binary_tensor_expression]#Binary Tensor Expression# + +===== Description + +The templated class `binary_tensor_expression` contains a +constant reference to a left and right expression that can be evaluated +by using the access operator. + +===== Definition + +Defined in the header tensor/expression.hpp. + +===== Model of + +Tensor Expression + +===== Type requirements + +None. + +===== Public base classes + +`tensor_expression>` + +===== Template parameters + +[cols=",",] +|=== +|Parameter |Description +|`T` |Type of the tensor. +|`EL` |Type of the left binary tensor expression. +|`ER` |Type of the right binary tensor expression. +|`OP` |Type of the binary operation. +|=== + +===== Member types + +[cols=",",] +|=== +|Member type |Description +|`expression_type_left` |Type of the left expression which is `EL`. +|`expression_type_right` |Type of the right expression which is `ER`. +|`tensor_type` |Reference type which is `T`. +|`binary_operation` |Type of the binary operation which is `OP`. +|=== + +===== Public Member Functions + +[cols=",",] +|=== +|Member |Description + +|`decltype(auto) operator()(std::size_t i) const` |Returns a `const` +reference to the i-th element of the expression. +|=== + +==== [#unary_tensor_expression]#Unary Tensor Expression# + +===== Description + +The templated class `unary_tensor_expression` contains a +constant reference to an expression that can be evaluated by using the +access operator. + +===== Definition + +Defined in the header tensor/expression.hpp. + +===== Model of + +Tensor Expression + +===== Type requirements + +None. + +===== Public base classes + +`tensor_expression>` + +===== Template parameters + +[cols=",",] +|=== +|Parameter |Description +|`T` |Type of the tensor. +|`E` |Type of the unary tensor expression. +|`OP` |Type of the unary operation. +|=== + +===== Member types + +[cols=",",] +|=== +|Member type |Description +|`expression_type` |Type of the expression which is `E`. +|`tensor_type` |Reference type which is `T`. +|`unary_operation` |Type of the unary operation which is `OP`. +|=== + +===== Public Member Functions + +[cols=",",] +|=== +|Member |Description + +|`decltype(auto) operator()(std::size_t i) const` |Returns a `const` +reference to the i-th element of the expression. +|=== + +''''' + +Copyright (©) 2018 Cem Bassoy + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/tensor/tensor_index.adoc b/doc/ublas/tensor/tensor_index.adoc new file mode 100644 index 000000000..b8e9198af --- /dev/null +++ b/doc/ublas/tensor/tensor_index.adoc @@ -0,0 +1,53 @@ +== Tensor Index + +[[toc]] + +=== [#tensor index]#tensor_index# + +==== Description + +The template class `tensor_index` decorates the +link:../tensor.html#tensor[tensor] template class with indices for +tensor contraction. + +==== Example + +[source, cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + shape s{4,3,2}; + for (auto i = 0u; i < s.size(); ++i) { + std::cout << s.at(i) << std::endl; + } +} +.... + +==== Definition + +Defined in the header tensor/tensor_einstein.hpp. + +==== Public base classes + +None. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description | +|`value_t` |The type of object stored in the tensor. | +|`format_t` |Storage organization of the tensor. | +|`storage_t` |The type of the storage array of the tensor. | +|`N` |Number of indices provided. | +|=== + +''''' + +Copyright (©) 2018 Cem Bassoy + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/triangular.adoc b/doc/ublas/triangular.adoc new file mode 100644 index 000000000..71259914e --- /dev/null +++ b/doc/ublas/triangular.adoc @@ -0,0 +1,416 @@ +== Triangular Matrix + +[[toc]] + +=== [#triangular_matrix]#Triangular Matrix# + +==== Description + +The templated class `triangular_matrix` is the base +container adaptor for triangular matrices. For a _(n x n_ )-dimensional +lower triangular matrix and _0 < = i < n_, _0 < = j < n_ holds __t__~_i,j_~ += 0 , if _i > j_. If furthermore holds __t__~_i,i_~= 1 the matrix +is called unit lower triangular. For a _(n x n_ )-dimensional lower +triangular matrix and _0 < = i < n_, _0 < = j < n_ holds __t__~_i,j_~= +0 , if _i < j_. If furthermore holds __t__~_i,i_~= 1 the matrix is +called unit lower triangular. The storage of triangular matrices is +packed. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + triangular_matrix ml (3, 3); + for (unsigned i = 0; i < ml.size1 (); ++ i) + for (unsigned j = 0; j <= i; ++ j) + ml (i, j) = 3 * i + j; + std::cout << ml << std::endl; + triangular_matrix mu (3, 3); + for (unsigned i = 0; i < mu.size1 (); ++ i) + for (unsigned j = i; j < mu.size2 (); ++ j) + mu (i, j) = 3 * i + j; + std::cout << mu << std::endl; +} +.... + +Please read the link:samples/ex_triangular.cpp[full triangular example] +for more details. + +==== Definition + +Defined in the header triangular.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the matrix. | + +|`F1` |Functor describing the type of the triangular matrix. +link:#triangular_matrix_1[[1]] |`lower` + +|`F2` |Functor describing the storage organization. +link:#triangular_matrix_2[[2]] |`row_major` + +|`A` |The type of the adapted array. link:#triangular_matrix_3[[3]] +|`unbounded_array` +|=== + +==== Model of + +link:container_concept.html#matrix[Matrix] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#matrix[Matrix] . + +==== Public base classes + +`matrix_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`triangular_matrix ()` |Allocates an uninitialized `triangular_matrix` +that holds zero rows of zero elements. + +|`triangular_matrix (size_type size1, size_type size2)` |Allocates an +uninitialized `triangular_matrix` that holds `size1` rows of `size2` +elements. + +|`triangular_matrix (const triangular_matrix &m)` |The copy constructor. + +|`template triangular_matrix (const matrix_expression &ae)` +|The extended copy constructor. + +|`void resize (size_type size1, size_type size2, bool preserve = true)` +|Reallocates a `triangular_matrix` to hold `size1` rows of `size2` +elements. The existing elements of the `triangular_matrix` are preseved +when specified. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +a `const` reference of the `j` -th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`triangular_matrix &operator = (const triangular_matrix &m)` |The +assignment operator. + +|`triangular_matrix &assign_temporary (triangular_matrix &m)` |Assigns a +temporary. May change the triangular matrix `m`. + +|`template triangular_matrix &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template triangular_matrix &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the triangular matrix. Left and right +hand side of the assignment should be independent. + +|`template triangular_matrix &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +triangular matrix. + +|`template triangular_matrix &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the triangular matrix. Left and right hand +side of the assignment should be independent. + +|`template triangular_matrix &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the triangular matrix. + +|`template triangular_matrix &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the triangular matrix. Left and +right hand side of the assignment should be independent. + +|`template triangular_matrix &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the triangular matrix with a +scalar. + +|`template triangular_matrix &operator /= (const AT &at)` |A +computed assignment operator. Divides the triangular matrix through a +scalar. + +|`void swap (triangular_matrix &m)` |Swaps the contents of the +triangular matrices. + +|`void insert (size_type i, size_type j, const_reference t)` |Inserts +the value `t` at the `j`-th element of the `i`-th row. + +|`void erase (size_type i, size_type j)` |Erases the value at the `j`-th +elemenst of the `i`-th row. + +|`void clear ()` |Clears the matrix. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `triangular_matrix`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `triangular_matrix`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `triangular_matrix`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`triangular_matrix`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `triangular_matrix`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `triangular_matrix`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `triangular_matrix`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`triangular_matrix`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`triangular_matrix`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`triangular_matrix`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `triangular_matrix`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `triangular_matrix`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`triangular_matrix`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`triangular_matrix`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `triangular_matrix`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `triangular_matrix`. +|=== + +==== Notes + +[#triangular_matrix_1]#[1]# Supported parameters for the type of the +triangular matrix are `lower` , `unit_lower`, `upper` and `unit_upper` . + +[#triangular_matrix_2]#[2]# Supported parameters for the storage +organization are `row_major` and `column_major`. + +[#triangular_matrix_3]#[3]# Supported parameters for the adapted array +are `unbounded_array` , `bounded_array` and `std::vector` . + +=== [#triangular_adaptor]#Triangular Adaptor# + +==== Description + +The templated class `triangular_adaptor` is a triangular matrix +adaptor for other matrices. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + matrix m (3, 3); + triangular_adaptor, lower> tal (m); + for (unsigned i = 0; i < tal.size1 (); ++ i) + for (unsigned j = 0; j <= i; ++ j) + tal (i, j) = 3 * i + j; + std::cout << tal << std::endl; + triangular_adaptor, upper> tau (m); + for (unsigned i = 0; i < tau.size1 (); ++ i) + for (unsigned j = i; j < tau.size2 (); ++ j) + tau (i, j) = 3 * i + j; + std::cout << tau << std::endl; +} +.... + +Please read the link:samples/ex_triangular.cpp[full triangular example] +for more details. + +==== Definition + +Defined in the header triangular.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`M` |The type of the adapted matrix. | + +|`F` |Functor describing the type of the triangular adaptor. +link:#triangular_adaptor_1[[1]] |`lower` +|=== + +==== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +==== Public base classes + +`matrix_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`triangular_adaptor (matrix_type &data)` |Constructs a +`triangular_adaptor` of a matrix. + +|`triangular_adaptor (const triangular_adaptor &m)` |The copy +constructor. + +|`template triangular_adaptor (const matrix_expression &ae)` +|The extended copy constructor. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +a `const` reference of the `j` -th element in the `i`-th row. + +|`reference operator () (size_type i, size_type j)` |Returns a reference +of the `j`-th element in the `i`-th row. + +|`triangular_adaptor &operator = (const triangular_adaptor &m)` |The +assignment operator. + +|`triangular_adaptor &assign_temporary (triangular_adaptor &m)` |Assigns +a temporary. May change the triangular adaptor `m`. + +|`template triangular_adaptor &operator = (const matrix_expression &ae)` +|The extended assignment operator. + +|`template triangular_adaptor &assign (const matrix_expression &ae)` +|Assigns a matrix expression to the triangular adaptor. Left and right +hand side of the assignment should be independent. + +|`template triangular_adaptor &operator += (const matrix_expression &ae)` +|A computed assignment operator. Adds the matrix expression to the +triangular adaptor. + +|`template triangular_adaptor &plus_assign (const matrix_expression &ae)` +|Adds a matrix expression to the triangular adaptor. Left and right hand +side of the assignment should be independent. + +|`template triangular_adaptor &operator -= (const matrix_expression &ae)` +|A computed assignment operator. Subtracts the matrix expression from +the triangular adaptor. + +|`template triangular_adaptor &minus_assign (const matrix_expression &ae)` +|Subtracts a matrix expression from the triangular adaptor. Left and +right hand side of the assignment should be independent. + +|`template triangular_adaptor &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the triangular adaptor with a +scalar. + +|`template triangular_adaptor &operator /= (const AT &at)` |A +computed assignment operator. Divides the triangular adaptor through a +scalar. + +|`void swap (triangular_adaptor &m)` |Swaps the contents of the +triangular adaptors. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the `triangular_adaptor`. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the `triangular_adaptor`. + +|`iterator1 begin1 ()` |Returns a `iterator1` pointing to the beginning +of the `triangular_adaptor`. + +|`iterator1 end1 ()` |Returns a `iterator1` pointing to the end of the +`triangular_adaptor`. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the `triangular_adaptor`. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the `triangular_adaptor`. + +|`iterator2 begin2 ()` |Returns a `iterator2` pointing to the beginning +of the `triangular_adaptor`. + +|`iterator2 end2 ()` |Returns a `iterator2` pointing to the end of the +`triangular_adaptor`. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +`triangular_adaptor`. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +`triangular_adaptor`. + +|`reverse_iterator1 rbegin1 ()` |Returns a `reverse_iterator1` pointing +to the beginning of the reversed `triangular_adaptor`. + +|`reverse_iterator1 rend1 ()` |Returns a `reverse_iterator1` pointing to +the end of the reversed `triangular_adaptor`. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +`triangular_adaptor`. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +`triangular_adaptor`. + +|`reverse_iterator2 rbegin2 ()` |Returns a `reverse_iterator2` pointing +to the beginning of the reversed `triangular_adaptor`. + +|`reverse_iterator2 rend2 ()` |Returns a `reverse_iterator2` pointing to +the end of the reversed `triangular_adaptor`. +|=== + +==== Notes + +[#triangular_adaptor_1]#[1]# Supported parameters for the type of the +triangular adaptor are `lower` , `unit_lower`, `upper` and `unit_upper` +. + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/types_overview.adoc b/doc/ublas/types_overview.adoc new file mode 100644 index 000000000..00c7220af --- /dev/null +++ b/doc/ublas/types_overview.adoc @@ -0,0 +1,352 @@ +== Overview of Tensor, Matrix- and Vector Types + +[[toc]] + +Contents: + + + link:#vectors[Vectors] + + + link:#vector_proxies[Vector Proxies] + + + link:#matrices[Matrices] + + + link:#matrix_proxies[Matrix Proxies] + + + link:#tensors[Tensors] + + + link:#storage_layout[Special Storage Layouts] + +=== Notation + +[cols=",",] +|=== +|`T` |is the data type. For general linear algebra operations this will +be a real type e.g. `double`, ... + +|`F` |is the orientation type, either `row_major` or `column_major` for +matrices and `first_order` or `last_order` for tensors + +|`A, IA, TA` |is an array storage type, e.g. +`std::vector, bounded_array, unbounded_array, ...` + +|`TRI` |is a triangular functor: +`lower, unit_lower, strict_lower, upper, unit_upper, strict_upper` + +|`M, N, K` |are unsigned integer sizes (`std::size_t`) + +|`IB` |is an index base (`std::size_t`) + +|`VEC` |is any vector type + +|`MAT` |is any matrix type + +|`TEN` |is any tensor type + +|`[...]` |denote optional arguments - for more details look at the +section "storage layout". +|=== + +=== [#vectors]#Vectors# + +[width="100%",cols="50%,50%",options="header",] +|=== +|Definition |Description +|`vector   v(size);` |a dense vector of values of type `T` of +variable size. A storage type `A` can be specified which defaults to +`unbounded_array`. Elements are constructed by `A`, which need not +initialise their value. + +|`bounded_vector   v;` |a dense vector of values of type `T` of +variable size but with maximum `N`. The default constructor creates `v` +with size `N`. Elements are constructed by the storage type +`bounded_array`, which need not initialise their value. + +|`c_vector   v(size);` |a dense vector of values of type `T` with +the given size. The data is stored as an ordinary C++ array `T data_[M]` + +|`zero_vector   v(size);` |the zero vector of type `T` with the given +size. + +|`unit_vector   v(size, index);` |the unit vector of type `T` with +the given size. The vector is zero other then a single specified +element. + +`index` should be less than `size`. + +|`mapped_vector   v(size);` |a sparse vector of values of type +`T` of variable size. The sparse storage type `S` can be +`std::map` or `map_array`. + +|`compressed_vector   v(size);` |a sparse vector of +values of type `T` of variable size. The non zero values are stored as +two seperate arrays - an index array and a value array. The index array +is always sorted and there is at most one entry for each index. + +|`coordinate_vector   v(size);` |a sparse vector of +values of type `T` of variable size. The non zero values are stored as +two seperate arrays - an index array and a value array. The arrays may +be out of order with multiple entries for each vector element. If there +are multiple values for the same index the sum of these values is the +real value. +|=== + +_Note:_ the default types are defined in `boost/numeric/ublas/fwd.hpp`. + +=== [#vector_proxies]#Vector Proxies# + +[cols=",",options="header",] +|=== +|Definition |Description +|`vector_range   vr(v, range);` |a vector referencing a continuous +subvector of elements of vector `v` containing all elements specified by +`range`. + +|`vector_slice   vs(v, slice);` |a vector referencing a non +continuous subvector of elements of vector `v` containing all elements +specified by `slice`. + +|`matrix_row   vr(m, index);` |a vector referencing the `index`-th +row of matrix `m` + +|`matrix_column   vc(m, index);` |a vector referencing the +`index`-th column of matrix `m` +|=== + +=== [#matrices]#Matrices# + +[cols=",",options="header",] +|=== +|Definition |Description +|`matrix   m(size1, size2);` |a dense matrix of values of +type `T` of variable size. A storage type `A` can be specified which +defaults to `unbounded_array`. The orientation functor `F` defaults to +`row_major`. Elements are constructed by `A`, which need not initialise +their value. + +|`bounded_matrix   m;` |a dense matrix of type `T` with +variable size with maximum `M`-by-`N`. The orientation functor `F` +defaults to `row_major`. The default constructor creates `m` with size +`M`-by-`N`. Elements are constructed by the storage type +`bounded_array`, which need not initialise their value. + +|`c_matrix   m(size1, size2);` |a dense matrix of values of +type `T` with the given size. The data is stored as an ordinary C++ +array `T data_[N][M]` + +|`vector_of_vector   m(size1, size2);` |a dense matrix of +values of type `T` with the given size. The data is stored as a vector +of vectors. The orientation `F` defaults to `row_major`. The storage +type `S` defaults to `unbounded_array >` + +|`zero_matrix   m(size1, size2);` |a zero matrix of type `T` with the +given size. + +|`identity_matrix   m(size1, size2);` |an identity matrix of type `T` +with the given size. The values are `v(i,j) = (i==j)?T(1):T()`. + +|`scalar_matrix   m(size1, size2, value);` |a matrix of type `T` with +the given size that has the value `value` everywhere. + +|`triangular_matrix   m(size);` |a triangular matrix of +values of type `T` of variable size. Only the nonzero elements are +stored in the given order `F`. ("triangular packed storage") The +triangular type `F` defaults to `lower`, the orientation type `F` +defaults to `row_major`. + +|`banded_matrix   m(size1, size2, n_lower, n_upper);` |a +banded matrix of values of type `T` of variable size with `n_lower` sub +diagonals and `n_upper` super diagonals. Only the nonzero elements are +stored in the given order `F`. ("packed storage") + +|`symmetric_matrix   m(size);` |a symmetric matrix of +values of type `T` of variable size. Only the given triangular matrix is +stored in the given order `F`. + +|`hermitian_matrix   m(size);` |a hermitian matrix of +values of type `T` of variable size. Only the given triangular matrix is +stored using the order `F`. + +|`mapped_matrix   m(size1, size2 [, non_zeros]);` |a sparse +matrix of values of type `T` of variable size. The sparse storage type +`S` can be either `std::map >` or +`map_array >`. + +|`sparse_vector_of_sparse_vector   m(size1, size2 [, non_zeros]);` +|a sparse matrix of values of type `T` of variable size. + +|`compressed_matrix   m(size1, size2 [, non_zeros]);` +|a sparse matrix of values of type `T` of variable size. The values are +stored in compressed row/column storage. + +|`coordinate_matrix   m(size1, size2 [, non_zeros]);` +|a sparse matrix of values of type `T` of variable size. The values are +stored in 3 parallel array as triples (i, j, value). More than one value +for each pair of indices is possible, the real value is the sum of all. + +|`generalized_vector_of_vector   m(size1, size2 [, non_zeros]);` +|a sparse matrix of values of type `T` of variable size. The values are +stored as a vector of sparse vectors, e.g. +`generalized_vector_of_vector > >` +|=== + +_Note:_ the default types are defined in `boost/numeric/ublas/fwd.hpp`. + +=== [#matrix_proxies]#Matrix Proxies# + +[cols=",",options="header",] +|=== +|Definition |Description +|`triangular_adaptor   ta(m);` |a triangular matrix +referencing a selection of elements of the matrix `m`. + +|`symmetric_adaptor   sa(m);` |a symmetric matrix referencing +a selection of elements of the matrix `m`. + +|`hermitian_adaptor   ha(m);` |a hermitian matrix referencing +a selection of elements of the matrix `m`. + +|`banded_adaptor   ba(m, n_lower, n_upper);` |a banded matrix +referencing a selection of elements of the matrix `m`. + +|`matrix_range   mr(m, range1, range2);` |a matrix referencing +a submatrix of elements in the matrix `m`. + +|`matrix_slice   ms(m, slice1, slice2);` |a matrix referencing +a non continues submatrix of elements in the matrix `m`. +|=== + +=== [#tensors]#Tensors# + +[cols=",",options="header",] +|=== +|Definition |Description +|`tensor   t(size1, size2, ... );` |a dense matrix of values +of type `T` of variable size. A storage type `A` can be specified which +defaults to `std::vector`. The orientation type `F` defaults to +`first_order`. Elements are constructed by `A`, which need not +initialise their value. +|=== + +=== [#storage_layout]#Special Storage Layouts# + +The library supports conventional dense, packed and basic sparse vector +and matrix storage layouts. The description of the most common +constructions of vectors and matrices comes next. + +[width="100%",cols="50%,50%",] +|=== +|Construction |Comment + +|`vector >   v (size)` |a dense vector, storage is +provided by a standard vector. + +The storage layout usually is BLAS compliant. + +|`vector >   v (size)` |a dense vector, storage +is provided by a heap-based array. + +The storage layout usually is BLAS compliant. + +|`vector >   v (size)` |a dense vector, storage +is provided by a stack-based array. + +The storage layout usually is BLAS compliant. + +|`mapped_vector >   v (size, non_zeros)` |a +sparse vector, storage is provided by a standard map. + +|`mapped_vector >   v (size, non_zeros)` +|a sparse vector, storage is provided by a map array. + +|`matrix >   m (size1, size2)` |a dense +matrix, orientation is row major, storage is provided by a standard +vector. + +|`matrix >   m (size1, size2)` |a +dense matrix, orientation is column major, storage is provided by a +standard vector. + +The storage layout usually is BLAS compliant. + +|`matrix >   m (size1, size2)` |a +dense matrix, orientation is row major, storage is provided by a +heap-based array. + +|`matrix >   m (size1, size2)` |a +dense matrix, orientation is column major, storage is provided by a +heap-based array. + +The storage layout usually is BLAS compliant. + +|`matrix >   m (size1, size2)` +|a dense matrix, orientation is row major, storage is provided by a +stack-based array. + +|`matrix >   m (size1, size2)` +|a dense matrix, orientation is column major, storage is provided by a +stack-based array. + +The storage layout usually is BLAS compliant. + +|`triangular_matrix   m (size)` |a packed +triangular matrix, orientation is row major. + +|`triangular_matrix   m (size)` |a packed +triangular matrix, orientation is column major. + +The storage layout usually is BLAS compliant. + +|`banded_matrix   m (size1, size2, lower, upper)` |a +packed banded matrix, orientation is row major. + +|`banded_matrix   m (size1, size2, lower, upper)` +|a packed banded matrix, orientation is column major. + +The storage layout usually is BLAS compliant. + +|`symmetric_matrix   m (size)` |a packed symmetric +matrix, orientation is row major. + +|`symmetric_matrix   m (size)` |a packed +symmetric matrix, orientation is column major. + +The storage layout usually is BLAS compliant. + +|`hermitian_matrix   m (size)` |a packed hermitian +matrix, orientation is row major. + +|`hermitian_matrix   m (size)` |a packed +hermitian matrix, orientation is column major. + +The storage layout usually is BLAS compliant. + +|`mapped_matrix >   m (size1, size2, non_zeros)` +|a sparse matrix, orientation is row major, storage is provided by a +standard map. + +|`mapped_matrix >   m (size1, size2, non_zeros)` +|a sparse matrix, orientation is column major, storage is provided by a +standard map. + +|`mapped_matrix >   m (size1, size2, non_zeros)` +|a sparse matrix, orientation is row major, storage is provided by a map +array. + +|`mapped_matrix >   m (size1, size2, non_zeros)` +|a sparse matrix, orientation is column major, storage is provided by a +map array. + +|`compressed_matrix   m (size1, size2, non_zeros)` |a +compressed matrix, orientation is row major. + +The storage layout usually is BLAS compliant. + +|`compressed_matrix   m (size1, size2, non_zeros)` |a +compressed matrix, orientation is column major. + +The storage layout usually is BLAS compliant. + +|`coordinate_matrix   m (size1, size2, non_zeros)` |a +coordinate matrix, orientation is row major. + +The storage layout usually is BLAS compliant. + +|`coordinate_matrix   m (size1, size2, non_zeros)` |a +coordinate matrix, orientation is column major. + +The storage layout usually is BLAS compliant. +|=== + +''''' + +Copyright (©) 2000-2004 Joerg Walter, Mathias Koch, Gunter Winkler, +Michael Stevens + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/unbounded_array.adoc b/doc/ublas/unbounded_array.adoc new file mode 100644 index 000000000..a64b2368e --- /dev/null +++ b/doc/ublas/unbounded_array.adoc @@ -0,0 +1,147 @@ +== Unbounded Array Storage + +[[toc]] + +=== [#unbounded_array]#Unbounded Array# + +==== Description + +The templated class `unbounded_array` implements a unbounded +storage array using an allocator. The unbounded array is similar to a +`std::vector` in that in can grow in size beyond any fixed bound. +However `unbounded_array` is aimed at optimal performance. Therefore +`unbounded_array` does not model a `Sequence` like `std::vector` does. + +When resized `unbounded_array` will reallocate it's storage even if the +new size requirement is smaller. It is therefore inefficient to resize a +`unbounded_array` + +==== Example + +[source, cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + unbounded_array a (3); + for (unsigned i = 0; i < a.size (); ++ i) { + a [i] = i; + std::cout << a [i] << std::endl; + } +} +.... + +==== Definition + +Defined in the header storage.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`T` |The type of object stored in the array. | +|`ALLOC` |An STL Allocator |std::allocator +|=== + +==== Model of + +link:storage_concept.html[Storage] + +==== Type requirements + +None, except for those imposed by the requirements of Storage. + +==== Public base classes + +None. + +==== Members + +* The description does not describe what the member actually does, this +can be looked up in the corresponding concept documentation, but instead +contains a remark on the implementation of the member inside this model +of the concept. +* Typography: +** Members that are not part of the implemented concepts are in blue. + +[cols=,,,] +|=== +|Member |Where defined |Description + +|`value_type` |https://www.boost.org/sgi/stl/Container.html[Container] | + +|`pointer` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `value_type*` + +|`const_pointer` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `const value_type*` + +|`reference` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `value_type&` + +|`const_reference` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `const value_type&` + +|`size_type` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `Alloc::size_type` + +|`difference_type` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `Alloc::difference_type` + +|`iterator` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `pointer` + +|`const_iterator` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `const_pointer` + +|`revere_iterator` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `std::reverse_iterator` + +|`const_revere_iterator` |https://www.boost.org/sgi/stl/Container.html[Container] |Defined as `std::reverse_iterator` + +|[blue]#allocator_type# | |Defined as ALLOC + +|`explicit unbounded_array (ALLOC &a = ALLOC())` |link:storage_concept.html[Storage] |Creates an `unbounded_array` that holds zero elements, using a specified allocator. + +|`explicit unbounded_array (size_type size, ALLOC &a = ALLOC())` |link:storage_concept.html[Storage] |Creates a uninitialized `unbounded_array` that holds `size` elements, using a specified allocator. All the elements are default constructed. + +|`unbounded_array (size_type size, const T& init, ALLOC& a = ALLOC())` |link:storage_concept.html[Storage] |Creates an initialized `unbounded_array` that holds `size` elements,using a specified allocator. All the elements are constructed from the `init` value. + +|`unbounded_array (const unbounded_array &a)` |https://www.boost.org/sgi/stl/Container.html[Container] |The copy constructor. + +|`~unbounded_array ()` |https://www.boost.org/sgi/stl/Container.html[Container] |Deallocates the `unbounded_array` itself. + +|`void resize (size_type n)` |link:storage_concept.html[Storage] |Reallocates an `unbounded_array` to hold `n` elements. Values are uninitialised. + +|`void resize(size_type n, const T& t)` |link:storage_concept.html[Storage] |Reallocates an `unbounded_array` to hold `n` elements. Values are copies of `t` + +|`size_type size () const` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns the size of the `unbounded_array`. + +|`const_reference operator [] (size_type i) const` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a `const` reference of the `i` -th element. + +|`reference operator [] (size_type i)` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a reference of the `i`-th element. + +|`unbounded_array &operator = (const unbounded_array &a)` |https://www.boost.org/sgi/stl/Container.html[Container] |The assignment operator. + +|[blue]#`unbounded_array &assign_temporary (unbounded_array &a)`# | |Assigns a temporary. May change the array `a`. + +|`void swap (unbounded_array &a)` |https://www.boost.org/sgi/stl/Container.html[Container] |Swaps the contents of the arrays. + +|`const_iterator begin () const` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a `const_iterator` pointing to the beginning of the `unbounded_array`. + +|`const_iterator end () const` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a `const_iterator` pointing to the end of the `unbounded_array`. + +|`iterator begin ()` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a `iterator` pointing to the beginning of the `unbounded_array`. + +|`iterator end ()` |https://www.boost.org/sgi/stl/Container.html[Container] |Returns a `iterator` pointing to the end of the `unbounded_array`. + +|`const_reverse_iterator rbegin () const` |https://www.boost.org/sgi/stl/ReversibleContainer.html[ReversibleContainer] |Returns a `const_reverse_iterator` pointing to the beginning of the reversed `unbounded_array`. + +|`const_reverse_iterator rend () const` |https://www.boost.org/sgi/stl/ReversibleContainer.html[ReversibleContainer] |Returns a `const_reverse_iterator` pointing to the end of the reversed `unbounded_array`. + +|`reverse_iterator rbegin ()` |https://www.boost.org/sgi/stl/ReversibleContainer.html[ReversibleContainer] |Returns a `reverse_iterator` pointing to the beginning of the reversed `unbounded_array`. + +|`reverse_iterator rend ()` |https://www.boost.org/sgi/stl/ReversibleContainer.html[ReversibleContainer] |Returns a `reverse_iterator` pointing to the end of the reversed `unbounded_array`. + +|=== + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/vector.adoc b/doc/ublas/vector.adoc new file mode 100644 index 000000000..d395d44fc --- /dev/null +++ b/doc/ublas/vector.adoc @@ -0,0 +1,555 @@ +== Vector + +[[toc]] + +=== [#vector]#Vector# + +==== Description + +The templated class `vector` is the base container adaptor for +dense vectors. For a _n_-dimensional vector and _0 < = i < n_ every +element __v__~_i_~ is mapped to the __i-__th element of the container. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + vector v (3); + for (unsigned i = 0; i < v.size (); ++ i) + v (i) = i; + std::cout << v << std::endl; +} +.... + +==== Definition + +Defined in the header vector.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the vector. | + +|`A` |The type of the link:storage_concept.html[Storage] array. +link:#vector_1[[1]] |`unbounded_array` +|=== + +==== Model of + +link:container_concept.html#vector[Vector], +http://www.boost.org/sgi/stl/RandomAccessContainer.html[RandomAccessContainer] + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#vector[Vector] and +http://www.boost.org/sgi/stl/RandomAccessContainer.html[RandomAccessContainer]. + +==== Public base classes + +`vector_container >` + +==== Members + +[cols=",,",] +|=== +|Member |Where defined |Description + +|`value_type` +|link:expression_concept.html#vector_expression[VectorExpression] | + +|`reference` +|link:expression_concept.html#vector_expression[VectorExpression] | + +|`const_reference` +|link:expression_concept.html#vector_expression[VectorExpression] | + +|`size_type` +|link:expression_concept.html#vector_expression[VectorExpression] | + +|`difference_type` +|link:expression_concept.html#vector_expression[VectorExpression] | + +|`const_iterator` +|link:expression_concept.html#vector_expression[VectorExpression] | + +|`iterator` +|link:expression_concept.html#vector_expression[VectorExpression] | + +|`const_reverse_iterator` +|link:expression_concept.html#vector_expression[VectorExpression] | + +|`reverse_iterator` +|link:expression_concept.html#vector_expression[VectorExpression] | + +|`array_type` |link:container_concept.html#vector[Vector] | + +|`vector ()` +|link:expression_concept.html#vector_expression[VectorExpression] +|Allocates an uninitialized `vector` that holds zero elements. + +|`vector (size_type size)` |link:container_concept.html#vector[Vector] +|Allocates an uninitialized `vector` that holds `size` elements. + +|`vector (const vector &v)` | |The copy constructor. + +|`template vector (const vector_expression &ae)` | |The +extended copy constructor. + +|`void resize (size_type size, bool preserve = true)` +|link:container_concept.html#vector[Vector] |Reallocates a `vector` to +hold `size` elements. The existing elements of the `vector` are preseved +when specified. + +|`size_type size () const` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns the size of the `vector`. + +|`size_type max_size () const` +|https://www.boost.org/sgi/stl/RandomAccessContainer.html[RandomAccessContainer] +|Returns the upper bound on the size of the `vector`. + +|`bool empty () const` +|http://www.boost.org/sgi/stl/RandomAccessContainer.html[RandomAccessContainer] +|Equivilent to `size () == 0`. + +|`const array_type& data () const` +|link:container_concept.html#vector[Vector] | + +|`array_type& data ()` |link:container_concept.html#vector[Vector] | + +|`const_reference operator () (size_type i) const` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns a `const` reference of the `i` -th element. + +|`reference operator () (size_type i)` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns a reference of the `i`-th element. + +|`const_reference operator [] (size_type i) const` +|link:container_concept.html#vector[Vector] |Returns a `const` reference +of the `i` -th element. + +|`reference operator [] (size_type i)` +|link:container_concept.html#vector[Vector] |Returns a reference of the +`i`-th element. + +|`vector &operator = (const vector &v)` +|link:expression_concept.html#vector_expression[VectorExpression] |The +assignment operator. + +|`vector &assign_temporary (vector &v)` +|link:expression_concept.html#vector_expression[VectorExpression] +|Assigns a temporary. May change the vector `v`. + +|`template vector &operator = (const vector_expression &ae)` +|link:expression_concept.html#vector_expression[VectorExpression] |The +extended assignment operator. + +|`template vector &assign (const vector_expression &ae)` +|link:expression_concept.html#vector_expression[VectorExpression] +|Assigns a vector expression to the vector. Left and right hand side of +the assignment should be independent. + +|`template vector &operator += (const vector_expression &ae)` +|link:expression_concept.html#vector_expression[VectorExpression] |A +computed assignment operator. Adds the vector expression to the vector. + +|`template vector &plus_assign (const vector_expression &ae)` +|link:expression_concept.html#vector_expression[VectorExpression] |Adds +a vector expression to the vector. Left and right hand side of the +assignment should be independent. + +|`template vector &operator -= (const vector_expression &ae)` +|link:expression_concept.html#vector_expression[VectorExpression] |A +computed assignment operator. Subtracts the vector expression from the +vector. + +|`template vector &minus_assign (const vector_expression &ae)` +|link:expression_concept.html#vector_expression[VectorExpression] +|Subtracts a vector expression from the vector. Left and right hand side +of the assignment should be independent. + +|`template vector &operator *= (const AT &at)` +|link:expression_concept.html#vector_expression[VectorExpression] |A +computed assignment operator. Multiplies the vector with a scalar. + +|`template vector &operator /= (const AT &at)` +|link:expression_concept.html#vector_expression[VectorExpression] |A +computed assignment operator. Divides the vector through a scalar. + +|`void swap (vector &v)` +|link:expression_concept.html#vector_expression[VectorExpression] |Swaps +the contents of the vectors. + +|`void insert_element (size_type i, const_reference t)` +|link:container_concept.html#vector[Vector] |Inserts the value `t` at +the `i`-th element. + +|`void erase_element (size_type i)` +|link:container_concept.html#vector[Vector] |Erases the value at the +`i`-th element. + +|`void clear ()` |link:container_concept.html#vector[Vector] |Clears the +vector. + +|`const_iterator begin () const` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns a `const_iterator` pointing to the beginning of the `vector`. + +|`const_iterator end () const` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns a `const_iterator` pointing to the end of the `vector`. + +|`iterator begin ()` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns a `iterator` pointing to the beginning of the `vector`. + +|`iterator end ()` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns a `iterator` pointing to the end of the `vector`. + +|`const_reverse_iterator rbegin () const` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns a `const_reverse_iterator` pointing to the beginning of the +reversed `vector`. + +|`const_reverse_iterator rend () const` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns a `const_reverse_iterator` pointing to the end of the reversed +`vector`. + +|`reverse_iterator rbegin ()` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns a `reverse_iterator` pointing to the beginning of the reversed +`vector`. + +|`reverse_iterator rend ()` +|link:expression_concept.html#vector_expression[VectorExpression] +|Returns a `reverse_iterator` pointing to the end of the reversed +`vector`. +|=== + +==== Notes + +[#vector_1]#[1]# Common parameters for the Storage array are +`unbounded_array` , `bounded_array` and `std::vector` . + +=== [#unit_vector]#Unit Vector# + +==== Description + +The templated class `unit_vector` represents canonical unit +vectors. For the _k_-th _n_-dimensional canonical unit vector and _0 <= +i < n_ holds __u__^_k_^~_i_~ _= 0_, if _i <> k_, and __u__^_k_^~_i_~ _= +1_. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + for (int i = 0; i < 3; ++ i) { + unit_vector v (3, i); + std::cout << v << std::endl; + } +} +.... + +==== Definition + +Defined in the header vector.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the vector. |`int` + +|`ALLOC` |An STL Allocator for size_type and difference_type. +|std::allocator +|=== + +==== Model of + +link:container_concept.html#vector[Vector] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#vector[Vector] . + +==== Public base classes + +`vector_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`unit_vector ()` |Constructs an `unit_vector` that holds zero elements. + +|`unit_vector (size_type size, size_type index)` |Constructs the +`index`-th `unit_vector` that holds `size` elements. + +|`unit_vector (const unit_vector &v)` |The copy constructor. + +|`void resize (size_type size, bool preserve = true)` |Resizes a +`unit_vector` to hold `size` elements. Therefore the existing elements +of the `unit_vector` are always preseved. + +|`size_type size () const` |Returns the size of the `unit_vector`. + +|`size_type index () const` |Returns the index of the `unit_vector`. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`const_reference operator [] (size_type i) const` |Returns the value of +the `i`-th element. + +|`unit_vector &operator = (const unit_vector &v)` |The assignment +operator. + +|`unit_vector &assign_temporary (unit_vector &v)` |Assigns a temporary. +May change the unit vector `v` . + +|`void swap (unit_vector &v)` |Swaps the contents of the unit vectors. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `unit_vector`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `unit_vector`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`unit_vector`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`unit_vector`. +|=== + +=== [#zero_vector]#Zero Vector# + +==== Description + +The templated class `zero_vector` represents zero vectors. For +a _n_-dimensional zero vector and _0 <= i < n_ holds __z__~_i_~ _= 0_. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + zero_vector v (3); + std::cout << v << std::endl; +} +.... + +==== Definition + +Defined in the header vector.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the vector. |`int` + +|`ALLOC` |An STL Allocator for size_type and difference_type. +|std::allocator +|=== + +==== Model of + +link:container_concept.html#vector[Vector] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#vector[Vector] . + +==== Public base classes + +`vector_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`zero_vector ()` |Constructs a `zero_vector` that holds zero elements. + +|`zero_vector (size_type size)` |Constructs a `zero_vector` that holds +`size` elements. + +|`zero_vector (const zero_vector &v)` |The copy constructor. + +|`void resize (size_type size, bool preserve = true)` |Resizes a +`zero_vector` to hold `size` elements. Therefore the existing elements +of the `zero_vector` are always preseved. + +|`size_type size () const` |Returns the size of the `zero_vector`. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`const_reference operator [] (size_type i) const` |Returns the value of +the `i`-th element. + +|`zero_vector &operator = (const zero_vector &v)` |The assignment +operator. + +|`zero_vector &assign_temporary (zero_vector &v)` |Assigns a temporary. +May change the zero vector `v` . + +|`void swap (zero_vector &v)` |Swaps the contents of the zero vectors. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `zero_vector`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `zero_vector`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`zero_vector`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`zero_vector`. +|=== + +=== [#scalar_vector]#Scalar Vector# + +==== Description + +The templated class `scalar_vector` represents scalar vectors. +For a _n_-dimensional scalar vector and _0 <= i < n_ holds __z__~_i_~ _= +s_. + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + scalar_vector v (3); + std::cout << v << std::endl; +} +.... + +==== Definition + +Defined in the header vector.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the vector. |`int` + +|`ALLOC` |An STL Allocator for size_type and difference_type. +|std::allocator +|=== + +==== Model of + +link:container_concept.html#vector[Vector] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#vector[Vector] . + +==== Public base classes + +`vector_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`scalar_vector ()` |Constructs a `scalar_vector` that holds zero +elements. + +|`scalar_vector (size_type size, const value_type &value)` |Constructs a +`scalar_vector` that holds `size` elements each of the specified value. + +|`scalar_vector (const scalar_vector &v)` |The copy constructor. + +|`void resize (size_type size, bool preserve = true)` |Resizes a +`scalar_vector` to hold `size` elements. Therefore the existing elements +of the `scalar_vector` are always preseved. + +|`size_type size () const` |Returns the size of the `scalar_vector`. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`const_reference operator [] (size_type i) const` |Returns the value of +the `i`-th element. + +|`scalar_vector &operator = (const scalar_vector &v)` |The assignment +operator. + +|`scalar_vector &assign_temporary (scalar_vector &v)` |Assigns a +temporary. May change the scalar vector `v` . + +|`void swap (scalar_vector &v)` |Swaps the contents of the scalar +vectors. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `scalar_vector`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `scalar_vector`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`scalar_vector`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`scalar_vector`. +|=== + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/vector_expression.adoc b/doc/ublas/vector_expression.adoc new file mode 100644 index 000000000..6ae7bbf3c --- /dev/null +++ b/doc/ublas/vector_expression.adoc @@ -0,0 +1,913 @@ +== Vector Expressions + +[[toc]] + +=== [#vector_expression]#Vector Expression# + +==== Description + +The templated class `vector_expression` is required to be a public +base of all classes which model the Vector Expression concept. + +==== Definition + +Defined in the header expression_types.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E` |The type of the vector expression. |  +|=== + +==== Model of + +None. +++Not a Vector Expression+++! + +==== Type requirements + +None. + +==== Public base classes + +None. + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`const expression_type &operator () () const` |Returns a `const` +reference of the expression. + +|`expression_type &operator () ()` |Returns a reference of the +expression. +|=== + +==== Notes + +The `range`, `slice` and `project` functions have been removed. Use the +free functions defined in link:vector_proxy.html[vector proxy] instead. + +=== [#vector_container]#Vector Container# + +==== Description + +The templated class `vector_container` is required to be a public +base of all classes which model the Vector concept. This includes the +class `vector` itself. + +==== Definition + +Defined in the header expression_types.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`C` |The type of the vector container. |  +|=== + +==== Model of + +None. +++Not a Vector Expression OR Vector+++! + +==== Type requirements + +None. + +==== Public base classes + +`vector_expression` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`const container_type &operator () () const` |Returns a `const` +reference of the container. + +|`container_type &operator () ()` |Returns a reference of the container. +|=== + +=== [#vector_references]#Vector References# + +==== Reference + +===== Description + +The templated class `vector_reference` contains a reference to a +vector expression. + +===== Definition + +Defined in the header vector_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E` |The type of the vector expression. |  +|=== + +===== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Public base classes + +`vector_expression >` + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`vector_reference (expression_type &e)` |Constructs a reference of the +expression. + +|`void resize (size_type size)` |Resizes the expression to hold at most +`size` elements. + +|`size_type size () const` |Returns the size of the expression. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator () (size_type i)` |Returns a reference of the +`i`-th element. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the expression. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the expression. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the expression. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +expression. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed expression. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed expression. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed expression. +|=== + +=== [#vector_operations]#Vector Operations# + +==== Unary Operation Description + +===== Description + +The templated class `vector_unary` describes a unary vector +operation. + +===== Definition + +Defined in the header vector_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E` |The type of the vector expression. |  +|`F` |The type of the operation. |  +|=== + +===== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Public base classes + +`vector_expression >` + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`vector_unary (const expression_type &e)` |Constructs a description of +the expression. + +|`size_type size () const` |Returns the size of the expression. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the expression. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the expression. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed expression. +|=== + +==== Unary Operations + +===== Prototypes + +[source,cpp] +.... +template + struct vector_unary_traits { + typedef vector_unary expression_type; + typedef expression_type result_type; + }; + + // (- v) [i] = - v [i] + template + typename vector_unary_traits >::result_type + operator - (const vector_expression &e); + + // (conj v) [i] = conj (v [i]) + template + typename vector_unary_traits >::result_type + conj (const vector_expression &e); + + // (real v) [i] = real (v [i]) + template + typename vector_unary_traits >::result_type + real (const vector_expression &e); + + // (imag v) [i] = imag (v [i]) + template + typename vector_unary_traits >::result_type + imag (const vector_expression &e); + + // (trans v) [i] = v [i] + template + typename vector_unary_traits >::result_type + trans (const vector_expression &e); + + // (herm v) [i] = conj (v [i]) + template + typename vector_unary_traits >::result_type + herm (const vector_expression &e); +.... + +===== Description + +`operator -` computes the additive inverse of a vector expression. +`conj` computes the complex conjugate of a vector expression. `real` and +`imag` compute the real and imaginary parts of a vector expression. +`trans` computes the transpose of a vector expression. `herm` computes +the hermitian, i.e. the complex conjugate of the transpose of a vector +expression. + +===== Definition + +Defined in the header vector_expression.hpp. + +===== Type requirements + +* `E` is a model of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Preconditions + +None. + +===== Complexity + +Linear depending from the size of the vector expression. + +===== Examples + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + vector > v (3); + for (unsigned i = 0; i < v.size (); ++ i) + v (i) = std::complex (i, i); + + std::cout << - v << std::endl; + std::cout << conj (v) << std::endl; + std::cout << real (v) << std::endl; + std::cout << imag (v) << std::endl; + std::cout << trans (v) << std::endl; + std::cout << herm (v) << std::endl; +} +.... + +==== Binary Operation Description + +===== Description + +The templated class `vector_binary` describes a binary vector +operation. + +===== Definition + +Defined in the header vector_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E1` |The type of the first vector expression. | +|`E2` |The type of the second vector expression. | +|`F` |The type of the operation. | +|=== + +===== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Public base classes + +`vector_expression >` + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`vector_binary (const expression1_type &e1, const expression2_type &e2)` +|Constructs a description of the expression. + +|`size_type size () const` |Returns the size of the expression. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the expression. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the expression. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed expression. +|=== + +==== Binary Operations + +===== Prototypes + +[source,cpp] +.... +template + struct vector_binary_traits { + typedef vector_binary expression_type; + typedef expression_type result_type; + }; + + // (v1 + v2) [i] = v1 [i] + v2 [i] + template + typename vector_binary_traits >::result_type + operator + (const vector_expression &e1, + const vector_expression &e2); + + // (v1 - v2) [i] = v1 [i] - v2 [i] + template + typename vector_binary_traits >::result_type + operator - (const vector_expression &e1, + const vector_expression &e2); +.... + +===== Description + +`operator +` computes the sum of two vector expressions. `operator -` +computes the difference of two vector expressions. + +===== Definition + +Defined in the header vector_expression.hpp. + +===== Type requirements + +* `E1` is a model of +link:expression_concept.html#vector_expression[Vector Expression] . +* `E2` is a model of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Preconditions + +* `e1 ().size () == e2 ().size ()` + +===== Complexity + +Linear depending from the size of the vector expressions. + +===== Examples + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + vector v1 (3), v2 (3); + for (unsigned i = 0; i < std::min (v1.size (), v2.size ()); ++ i) + v1 (i) = v2 (i) = i; + + std::cout << v1 + v2 << std::endl; + std::cout << v1 - v2 << std::endl; +} +.... + +==== Binary Outer Operation Description + +===== Description + +The templated class `vector_matrix_binary` describes a binary +outer vector operation. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E1` |The type of the first vector expression. | +|`E2` |The type of the second vector expression. | +|`F` |The type of the operation. | +|=== + +===== Model of + +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#matrix_expression[Matrix Expression] . + +===== Public base classes + +`matrix_expression >` + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`vector_matrix_binary (const expression1_type &e1, const expression2_type &e2)` +|Constructs a description of the expression. + +|`size_type size1 () const` |Returns the number of rows. + +|`size_type size2 () const` |Returns the number of columns. + +|`const_reference operator () (size_type i, size_type j) const` |Returns +the value of the `j`-th element in the `i`-th row. + +|`const_iterator1 begin1 () const` |Returns a `const_iterator1` pointing +to the beginning of the expression. + +|`const_iterator1 end1 () const` |Returns a `const_iterator1` pointing +to the end of the expression. + +|`const_iterator2 begin2 () const` |Returns a `const_iterator2` pointing +to the beginning of the expression. + +|`const_iterator2 end2 () const` |Returns a `const_iterator2` pointing +to the end of the expression. + +|`const_reverse_iterator1 rbegin1 () const` |Returns a +`const_reverse_iterator1` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator1 rend1 () const` |Returns a +`const_reverse_iterator1` pointing to the end of the reversed +expression. + +|`const_reverse_iterator2 rbegin2 () const` |Returns a +`const_reverse_iterator2` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator2 rend2 () const` |Returns a +`const_reverse_iterator2` pointing to the end of the reversed +expression. +|=== + +==== Binary Outer Operations + +===== Prototypes + +[source,cpp] +.... +template + struct vector_matrix_binary_traits { + typedef vector_matrix_binary expression_type; + typedef expression_type result_type; + }; + + // (outer_prod (v1, v2)) [i] [j] = v1 [i] * v2 [j] + template + typename vector_matrix_binary_traits >::result_type + outer_prod (const vector_expression &e1, + const vector_expression &e2); +.... + +===== Description + +`outer_prod` computes the outer product of two vector expressions. + +===== Definition + +Defined in the header matrix_expression.hpp. + +===== Type requirements + +* `E1` is a model of +link:expression_concept.html#vector_expression[Vector Expression] . +* `E2` is a model of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Preconditions + +None. + +===== Complexity + +Quadratic depending from the size of the vector expressions. + +===== Examples + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + vector v1 (3), v2 (3); + for (unsigned i = 0; i < std::min (v1.size (), v2.size ()); ++ i) + v1 (i) = v2 (i) = i; + + std::cout << outer_prod (v1, v2) << std::endl; +} +.... + +==== Scalar Vector Operation Description + +===== Description + +The templated classes `vector_binary_scalar1` and +`vector_binary_scalar2` describe binary operations between a +scalar and a vector. + +===== Definition + +Defined in the header vector_expression.hpp. + +===== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`E1/E2` |The type of the scalar expression. | +|`E2/E1` |The type of the vector expression. | +|`F` |The type of the operation. | +|=== + +===== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Public base classes + +`vector_expression >` and +`vector_expression >` resp. + +===== Members + +[cols=",",] +|=== +|Member |Description + +|`vector_binary_scalar1 (const expression1_type &e1, const expression2_type &e2)` +|Constructs a description of the expression. + +|`vector_binary_scalar2 (const expression1_type &e1, const expression2_type &e2)` +|Constructs a description of the expression. + +|`size_type size () const` |Returns the size of the expression. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the expression. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the expression. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +expression. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed expression. +|=== + +==== Scalar Vector Operations + +===== Prototypes + +[source,cpp] +.... +template + struct vector_binary_scalar1_traits { + typedef vector_binary_scalar1, + typename E2::const_closure_type, F> expression_type; + typedef expression_type result_type; + }; + + // (t * v) [i] = t * v [i] + template + typename vector_binary_scalar1_traits >::result_type + operator * (const T1 &e1, + const vector_expression &e2); + + template + struct vector_binary_scalar2_traits { + typedef vector_binary_scalar2, F> expression_type; + typedef expression_type result_type; + }; + + // (v * t) [i] = v [i] * t + template + typename vector_binary_scalar2_traits >::result_type + operator * (const vector_expression &e1, + const T2 &e2); + + // (v / t) [i] = v [i] / t + template + typename vector_binary_scalar2_traits >::result_type + operator / (const vector_expression &e1, + const T2 &e2); +.... + +===== Description + +`operator *` computes the product of a scalar and a vector expression. +`operator /` multiplies the vector with the reciprocal of the scalar. + +===== Definition + +Defined in the header vector_expression.hpp. + +===== Type requirements + +* `T1/T2` is a model of +link:expression_concept.html#scalar_expression[Scalar Expression] . +* `E2/E1` is a model of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Preconditions + +None. + +===== Complexity + +Linear depending from the size of the vector expression. + +===== Examples + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + vector v (3); + for (unsigned i = 0; i < v.size (); ++ i) + v (i) = i; + + std::cout << 2.0 * v << std::endl; + std::cout << v * 2.0 << std::endl; +} +.... + +=== [#vector_reductions]#Vector Reductions# + +==== Unary Reductions + +===== Prototypes + +[source,cpp] +.... +template + struct vector_scalar_unary_traits { + typedef typename F::result_type result_type; + }; + + // sum v = sum (v [i]) + template + typename vector_scalar_unary_traits >::result_type + sum (const vector_expression &e); + + // norm_1 v = sum (abs (v [i])) + template + typename vector_scalar_unary_traits >::result_type + norm_1 (const vector_expression &e); + + // norm_2 v = sqrt (sum (v [i] * v [i])) + template + typename vector_scalar_unary_traits >::result_type + norm_2 (const vector_expression &e); + + // norm_2_square v = sum (v [i] * v [i]) + template + typename vector_scalar_unary_traits >::result_type + norm_2_square (const vector_expression &e); + + // norm_inf v = max (abs (v [i])) + template + typename vector_scalar_unary_traits >::result_type + norm_inf (const vector_expression &e); + + // index_norm_inf v = min (i: abs (v [i]) == max (abs (v [i]))) + template + typename vector_scalar_unary_traits >::result_type + index_norm_inf (const vector_expression &e); +.... + +===== Description + +`sum` computes the sum of the vector expression's elements. `norm_1`, +`norm_2` and `norm_inf` compute the corresponding __||.||__~_1_~, +__||.||__~_2_~ and __||.||__~_inf_~ vector norms. `index_norm_1` +computes the index of the vector expression's first element having +maximal absolute value. + +===== Definition + +Defined in the header vector_expression.hpp. + +===== Type requirements + +* `E` is a model of link:#vector_expression[Vector Expression] . + +===== Preconditions + +None. + +===== Complexity + +Linear depending from the size of the vector expression. + +===== Examples + +[source,cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + vector v (3); + for (unsigned i = 0; i < v.size (); ++ i) + v (i) = i; + + std::cout << sum (v) << std::endl; + std::cout << norm_1 (v) << std::endl; + std::cout << norm_2 (v) << std::endl; + std::cout << norm_inf (v) << std::endl; + std::cout << index_norm_inf (v) << std::endl; +} +.... + +==== Binary Reductions + +===== Prototypes + +[source,cpp] +.... +template + struct vector_scalar_binary_traits { + typedef typename F::result_type result_type; + }; + + // inner_prod (v1, v2) = sum (v1 [i] * v2 [i]) + template + typename vector_scalar_binary_traits::promote_type> >::result_type + inner_prod (const vector_expression &e1, + const vector_expression &e2); + + template + typename vector_scalar_binary_traits::promote_type>::precision_type> >::result_type + prec_inner_prod (const vector_expression &e1, + const vector_expression &e2); +.... + +===== Description + +`inner_prod` computes the inner product of the vector expressions. +`prec_inner_prod` computes the double precision inner product of the +vector expressions`.` + +===== Definition + +Defined in the header vector_expression.hpp. + +===== Type requirements + +* `E1` is a model of link:#vector_expression[Vector Expression] . +* `E2` is a model of link:#vector_expression[Vector Expression] . + +===== Preconditions + +* `e1 ().size () == e2 ().size ()` + +===== Complexity + +Linear depending from the size of the vector expressions. + +===== Examples + +[source,cpp] +.... +#include + +int main () { + using namespace boost::numeric::ublas; + vector v1 (3), v2 (3); + for (unsigned i = 0; i < std::min (v1.size (), v2.size ()); ++ i) + v1 (i) = v2 (i) = i; + + std::cout << inner_prod (v1, v2) << std::endl; +} +.... + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/vector_proxy.adoc b/doc/ublas/vector_proxy.adoc new file mode 100644 index 000000000..f230c7da6 --- /dev/null +++ b/doc/ublas/vector_proxy.adoc @@ -0,0 +1,443 @@ +== Vector Proxies + +[[toc]] + +=== [#vector_range]#Vector Range# + +==== Description + +The templated class `vector_range` allows addressing a sub-range of a +vector's element. + +==== Example + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + vector v (3); + vector_range > vr (v, range (0, 3)); + for (unsigned i = 0; i < vr.size (); ++ i) + vr (i) = i; + std::cout << vr << std::endl; +} +.... + +==== Definition + +Defined in the header vector_proxy.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`V` |The type of vector referenced. | +|=== + +==== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +If the specified range falls outside that of the index range of the +vector, then the `vector_range` is not a well formed Vector Expression. +That is, access to an element which is outside of index range of the +vector is _undefined_. + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +==== Public base classes + +`vector_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`vector_range (vector_type &data, const range &r)` |Constructs a sub +vector. + +|`size_type start () const` |Returns the start of the sub vector. + +|`size_type size () const` |Returns the size of the sub vector. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator () (size_type i)` |Returns a reference of the +`i`-th element. + +|`const_reference operator [] (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator [] (size_type i)` |Returns a reference of the +`i`-th element. + +|`vector_range &operator = (const vector_range &vr)` |The assignment +operator. + +|`vector_range &assign_temporary (vector_range &vr)` |Assigns a +temporary. May change the vector range `vr` . + +|`template vector_range &operator = (const vector_expression &ae)` +|The extended assignment operator. + +|`template vector_range &assign (const vector_expression &ae)` +|Assigns a vector expression to the sub vector. Left and right hand side +of the assignment should be independent. + +|`template vector_range &operator += (const vector_expression &ae)` +|A computed assignment operator. Adds the vector expression to the sub +vector. + +|`template vector_range &plus_assign (const vector_expression &ae)` +|Adds a vector expression to the sub vector. Left and right hand side of +the assignment should be independent. + +|`template vector_range &operator -= (const vector_expression &ae)` +|A computed assignment operator. Subtracts the vector expression from +the sub vector. + +|`template vector_range &minus_assign (const vector_expression &ae)` +|Subtracts a vector expression from the sub vector. Left and right hand +side of the assignment should be independent. + +|`template vector_range &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the sub vector with a scalar. + +|`template vector_range &operator /= (const AT &at)` |A +computed assignment operator. Divides the sub vector through a scalar. + +|`void swap (vector_range &vr)` |Swaps the contents of the sub vectors. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `vector_range`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `vector_range`. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the `vector_range`. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +`vector_range`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`vector_range`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`vector_range`. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed `vector_range`. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed `vector_range`. +|=== + +==== Simple Projections + +===== Description + +The free `subrange` functions support the construction of vector ranges. + +===== Prototypes + +[source,cpp] +.... + template + vector_range subrange (V &data, + V::size_type start, V::size_type stop); + template + const vector_range subrange (const V &data, + V::size_type start, V::size_type stop); +.... + +==== Generic Projections + +===== Description + +The free `project` functions support the construction of vector ranges. +Existing `matrix_range` 's can be composed with a further range. The +resulting range is computed using this existing range's `compose` +function. + +===== Prototypes + +[source,cpp] +.... + template + vector_range project (V &data, const range &r); + template + const vector_range project (const V &data, const range &r); + template + vector_range project (vector_range &data, const range &r); + template + const vector_range project (const vector_range &data, const range &r); +.... + +===== Definition + +Defined in the header vector_proxy.hpp. + +===== Type requirements + +* `V` is a model of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Complexity + +Linear depending from the size of the range. + +===== Examples + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + vector v (3); + for (int i = 0; i < 3; ++ i) + project (v, range (0, 3)) (i) = i; + std::cout << project (v, range (0, 3)) << std::endl; +} +.... + +=== [#vector_slice]#Vector Slice# + +==== Description + +The templated class `vector_slice` allows addressing a slice of a +vector. + +==== Example + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + vector v (3); + vector_slice > vs (v, slice (0, 1, 3)); + for (unsigned i = 0; i < vs.size (); ++ i) + vs (i) = i; + std::cout << vs << std::endl; +} +.... + +==== Definition + +Defined in the header vector_proxy.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default +|`V` |The type of vector referenced. | +|=== + +==== Model of + +link:expression_concept.html#vector_expression[Vector Expression] . + +If the specified slice falls outside that of the index range of the +vector, then the `vector_slice` is not a well formed Vector Expression. +That is, access to an element which is outside of index range of the +vector is _undefined_. + +==== Type requirements + +None, except for those imposed by the requirements of +link:expression_concept.html#vector_expression[Vector Expression] . + +==== Public base classes + +`vector_expression >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`vector_slice (vector_type &data, const slice &s)` |Constructs a sub +vector. + +|`size_type size () const` |Returns the size of the sub vector. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator () (size_type i)` |Returns a reference of the +`i`-th element. + +|`const_reference operator [] (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator [] (size_type i)` |Returns a reference of the +`i`-th element. + +|`vector_slice &operator = (const vector_slice &vs)` |The assignment +operator. + +|`vector_slice &assign_temporary (vector_slice &vs)` |Assigns a +temporary. May change the vector slice `vs` . + +|`template vector_slice &operator = (const vector_expression &ae)` +|The extended assignment operator. + +|`template vector_slice &assign (const vector_expression &ae)` +|Assigns a vector expression to the sub vector. Left and right hand side +of the assignment should be independent. + +|`template vector_slice &operator += (const vector_expression &ae)` +|A computed assignment operator. Adds the vector expression to the sub +vector. + +|`template vector_slice &plus_assign (const vector_expression &ae)` +|Adds a vector expression to the sub vector. Left and right hand side of +the assignment should be independent. + +|`template vector_slice &operator -= (const vector_expression &ae)` +|A computed assignment operator. Subtracts the vector expression from +the sub vector. + +|`template vector_slice &minus_assign (const vector_expression &ae)` +|Subtracts a vector expression from the sub vector. Left and right hand +side of the assignment should be independent. + +|`template vector_slice &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the sub vector with a scalar. + +|`template vector_slice &operator /= (const AT &at)` |A +computed assignment operator. Divides the sub vector through a scalar. + +|`void swap (vector_slice &vs)` |Swaps the contents of the sub vectors. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `vector_slice`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `vector_slice`. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the `vector_slice`. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +`vector_slice`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`vector_slice`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`vector_slice`. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed `vector_slice`. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed `vector_slice`. +|=== + +==== Simple Projections + +===== Description + +The free `subslice` functions support the construction of vector slices. + +===== Prototypes + +[source,cpp] +.... + template + vector_slice subslice (V &data, + V::size_type start, V::difference_type stride, V::size_type size); + template + const vector_slice subslice (const V &data, + V::size_type start, V::difference_type stride, V::size_type size); +.... + +==== Generic Projections + +===== Description + +The free `project` functions support the construction of vector slices. +Existing `vector_slice` 's can be composed with a further range or +slices. The resulting slice is computed using this existing slices's +`compose` function. + +===== Prototypes + +[source,cpp] +.... + template + vector_slice project (V &data, const slice &s); + template + const vector_slice project (const V &data, const slice &s); + template + vector_slice project (vector_slice &data, const range &r); + template + const vector_slice project (const vector_slice &data, const range &r); + template + vector_slice project (vector_slice &data, const slice &s); + template + const vector_slice project (const vector_slice &data, const slice &s); +.... + +===== Definition + +Defined in the header vector_proxy.hpp. + +===== Type requirements + +* `V` is a model of +link:expression_concept.html#vector_expression[Vector Expression] . + +===== Complexity + +Linear depending from the size of the slice. + +===== Examples + +[source,cpp] +.... +#include +#include +#include + +int main () { + using namespace boost::numeric::ublas; + vector v (3); + for (int i = 0; i < 3; ++ i) + project (v, slice (0, 1, 3)) (i) = i; + std::cout << project (v, slice (0, 1, 3)) << std::endl; +} +.... + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/ublas/vector_sparse.adoc b/doc/ublas/vector_sparse.adoc new file mode 100644 index 000000000..e22d11cfd --- /dev/null +++ b/doc/ublas/vector_sparse.adoc @@ -0,0 +1,551 @@ +== Sparse Vector + +[[toc]] + +=== [#mapped_vector]#Mapped Vector# + +==== Description + +The templated class `mapped_vector` is the base container adaptor +for sparse vectors using element maps. For a _n_-dimensional sparse +vector and __0 < = i < n__ the non-zero elements __v__~_i_~ are mapped to +consecutive elements of the associative container, i.e. for elements _k_ += __v__~_i_~_~1~_ and __k + 1 = __v__~_i_~__~2~__ of the container holds +__i__~_1_~ __< __i__~_2_~ . + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + mapped_vector v (3, 3); + for (unsigned i = 0; i < v.size (); ++ i) + v (i) = i; + std::cout << v << std::endl; +} +.... + +==== Definition + +Defined in the header vector_sparse.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the mapped vector. | + +|`A` |The type of the adapted array. link:#mapped_vector_1[[1]] +|`map_std` +|=== + +==== Model of + +link:container_concept.html#vector[Vector] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#vector[Vector] . + +==== Public base classes + +`vector_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`mapped_vector ()` |Allocates a `mapped_vector` that holds zero +elements. + +|`mapped_vector (size_type size, size_type non_zeros = 0)` |Allocates a +`mapped_vector` that holds at most `size` elements. + +|`mapped_vector (const mapped_vector &v)` |The copy constructor. + +|`template mapped_vector (size_type non_zeros, const vector_expression &ae)` +|The extended copy constructor. + +|`void resize (size_type size, bool preserve = true)` |Reallocates a +`mapped_vector` to hold at most `size` elements. The existing elements +of the `mapped_vector` are preseved when specified. + +|`size_type size () const` |Returns the size of the `mapped_vector`. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator () (size_type i)` |Returns a reference of the +`i`-th element. + +|`const_reference operator [] (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator [] (size_type i)` |Returns a reference of the +`i`-th element. + +|`mapped_vector &operator = (const mapped_vector &v)` |The assignment +operator. + +|`mapped_vector &assign_temporary (mapped_vector &v)` |Assigns a +temporary. May change the mapped vector `v` . + +|`template mapped_vector &operator = (const vector_expression &ae)` +|The extended assignment operator. + +|`template mapped_vector &assign (const vector_expression &ae)` +|Assigns a vector expression to the mapped vector. Left and right hand +side of the assignment should be independent. + +|`template mapped_vector &operator += (const vector_expression &ae)` +|A computed assignment operator. Adds the vector expression to the +mapped vector. + +|`template mapped_vector &plus_assign (const vector_expression &ae)` +|Adds a vector expression to the mapped vector. Left and right hand side +of the assignment should be independent. + +|`template mapped_vector &operator -= (const vector_expression &ae)` +|A computed assignment operator. Subtracts the vector expression from +the mapped vector. + +|`template mapped_vector &minus_assign (const vector_expression &ae)` +|Subtracts a vector expression from the mapped vector. Left and right +hand side of the assignment should be independent. + +|`template mapped_vector &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the mapped vector with a +scalar. + +|`template mapped_vector &operator /= (const AT &at)` |A +computed assignment operator. Divides the mapped vector through a +scalar. + +|`void swap (mapped_vector &v)` |Swaps the contents of the mapped +vectors. + +|`true_reference insert_element (size_type i, const_reference t)` +|Inserts the value `t` at the `i`-th element. Duplicates elements are +not allowed. + +|`void erase_element (size_type i)` |Erases the value at the `i`-th +element. + +|`void clear ()` |Clears the mapped vector. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `mapped_vector`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `mapped_vector`. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the `mapped_vector`. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +`mapped_vector`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`mapped_vector`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`mapped_vector`. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed `mapped_vector`. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed `mapped_vector`. +|=== + +==== Notes + +[#mapped_vector_1]#[1]# Supported parameters for the adapted array are +`map_array` and `map_std`. The latter is +equivalent to `std::map`. + +=== [#compressed_vector]#Compressed Vector# + +==== Description + +The templated class `compressed_vector` is the base +container adaptor for compressed vectors. For a _n_-dimensional +compressed vector and _0 <= i < n_ the non-zero elements __v__~_i_~ are +mapped to consecutive elements of the index and value container, i.e. +for elements _k_ = __v__~_i_~__~1~__ and __k + 1 = __v__~_i_~__~2~__ of +these containers holds __i__~_1_~ __< __i__~_2_~ . + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + compressed_vector v (3, 3); + for (unsigned i = 0; i < v.size (); ++ i) + v (i) = i; + std::cout << v << std::endl; +} +.... + +==== Definition + +Defined in the header vector_sparse.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the compressed vector. | + +|`IB` |The index base of the compressed vector. +link:#compressed_vector_1[[1]] |`0` + +|`IA` |The type of the adapted array for indices. +link:#compressed_vector_2[[2]] |`unbounded_array` + +|`TA` |The type of the adapted array for values. +link:#compressed_vector_2[[2]] |`unbounded_array` +|=== + +==== Model of + +link:container_concept.html#vector[Vector] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#vector[Vector] . + +==== Public base classes + +`vector_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`compressed_vector ()` |Allocates a `compressed_vector` that holds zero +elements. + +|`compressed_vector (size_type size, size_type non_zeros)` |Allocates a +`compressed_vector` that holds at most `size` elements. + +|`compressed_vector (const compressed_vector &v)` |The copy constructor. + +|`template compressed_vector (size_type non_zeros, const vector_expression &ae)` +|The extended copy constructor. + +|`void resize (size_type size, bool preserve = true)` |Reallocates a +`compressed_vector` to hold at most `size` elements. The existing +elements of the `compress_vector` are preseved when specified. + +|`size_type size () const` |Returns the size of the `compressed_vector`. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator () (size_type i)` |Returns a reference of the +`i`-th element. + +|`const_reference operator [] (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator [] (size_type i)` |Returns a reference of the +`i`-th element. + +|`compressed_vector &operator = (const compressed_vector &v)` |The +assignment operator. + +|`compressed_vector &assign_temporary (compressed_vector &v)` |Assigns a +temporary. May change the compressed vector `v`. + +|`template compressed_vector &operator = (const vector_expression &ae)` +|The extended assignment operator. + +|`template compressed_vector &assign (const vector_expression &ae)` +|Assigns a vector expression to the compressed vector. Left and right +hand side of the assignment should be independent. + +|`template compressed_vector &operator += (const vector_expression &ae)` +|A computed assignment operator. Adds the vector expression to the +compressed vector. + +|`template compressed_vector &plus_assign (const vector_expression &ae)` +|Adds a vector expression to the compressed vector. Left and right hand +side of the assignment should be independent. + +|`template compressed_vector &operator -= (const vector_expression &ae)` +|A computed assignment operator. Subtracts the vector expression from +the compressed vector. + +|`template compressed_vector &minus_assign (const vector_expression &ae)` +|Subtracts a vector expression from the compressed vector. Left and +right hand side of the assignment should be independent. + +|`template compressed_vector &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the compressed vector with a +scalar. + +|`template compressed_vector &operator /= (const AT &at)` |A +computed assignment operator. Divides the compressed vector through a +scalar. + +|`void swap (compressed_vector &v)` |Swaps the contents of the +compressed vectors. + +|`true_reference insert_element (size_type i, const_reference t)` +|Inserts the value `t` at the `i`-th element. Duplicates elements are +not allowed. + +|`void erase_element (size_type i)` |Erases the value at the `i`-th +element. + +|`void clear ()` |Clears the compressed vector. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `compressed_vector`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `compressed_vector`. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the `compressed_vector`. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +`compressed_vector`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`compressed_vector`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`compressed_vector`. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed `compressed_vector`. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed `compressed_vector`. +|=== + +==== Notes + +[#compressed_vector_1]#[1]# Supported parameters for the index base are +`0` and `1` at least. + +[#compressed_vector_2]#[2]# Supported parameters for the adapted array +are `unbounded_array<>` , `bounded_array<>` and `std::vector<>` . + +=== [#coordinate_vector]#Coordinate Vector# + +==== Description + +The templated class `coordinate_vector` is the base +container adaptor for compressed vectors. For a _n_-dimensional sorted +coordinate vector and _0 <= i < n_ the non-zero elements __v__~_i_~ are +mapped to consecutive elements of the index and value container, i.e. +for elements _k_ = __v__~_i_~__~1~__ and __k + 1 = __v__~_i_~__~2~__ of +these containers holds __i__~_1_~ __< __i__~_2_~ . + +==== Example + +[source,cpp] +.... +#include +#include + +int main () { + using namespace boost::numeric::ublas; + coordinate_vector v (3, 3); + for (unsigned i = 0; i < v.size (); ++ i) + v (i) = i; + std::cout << v << std::endl; +} +.... + +==== Definition + +Defined in the header vector_sparse.hpp. + +==== Template parameters + +[cols=",,",] +|=== +|Parameter |Description |Default + +|`T` |The type of object stored in the coordinate vector. | + +|`IB` |The index base of the coordinate vector. +link:#coordinate_vector_1[[1]] |`0` + +|`IA` |The type of the adapted array for indices. +link:#coordinate_vector_2[[2]] |`unbounded_array` + +|`TA` |The type of the adapted array for values. +link:#coordinate_vector_2[[2]] |`unbounded_array` +|=== + +==== Model of + +link:container_concept.html#vector[Vector] . + +==== Type requirements + +None, except for those imposed by the requirements of +link:container_concept.html#vector[Vector] . + +==== Public base classes + +`vector_container >` + +==== Members + +[cols=",",] +|=== +|Member |Description + +|`coordinate_vector ()` |Allocates a `coordinate_vector` that holds zero +elements. + +|`coordinate_vector (size_type size, size_type non_zeros)` |Allocates a +`coordinate_vector` that holds at most `size` elements. + +|`coordinate_vector (const coordinate_vector &v)` |The copy constructor. + +|`template coordinate_vector (size_type non_zeros, const vector_expression &ae)` +|The extended copy constructor. + +|`void resize (size_type size, bool preserve = true)` |Reallocates a +`coordinate_vector` to hold at most `size` elements. The existing +elements of the `coordinate_vector` are preseved when specified. + +|`size_type size () const` |Returns the size of the `coordinate_vector`. + +|`const_reference operator () (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator () (size_type i)` |Returns a reference of the +`i`-th element. + +|`const_reference operator [] (size_type i) const` |Returns the value of +the `i`-th element. + +|`reference operator [] (size_type i)` |Returns a reference of the +`i`-th element. + +|`coordinate_vector &operator = (const coordinate_vector &v)` |The +assignment operator. + +|`coordinate_vector &assign_temporary (coordinate_vector &v)` |Assigns a +temporary. May change the coordinate vector `v`. + +|`template coordinate_vector &operator = (const vector_expression &ae)` +|The extended assignment operator. + +|`template coordinate_vector &assign (const vector_expression &ae)` +|Assigns a vector expression to the coordinate vector. Left and right +hand side of the assignment should be independent. + +|`template coordinate_vector &operator += (const vector_expression &ae)` +|A computed assignment operator. Adds the vector expression to the +coordinate vector. + +|`template coordinate_vector &plus_assign (const vector_expression &ae)` +|Adds a vector expression to the coordinate vector. Left and right hand +side of the assignment should be independent. + +|`template coordinate_vector &operator -= (const vector_expression &ae)` +|A computed assignment operator. Subtracts the vector expression from +the coordinate vector. + +|`template coordinate_vector &minus_assign (const vector_expression &ae)` +|Subtracts a vector expression from the coordinate vector. Left and +right hand side of the assignment should be independent. + +|`template coordinate_vector &operator *= (const AT &at)` |A +computed assignment operator. Multiplies the coordinate vector with a +scalar. + +|`template coordinate_vector &operator /= (const AT &at)` |A +computed assignment operator. Divides the coordinate vector through a +scalar. + +|`void swap (coordinate_vector &v)` |Swaps the contents of the +coordinate vectors. + +|`true_reference insert_element (size_type i, const_reference t)` +|Inserts the value `t` at the `i`-th element. Duplicates elements are +not allowed. + +|`void append_element (size_type i, size_type j, const_reference t)` +|Appends the value `t` at the `i`-th element. Duplicate elements can be +appended to a `coordinate_vector`. They are merged into a single +arithmetically summed element by the `sort` function. + +|`void erase_element (size_type i)` |Erases the value at the `i`-th +element. + +|`void clear ()` |Clears the coordinate vector. + +|`const_iterator begin () const` |Returns a `const_iterator` pointing to +the beginning of the `coordinate_vector`. + +|`const_iterator end () const` |Returns a `const_iterator` pointing to +the end of the `coordinate_vector`. + +|`iterator begin ()` |Returns a `iterator` pointing to the beginning of +the `coordinate_vector`. + +|`iterator end ()` |Returns a `iterator` pointing to the end of the +`coordinate_vector`. + +|`const_reverse_iterator rbegin () const` |Returns a +`const_reverse_iterator` pointing to the beginning of the reversed +`coordinate_vector`. + +|`const_reverse_iterator rend () const` |Returns a +`const_reverse_iterator` pointing to the end of the reversed +`coordinate_vector`. + +|`reverse_iterator rbegin ()` |Returns a `reverse_iterator` pointing to +the beginning of the reversed `coordinate_vector`. + +|`reverse_iterator rend ()` |Returns a `reverse_iterator` pointing to +the end of the reversed `coordinate_vector`. +|=== + +==== Notes + +[#coordinate_vector_1]#[1]# Supported parameters for the index base are +`0` and `1` at least. + +[#coordinate_vector_2]#[2]# Supported parameters for the adapted array +are `unbounded_array<>` , `bounded_array<>` and `std::vector<>` . + +''''' + +Copyright (©) 2000-2002 Joerg Walter, Mathias Koch + +Copyright (©) 2021 Shikhar Vashistha + +Use, modification and distribution are 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 ). diff --git a/doc/unbounded_array.html b/doc/unbounded_array.html deleted file mode 100644 index 3be073054..000000000 --- a/doc/unbounded_array.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - -Unbounded array - - -

        Unbounded Array Storage

        -
        -

        Unbounded Array

        -

        Description

        -

        The templated class unbounded_array<T, ALLOC> implements a unbounded storage array using an allocator. -The unbounded array is similar to a std::vector in that in can grow in size beyond any fixed bound. -However unbounded_array is aimed at optimal performance. Therefore unbounded_array does not model a -Sequence like std::vector does. -

        When resized unbounded_array will reallocate it's storage even if the new size requirement is smaller. It is therefore inefficient to resize a unbounded_array

        -

        Example

        -
        -#include <boost/numeric/ublas/storage.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    unbounded_array<double> a (3);
        -    for (unsigned i = 0; i < a.size (); ++ i) {
        -        a [i] = i;
        -        std::cout << a [i] << std::endl;
        -    }
        -}
        -
        -

        Definition

        -

        Defined in the header storage.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the array.
        ALLOCAn STL Allocatorstd::allocator
        -

        Model of

        -

        Storage

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Storage.

        -

        Public base classes

        -

        None.

        -

        Members

        -
          -
        • The description does not describe what the member actually does, this can be looked up -in the corresponding concept documentation, but instead contains a remark on the implementation of the -member inside this model of the concept.
        • -
        • Typography: -
            -
          • Members that are not part of the implemented concepts are in blue.
          • -
          -
        • -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberWhere definedDescription
        value_typeContainer
        pointerContainerDefined as value_type*
        const_pointerContainerDefined as const value_type*
        referenceContainerDefined as value_type&
        const_referenceContainerDefined as const value_type&
        size_typeContainerDefined as Alloc::size_type
        difference_typeContainerDefined as Alloc::difference_type
        iteratorContainerDefined as pointer
        const_iteratorContainerDefined as const_pointer
        revere_iteratorContainerDefined as std::reverse_iterator<iterator>
        const_revere_iteratorContainerDefined as std::reverse_iterator<const_iterator>
        allocator_typeDefined as ALLOC
        explicit unbounded_array (ALLOC &a = ALLOC())StorageCreates an unbounded_array that holds zero elements, using a specified allocator.
        explicit unbounded_array (size_type size, ALLOC &a = ALLOC())StorageCreates a uninitialized unbounded_array that holds size elements, using a specified allocator. All the elements are default constructed.
        unbounded_array (size_type size, const T& init, ALLOC& a = ALLOC())StorageCreates an initialized unbounded_array that holds size elements, using a specified allocator. All the elements are constructed from the init value.
        unbounded_array (const unbounded_array &a)ContainerThe copy constructor.
        ~unbounded_array ()ContainerDeallocates the unbounded_array itself.
        void resize (size_type n)StorageReallocates an unbounded_array to hold n elements. Values are uninitialised.
        void resize(size_type n, const T& t)StorageReallocates an unbounded_array to hold n elements. Values are copies of t -
        size_type size () constContainerReturns the size of the unbounded_array.
        const_reference operator [] (size_type i) constContainerReturns a const reference of the i -th element.
        reference operator [] (size_type i)ContainerReturns a reference of the i-th element.
        unbounded_array &operator = (const unbounded_array &a)ContainerThe assignment operator.
        unbounded_array &assign_temporary (unbounded_array &a)Assigns a temporary. May change the array a.
        void swap (unbounded_array &a)ContainerSwaps the contents of the arrays.
        const_iterator begin () constContainerReturns a const_iterator pointing to the beginning -of the unbounded_array.
        const_iterator end () constContainerReturns a const_iterator pointing to the end of -the unbounded_array.
        iterator begin ()ContainerReturns a iterator pointing to the beginning of -the unbounded_array.
        iterator end ()ContainerReturns a iterator pointing to the end of the -unbounded_array.
        const_reverse_iterator rbegin () constReversible ContainerReturns a const_reverse_iterator pointing to the beginning of the reversed unbounded_array.
        const_reverse_iterator rend () constReversible ContainerReturns a const_reverse_iterator pointing to the end of the reversed unbounded_array.
        reverse_iterator rbegin ()Reversible ContainerReturns a reverse_iterator pointing to the beginning of the reversed unbounded_array.
        reverse_iterator rend ()Reversible ContainerReturns a reverse_iterator pointing to the end of the reversed unbounded_array.
        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/vector.html b/doc/vector.html deleted file mode 100644 index 2f9569d35..000000000 --- a/doc/vector.html +++ /dev/null @@ -1,755 +0,0 @@ - - - - - - - - - -Vector - - -

        Vector

        -
        -

        Vector

        -

        Description

        -

        The templated class vector<T, A> is the base -container adaptor for dense vectors. For a n-dimensional -vector and 0 <= i < n every element -vi is mapped to the i-th -element of the container.

        -

        Example

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<double> v (3);
        -    for (unsigned i = 0; i < v.size (); ++ i)
        -        v (i) = i;
        -    std::cout << v << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header vector.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the vector.
        AThe type of the Storage array. [1]unbounded_array<T>
        -

        Model of

        -

        Vector, -RandomAccessContainer -

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector -and RandomAccessContainer.

        -

        Public base classes

        -

        vector_container<vector<T, A> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberWhere definedDescription
        value_type -VectorExpression
        reference -VectorExpression
        const_reference -VectorExpression
        size_type -VectorExpression
        difference_type -VectorExpression
        const_iterator -VectorExpression
        iterator -VectorExpression
        const_reverse_iterator -VectorExpression
        reverse_iterator -VectorExpression
        array_type -Vector
        vector ()VectorExpressionAllocates an uninitialized vector that holds zero -elements.
        vector (size_type size)VectorAllocates an uninitialized vector that holds -size elements.
        vector (const vector &v)The copy constructor.
        template<class AE>
        -vector (const vector_expression<AE> &ae)
        The extended copy constructor.
        void resize (size_type size, bool preserve = -true)VectorReallocates a vector to hold size -elements. The existing elements of the vector are -preseved when specified.
        size_type size () constVectorExpressionReturns the size of the vector.
        size_type max_size () constRandomAccessContainerReturns the upper bound on the size of the vector.
        bool empty () constRandomAccessContainerEquivilent to size () == 0.
        const array_type& data () constVector
        array_type& data ()Vector
        const_reference operator () (size_type i) -constVectorExpressionReturns a const reference of the i --th element.
        reference operator () (size_type i)VectorExpressionReturns a reference of the i-th element.
        const_reference operator [] (size_type i) constVectorReturns a const reference of the i --th element.
        reference operator [] (size_type i)VectorReturns a reference of the i-th element.
        vector &operator = (const vector &v)VectorExpressionThe assignment operator.
        vector &assign_temporary (vector &v)VectorExpressionAssigns a temporary. May change the vector v.
        template<class AE>
        -vector &operator = (const vector_expression<AE> -&ae)
        VectorExpressionThe extended assignment operator.
        template<class AE>
        -vector &assign (const vector_expression<AE> -&ae)
        VectorExpressionAssigns a vector expression to the vector. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -vector &operator += (const vector_expression<AE> -&ae)
        VectorExpressionA computed assignment operator. Adds the vector expression to -the vector.
        template<class AE>
        -vector &plus_assign (const vector_expression<AE> -&ae)
        VectorExpressionAdds a vector expression to the vector. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -vector &operator -= (const vector_expression<AE> -&ae)
        VectorExpressionA computed assignment operator. Subtracts the vector expression -from the vector.
        template<class AE>
        -vector &minus_assign (const vector_expression<AE> -&ae)
        VectorExpressionSubtracts a vector expression from the vector. Left and right -hand side of the assignment should be independent.
        template<class AT>
        -vector &operator *= (const AT &at)
        VectorExpressionA computed assignment operator. Multiplies the vector with a -scalar.
        template<class AT>
        -vector &operator /= (const AT &at)
        VectorExpressionA computed assignment operator. Divides the vector through a -scalar.
        void swap (vector &v)VectorExpressionSwaps the contents of the vectors.
        void insert_element (size_type i, const_reference t)VectorInserts the value t at the i-th -element.
        void erase_element (size_type i)VectorErases the value at the i-th element.
        void clear ()VectorClears the vector.
        const_iterator begin () constVectorExpressionReturns a const_iterator pointing to the beginning -of the vector.
        const_iterator end () constVectorExpressionReturns a const_iterator pointing to the end of -the vector.
        iterator begin ()VectorExpressionReturns a iterator pointing to the beginning of -the vector.
        iterator end ()VectorExpressionReturns a iterator pointing to the end of the -vector.
        const_reverse_iterator rbegin () constVectorExpressionReturns a const_reverse_iterator pointing to the -beginning of the reversed vector.
        const_reverse_iterator rend () constVectorExpressionReturns a const_reverse_iterator pointing to the -end of the reversed vector.
        reverse_iterator rbegin ()VectorExpressionReturns a reverse_iterator pointing to the -beginning of the reversed vector.
        reverse_iterator rend ()VectorExpressionReturns a reverse_iterator pointing to the end of -the reversed vector.
        -

        Notes

        -

        [1] Common parameters -for the Storage array are unbounded_array<T> , -bounded_array<T> and -std::vector<T> .

        -

        Unit Vector

        -

        Description

        -

        The templated class unit_vector<T, ALLOC> represents -canonical unit vectors. For the k-th -n-dimensional canonical unit vector and 0 <= i < -n holds uki -= 0, if i <> k, and -uki = -1.

        -

        Example

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    for (int i = 0; i < 3; ++ i) {
        -        unit_vector<double> v (3, i);
        -        std::cout << v << std::endl;
        -    }
        -}
        -
        -

        Definition

        -

        Defined in the header vector.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the vector.int
        ALLOCAn STL Allocator for size_type and difference_type.std::allocator
        -

        Model of

        -

        Vector .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of -Vector .

        -

        Public base classes

        -

        vector_container<unit_vector<T> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        unit_vector ()Constructs an unit_vector that holds zero -elements.
        unit_vector (size_type size, size_type index)Constructs the index-th unit_vector -that holds size elements.
        unit_vector (const unit_vector &v)The copy constructor.
        void resize (size_type size, bool preserve = -true)Resizes a unit_vector to hold size -elements. Therefore the existing elements of the -unit_vector are always preseved.
        size_type size () constReturns the size of the unit_vector.
        size_type index () constReturns the index of the unit_vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        const_reference operator [] (size_type i) -constReturns the value of the i-th element.
        unit_vector &operator = (const unit_vector -&v)The assignment operator.
        unit_vector &assign_temporary (unit_vector -&v)Assigns a temporary. May change the unit vector v -.
        void swap (unit_vector &v)Swaps the contents of the unit vectors.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the unit_vector.
        const_iterator end () constReturns a const_iterator pointing to the end of -the unit_vector.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed unit_vector.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed unit_vector.
        -

        Zero Vector

        -

        Description

        -

        The templated class zero_vector<T, ALLOC> represents -zero vectors. For a n-dimensional zero vector and 0 -<= i < n holds zi = -0.

        -

        Example

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    zero_vector<double> v (3);
        -    std::cout << v << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header vector.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the vector.int
        ALLOCAn STL Allocator for size_type and difference_type.std::allocator
        -

        Model of

        -

        Vector .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of -Vector .

        -

        Public base classes

        -

        vector_container<zero_vector<T> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        zero_vector ()Constructs a zero_vector that holds zero -elements.
        zero_vector (size_type size)Constructs a zero_vector that holds -size elements.
        zero_vector (const zero_vector &v)The copy constructor.
        void resize (size_type size, bool preserve = -true)Resizes a zero_vector to hold size -elements. Therefore the existing elements of the -zero_vector are always preseved.
        size_type size () constReturns the size of the zero_vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        const_reference operator [] (size_type i) -constReturns the value of the i-th element.
        zero_vector &operator = (const zero_vector -&v)The assignment operator.
        zero_vector &assign_temporary (zero_vector -&v)Assigns a temporary. May change the zero vector v -.
        void swap (zero_vector &v)Swaps the contents of the zero vectors.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the zero_vector.
        const_iterator end () constReturns a const_iterator pointing to the end of -the zero_vector.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed zero_vector.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed zero_vector.
        -

        Scalar Vector

        -

        Description

        -

        The templated class scalar_vector<T, ALLOC> -represents scalar vectors. For a n-dimensional scalar -vector and 0 <= i < n holds -zi = s.

        -

        Example

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    scalar_vector<double> v (3);
        -    std::cout << v << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header vector.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the vector.int
        ALLOCAn STL Allocator for size_type and difference_type.std::allocator
        -

        Model of

        -

        Vector .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of -Vector .

        -

        Public base classes

        -

        vector_container<scalar_vector<T> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        scalar_vector ()Constructs a scalar_vector that holds zero -elements.
        scalar_vector (size_type size, const value_type -&value)Constructs a scalar_vector that holds -size elements each of the specified value.
        scalar_vector (const scalar_vector &v)The copy constructor.
        void resize (size_type size, bool preserve = -true)Resizes a scalar_vector to hold size -elements. Therefore the existing elements of the -scalar_vector are always preseved.
        size_type size () constReturns the size of the scalar_vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        const_reference operator [] (size_type i) -constReturns the value of the i-th element.
        scalar_vector &operator = (const scalar_vector -&v)The assignment operator.
        scalar_vector &assign_temporary (scalar_vector -&v)Assigns a temporary. May change the scalar vector -v .
        void swap (scalar_vector &v)Swaps the contents of the scalar vectors.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the scalar_vector.
        const_iterator end () constReturns a const_iterator pointing to the end of -the scalar_vector.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed scalar_vector.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed scalar_vector.
        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/vector_expression.html b/doc/vector_expression.html deleted file mode 100644 index 2372ec3df..000000000 --- a/doc/vector_expression.html +++ /dev/null @@ -1,974 +0,0 @@ - - - - - - - - - -Vector Expressions - - -

        Vector Expressions

        -
        -

        Vector Expression

        -

        Description

        -

        The templated class vector_expression<E> -is required to be a public base of all classes which model the Vector Expression concept.

        -

        Definition

        -

        Defined in the header expression_types.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        EThe type of the vector expression. 
        -

        Model of

        -

        None. Not a Vector Expression! -

        -

        Type requirements

        -

        None.

        -

        Public base classes

        -

        None.

        -

        Members

        - - - - - - - - - - - - - - - -
        MemberDescription
        const expression_type &operator () () -constReturns a const reference of the expression.
        expression_type &operator () ()Returns a reference of the expression.
        -

        Notes

        -

        The range, slice and project functions have been removed. Use the free functions defined in vector proxy instead.

        - -

        Vector Container

        -

        Description

        -

        The templated class vector_container<C> -is required to be a public base of all classes which model the Vector concept. -This includes the class vector itself.

        -

        Definition

        -

        Defined in the header expression_types.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        CThe type of the vector container. 
        -

        Model of

        -

        None. Not a Vector Expression OR Vector! -

        -

        Type requirements

        -

        None.

        -

        Public base classes

        -

        vector_expression<C>

        -

        Members

        - - - - - - - - - - - - - - - -
        MemberDescription
        const container_type &operator () () -constReturns a const reference of the container.
        container_type &operator () ()Returns a reference of the container.
        - -

        Vector References

        -

        Reference

        -

        Description

        -

        The templated class vector_reference<E> -contains a reference to a vector expression.

        -

        Definition

        -

        Defined in the header vector_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        EThe type of the vector expression. 
        -

        Model of

        -

        Vector Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<vector_reference<E> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        vector_reference (expression_type &e)Constructs a reference of the expression.
        void resize (size_type size)Resizes the expression to hold at most size -elements.
        size_type size () constReturns the size of the expression.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        reference operator () (size_type i)Returns a reference of the i-th element.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the expression.
        const_iterator end () constReturns a const_iterator pointing to the end of -the expression.
        iterator begin ()Returns a iterator pointing to the beginning of -the expression.
        iterator end ()Returns a iterator pointing to the end of the -expression.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed expression.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed expression.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed expression.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed expression.
        -

        Vector Operations

        -

        Unary Operation Description

        -

        Description

        -

        The templated class vector_unary<E, F> -describes a unary vector operation.

        -

        Definition

        -

        Defined in the header vector_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        EThe type of the vector expression. 
        FThe type of the operation. 
        -

        Model of

        -

        Vector Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<vector_unary<E, F> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        vector_unary (const expression_type &e)Constructs a description of the expression.
        size_type size () constReturns the size of the expression.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the expression.
        const_iterator end () constReturns a const_iterator pointing to the end of -the expression.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed expression.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed expression.
        -

        Unary Operations

        -

        Prototypes

        -
        -template<class E, class F>
        -    struct vector_unary_traits {
        -        typedef vector_unary<typename E::const_closure_type, F> expression_type;
        -        typedef expression_type result_type;
        -     };
        -
        -    // (- v) [i] = - v [i]
        -    template<class E>
        -     typename vector_unary_traits<E, scalar_negate<typename E::value_type> >::result_type
        -    operator - (const vector_expression<E> &e);
        -
        -    // (conj v) [i] = conj (v [i])
        -    template<class E>
        -     typename vector_unary_traits<E, scalar_conj<typename E::value_type> >::result_type
        -    conj (const vector_expression<E> &e);
        -
        -    // (real v) [i] = real (v [i])
        -    template<class E>
        -     typename vector_unary_traits<E, scalar_real<typename E::value_type> >::result_type
        -    real (const vector_expression<E> &e);
        -
        -    // (imag v) [i] = imag (v [i])
        -    template<class E>
        -     typename vector_unary_traits<E, scalar_imag<typename E::value_type> >::result_type
        -    imag (const vector_expression<E> &e);
        -
        -    // (trans v) [i] = v [i]
        -    template<class E>
        -     typename vector_unary_traits<E, scalar_identity<typename E::value_type> >::result_type
        -    trans (const vector_expression<E> &e);
        -
        -    // (herm v) [i] = conj (v [i])
        -    template<class E>
        -     typename vector_unary_traits<E, scalar_conj<typename E::value_type> >::result_type
        -    herm (const vector_expression<E> &e);
        -
        -

        Description

        -

        operator - computes the additive inverse of a -vector expression. conj computes the complex conjugate -of a vector expression. real and imag -compute the real and imaginary parts of a vector expression. -trans computes the transpose of a vector expression. -herm computes the hermitian, i.e. the complex -conjugate of the transpose of a vector expression.

        -

        Definition

        -

        Defined in the header vector_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -

        None.

        -

        Complexity

        -

        Linear depending from the size of the vector expression.

        -

        Examples

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<std::complex<double> > v (3);
        -    for (unsigned i = 0; i < v.size (); ++ i)
        -        v (i) = std::complex<double> (i, i);
        -
        -    std::cout << - v << std::endl;
        -    std::cout << conj (v) << std::endl;
        -    std::cout << real (v) << std::endl;
        -    std::cout << imag (v) << std::endl;
        -    std::cout << trans (v) << std::endl;
        -    std::cout << herm (v) << std::endl;
        -}
        -
        -

        Binary Operation Description

        -

        Description

        -

        The templated class vector_binary<E1, E2, F> -describes a binary vector operation.

        -

        Definition

        -

        Defined in the header vector_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        E1The type of the first vector expression.
        E2The type of the second vector expression.
        FThe type of the operation.
        -

        Model of

        -

        Vector Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<vector_binary<E1, E2, F> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        vector_binary (const expression1_type &e1, const -expression2_type &e2)Constructs a description of the expression.
        size_type size () constReturns the size of the expression.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the expression.
        const_iterator end () constReturns a const_iterator pointing to the end of -the expression.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed expression.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed expression.
        -

        Binary Operations

        -

        Prototypes

        -
        -template<class E1, class E2, class F>
        -    struct vector_binary_traits {
        -        typedef vector_binary<typename E1::const_closure_type,
        -                               typename E2::const_closure_type, F> expression_type;
        -        typedef expression_type result_type;
        -     };
        -
        -    // (v1 + v2) [i] = v1 [i] + v2 [i]
        -    template<class E1, class E2>
        -    typename vector_binary_traits<E1, E2, scalar_plus<typename E1::value_type,
        -                                                       typename E2::value_type> >::result_type
        -    operator + (const vector_expression<E1> &e1,
        -                 const vector_expression<E2> &e2);
        -
        -    // (v1 - v2) [i] = v1 [i] - v2 [i]
        -    template<class E1, class E2>
        -    typename vector_binary_traits<E1, E2, scalar_minus<typename E1::value_type,
        -                                                        typename E2::value_type> >::result_type
        -    operator - (const vector_expression<E1> &e1,
        -                 const vector_expression<E2> &e2);
        -
        -

        Description

        -

        operator + computes the sum of two vector -expressions. operator - computes the difference of two -vector expressions.

        -

        Definition

        -

        Defined in the header vector_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -
          -
        • e1 ().size () == e2 ().size ()
        • -
        -

        Complexity

        -

        Linear depending from the size of the vector expressions.

        -

        Examples

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<double> v1 (3), v2 (3);
        -    for (unsigned i = 0; i < std::min (v1.size (), v2.size ()); ++ i)
        -        v1 (i) = v2 (i) = i;
        -
        -    std::cout << v1 + v2 << std::endl;
        -    std::cout << v1 - v2 << std::endl;
        -}
        -
        -

        Binary Outer Operation Description

        -

        Description

        -

        The templated class vector_matrix_binary<E1, E2, -F> describes a binary outer vector operation.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        E1The type of the first vector expression.
        E2The type of the second vector expression.
        FThe type of the operation.
        -

        Model of

        -

        Matrix Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Matrix Expression .

        -

        Public base classes

        -

        matrix_expression<vector_matrix_binary<E1, E2, F> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        vector_matrix_binary (const expression1_type &e1, -const expression2_type &e2)Constructs a description of the expression.
        size_type size1 () constReturns the number of rows.
        size_type size2 () constReturns the number of columns.
        const_reference operator () (size_type i, size_type j) -constReturns the value of the j-th element in the -i-th row.
        const_iterator1 begin1 () constReturns a const_iterator1 pointing to the -beginning of the expression.
        const_iterator1 end1 () constReturns a const_iterator1 pointing to the end of -the expression.
        const_iterator2 begin2 () constReturns a const_iterator2 pointing to the -beginning of the expression.
        const_iterator2 end2 () constReturns a const_iterator2 pointing to the end of -the expression.
        const_reverse_iterator1 rbegin1 () constReturns a const_reverse_iterator1 pointing to the -beginning of the reversed expression.
        const_reverse_iterator1 rend1 () constReturns a const_reverse_iterator1 pointing to the -end of the reversed expression.
        const_reverse_iterator2 rbegin2 () constReturns a const_reverse_iterator2 pointing to the -beginning of the reversed expression.
        const_reverse_iterator2 rend2 () constReturns a const_reverse_iterator2 pointing to the -end of the reversed expression.
        -

        Binary Outer Operations

        -

        Prototypes

        -
        -template<class E1, class E2, class F>
        -    struct vector_matrix_binary_traits {
        -        typedef vector_matrix_binary<typename E1::const_closure_type,
        -                                      typename E2::const_closure_type, F> expression_type;
        -        typedef expression_type result_type;
        -     };
        -
        -    // (outer_prod (v1, v2)) [i] [j] = v1 [i] * v2 [j]
        -    template<class E1, class E2>
        -    typename vector_matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, typename E2::value_type> >::result_type
        -    outer_prod (const vector_expression<E1> &e1,
        -                 const vector_expression<E2> &e2);
        -
        -

        Description

        -

        outer_prod computes the outer product of two vector -expressions.

        -

        Definition

        -

        Defined in the header matrix_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -

        None.

        -

        Complexity

        -

        Quadratic depending from the size of the vector expressions.

        -

        Examples

        -
        -#include <boost/numeric/ublas/matrix.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<double> v1 (3), v2 (3);
        -    for (unsigned i = 0; i < std::min (v1.size (), v2.size ()); ++ i)
        -        v1 (i) = v2 (i) = i;
        -
        -    std::cout << outer_prod (v1, v2) << std::endl;
        -}
        -
        -

        Scalar Vector Operation Description

        -

        Description

        -

        The templated classes vector_binary_scalar1<E1, E2, -F> and vector_binary_scalar2<E1, E2, -F> describe binary operations between a scalar and a -vector.

        -

        Definition

        -

        Defined in the header vector_expression.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        E1/E2The type of the scalar expression.
        E2/E1The type of the vector expression.
        FThe type of the operation.
        -

        Model of

        -

        Vector Expression -.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<vector_binary_scalar1<E1, E2, -F> > and -vector_expression<vector_binary_scalar2<E1, E2, F> -> resp.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        vector_binary_scalar1 (const expression1_type &e1, -const expression2_type &e2)Constructs a description of the expression.
        vector_binary_scalar2 (const expression1_type &e1, -const expression2_type &e2)Constructs a description of the expression.
        size_type size () constReturns the size of the expression.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the expression.
        const_iterator end () constReturns a const_iterator pointing to the end of -the expression.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed expression.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed expression.
        -

        Scalar Vector Operations

        -

        Prototypes

        -
        -template<class T1, class E2, class F>
        -    struct vector_binary_scalar1_traits {
        -        typedef vector_binary_scalar1<scalar_const_reference<T1>,
        -                                      typename E2::const_closure_type, F> expression_type;
        -        typedef expression_type result_type;
        -    };
        -
        -    // (t * v) [i] = t * v [i]
        -    template<class T1, class E2>
        -    typename vector_binary_scalar1_traits<T1, E2, scalar_multiplies<T1, typename E2::value_type> >::result_type
        -    operator * (const T1 &e1,
        -                const vector_expression<E2> &e2);
        -
        -    template<class E1, class T2, class F>
        -    struct vector_binary_scalar2_traits {
        -        typedef vector_binary_scalar2<typename E1::const_closure_type,
        -                                      scalar_const_reference<T2>, F> expression_type;
        -        typedef expression_type result_type;
        -    };
        -
        -    // (v * t) [i] = v [i] * t
        -    template<class E1, class T2>
        -    typename vector_binary_scalar2_traits<E1, T2, scalar_multiplies<typename E1::value_type, T2> >::result_type
        -    operator * (const vector_expression<E1> &e1,
        -                const T2 &e2);
        -
        -    // (v / t) [i] = v [i] / t
        -    template<class E1, class T2>
        -    typename vector_binary_scalar2_traits<E1, T2, scalar_divides<typename E1::value_type, T2> >::result_type
        -    operator / (const vector_expression<E1> &e1,
        -                const T2 &e2);
        -
        -

        Description

        -

        operator * computes the product of a scalar and a -vector expression. operator / multiplies the vector -with the reciprocal of the scalar.

        -

        Definition

        -

        Defined in the header vector_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -

        None.

        -

        Complexity

        -

        Linear depending from the size of the vector expression.

        -

        Examples

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<double> v (3);
        -    for (unsigned i = 0; i < v.size (); ++ i)
        -        v (i) = i;
        -
        -    std::cout << 2.0 * v << std::endl;
        -    std::cout << v * 2.0 << std::endl;
        -}
        -
        -

        Vector Reductions

        -

        Unary Reductions

        -

        Prototypes

        -
        -template<class E, class F>
        -    struct vector_scalar_unary_traits {
        -         typedef typename F::result_type result_type;
        -    };
        -
        -    // sum v = sum (v [i])
        -    template<class E>
        -    typename vector_scalar_unary_traits<E, vector_sum<typename E::value_type> >::result_type
        -    sum (const vector_expression<E> &e);
        -
        -    // norm_1 v = sum (abs (v [i]))
        -    template<class E>
        -    typename vector_scalar_unary_traits<E, vector_norm_1<typename E::value_type> >::result_type
        -    norm_1 (const vector_expression<E> &e);
        -
        -    // norm_2 v = sqrt (sum (v [i] * v [i]))
        -    template<class E>
        -    typename vector_scalar_unary_traits<E, vector_norm_2<typename E::value_type> >::result_type
        -    norm_2 (const vector_expression<E> &e);
        -
        -    // norm_2_square v = sum (v [i] * v [i])
        -    template<class E>
        -    typename vector_scalar_unary_traits<E, vector_norm_2_square<typename E::value_type> >::result_type
        -    norm_2_square (const vector_expression<E> &e);
        -
        -    // norm_inf v = max (abs (v [i]))
        -    template<class E>
        -    typename vector_scalar_unary_traits<E, vector_norm_inf<typename E::value_type> >::result_type
        -    norm_inf (const vector_expression<E> &e);
        -
        -    // index_norm_inf v = min (i: abs (v [i]) == max (abs (v [i])))
        -    template<class E>
        -    typename vector_scalar_unary_traits<E, vector_index_norm_inf<typename E::value_type> >::result_type
        -    index_norm_inf (const vector_expression<E> &e);
        -
        -

        Description

        -

        sum computes the sum of the vector expression's -elements. norm_1, norm_2 and -norm_inf compute the corresponding -||.||1, -||.||2 and -||.||inf vector norms. -index_norm_1 computes the index of the vector -expression's first element having maximal absolute value.

        -

        Definition

        -

        Defined in the header vector_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -

        None.

        -

        Complexity

        -

        Linear depending from the size of the vector expression.

        -

        Examples

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<double> v (3);
        -    for (unsigned i = 0; i < v.size (); ++ i)
        -        v (i) = i;
        -
        -    std::cout << sum (v) << std::endl;
        -    std::cout << norm_1 (v) << std::endl;
        -    std::cout << norm_2 (v) << std::endl;
        -    std::cout << norm_inf (v) << std::endl;
        -    std::cout << index_norm_inf (v) << std::endl;
        -}
        -
        -

        Binary Reductions

        -

        Prototypes

        -
        -template<class E1, class E2, class F>
        -    struct vector_scalar_binary_traits {
        -        typedef typename F::result_type result_type;
        -    };
        -
        -    // inner_prod (v1, v2) = sum (v1 [i] * v2 [i])
        -    template<class E1, class E2>
        -    typename vector_scalar_binary_traits<E1, E2, vector_inner_prod<typename E1::value_type,
        -                                                                   typename E2::value_type,
        -                                                                   typename promote_traits<typename E1::value_type,
        -                                                                                           typename E2::value_type>::promote_type> >::result_type
        -    inner_prod (const vector_expression<E1> &e1,
        -                const vector_expression<E2> &e2);
        -
        -    template<class E1, class E2>
        -    typename vector_scalar_binary_traits<E1, E2, vector_inner_prod<typename E1::value_type,
        -                                                                   typename E2::value_type,
        -                                                                   typename type_traits<typename promote_traits<typename E1::value_type,
        -                                                                                                                typename E2::value_type>::promote_type>::precision_type> >::result_type
        -    prec_inner_prod (const vector_expression<E1> &e1,
        -                     const vector_expression<E2> &e2);
        -
        -

        Description

        -

        inner_prod computes the inner product of the vector -expressions. prec_inner_prod computes the double -precision inner product of the vector expressions.

        -

        Definition

        -

        Defined in the header vector_expression.hpp.

        -

        Type requirements

        - -

        Preconditions

        -
          -
        • e1 ().size () == e2 ().size ()
        • -
        -

        Complexity

        -

        Linear depending from the size of the vector expressions.

        -

        Examples

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<double> v1 (3), v2 (3);
        -    for (unsigned i = 0; i < std::min (v1.size (), v2.size ()); ++ i)
        -        v1 (i) = v2 (i) = i;
        -
        -    std::cout << inner_prod (v1, v2) << std::endl;
        -}
        -
        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/vector_proxy.html b/doc/vector_proxy.html deleted file mode 100644 index a8a7376cd..000000000 --- a/doc/vector_proxy.html +++ /dev/null @@ -1,527 +0,0 @@ - - - - - - - - - -Vector Proxies - - -

        Vector Proxies

        -
        -

        Vector Range

        -

        Description

        -

        The templated class vector_range<V> allows -addressing a sub-range of a vector's element.

        -

        Example

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/vector_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<double> v (3);
        -    vector_range<vector<double> > vr (v, range (0, 3));
        -    for (unsigned i = 0; i < vr.size (); ++ i)
        -        vr (i) = i;
        -    std::cout << vr << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header vector_proxy.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        VThe type of vector referenced.
        -

        Model of

        -

        Vector Expression -.

        -

        If the specified range falls outside that of the index range of -the vector, then the vector_range is not a well formed -Vector Expression. That is, access to an element which is outside -of index range of the vector is undefined.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<vector_range<V> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        vector_range (vector_type &data, const range -&r)Constructs a sub vector.
        size_type start () constReturns the start of the sub vector.
        size_type size () constReturns the size of the sub vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        reference operator () (size_type i)Returns a reference of the i-th element.
        const_reference operator [] (size_type i) -constReturns the value of the i-th element.
        reference operator [] (size_type i)Returns a reference of the i-th element.
        vector_range &operator = (const vector_range -&vr)The assignment operator.
        vector_range &assign_temporary (vector_range -&vr)Assigns a temporary. May change the vector range -vr .
        template<class AE>
        -vector_range &operator = (const vector_expression<AE> -&ae)
        The extended assignment operator.
        template<class AE>
        -vector_range &assign (const vector_expression<AE> -&ae)
        Assigns a vector expression to the sub vector. Left and right -hand side of the assignment should be independent.
        template<class AE>
        -vector_range &operator += (const vector_expression<AE> -&ae)
        A computed assignment operator. Adds the vector expression to -the sub vector.
        template<class AE>
        -vector_range &plus_assign (const vector_expression<AE> -&ae)
        Adds a vector expression to the sub vector. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -vector_range &operator -= (const vector_expression<AE> -&ae)
        A computed assignment operator. Subtracts the vector expression -from the sub vector.
        template<class AE>
        -vector_range &minus_assign (const vector_expression<AE> -&ae)
        Subtracts a vector expression from the sub vector. Left and -right hand side of the assignment should be independent.
        template<class AT>
        -vector_range &operator *= (const AT &at)
        A computed assignment operator. Multiplies the sub vector with -a scalar.
        template<class AT>
        -vector_range &operator /= (const AT &at)
        A computed assignment operator. Divides the sub vector through -a scalar.
        void swap (vector_range &vr)Swaps the contents of the sub vectors.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the vector_range.
        const_iterator end () constReturns a const_iterator pointing to the end of -the vector_range.
        iterator begin ()Returns a iterator pointing to the beginning of -the vector_range.
        iterator end ()Returns a iterator pointing to the end of the -vector_range.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed vector_range.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed vector_range.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed vector_range.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed vector_range.
        -

        Simple Projections

        -

        Description

        -

        The free subrange functions support the construction -of vector ranges.

        -

        Prototypes

        -
        
        -    template<class V>
        -    vector_range<V> subrange (V &data,
        -       V::size_type start, V::size_type stop);
        -    template<class V>
        -    const vector_range<const V> subrange (const V &data,
        -       V::size_type start, V::size_type stop);
        -
        -

        Generic Projections

        -

        Description

        -

        The free project functions support the construction -of vector ranges. Existing matrix_range's can be composed with a further range. The resulting range is computed using this existing range's compose function.

        -

        Prototypes

        -
        
        -    template<class V>
        -    vector_range<V> project (V &data, const range &r);
        -    template<class V>
        -    const vector_range<const V> project (const V &data, const range &r);
        -    template<class V>
        -    vector_range<V> project (vector_range<V> &data, const range &r);
        -    template<class V>
        -    const vector_range<V> project (const vector_range<V> &data, const range &r);
        -
        -

        Definition

        -

        Defined in the header vector_proxy.hpp.

        -

        Type requirements

        - -

        Complexity

        -

        Linear depending from the size of the range.

        -

        Examples

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/vector_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<double> v (3);
        -    for (int i = 0; i < 3; ++ i)
        -        project (v, range (0, 3)) (i) = i;
        -    std::cout << project (v, range (0, 3)) << std::endl;
        -}
        -
        -

        Vector Slice

        -

        Description

        -

        The templated class vector_slice<V> allows -addressing a slice of a vector.

        -

        Example

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/vector_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<double> v (3);
        -    vector_slice<vector<double> > vs (v, slice (0, 1, 3));
        -    for (unsigned i = 0; i < vs.size (); ++ i)
        -        vs (i) = i;
        -    std::cout << vs << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header vector_proxy.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        VThe type of vector referenced.
        -

        Model of

        -

        Vector Expression -.

        -

        If the specified slice falls outside that of the index range of -the vector, then the vector_slice is not a well formed -Vector Expression. That is, access to an element which is outside -of index range of the vector is undefined.

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector Expression .

        -

        Public base classes

        -

        vector_expression<vector_slice<V> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        vector_slice (vector_type &data, const slice -&s)Constructs a sub vector.
        size_type size () constReturns the size of the sub vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        reference operator () (size_type i)Returns a reference of the i-th element.
        const_reference operator [] (size_type i) -constReturns the value of the i-th element.
        reference operator [] (size_type i)Returns a reference of the i-th element.
        vector_slice &operator = (const vector_slice -&vs)The assignment operator.
        vector_slice &assign_temporary (vector_slice -&vs)Assigns a temporary. May change the vector slice -vs .
        template<class AE>
        -vector_slice &operator = (const vector_expression<AE> -&ae)
        The extended assignment operator.
        template<class AE>
        -vector_slice &assign (const vector_expression<AE> -&ae)
        Assigns a vector expression to the sub vector. Left and right -hand side of the assignment should be independent.
        template<class AE>
        -vector_slice &operator += (const vector_expression<AE> -&ae)
        A computed assignment operator. Adds the vector expression to -the sub vector.
        template<class AE>
        -vector_slice &plus_assign (const vector_expression<AE> -&ae)
        Adds a vector expression to the sub vector. Left and right hand -side of the assignment should be independent.
        template<class AE>
        -vector_slice &operator -= (const vector_expression<AE> -&ae)
        A computed assignment operator. Subtracts the vector expression -from the sub vector.
        template<class AE>
        -vector_slice &minus_assign (const vector_expression<AE> -&ae)
        Subtracts a vector expression from the sub vector. Left and -right hand side of the assignment should be independent.
        template<class AT>
        -vector_slice &operator *= (const AT &at)
        A computed assignment operator. Multiplies the sub vector with -a scalar.
        template<class AT>
        -vector_slice &operator /= (const AT &at)
        A computed assignment operator. Divides the sub vector through -a scalar.
        void swap (vector_slice &vs)Swaps the contents of the sub vectors.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the vector_slice.
        const_iterator end () constReturns a const_iterator pointing to the end of -the vector_slice.
        iterator begin ()Returns a iterator pointing to the beginning of -the vector_slice.
        iterator end ()Returns a iterator pointing to the end of the -vector_slice.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed vector_slice.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed vector_slice.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed vector_slice.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed vector_slice.
        -

        Simple Projections

        -

        Description

        -

        The free subslice functions support the construction -of vector slices.

        -

        Prototypes

        -
        
        -    template<class V>
        -    vector_slice<V> subslice (V &data,
        -       V::size_type start, V::difference_type stride, V::size_type size);
        -    template<class V>
        -    const vector_slice<const V> subslice (const V &data,
        -       V::size_type start, V::difference_type stride, V::size_type size);
        -
        -

        Generic Projections

        -

        Description

        -

        The free project functions support the construction -of vector slices. Existing vector_slice's can be composed with a further range or slices. The resulting slice is computed using this existing slices's compose function.

        -

        Prototypes

        -
        
        -    template<class V>
        -    vector_slice<V> project (V &data, const slice &s);
        -    template<class V>
        -    const vector_slice<const V> project (const V &data, const slice &s);
        -    template<class V>
        -    vector_slice<V> project (vector_slice<V> &data, const range &r);
        -    template<class V>
        -    const vector_slice<V> project (const vector_slice<V> &data, const range &r);
        -    template<class V>
        -    vector_slice<V> project (vector_slice<V> &data, const slice &s);
        -    template<class V>
        -    const vector_slice<V> project (const vector_slice<V> &data, const slice &s);
        -
        -

        Definition

        -

        Defined in the header vector_proxy.hpp.

        -

        Type requirements

        - -

        Complexity

        -

        Linear depending from the size of the slice.

        -

        Examples

        -
        -#include <boost/numeric/ublas/vector.hpp>
        -#include <boost/numeric/ublas/vector_proxy.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    vector<double> v (3);
        -    for (int i = 0; i < 3; ++ i)
        -        project (v, slice (0, 1, 3)) (i) = i;
        -    std::cout << project (v, slice (0, 1, 3)) << std::endl;
        -}
        -
        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/doc/vector_sparse.html b/doc/vector_sparse.html deleted file mode 100644 index 32279b0e9..000000000 --- a/doc/vector_sparse.html +++ /dev/null @@ -1,800 +0,0 @@ - - - - - - - - - - - - -

        Sparse Vector

        -
        -

        Mapped Vector

        -

        Description

        -

        The templated class mapped_vector<T, A> is -the base container adaptor for sparse vectors using element maps. For a -n-dimensional sparse vector and 0 <= i < n -the non-zero elements vi are mapped to -consecutive elements of the associative container, i.e. for -elements k = -vi1and -k + 1 = -vi2of the -container holds i1 < -i2.

        -

        Example

        -
        -#include <boost/numeric/ublas/vector_sparse.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    mapped_vector<double> v (3, 3);
        -    for (unsigned i = 0; i < v.size (); ++ i)
        -        v (i) = i;
        -    std::cout << v << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header vector_sparse.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the mapped vector.
        AThe type of the adapted array. [1]map_std<std::size_t, T>
        -

        Model of

        -

        Vector .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector .

        -

        Public base classes

        -

        vector_container<mapped_vector<T, A> ->

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        mapped_vector ()Allocates a mapped_vector that holds zero -elements.
        mapped_vector (size_type size, size_type -non_zeros = 0)Allocates a mapped_vector that holds at most -size elements.
        mapped_vector (const mapped_vector &v)The copy constructor.
        template<class AE>
        -mapped_vector (size_type non_zeros, const -vector_expression<AE> &ae)
        The extended copy constructor.
        void resize (size_type size, bool -preserve = true)Reallocates a mapped_vector to hold at most -size elements. The existing elements of the -mapped_vector are preseved when specified.
        size_type size () constReturns the size of the mapped_vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        reference operator () (size_type i)Returns a reference of the i-th element.
        const_reference operator [] (size_type i) -constReturns the value of the i-th element.
        reference operator [] (size_type i)Returns a reference of the i-th element.
        mapped_vector &operator = (const mapped_vector -&v)The assignment operator.
        mapped_vector &assign_temporary (mapped_vector -&v)Assigns a temporary. May change the mapped vector -v .
        template<class AE>
        -mapped_vector &operator = (const vector_expression<AE> -&ae)
        The extended assignment operator.
        template<class AE>
        -mapped_vector &assign (const vector_expression<AE> -&ae)
        Assigns a vector expression to the mapped vector. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -mapped_vector &operator += (const vector_expression<AE> -&ae)
        A computed assignment operator. Adds the vector expression to -the mapped vector.
        template<class AE>
        -mapped_vector &plus_assign (const vector_expression<AE> -&ae)
        Adds a vector expression to the mapped vector. Left and right -hand side of the assignment should be independent.
        template<class AE>
        -mapped_vector &operator -= (const vector_expression<AE> -&ae)
        A computed assignment operator. Subtracts the vector expression -from the mapped vector.
        template<class AE>
        -mapped_vector &minus_assign (const vector_expression<AE> -&ae)
        Subtracts a vector expression from the mapped vector. Left and -right hand side of the assignment should be independent.
        template<class AT>
        -mapped_vector &operator *= (const AT &at)
        A computed assignment operator. Multiplies the mapped vector -with a scalar.
        template<class AT>
        -mapped_vector &operator /= (const AT &at)
        A computed assignment operator. Divides the mapped vector -through a scalar.
        void swap (mapped_vector &v)Swaps the contents of the mapped vectors.
        true_reference insert_element (size_type i, const_reference t)Inserts the value t at the i-th -element. Duplicates elements are not allowed.
        void erase_element (size_type i)Erases the value at the i-th element.
        void clear ()Clears the mapped vector.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the mapped_vector.
        const_iterator end () constReturns a const_iterator pointing to the end of -the mapped_vector.
        iterator begin ()Returns a iterator pointing to the beginning of -the mapped_vector.
        iterator end ()Returns a iterator pointing to the end of the -mapped_vector.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed mapped_vector.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed mapped_vector.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed mapped_vector.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed mapped_vector.
        -

        Notes

        -

        [1] Supported -parameters for the adapted array are -map_array<std::size_t, T> and -map_std<std::size_t, T>. The latter is -equivalent to std::map<std::size_t, T>.

        -

        Compressed Vector

        -

        Description

        -

        The templated class compressed_vector<T, IB, IA, -TA> is the base container adaptor for compressed vectors. -For a n-dimensional compressed vector and 0 <= i -< n the non-zero elements vi -are mapped to consecutive elements of the index and value -container, i.e. for elements k = -vi1and -k + 1 = -vi2of these -containers holds i1 < -i2.

        -

        Example

        -
        -#include <boost/numeric/ublas/vector_sparse.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    compressed_vector<double> v (3, 3);
        -    for (unsigned i = 0; i < v.size (); ++ i)
        -        v (i) = i;
        -    std::cout << v << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header vector_sparse.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the compressed vector.
        IBThe index base of the compressed vector. [1]0
        IAThe type of the adapted array for indices. [2]unbounded_array<std::size_t>
        TAThe type of the adapted array for values. [2]unbounded_array<T>
        -

        Model of

        -

        Vector .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector .

        -

        Public base classes

        -

        vector_container<compressed_vector<T, IB, IA, -TA> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        compressed_vector ()Allocates a compressed_vector that holds zero -elements.
        compressed_vector (size_type size, size_type -non_zeros)Allocates a compressed_vector that holds at most -size elements.
        compressed_vector (const compressed_vector -&v)The copy constructor.
        template<class AE>
        -compressed_vector (size_type non_zeros, const -vector_expression<AE> &ae)
        The extended copy constructor.
        void resize (size_type size, bool -preserve = true)Reallocates a compressed_vector to hold at most -size elements. The existing elements of the -compress_vector are preseved when specified.
        size_type size () constReturns the size of the compressed_vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        reference operator () (size_type i)Returns a reference of the i-th element.
        const_reference operator [] (size_type i) -constReturns the value of the i-th element.
        reference operator [] (size_type i)Returns a reference of the i-th element.
        compressed_vector &operator = (const -compressed_vector &v)The assignment operator.
        compressed_vector &assign_temporary -(compressed_vector &v)Assigns a temporary. May change the compressed vector -v.
        template<class AE>
        -compressed_vector &operator = (const -vector_expression<AE> &ae)
        The extended assignment operator.
        template<class AE>
        -compressed_vector &assign (const vector_expression<AE> -&ae)
        Assigns a vector expression to the compressed vector. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -compressed_vector &operator += (const -vector_expression<AE> &ae)
        A computed assignment operator. Adds the vector expression to -the compressed vector.
        template<class AE>
        -compressed_vector &plus_assign (const -vector_expression<AE> &ae)
        Adds a vector expression to the compressed vector. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -compressed_vector &operator -= (const -vector_expression<AE> &ae)
        A computed assignment operator. Subtracts the vector expression -from the compressed vector.
        template<class AE>
        -compressed_vector &minus_assign (const -vector_expression<AE> &ae)
        Subtracts a vector expression from the compressed vector. Left -and right hand side of the assignment should be independent.
        template<class AT>
        -compressed_vector &operator *= (const AT &at)
        A computed assignment operator. Multiplies the compressed -vector with a scalar.
        template<class AT>
        -compressed_vector &operator /= (const AT &at)
        A computed assignment operator. Divides the compressed vector -through a scalar.
        void swap (compressed_vector &v)Swaps the contents of the compressed vectors.
        true_reference insert_element (size_type i, const_reference t)Inserts the value t at the i-th -element. Duplicates elements are not allowed.
        void erase_element (size_type i)Erases the value at the i-th element.
        void clear ()Clears the compressed vector.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the compressed_vector.
        const_iterator end () constReturns a const_iterator pointing to the end of -the compressed_vector.
        iterator begin ()Returns a iterator pointing to the beginning of -the compressed_vector.
        iterator end ()Returns a iterator pointing to the end of the -compressed_vector.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed compressed_vector.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed compressed_vector.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed compressed_vector.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed compressed_vector.
        -

        Notes

        -

        [1] -Supported parameters for the index base are 0 and -1 at least.

        -

        [2] -Supported parameters for the adapted array are -unbounded_array<> , -bounded_array<> and -std::vector<> .

        -

        Coordinate Vector

        -

        Description

        -

        The templated class coordinate_vector<T, IB, IA, -TA> is the base container adaptor for compressed vectors. -For a n-dimensional sorted coordinate vector and 0 -<= i < n the non-zero elements -vi are mapped to consecutive elements -of the index and value container, i.e. for elements k = -vi1and -k + 1 = -vi2of these -containers holds i1 < -i2.

        -

        Example

        -
        -#include <boost/numeric/ublas/vector_sparse.hpp>
        -#include <boost/numeric/ublas/io.hpp>
        -
        -int main () {
        -    using namespace boost::numeric::ublas;
        -    coordinate_vector<double> v (3, 3);
        -    for (unsigned i = 0; i < v.size (); ++ i)
        -        v (i) = i;
        -    std::cout << v << std::endl;
        -}
        -
        -

        Definition

        -

        Defined in the header vector_sparse.hpp.

        -

        Template parameters

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        ParameterDescriptionDefault
        TThe type of object stored in the coordinate vector.
        IBThe index base of the coordinate vector. [1]0
        IAThe type of the adapted array for indices. [2]unbounded_array<std::size_t>
        TAThe type of the adapted array for values. [2]unbounded_array<T>
        -

        Model of

        -

        Vector .

        -

        Type requirements

        -

        None, except for those imposed by the requirements of Vector .

        -

        Public base classes

        -

        vector_container<coordinate_vector<T, IB, IA, -TA> >

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        MemberDescription
        coordinate_vector ()Allocates a coordinate_vector that holds zero -elements.
        coordinate_vector (size_type size, size_type -non_zeros)Allocates a coordinate_vector that holds at most -size elements.
        coordinate_vector (const coordinate_vector -&v)The copy constructor.
        template<class AE>
        -coordinate_vector (size_type non_zeros, const -vector_expression<AE> &ae)
        The extended copy constructor.
        void resize (size_type size, bool -preserve = true)Reallocates a coordinate_vector to hold at most -size elements. The existing elements of the -coordinate_vector are preseved when specified.
        size_type size () constReturns the size of the coordinate_vector.
        const_reference operator () (size_type i) -constReturns the value of the i-th element.
        reference operator () (size_type i)Returns a reference of the i-th element.
        const_reference operator [] (size_type i) -constReturns the value of the i-th element.
        reference operator [] (size_type i)Returns a reference of the i-th element.
        coordinate_vector &operator = (const -coordinate_vector &v)The assignment operator.
        coordinate_vector &assign_temporary -(coordinate_vector &v)Assigns a temporary. May change the coordinate vector -v.
        template<class AE>
        -coordinate_vector &operator = (const -vector_expression<AE> &ae)
        The extended assignment operator.
        template<class AE>
        -coordinate_vector &assign (const vector_expression<AE> -&ae)
        Assigns a vector expression to the coordinate vector. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -coordinate_vector &operator += (const -vector_expression<AE> &ae)
        A computed assignment operator. Adds the vector expression to -the coordinate vector.
        template<class AE>
        -coordinate_vector &plus_assign (const -vector_expression<AE> &ae)
        Adds a vector expression to the coordinate vector. Left and -right hand side of the assignment should be independent.
        template<class AE>
        -coordinate_vector &operator -= (const -vector_expression<AE> &ae)
        A computed assignment operator. Subtracts the vector expression -from the coordinate vector.
        template<class AE>
        -coordinate_vector &minus_assign (const -vector_expression<AE> &ae)
        Subtracts a vector expression from the coordinate vector. Left -and right hand side of the assignment should be independent.
        template<class AT>
        -coordinate_vector &operator *= (const AT &at)
        A computed assignment operator. Multiplies the coordinate -vector with a scalar.
        template<class AT>
        -coordinate_vector &operator /= (const AT &at)
        A computed assignment operator. Divides the coordinate vector -through a scalar.
        void swap (coordinate_vector &v)Swaps the contents of the coordinate vectors.
        true_reference insert_element (size_type i, const_reference t)Inserts the value t at the i-th -element. Duplicates elements are not allowed.
        void append_element (size_type i, size_type j, const_reference t)Appends the value t at the i-th element. -Duplicate elements can be appended to a coordinate_vector. They are merged into a single -arithmetically summed element by the sort function.
        void erase_element (size_type i)Erases the value at the i-th element.
        void clear ()Clears the coordinate vector.
        const_iterator begin () constReturns a const_iterator pointing to the beginning -of the coordinate_vector.
        const_iterator end () constReturns a const_iterator pointing to the end of -the coordinate_vector.
        iterator begin ()Returns a iterator pointing to the beginning of -the coordinate_vector.
        iterator end ()Returns a iterator pointing to the end of the -coordinate_vector.
        const_reverse_iterator rbegin () constReturns a const_reverse_iterator pointing to the -beginning of the reversed coordinate_vector.
        const_reverse_iterator rend () constReturns a const_reverse_iterator pointing to the -end of the reversed coordinate_vector.
        reverse_iterator rbegin ()Returns a reverse_iterator pointing to the -beginning of the reversed coordinate_vector.
        reverse_iterator rend ()Returns a reverse_iterator pointing to the end of -the reversed coordinate_vector.
        -

        Notes

        -

        [1] -Supported parameters for the index base are 0 and -1 at least.

        -

        [2] -Supported parameters for the adapted array are -unbounded_array<> , -bounded_array<> and -std::vector<> .

        -
        -

        Copyright (©) 2000-2002 Joerg Walter, Mathias Koch
        - Use, modification and distribution are 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 - ). -

        - - - diff --git a/index.html b/index.html index 16cd00158..44928f8ff 100644 --- a/index.html +++ b/index.html @@ -1,10 +1,32 @@ + - + + + +

        Automatic redirection failed, please go to -doc/index.html  


        -

        Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at www.boost.org/LICENSE_1_0.txt)

        +doc/html/ublas.html. +

        + \ No newline at end of file From 09db8baf24f93587778a5895e234031746a3e1e6 Mon Sep 17 00:00:00 2001 From: Cem Bassoy Date: Mon, 6 Sep 2021 11:25:21 +0200 Subject: [PATCH 28/36] fix: update windows.yml for Github Actions Resolves #134 --- .github/workflows/windows.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 7bdfc69be..3f761707e 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -24,7 +24,8 @@ jobs: # - {os: windows-2016, toolset: msvc, version: 14.16, cxxstd: 11} # - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: 11} # - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: 17} - - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: latest} + - {os: windows-2019, toolset: msvc, version: 14.29, cxxstd: latest} +# - {os: windows-2022, toolset: msvc, version: 14.30, cxxstd: latest} steps: - uses: actions/checkout@v2 From d07ab80852a9749e6bbd979ba421ea6ba4a40f6a Mon Sep 17 00:00:00 2001 From: Cem Bassoy Date: Sun, 12 Sep 2021 12:23:09 +0200 Subject: [PATCH 29/36] docs: update README.md --- README.md | 53 +++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 1e9ec9223..a91b781f1 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ Boost Linear and Multilinear Algebra Library ===== -[![Language](https://img.shields.io/badge/C%2B%2B-11-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) +[![Language](https://img.shields.io/badge/C%2B%2B-20-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) [![License](https://img.shields.io/badge/license-BSL-blue.svg)](https://opensource.org/licenses/BSL-1.0) [![Documentation](https://img.shields.io/badge/ublas-documentation-blue.svg)](https://www.boost.org/doc/libs/1_69_0/libs/numeric/ublas/doc/index.html) [![Wiki](https://img.shields.io/badge/ublas-wiki-blue.svg)](https://github.com/boostorg/ublas/wiki) [![Mailing List](https://img.shields.io/badge/ublas-mailing%20list-4eb899.svg)](https://lists.boost.org/mailman/listinfo.cgi/ublas) +[![Discussions](https://img.shields.io/badge/ublas-discussions-blue)](https://github.com/boostorg/ublas/discussions) [![Gitter](https://img.shields.io/badge/ublas-chat%20on%20gitter-4eb899.svg)](https://gitter.im/boostorg/ublas) +[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](https://github.com/boostorg/ublas/wiki/Code-of-Conduct) [![Windows](https://github.com/boostorg/ublas/actions/workflows/windows.yml/badge.svg)](https://github.com/boostorg/ublas/actions/workflows/windows.yml) [![Linux](https://github.com/boostorg/ublas/actions/workflows/linux.yml/badge.svg)](https://github.com/boostorg/ublas/actions/workflows/linux.yml) @@ -15,24 +17,10 @@ Boost Linear and Multilinear Algebra Library [![Clang Tidy](https://github.com/boostorg/ublas/actions/workflows/clangtidy.yml/badge.svg)](https://github.com/boostorg/ublas/actions/workflows/clangtidy.yml) [![Codecov](https://codecov.io/gh/boostorg/ublas/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/ublas/branch/master) - -**Boost.uBLAS** is part of the [Boost C++ Libraries](http://github.com/boostorg). -It is directed towards scientific computing on the level of basic linear and multilinear algebra operations with tensors, matrices and vectors. - -## Documentation -uBLAS is documented at [boost.org](https://www.boost.org/doc/libs/1_69_0/libs/numeric/ublas/doc/index.html). -The tensor extension has also a [wiki page](https://github.com/boostorg/ublas/wiki/Tensor). - -## License -Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). - -## Properties -* header-only -* requires C++20 compatible compiler - * gcc version >= 10.x.x - * clang version >= 10.x.x - * msvc version >= 14.28 -* Unit-tests require Boost.Test +Boost.uBlas is a header-only library and part of the [Boost C++ libraries](http://github.com/boostorg). +It provides a set of basic linear and multilinear algebra operations with tensors, matrices and vectors. +uBLAS is documented at [boost.org](https://www.boost.org/doc/libs/1_69_0/libs/numeric/ublas/doc/index.html) or in [docs](https://github.com/BoostGSoC21/ublas/blob/develop/doc/ublas.adoc). +Simple examples of the tensor extension is provided by the [wiki page](https://github.com/boostorg/ublas/wiki/Tensor). ## Simple Example @@ -56,6 +44,24 @@ int main() } ``` +## Requirements +* Boost.uBlas requires a C++20 compatible compiler + * gcc version >= 10.x.x + * clang version >= 10.x.x + * msvc version >= 14.28 +* Unit-tests require Boost.Test + +## Discussions and Questions +* Be sure to have read our [code of conduct](https://github.com/boostorg/ublas/wiki/Code-of-Conduct) and Boost's [discussion policy](http://www.boost.org/community/policy.html) +* Contributors and maintainers mainly use [Discussions](https://github.com/boostorg/ublas/discussions) (previously [Gitter](https://gitter.im/boostorg/ublas)) to discuss library design or governance topics. +* Users of the library can choose between the following platforms preferably [Gitter](https://gitter.im/boostorg/ublas), the [Boost developers mailing list](https://lists.boost.org/mailman/listinfo.cgi/ublas) using the `[ublas]` tag at the beginning of the subject line or [Stackoverflow](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-ublas) using `boost-ublas` or `ublas` tags +* Contact the maintainers [Cem](https://gitter.im/bassoy), [David](https://gitter.im/yimyom) or [Stefan](https://gitter.im/stefanseefeld) if you have suggestions + +## Contribution +* Be sure that you have read our [contribution guidelines](https://github.com/boostorg/ublas/wiki/Guidelines-for-Contribution) and our [code of conduct](https://github.com/boostorg/ublas/wiki/Code-of-Conduct) +* If you want to report a bug, create an [issue](https://github.com/boostorg/ublas/issues) +* If you want to submit a patch, create pull request against **develop** branch. + ## Directories | Name | Purpose | @@ -65,12 +71,3 @@ int main() | `include` | headers | | `test` | unit tests | | `benchmarks` | timing and benchmarking | - -## More information - -* If you would like to test the library, contribute new feature or a bug fix, see [contribution](https://github.com/boostorg/ublas/wiki/Guidelines-for-Contribution). -* Ask questions in [stackoverflow](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-ublas) with `boost-ublas` or `ublas` tags. -* Report [bugs](https://github.com/boostorg/ublas/issues) and be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well. -* Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). -* Developer discussions about the library are held on the [Boost developers mailing list](https://lists.boost.org/mailman/listinfo.cgi/ublas). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[ublas]` tag at the beginning of the subject line -* For any other questions, you can contact David, Stefan or Cem: david.bellot-AT-gmail-DOT-com, cem.bassoy-AT-gmail-DOT-com stefan-AT-seefeld-DOT-name From dae5364e44e981698f3de1b0f46b06256ddaf56b Mon Sep 17 00:00:00 2001 From: Shikhar Vashistha <51105234+shikharvashistha@users.noreply.github.com> Date: Sat, 6 Nov 2021 17:05:31 +0530 Subject: [PATCH 30/36] ci: add CI for asciidoc documentation compilation (#143) --- .github/workflows/documentation.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/documentation.yml diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 000000000..ebbb2fb3d --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,21 @@ +name: documentation +'on': + push: + paths: + - doc/** + pull_request: + paths: + - doc/** +jobs: + asciidoc: + runs-on: ubuntu-latest + name: asciidoc-documentation + steps: + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.7 + - uses: reitzig/actions-asciidoctor@v2.0.0 + with: + version: 2.0.10 + - run: asciidoctor doc/ublas.adoc From f5bf276fc08e059a3ac11b0d714b1c9bd5a8eb85 Mon Sep 17 00:00:00 2001 From: amitsingh19975 Date: Thu, 3 Feb 2022 22:55:09 +0530 Subject: [PATCH 31/36] refactor(test): Improve unit test source files (#122) Unit tests have been revamped in order to improve maintainability and readability. Many of them have been split into smaller tests. Missing tests for various tensor types and extents have been added. This will simply the addition of new tests for various tensor types and instances. --- test/tensor/Jamfile | 84 +- .../algorithm/test_algorithm_accumulate.cpp | 277 +++++ test/tensor/algorithm/test_algorithm_copy.cpp | 442 ++++++++ .../tensor/algorithm/test_algorithm_trans.cpp | 326 ++++++ .../algorithm/test_algorithm_transform.cpp | 473 +++++++++ .../extents/test_extents_access_operator.cpp | 137 +++ .../test_extents_assignment_operator.cpp | 112 ++ test/tensor/extents/test_extents_at.cpp | 136 +++ .../extents/test_extents_comparision.cpp | 219 ++++ .../extents/test_extents_construction.cpp | 255 +++++ test/tensor/extents/test_extents_empty.cpp | 141 +++ .../tensor/extents/test_extents_is_matrix.cpp | 142 +++ .../tensor/extents/test_extents_is_scalar.cpp | 142 +++ .../tensor/extents/test_extents_is_tensor.cpp | 142 +++ test/tensor/extents/test_extents_is_valid.cpp | 145 +++ .../tensor/extents/test_extents_is_vector.cpp | 142 +++ test/tensor/extents/test_extents_product.cpp | 145 +++ test/tensor/extents/test_extents_size.cpp | 141 +++ test/tensor/fixture_utility.hpp | 365 +++++++ .../tensor/functions/test_functions_inner.cpp | 100 ++ .../functions/test_functions_matrix.cpp | 115 ++ test/tensor/functions/test_functions_norm.cpp | 102 ++ .../tensor/functions/test_functions_outer.cpp | 109 ++ .../test_functions_real_imag_conj.cpp | 265 +++++ .../functions/test_functions_tensor.cpp | 127 +++ .../test_functions_tensor_permutation.cpp | 170 +++ .../tensor/functions/test_functions_trans.cpp | 163 +++ .../functions/test_functions_vector.cpp | 163 +++ .../test_multiplication_inner.cpp | 146 +++ .../test_multiplication_mtm.cpp | 190 ++++ .../test_multiplication_mtv.cpp | 232 ++++ .../test_multiplication_outer.cpp | 222 ++++ .../test_multiplication_ttm.cpp | 196 ++++ .../test_multiplication_ttt.cpp | 284 +++++ .../test_multiplication_ttt_permutation.cpp | 238 +++++ .../test_multiplication_ttv.cpp | 235 +++++ .../tensor/test_tensor_access_operator.cpp | 385 +++++++ .../test_tensor_assignment_operator.cpp | 422 ++++++++ test/tensor/tensor/test_tensor_at.cpp | 362 +++++++ .../tensor/test_tensor_binary_expression.cpp | 222 ++++ .../tensor/tensor/test_tensor_comparision.cpp | 162 +++ .../test_tensor_comparision_with_scalar.cpp | 292 ++++++ ...sor_comparision_with_tensor_expression.cpp | 180 ++++ .../tensor/test_tensor_construction.cpp | 989 ++++++++++++++++++ test/tensor/tensor/test_tensor_empty.cpp | 131 +++ .../tensor/test_tensor_expression_access.cpp | 123 +++ ...xpression_evaluation_all_extents_equal.cpp | 312 ++++++ ...expression_evaluation_retrieve_extents.cpp | 300 ++++++ ..._tensor_operator_arithmetic_assignment.cpp | 291 ++++++ ...test_tensor_operator_arithmetic_binary.cpp | 223 ++++ .../test_tensor_operator_arithmetic_unary.cpp | 216 ++++ test/tensor/tensor/test_tensor_size.cpp | 130 +++ .../tensor/test_tensor_unary_expression.cpp | 168 +++ test/tensor/test_algorithms.cpp | 565 ---------- test/tensor/test_einstein_notation.cpp | 414 ++++++-- test/tensor/test_expression.cpp | 183 ---- test/tensor/test_expression_evaluation.cpp | 244 ----- test/tensor/test_extents_dynamic.cpp | 190 ---- .../test_extents_dynamic_rank_static.cpp | 155 --- test/tensor/test_extents_functions.cpp | 634 ----------- .../test_fixed_rank_expression_evaluation.cpp | 287 ----- test/tensor/test_fixed_rank_extents.cpp | 555 ---------- test/tensor/test_fixed_rank_functions.cpp | 460 -------- .../test_fixed_rank_operators_arithmetic.cpp | 238 ----- .../test_fixed_rank_operators_comparison.cpp | 197 ---- test/tensor/test_fixed_rank_strides.cpp | 184 ---- test/tensor/test_fixed_rank_tensor.cpp | 510 --------- .../test_fixed_rank_tensor_matrix_vector.cpp | 472 --------- test/tensor/test_functions.cpp | 554 ---------- test/tensor/test_main.cpp | 24 + test/tensor/test_multi_index.cpp | 280 +++-- test/tensor/test_multi_index_utility.cpp | 509 ++++----- test/tensor/test_multiplication.cpp | 486 --------- test/tensor/test_operators_arithmetic.cpp | 262 ----- test/tensor/test_operators_comparison.cpp | 246 ----- .../test_static_expression_evaluation.cpp | 220 ---- test/tensor/test_static_extents.cpp | 366 ------- .../test_static_operators_arithmetic.cpp | 242 ----- .../test_static_operators_comparison.cpp | 198 ---- test/tensor/test_static_strides.cpp | 156 --- test/tensor/test_static_tensor.cpp | 398 ------- .../test_static_tensor_matrix_vector.cpp | 454 -------- test/tensor/test_strides.cpp | 539 +++++++--- test/tensor/test_tensor_matrix_vector.cpp | 460 -------- test/tensor/utility.hpp | 47 +- 85 files changed, 13091 insertions(+), 9569 deletions(-) create mode 100644 test/tensor/algorithm/test_algorithm_accumulate.cpp create mode 100644 test/tensor/algorithm/test_algorithm_copy.cpp create mode 100644 test/tensor/algorithm/test_algorithm_trans.cpp create mode 100644 test/tensor/algorithm/test_algorithm_transform.cpp create mode 100644 test/tensor/extents/test_extents_access_operator.cpp create mode 100644 test/tensor/extents/test_extents_assignment_operator.cpp create mode 100644 test/tensor/extents/test_extents_at.cpp create mode 100644 test/tensor/extents/test_extents_comparision.cpp create mode 100644 test/tensor/extents/test_extents_construction.cpp create mode 100644 test/tensor/extents/test_extents_empty.cpp create mode 100644 test/tensor/extents/test_extents_is_matrix.cpp create mode 100644 test/tensor/extents/test_extents_is_scalar.cpp create mode 100644 test/tensor/extents/test_extents_is_tensor.cpp create mode 100644 test/tensor/extents/test_extents_is_valid.cpp create mode 100644 test/tensor/extents/test_extents_is_vector.cpp create mode 100644 test/tensor/extents/test_extents_product.cpp create mode 100644 test/tensor/extents/test_extents_size.cpp create mode 100644 test/tensor/fixture_utility.hpp create mode 100644 test/tensor/functions/test_functions_inner.cpp create mode 100644 test/tensor/functions/test_functions_matrix.cpp create mode 100644 test/tensor/functions/test_functions_norm.cpp create mode 100644 test/tensor/functions/test_functions_outer.cpp create mode 100644 test/tensor/functions/test_functions_real_imag_conj.cpp create mode 100644 test/tensor/functions/test_functions_tensor.cpp create mode 100644 test/tensor/functions/test_functions_tensor_permutation.cpp create mode 100644 test/tensor/functions/test_functions_trans.cpp create mode 100644 test/tensor/functions/test_functions_vector.cpp create mode 100644 test/tensor/multiplication/test_multiplication_inner.cpp create mode 100644 test/tensor/multiplication/test_multiplication_mtm.cpp create mode 100644 test/tensor/multiplication/test_multiplication_mtv.cpp create mode 100644 test/tensor/multiplication/test_multiplication_outer.cpp create mode 100644 test/tensor/multiplication/test_multiplication_ttm.cpp create mode 100644 test/tensor/multiplication/test_multiplication_ttt.cpp create mode 100644 test/tensor/multiplication/test_multiplication_ttt_permutation.cpp create mode 100644 test/tensor/multiplication/test_multiplication_ttv.cpp create mode 100644 test/tensor/tensor/test_tensor_access_operator.cpp create mode 100644 test/tensor/tensor/test_tensor_assignment_operator.cpp create mode 100644 test/tensor/tensor/test_tensor_at.cpp create mode 100644 test/tensor/tensor/test_tensor_binary_expression.cpp create mode 100644 test/tensor/tensor/test_tensor_comparision.cpp create mode 100644 test/tensor/tensor/test_tensor_comparision_with_scalar.cpp create mode 100644 test/tensor/tensor/test_tensor_comparision_with_tensor_expression.cpp create mode 100644 test/tensor/tensor/test_tensor_construction.cpp create mode 100644 test/tensor/tensor/test_tensor_empty.cpp create mode 100644 test/tensor/tensor/test_tensor_expression_access.cpp create mode 100644 test/tensor/tensor/test_tensor_expression_evaluation_all_extents_equal.cpp create mode 100644 test/tensor/tensor/test_tensor_expression_evaluation_retrieve_extents.cpp create mode 100644 test/tensor/tensor/test_tensor_operator_arithmetic_assignment.cpp create mode 100644 test/tensor/tensor/test_tensor_operator_arithmetic_binary.cpp create mode 100644 test/tensor/tensor/test_tensor_operator_arithmetic_unary.cpp create mode 100644 test/tensor/tensor/test_tensor_size.cpp create mode 100644 test/tensor/tensor/test_tensor_unary_expression.cpp delete mode 100644 test/tensor/test_algorithms.cpp delete mode 100644 test/tensor/test_expression.cpp delete mode 100644 test/tensor/test_expression_evaluation.cpp delete mode 100644 test/tensor/test_extents_dynamic.cpp delete mode 100644 test/tensor/test_extents_dynamic_rank_static.cpp delete mode 100644 test/tensor/test_extents_functions.cpp delete mode 100644 test/tensor/test_fixed_rank_expression_evaluation.cpp delete mode 100644 test/tensor/test_fixed_rank_extents.cpp delete mode 100644 test/tensor/test_fixed_rank_functions.cpp delete mode 100644 test/tensor/test_fixed_rank_operators_arithmetic.cpp delete mode 100644 test/tensor/test_fixed_rank_operators_comparison.cpp delete mode 100644 test/tensor/test_fixed_rank_strides.cpp delete mode 100644 test/tensor/test_fixed_rank_tensor.cpp delete mode 100644 test/tensor/test_fixed_rank_tensor_matrix_vector.cpp delete mode 100644 test/tensor/test_functions.cpp create mode 100644 test/tensor/test_main.cpp delete mode 100644 test/tensor/test_multiplication.cpp delete mode 100644 test/tensor/test_operators_arithmetic.cpp delete mode 100644 test/tensor/test_operators_comparison.cpp delete mode 100644 test/tensor/test_static_expression_evaluation.cpp delete mode 100644 test/tensor/test_static_extents.cpp delete mode 100644 test/tensor/test_static_operators_arithmetic.cpp delete mode 100644 test/tensor/test_static_operators_comparison.cpp delete mode 100644 test/tensor/test_static_strides.cpp delete mode 100644 test/tensor/test_static_tensor.cpp delete mode 100644 test/tensor/test_static_tensor_matrix_vector.cpp delete mode 100644 test/tensor/test_tensor_matrix_vector.cpp diff --git a/test/tensor/Jamfile b/test/tensor/Jamfile index 723f5b11a..908e359ea 100644 --- a/test/tensor/Jamfile +++ b/test/tensor/Jamfile @@ -29,40 +29,64 @@ alias unit_test_framework explicit unit_test_framework ; - test-suite boost-ublas-tensor-test : - [ run test_algorithms.cpp - test_einstein_notation.cpp - test_expression.cpp - test_expression_evaluation.cpp - test_extents_dynamic.cpp - test_extents_dynamic_rank_static.cpp - test_extents_functions.cpp - test_fixed_rank_expression_evaluation.cpp - test_fixed_rank_extents.cpp - test_fixed_rank_functions.cpp - test_fixed_rank_operators_arithmetic.cpp - test_fixed_rank_operators_comparison.cpp - test_fixed_rank_strides.cpp - test_fixed_rank_tensor.cpp - test_fixed_rank_tensor_matrix_vector.cpp - test_functions.cpp + [ run test_main.cpp + extents/test_extents_empty.cpp + extents/test_extents_size.cpp + extents/test_extents_at.cpp + extents/test_extents_access_operator.cpp + extents/test_extents_construction.cpp + extents/test_extents_assignment_operator.cpp + extents/test_extents_is_scalar.cpp + extents/test_extents_is_vector.cpp + extents/test_extents_is_matrix.cpp + extents/test_extents_is_tensor.cpp + extents/test_extents_is_valid.cpp + extents/test_extents_product.cpp + extents/test_extents_comparision.cpp + tensor/test_tensor_empty.cpp + tensor/test_tensor_size.cpp + tensor/test_tensor_at.cpp + tensor/test_tensor_access_operator.cpp + tensor/test_tensor_construction.cpp + tensor/test_tensor_assignment_operator.cpp + tensor/test_tensor_comparision.cpp + tensor/test_tensor_comparision_with_tensor_expression.cpp + tensor/test_tensor_comparision_with_scalar.cpp + tensor/test_tensor_operator_arithmetic_binary.cpp + tensor/test_tensor_operator_arithmetic_unary.cpp + tensor/test_tensor_operator_arithmetic_assignment.cpp + tensor/test_tensor_expression_evaluation_retrieve_extents.cpp + tensor/test_tensor_expression_evaluation_all_extents_equal.cpp + tensor/test_tensor_expression_access.cpp + tensor/test_tensor_unary_expression.cpp + tensor/test_tensor_binary_expression.cpp + algorithm/test_algorithm_copy.cpp + algorithm/test_algorithm_transform.cpp + algorithm/test_algorithm_accumulate.cpp + algorithm/test_algorithm_trans.cpp + multiplication/test_multiplication_mtv.cpp + multiplication/test_multiplication_mtm.cpp + multiplication/test_multiplication_ttv.cpp + multiplication/test_multiplication_ttm.cpp + multiplication/test_multiplication_ttt_permutation.cpp + multiplication/test_multiplication_inner.cpp + multiplication/test_multiplication_outer.cpp + multiplication/test_multiplication_ttt.cpp + functions/test_functions_vector.cpp + functions/test_functions_matrix.cpp + functions/test_functions_tensor.cpp + functions/test_functions_tensor_permutation.cpp + functions/test_functions_inner.cpp + functions/test_functions_norm.cpp + functions/test_functions_real_imag_conj.cpp + functions/test_functions_outer.cpp + functions/test_functions_trans.cpp + test_strides.cpp test_multi_index.cpp test_multi_index_utility.cpp - test_multiplication.cpp - test_operators_arithmetic.cpp - test_operators_comparison.cpp - test_static_expression_evaluation.cpp - test_static_extents.cpp - test_static_operators_arithmetic.cpp - test_static_operators_comparison.cpp - test_static_strides.cpp - test_static_tensor.cpp - test_static_tensor_matrix_vector.cpp - test_strides.cpp - test_tensor.cpp - test_tensor_matrix_vector.cpp + test_einstein_notation.cpp unit_test_framework : : diff --git a/test/tensor/algorithm/test_algorithm_accumulate.cpp b/test/tensor/algorithm/test_algorithm_accumulate.cpp new file mode 100644 index 000000000..491fd40f5 --- /dev/null +++ b/test/tensor/algorithm/test_algorithm_accumulate.cpp @@ -0,0 +1,277 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_algorithm_accumulate, + *boost::unit_test::description("Validate Accumulate Algorithm") + *boost::unit_test::depends_on("test_extents_constructor") + *boost::unit_test::depends_on("test_extents_product") + *boost::unit_test::depends_on("test_strides") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("accumulate_algorithm") + *boost::unit_test::description("Testing accumulate algorithm using dynamic extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_dynamic; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [](auto /*id*/, auto const& n){ + if(ublas::empty(n)) + return; + auto const rank = ublas::size(n); + auto const s = ublas::product(n); + + auto const v = value_type{0}; + auto const one = std::size_t{1}; + auto const two = std::size_t{2}; + + + BOOST_TEST_CONTEXT("[Accumulate Algorithm] rank("<< rank <<") dynamic extents"){ + auto a = vector_t(s); + + auto const wa = ublas::to_strides(n, layout_type{}); + + ublas::iota(a, one); + + auto const acc = ublas::accumulate( rank, n.data(), a.data(), wa.data(), v); + + auto const sum = value_type{ static_cast( (s * (s + one)) / two ) }; + + BOOST_CHECK_EQUAL( acc, sum ); + + auto zero = std::size_t{0}; + BOOST_CHECK_EQUAL( ublas::accumulate(zero, n.data(), a.data(), wa.data(),v), v ); + + auto acc2 = ublas::accumulate( rank, n.data(), a.data(), wa.data(), v, std::plus<>{}); + + BOOST_CHECK_EQUAL( acc2, sum ); + + BOOST_CHECK_EQUAL( ublas::accumulate(zero, n.data(), a.data(), wa.data(), v, std::plus<>{}), v ); + } + + BOOST_TEST_CONTEXT("[Accumulate Algorithm(Exception)] rank("<< rank <<") dynamic extents"){ + { + BOOST_TEST_CHECKPOINT("if input is null"); + value_type* a = nullptr; + auto const wa = ublas::to_strides(n,layout_type{}); + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a, wa.data(), v ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input is null and with predicate"); + value_type* a = nullptr; + auto const wa = ublas::to_strides(n,layout_type{}); + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a, wa.data(), v, std::plus<>{} ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if stride is null"); + auto const a = vector_t(s); + std::size_t const* wa = nullptr; + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a.data(), wa, v ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if stride is null and predicate"); + auto const a = vector_t(s); + std::size_t const* wa = nullptr; + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a.data(), wa, v, std::plus<>{} ), std::runtime_error ); + } + } + }); + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("accumulate_algorithm") + *boost::unit_test::description("Testing accumulate algorithm using static rank extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_static_rank; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [](auto /*id*/, auto const& n){ + + if(ublas::empty(n)) + return; + + auto const rank = ublas::size(n); + auto const s = ublas::product(n); + + auto const v = value_type{0}; + auto const one = std::size_t{1}; + auto const two = std::size_t{2}; + + BOOST_TEST_CONTEXT("[Accumulate Algorithm] static rank("<< rank <<") extents"){ + auto a = vector_t(s); + + auto wa = ublas::to_strides(n, layout_type{}); + + ublas::iota(a, one); + + auto const acc = ublas::accumulate( rank, n.data(), a.data(), wa.data(), v); + + auto const sum = value_type{ static_cast( (s * (s + one)) / two ) }; + + BOOST_CHECK_EQUAL( acc, sum ); + + auto zero = std::size_t{0}; + BOOST_CHECK_EQUAL( ublas::accumulate(zero, n.data(), a.data(), wa.data(),v), v ); + + auto acc2 = ublas::accumulate( rank, n.data(), a.data(), wa.data(), v, std::plus<>{}); + + BOOST_CHECK_EQUAL( acc2, sum ); + + BOOST_CHECK_EQUAL( ublas::accumulate(zero, n.data(), a.data(), wa.data(), v, std::plus<>{}), v ); + } + + BOOST_TEST_CONTEXT("[Accumulate Algorithm(Exception)] static rank("<< rank <<") extents"){ + { + BOOST_TEST_CHECKPOINT("if input is null"); + value_type* a = nullptr; + auto const wa = ublas::to_strides(n,layout_type{}); + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a, wa.data(), v ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input is null and with predicate"); + value_type* a = nullptr; + auto const wa = ublas::to_strides(n,layout_type{}); + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a, wa.data(), v, std::plus<>{} ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if stride is null"); + auto const a = vector_t(s); + std::size_t const* wa = nullptr; + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a.data(), wa, v ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if stride is null and predicate"); + auto const a = vector_t(s); + std::size_t const* wa = nullptr; + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a.data(), wa, v, std::plus<>{} ), std::runtime_error ); + } + } + }); + +} + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("accumulate_algorithm") + *boost::unit_test::description("Testing accumulate algorithm using static extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_static; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& n){ + + if constexpr(!ublas::empty_v){ + + constexpr auto rank = ublas::size_v; + constexpr auto s = ublas::product_v; + + auto const v = value_type{0}; + auto const one = std::size_t{1}; + auto const two = std::size_t{2}; + + + // TODO: Enable test for the rank one and the rank two after the issue #119 has been fixed + if constexpr(rank > 2ul){ + + BOOST_TEST_CONTEXT("[Accumulate Algorithm] rank("<< rank <<") static extents"){ + auto a = vector_t(s); + + auto wa = ublas::to_strides_v; + + ublas::iota(a, one); + + auto const acc = ublas::accumulate( rank, n.data(), a.data(), wa.data(), v); + + auto const sum = value_type{ static_cast( (s * (s + one)) / two ) }; + + BOOST_CHECK_EQUAL( acc, sum ); + + auto zero = std::size_t{0}; + BOOST_CHECK_EQUAL( ublas::accumulate(zero, n.data(), a.data(), wa.data(),v), v ); + + auto acc2 = ublas::accumulate( rank, n.data(), a.data(), wa.data(), v, std::plus<>{}); + + BOOST_CHECK_EQUAL( acc2, sum ); + + BOOST_CHECK_EQUAL( ublas::accumulate(zero, n.data(), a.data(), wa.data(), v, std::plus<>{}), v ); + } + + BOOST_TEST_CONTEXT("[Accumulate Algorithm(Exception)] rank("<< rank <<") static extents"){ + { + BOOST_TEST_CHECKPOINT("if input is null"); + value_type* a = nullptr; + auto const wa = ublas::to_strides_v; + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a, wa.data(), v ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input is null and with predicate"); + value_type* a = nullptr; + auto const wa = ublas::to_strides_v; + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a, wa.data(), v, std::plus<>{} ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if stride is null"); + auto const a = vector_t(s); + std::size_t const* wa = nullptr; + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a.data(), wa, v ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if stride is null and predicate"); + auto const a = vector_t(s); + std::size_t const* wa = nullptr; + BOOST_REQUIRE_THROW( (void)ublas::accumulate( rank, n.data(), a.data(), wa, v, std::plus<>{} ), std::runtime_error ); + } + } + } + + } + + }); + +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/algorithm/test_algorithm_copy.cpp b/test/tensor/algorithm/test_algorithm_copy.cpp new file mode 100644 index 000000000..2c6c797a7 --- /dev/null +++ b/test/tensor/algorithm/test_algorithm_copy.cpp @@ -0,0 +1,442 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_algorithm_copy, + *boost::unit_test::description("Validate Copy Algorithm") + *boost::unit_test::depends_on("test_extents_constructor") + *boost::unit_test::depends_on("test_extents_product") + *boost::unit_test::depends_on("test_strides") +) +constexpr auto check1(auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n) noexcept{ + for(auto i = 0ul; i < n[0]; ++i){ + auto const& le = l[ i * wl[0] ]; + auto const& re = r[ i * wr[0] ]; + BOOST_CHECK_EQUAL(le, re); + } +}; + +constexpr auto check2(auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n) noexcept{ + for(auto i = 0ul; i < n[0]; ++i){ + for(auto j = 0ul; j < n[1]; ++j){ + auto const& le = l[ i * wl[0] + j * wl[1] ]; + auto const& re = r[ i * wr[0] + j * wr[1] ]; + BOOST_CHECK_EQUAL(le, re); + } + } +}; + +constexpr auto check3(auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n) noexcept{ + for(auto i = 0ul; i < n[0]; ++i){ + for(auto j = 0ul; j < n[1]; ++j){ + for(auto k = 0ul; k < n[2]; ++k){ + auto const& le = l[ i * wl[0] + j * wl[1] + k * wl[2] ]; + auto const& re = r[ i * wr[0] + j * wr[1] + k * wr[2] ]; + BOOST_CHECK_EQUAL(le, re); + } + } + } +}; + +constexpr auto check4(auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n) noexcept{ + for(auto i = 0ul; i < n[0]; ++i){ + for(auto j = 0ul; j < n[1]; ++j){ + for(auto k = 0ul; k < n[2]; ++k){ + for(auto m = 0ul; m < n[3]; ++m){ + auto const& le = l[ i * wl[0] + j * wl[1] + k * wl[2] + m * wl[3] ]; + auto const& re = r[ i * wr[0] + j * wr[1] + k * wr[2] + m * wr[3] ]; + BOOST_CHECK_EQUAL(le, re); + } + } + } + } +}; + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("copy_algorithm") + *boost::unit_test::description("Testing copy algorithm using dynamic extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + ValueType, + boost::numeric::ublas::test_types_with_no_layout, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_dynamic; + using value_type = ValueType; + using vector_t = std::vector; + + constexpr auto check = [](auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n){ + if(ublas::size(n) == 1ul) + check1(l, wl, r, wr, n); + else if(ublas::size(n) == 2ul) + check2(l, wl, r, wr, n); + else if(ublas::size(n) == 3ul) + check3(l, wl, r, wr, n); + else if(ublas::size(n) == 4ul) + check4(l, wl, r, wr, n); + else assert(false && "Not Implemented"); + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [check](auto /*id*/, auto const& n){ + constexpr auto first_order = ublas::layout::first_order{}; + constexpr auto last_order = ublas::layout::last_order{}; + + if(ublas::empty(n)) + return; + auto const rank = ublas::size(n); + + BOOST_TEST_CONTEXT("[Copy Algorithm] rank("<< rank <<") dynamic extents"){ + auto a = vector_t(ublas::product(n)); + auto b = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + auto wa = ublas::to_strides(n, first_order); + auto wb = ublas::to_strides(n, last_order ); + auto wc = ublas::to_strides(n, first_order); + + ublas::iota(a, value_type{}); + + ublas::copy( rank, n.data(), b.data(), wb.data(), a.data(), wa.data() ); + ublas::copy( rank, n.data(), c.data(), wc.data(), b.data(), wb.data() ); + + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(c), std::end(c), std::begin(a), std::end(a)); + check(b, wb, a, wa, n); + } + + BOOST_TEST_CONTEXT("[Copy Algorithm(Exception)] rank("<< rank <<") dynamic extents"){ + { + BOOST_TEST_CHECKPOINT("if input is null"); + value_type* a = nullptr; + auto c = vector_t(ublas::product(n)); + + auto const wa = ublas::to_strides(n,first_order); + auto const wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input and output are null"); + value_type* a = nullptr; + value_type* c = nullptr; + + auto const wa = ublas::to_strides(n,first_order); + auto const wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if output is null"); + auto a = vector_t(ublas::product(n)); + value_type* c = nullptr; + + auto const wa = ublas::to_strides(n,first_order); + auto const wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c, wc.data(), a.data(), wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input stride is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t const* wa = nullptr; + auto const wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if output stride is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t const* wc = nullptr; + auto const wa = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if extents pointer is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t const* m = nullptr; + auto const wa = ublas::to_strides(n,first_order); + auto const wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), m, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + } + } + }); + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("copy_algorithm") + *boost::unit_test::description("Testing copy algorithm using static rank extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + ValueType, + boost::numeric::ublas::test_types_with_no_layout, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_static_rank; + using value_type = ValueType; + using vector_t = std::vector; + + constexpr auto check = [](auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n){ + if(ublas::size(n) == 1ul) + check1(l, wl, r, wr, n); + else if(ublas::size(n) == 2ul) + check2(l, wl, r, wr, n); + else if(ublas::size(n) == 3ul) + check3(l, wl, r, wr, n); + else if(ublas::size(n) == 4ul) + check4(l, wl, r, wr, n); + else assert(false && "Not Implemented"); + }; + + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [check](auto /*id*/, auto const& n){ + constexpr auto first_order = ublas::layout::first_order{}; + constexpr auto last_order = ublas::layout::last_order{}; + + if(ublas::empty(n)) + return; + + auto const rank = ublas::size(n); + + BOOST_TEST_CONTEXT("[Copy Algorithm] static rank("<< rank <<") extents"){ + auto a = vector_t(ublas::product(n)); + auto b = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + auto wa = ublas::to_strides(n, first_order); + auto wb = ublas::to_strides(n, last_order ); + auto wc = ublas::to_strides(n, first_order); + + ublas::iota(a, value_type{}); + + ublas::copy( rank, n.data(), b.data(), wb.data(), a.data(), wa.data() ); + ublas::copy( rank, n.data(), c.data(), wc.data(), b.data(), wb.data() ); + + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(c), std::end(c), std::begin(a), std::end(a)); + check(b, wb, a, wa, n); + } + + BOOST_TEST_CONTEXT("[Copy Algorithm(Exception)] static rank("<< rank <<") extents"){ + { + BOOST_TEST_CHECKPOINT("if input is null"); + value_type* a = nullptr; + auto c = vector_t(ublas::product(n)); + + auto const wa = ublas::to_strides(n,first_order); + auto const wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( rank, n.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input and output are null"); + value_type* a = nullptr; + value_type* c = nullptr; + + auto const wa = ublas::to_strides(n,first_order); + auto const wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( rank, n.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if output is null"); + auto a = vector_t(ublas::product(n)); + value_type* c = nullptr; + + auto const wa = ublas::to_strides(n,first_order); + auto const wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( rank, n.data(), c, wc.data(), a.data(), wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input stride is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t const* wa = nullptr; + auto const wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( rank, n.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if output stride is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t const* wc = nullptr; + auto const wa = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( rank, n.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if extents pointer is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t const* m = nullptr; + auto const wa = ublas::to_strides(n,first_order); + auto const wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::copy( rank, m, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + } + } + }); + +} + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("copy_algorithm") + *boost::unit_test::description("Testing copy algorithm using static extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + ValueType, + boost::numeric::ublas::test_types_with_no_layout, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_static; + using value_type = ValueType; + using vector_t = std::vector; + + constexpr auto check = [](auto const& l, auto const& wl, auto const& r, auto const& wr, extents_type const& n){ + if constexpr(ublas::size_v == 1ul){ + for(auto i = 0ul; i < ublas::get_v; ++i){ + auto const& le = l[ i * wl[0] ]; + auto const& re = r[ i * wr[0] ]; + BOOST_CHECK_EQUAL(le, re); + } + }else if constexpr(ublas::size_v == 2ul) + check2(l, wl, r, wr, n); + else if constexpr(ublas::size_v == 3ul) + check3(l, wl, r, wr, n); + else if constexpr(ublas::size_v == 4ul) + check4(l, wl, r, wr, n); + else assert(false && "Not Implemented"); + }; + + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [check](auto /*id*/, extents_type const& n){ + using first_order_t = ublas::layout::first_order; + using last_order_t = ublas::layout::last_order; + + if constexpr(!ublas::empty_v){ + + constexpr auto rank = ublas::size_v; + + // TODO: Enable test for the rank one and the rank two after the issue #119 has been fixed + if constexpr(rank > 2ul){ + + BOOST_TEST_CONTEXT("[Copy Algorithm] rank("<< rank <<") static extents"){ + auto a = vector_t(ublas::product_v); + auto b = vector_t(ublas::product_v); + auto c = vector_t(ublas::product_v); + + auto wa = ublas::to_strides_v; + auto wb = ublas::to_strides_v; + auto wc = ublas::to_strides_v; + + ublas::iota(a, value_type{}); + + ublas::copy( rank, n.data(), b.data(), wb.data(), a.data(), wa.data() ); + ublas::copy( rank, n.data(), c.data(), wc.data(), b.data(), wb.data() ); + + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(c), std::end(c), std::begin(a), std::end(a)); + check(b, wb, a, wa, n); + } + + BOOST_TEST_CONTEXT("[Copy Algorithm(Exception)] rank("<< rank <<") static extents"){ + { + BOOST_TEST_CHECKPOINT("if input is null"); + value_type* a = nullptr; + auto c = vector_t(ublas::product_v); + + auto const wa = ublas::to_strides_v; + auto const wc = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::copy( rank, n.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input and output are null"); + value_type* a = nullptr; + value_type* c = nullptr; + + auto const wa = ublas::to_strides_v; + auto const wc = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::copy( rank, n.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if output is null"); + auto a = vector_t(ublas::product_v); + value_type* c = nullptr; + + auto const wa = ublas::to_strides_v; + auto const wc = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::copy( rank, n.data(), c, wc.data(), a.data(), wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input stride is null"); + auto a = vector_t(ublas::product_v); + auto c = vector_t(ublas::product_v); + + std::size_t const* wa = nullptr; + auto const wc = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::copy( rank, n.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if output stride is null"); + auto a = vector_t(ublas::product_v); + auto c = vector_t(ublas::product_v); + + std::size_t const* wc = nullptr; + auto const wa = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::copy( rank, n.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if extents pointer is null"); + auto a = vector_t(ublas::product_v); + auto c = vector_t(ublas::product_v); + + std::size_t const* m = nullptr; + auto const wa = ublas::to_strides_v; + auto const wc = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::copy( rank, m, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + } + } + } + + } + + }); + +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/algorithm/test_algorithm_trans.cpp b/test/tensor/algorithm/test_algorithm_trans.cpp new file mode 100644 index 000000000..8cda5a307 --- /dev/null +++ b/test/tensor/algorithm/test_algorithm_trans.cpp @@ -0,0 +1,326 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_algorithm_trans, + *boost::unit_test::description("Validate Transpose Algorithm") + *boost::unit_test::depends_on("test_algorithm_copy") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("transpose_algorithm") + *boost::unit_test::description("Testing transpose algorithm using dynamic extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_dynamic; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using vector_t = std::vector; + using permutation_type = std::vector; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& n){ + using base_t = typename extents_type::base_type; + + auto const rank = ublas::size(n); + auto const s = ublas::product(n); + + // FIXME: enbale tests for rank one after the enhancement #120 + if(rank < 2ul) + return; + + BOOST_TEST_CONTEXT("[Transpose Algorithm] rank("<< rank <<") dynamic extents"){ + auto pi = permutation_type(rank); + auto a = vector_t(s); + auto b1 = vector_t(s); + auto b2 = vector_t(s); + auto c1 = vector_t(s); + auto c2 = vector_t(s); + + auto wa = ublas::to_strides(n,layout_type{}); + + ublas::iota(a, value_type{}); + + // so wie last-order. + std::iota(pi.rbegin(), pi.rend(), 1ul); + + auto nc_base = base_t(rank); + for(auto i = 0u; i < rank; ++i) + nc_base[pi[i]-1] = n[i]; + + auto nc = extents_type(std::move(nc_base)); + + auto wc = ublas::to_strides(nc,layout_type{}); + auto wc_pi = base_t(rank); + for(auto i = 0u; i < rank; ++i) + wc_pi[pi[i]-1] = wc[i]; + + ublas::copy ( rank, n.data(), c1.data(), wc_pi.data(), a.data(), wa.data()); + ublas::trans( rank, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() ); + + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(c1), std::end(c1), std::begin(c2), std::end(c2)); + + auto nb_base = base_t(rank); + for(auto i = 0u; i < rank; ++i) + nb_base[pi[i]-1] = nc[i]; + + auto nb = extents_type(std::move(nb_base)); + + auto wb = ublas::to_strides(nb,layout_type{}); + auto wb_pi = base_t(rank); + for(auto i = 0u; i < rank; ++i) + wb_pi[pi[i]-1] = wb[i]; + + ublas::copy ( rank, nc.data(), b1.data(), wb_pi.data(), c1.data(), wc.data()); + ublas::trans( rank, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() ); + + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(b1), std::end(b1), std::begin(b2), std::end(b2)); + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(a), std::end(a), std::begin(b2), std::end(b2)); + } + + BOOST_TEST_CONTEXT("[Transpose Algorithm(Exception)] rank("<< rank <<") dynamic extents"){ + auto pi = permutation_type(rank); + auto a = vector_t(s); + auto c = vector_t(s); + auto wa = ublas::to_strides(n,layout_type{}); + auto wc = ublas::to_strides(n,layout_type{}); + value_type* data = nullptr; + std::size_t* size = nullptr; + BOOST_REQUIRE_THROW( ublas::trans( rank, size , pi.data(), c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , size , c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), size , a.data(), size ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), wc.data(), a.data(), size ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), size , a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), data , wc.data(), data , wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), wc.data(), data , wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), data , wc.data(), a.data(), wa.data() ), std::runtime_error ); + } + }); + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("transpose_algorithm") + *boost::unit_test::description("Testing transpose algorithm using static rank extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_static_rank; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using vector_t = std::vector; + using permutation_type = std::vector; + + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& n){ + using base_t = typename extents_type::base_type; + auto const rank = ublas::size(n); + auto const s = ublas::product(n); + + // FIXME: enbale tests for rank one after the enhancement #120 + if(rank < 2ul) + return; + + BOOST_TEST_CONTEXT("[Transpose Algorithm] static rank("<< rank <<") extents"){ + auto pi = permutation_type(rank); + auto a = vector_t(s); + auto b1 = vector_t(s); + auto b2 = vector_t(s); + auto c1 = vector_t(s); + auto c2 = vector_t(s); + + auto wa = ublas::to_strides(n,layout_type{}); + + ublas::iota(a, value_type{}); + + // so wie last-order. + std::iota(pi.rbegin(), pi.rend(), 1ul); + + auto nc_base = base_t(); + for(auto i = 0u; i < rank; ++i) + nc_base[pi[i]-1] = n[i]; + + auto nc = extents_type(std::move(nc_base)); + + auto wc = ublas::to_strides(nc,layout_type{}); + auto wc_pi = base_t(); + for(auto i = 0u; i < rank; ++i) + wc_pi[pi[i]-1] = wc[i]; + + ublas::copy ( rank, n.data(), c1.data(), wc_pi.data(), a.data(), wa.data()); + ublas::trans( rank, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() ); + + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(c1), std::end(c1), std::begin(c2), std::end(c2)); + + auto nb_base = base_t(); + for(auto i = 0u; i < rank; ++i) + nb_base[pi[i]-1] = nc[i]; + + auto nb = extents_type(std::move(nb_base)); + + auto wb = ublas::to_strides(nb,layout_type{}); + auto wb_pi = base_t(); + for(auto i = 0u; i < rank; ++i) + wb_pi[pi[i]-1] = wb[i]; + + ublas::copy ( rank, nc.data(), b1.data(), wb_pi.data(), c1.data(), wc.data()); + ublas::trans( rank, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() ); + + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(b1), std::end(b1), std::begin(b2), std::end(b2)); + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(a), std::end(a), std::begin(b2), std::end(b2)); + } + + BOOST_TEST_CONTEXT("[Transpose Algorithm(Exception)] static rank("<< rank <<") extents"){ + auto pi = permutation_type(rank); + auto a = vector_t(s); + auto c = vector_t(s); + auto wa = ublas::to_strides(n,layout_type{}); + auto wc = ublas::to_strides(n,layout_type{}); + value_type* data = nullptr; + std::size_t* size = nullptr; + BOOST_REQUIRE_THROW( ublas::trans( rank, size , pi.data(), c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , size , c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), size , a.data(), size ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), wc.data(), a.data(), size ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), size , a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), data , wc.data(), data , wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), wc.data(), data , wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), data , wc.data(), a.data(), wa.data() ), std::runtime_error ); + } + }); + +} + +template +constexpr auto generate_permuated_extents() noexcept{ + namespace ublas = boost::numeric::ublas; + using value_type = typename E::value_type; + constexpr auto sz = ublas::size_v; + + + constexpr auto helper = [](std::index_sequence ids){ + constexpr auto helper1 = [](){ + std::array pi; + (( pi[sz - Is - 1ul] = ublas::get_v ),...); + return pi; + }; + constexpr auto arr = helper1(); + return ublas::extents_core{}; + }; + + return helper(std::make_index_sequence{}); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("transpose_algorithm") + *boost::unit_test::description("Testing transpose algorithm using staticextents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_static; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using vector_t = std::vector; + using permutation_type = std::vector; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& n){ + using base_t = typename extents_type::base_type; + constexpr auto rank = ublas::size_v; + constexpr auto s = ublas::product_v; + + // FIXME: Enable test for the rank one and the rank two after the issue #119 has been fixed + if constexpr(rank > 2ul){ + + BOOST_TEST_CONTEXT("[Transpose Algorithm] rank("<< rank <<") static extents"){ + auto pi = permutation_type(rank); + auto a = vector_t(s); + auto b1 = vector_t(s); + auto b2 = vector_t(s); + auto c1 = vector_t(s); + auto c2 = vector_t(s); + + constexpr auto wa = ublas::to_strides_v; + + ublas::iota(a, value_type{}); + + // so wie last-order. + std::iota(pi.rbegin(), pi.rend(), 1ul); + + constexpr auto nc = generate_permuated_extents(); + constexpr auto wc = ublas::to_strides_v; + + auto wc_pi = base_t(); + for(auto i = 0u; i < rank; ++i) + wc_pi[pi[i]-1] = wc[i]; + + ublas::copy ( rank, n.data(), c1.data(), wc_pi.data(), a.data(), wa.data()); + ublas::trans( rank, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() ); + + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(c1), std::end(c1), std::begin(c2), std::end(c2)); + + constexpr auto nb = generate_permuated_extents(); + constexpr auto wb = ublas::to_strides_v; + + auto wb_pi = base_t(); + for(auto i = 0u; i < rank; ++i) + wb_pi[pi[i]-1] = wb[i]; + + ublas::copy ( rank, nc.data(), b1.data(), wb_pi.data(), c1.data(), wc.data()); + ublas::trans( rank, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() ); + + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(b1), std::end(b1), std::begin(b2), std::end(b2)); + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(a), std::end(a), std::begin(b2), std::end(b2)); + } + + BOOST_TEST_CONTEXT("[Transpose Algorithm(Exception)] rank("<< rank <<") static extents"){ + auto pi = permutation_type(rank); + auto a = vector_t(s); + auto c = vector_t(s); + constexpr auto wa = ublas::to_strides_v; + constexpr auto wc = ublas::to_strides_v; + value_type* data = nullptr; + std::size_t* size = nullptr; + BOOST_REQUIRE_THROW( ublas::trans( rank, size , pi.data(), c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , size , c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), size , a.data(), size ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), wc.data(), a.data(), size ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), size , a.data(), wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), data , wc.data(), data , wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), c.data(), wc.data(), data , wa.data() ), std::runtime_error ); + BOOST_REQUIRE_THROW( ublas::trans( rank, n.data() , pi.data(), data , wc.data(), a.data(), wa.data() ), std::runtime_error ); + } + + } + + }); + +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/algorithm/test_algorithm_transform.cpp b/test/tensor/algorithm/test_algorithm_transform.cpp new file mode 100644 index 000000000..a245abedc --- /dev/null +++ b/test/tensor/algorithm/test_algorithm_transform.cpp @@ -0,0 +1,473 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_algorithm_transform, + *boost::unit_test::description("Validate Transfrom Algorithm") + *boost::unit_test::depends_on("test_extents_constructor") + *boost::unit_test::depends_on("test_extents_product") + *boost::unit_test::depends_on("test_strides") +) + +template +constexpr auto check1(auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n, FnType&& pred) noexcept{ + for(auto i = 0ul; i < n[0]; ++i){ + auto const& le = l[ i * wl[0] ]; + auto const& re = r[ i * wr[0] ]; + BOOST_CHECK( std::invoke(std::forward(pred), le, re) ); + } +}; + +template +constexpr auto check2(auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n, FnType&& pred) noexcept{ + for(auto i = 0ul; i < n[0]; ++i){ + for(auto j = 0ul; j < n[1]; ++j){ + auto const& le = l[ i * wl[0] + j * wl[1] ]; + auto const& re = r[ i * wr[0] + j * wr[1] ]; + BOOST_CHECK( std::invoke(std::forward(pred), le, re) ); + } + } +}; + +template +constexpr auto check3(auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n, FnType&& pred) noexcept{ + for(auto i = 0ul; i < n[0]; ++i){ + for(auto j = 0ul; j < n[1]; ++j){ + for(auto k = 0ul; k < n[2]; ++k){ + auto const& le = l[ i * wl[0] + j * wl[1] + k * wl[2] ]; + auto const& re = r[ i * wr[0] + j * wr[1] + k * wr[2] ]; + BOOST_CHECK( std::invoke(std::forward(pred), le, re) ); + } + } + } +}; + +template +constexpr auto check4(auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n, FnType&& pred) noexcept{ + for(auto i = 0ul; i < n[0]; ++i){ + for(auto j = 0ul; j < n[1]; ++j){ + for(auto k = 0ul; k < n[2]; ++k){ + for(auto m = 0ul; m < n[3]; ++m){ + auto const& le = l[ i * wl[0] + j * wl[1] + k * wl[2] + m * wl[3] ]; + auto const& re = r[ i * wr[0] + j * wr[1] + k * wr[2] + m * wr[3] ]; + BOOST_CHECK( std::invoke(std::forward(pred), le, re) ); + } + } + } + } +}; + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("transform_algorithm") + *boost::unit_test::description("Testing transform algorithm using dynamic extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + ValueType, + boost::numeric::ublas::test_types_with_no_layout, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_dynamic; + using value_type = ValueType; + using vector_t = std::vector; + + constexpr auto check = [](auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n, FnType&& pred){ + if(ublas::size(n) == 1ul) + check1(l, wl, r, wr, n, std::forward(pred)); + else if(ublas::size(n) == 2ul) + check2(l, wl, r, wr, n, std::forward(pred)); + else if(ublas::size(n) == 3ul) + check3(l, wl, r, wr, n, std::forward(pred)); + else if(ublas::size(n) == 4ul) + check4(l, wl, r, wr, n, std::forward(pred)); + else assert(false && "Not Implemented"); + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [check](auto /*id*/, auto const& n){ + constexpr auto first_order = ublas::layout::first_order{}; + constexpr auto last_order = ublas::layout::last_order{}; + + constexpr auto add_one = [](auto const& a){ return a + value_type{1}; }; + constexpr auto sub_one = [](auto const& a){ return a - value_type{1}; }; + + if(ublas::empty(n)) + return; + auto const rank = ublas::size(n); + + BOOST_TEST_CONTEXT("[Transform Algorithm] rank("<< rank <<") dynamic extents"){ + auto a = vector_t(ublas::product(n)); + auto b = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + auto wa = ublas::to_strides(n, first_order); + auto wb = ublas::to_strides(n, last_order ); + auto wc = ublas::to_strides(n, first_order); + + ublas::iota(a, value_type{}); + + ublas::transform( rank, n.data(), b.data(), wb.data(), a.data(), wa.data(), add_one ); + ublas::transform( rank, n.data(), c.data(), wc.data(), b.data(), wb.data(), sub_one ); + + check(b, wb, a, wa, n, [](auto const& l, auto const& r){ return l == (r + value_type{1}); }); + check(c, wc, b, wb, n, [](auto const& l, auto const& r){ return l == (r - value_type{1}); }); + + auto zero = std::size_t{0}; + ublas::transform(zero, n.data(), c.data(), wc.data(), b.data(), wb.data(), add_one ); + + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(c), std::end(c), std::begin(a), std::end(a)); + } + + BOOST_TEST_CONTEXT("[Transform Algorithm(Exception)] rank("<< rank <<") dynamic extents"){ + { + BOOST_TEST_CHECKPOINT("if input is null"); + value_type* a = nullptr; + auto c = vector_t(ublas::product(n)); + + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c.data(), wc.data(), a, wa.data(), add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input and output is null"); + value_type* a = nullptr; + value_type* c = nullptr; + + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c, wc.data(), a, wa.data(), add_one), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if output is null"); + auto a = vector_t(ublas::product(n)); + value_type* c = nullptr; + + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c, wc.data(), a.data(), wa.data(), add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input stride is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t* wa = nullptr; + auto wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c.data(), wc.data(), a.data(), wa, add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input stride is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t* wc = nullptr; + auto wa = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c.data(), wc, a.data(), wa.data(), add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if extents is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t* m = nullptr; + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, m, c.data(), wc.data(), a.data(), wa.data(), add_one ), std::runtime_error ); + } + + } + }); + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("transform_algorithm") + *boost::unit_test::description("Testing transform algorithm using static rank extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + ValueType, + boost::numeric::ublas::test_types_with_no_layout, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_static_rank; + using value_type = ValueType; + using vector_t = std::vector; + + constexpr auto check = [](auto const& l, auto const& wl, auto const& r, auto const& wr, auto const& n, FnType&& pred){ + if(ublas::size(n) == 1ul) + check1(l, wl, r, wr, n, std::forward(pred)); + else if(ublas::size(n) == 2ul) + check2(l, wl, r, wr, n, std::forward(pred)); + else if(ublas::size(n) == 3ul) + check3(l, wl, r, wr, n, std::forward(pred)); + else if(ublas::size(n) == 4ul) + check4(l, wl, r, wr, n, std::forward(pred)); + else assert(false && "Not Implemented"); + }; + + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [check](auto /*id*/, auto const& n){ + constexpr auto first_order = ublas::layout::first_order{}; + constexpr auto last_order = ublas::layout::last_order{}; + + constexpr auto add_one = [](auto const& a){ return a + value_type{1}; }; + constexpr auto sub_one = [](auto const& a){ return a - value_type{1}; }; + + if(ublas::empty(n)) + return; + + auto const rank = ublas::size(n); + + BOOST_TEST_CONTEXT("[Transform Algorithm] static rank("<< rank <<") extents"){ + auto a = vector_t(ublas::product(n)); + auto b = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + auto wa = ublas::to_strides(n, first_order); + auto wb = ublas::to_strides(n, last_order ); + auto wc = ublas::to_strides(n, first_order); + + ublas::iota(a, value_type{}); + + ublas::transform( rank, n.data(), b.data(), wb.data(), a.data(), wa.data(), add_one ); + ublas::transform( rank, n.data(), c.data(), wc.data(), b.data(), wb.data(), sub_one ); + + check(b, wb, a, wa, n, [](auto const& l, auto const& r){ return l == (r + value_type{1}); }); + check(c, wc, b, wb, n, [](auto const& l, auto const& r){ return l == (r - value_type{1}); }); + + auto zero = std::size_t{0}; + ublas::transform(zero, n.data(), c.data(), wc.data(), b.data(), wb.data(), add_one ); + + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(c), std::end(c), std::begin(a), std::end(a)); + } + + BOOST_TEST_CONTEXT("[Transform Algorithm(Exception)] static rank("<< rank <<") extents"){ + { + BOOST_TEST_CHECKPOINT("if input is null"); + value_type* a = nullptr; + auto c = vector_t(ublas::product(n)); + + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c.data(), wc.data(), a, wa.data(), add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input and output is null"); + value_type* a = nullptr; + value_type* c = nullptr; + + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c, wc.data(), a, wa.data(), add_one), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if output is null"); + auto a = vector_t(ublas::product(n)); + value_type* c = nullptr; + + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c, wc.data(), a.data(), wa.data(), add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input stride is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t* wa = nullptr; + auto wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c.data(), wc.data(), a.data(), wa, add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input stride is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t* wc = nullptr; + auto wa = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c.data(), wc, a.data(), wa.data(), add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if extents is null"); + auto a = vector_t(ublas::product(n)); + auto c = vector_t(ublas::product(n)); + + std::size_t* m = nullptr; + auto wa = ublas::to_strides(n,first_order); + auto wc = ublas::to_strides(n,first_order); + + BOOST_REQUIRE_THROW( ublas::transform( rank, m, c.data(), wc.data(), a.data(), wa.data(), add_one ), std::runtime_error ); + } + } + }); + +} + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("transform_algorithm") + *boost::unit_test::description("Testing transform algorithm using static extents") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + ValueType, + boost::numeric::ublas::test_types_with_no_layout, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using fixture_t = ublas::fixture_extents_static; + using value_type = ValueType; + using vector_t = std::vector; + + constexpr auto check = [](auto const& l, auto const& wl, auto const& r, auto const& wr, extents_type const& n, FnType&& pred){ + if constexpr(ublas::size_v == 1ul){ + for(auto i = 0ul; i < ublas::get_v; ++i){ + auto const& le = l[ i * wl[0] ]; + auto const& re = r[ i * wr[0] ]; + BOOST_CHECK( std::invoke(std::forward(pred), le, re) ); + } + }else if constexpr(ublas::size_v == 2ul) + check2(l, wl, r, wr, n, std::forward(pred)); + else if constexpr(ublas::size_v == 3ul) + check3(l, wl, r, wr, n, std::forward(pred)); + else if constexpr(ublas::size_v == 4ul) + check4(l, wl, r, wr, n, std::forward(pred)); + else assert(false && "Not Implemented"); + }; + + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [check](auto /*id*/, extents_type const& n){ + using first_order_t = ublas::layout::first_order; + using last_order_t = ublas::layout::last_order; + + constexpr auto add_one = [](auto const& a){ return a + value_type{1}; }; + constexpr auto sub_one = [](auto const& a){ return a - value_type{1}; }; + + + if constexpr(!ublas::empty_v){ + + constexpr auto rank = ublas::size_v; + + // TODO: Enable test for the rank one and the rank two after the issue #119 has been fixed + if constexpr(rank > 2ul){ + + BOOST_TEST_CONTEXT("[Transform Algorithm] rank("<< rank <<") static extents"){ + auto a = vector_t(ublas::product_v); + auto b = vector_t(ublas::product_v); + auto c = vector_t(ublas::product_v); + + auto wa = ublas::to_strides_v; + auto wb = ublas::to_strides_v; + auto wc = ublas::to_strides_v; + + ublas::iota(a, value_type{}); + + ublas::transform( ublas::size(n), n.data(), b.data(), wb.data(), a.data(), wa.data(), add_one ); + ublas::transform( ublas::size(n), n.data(), c.data(), wc.data(), b.data(), wb.data(), sub_one ); + + check(b, wb, a, wa, n, [](auto const& l, auto const& r){ return l == (r + value_type{1}); }); + check(c, wc, b, wb, n, [](auto const& l, auto const& r){ return l == (r - value_type{1}); }); + + auto zero = std::size_t{0}; + ublas::transform(zero, n.data(), c.data(), wc.data(), b.data(), wb.data(), add_one ); + + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(c), std::end(c), std::begin(a), std::end(a)); + } + + BOOST_TEST_CONTEXT("[Transform Algorithm(Exception)] rank("<< rank <<") static extents"){ + { + BOOST_TEST_CHECKPOINT("if input is null"); + value_type* a = nullptr; + auto c = vector_t(ublas::product_v); + + auto wa = ublas::to_strides_v; + auto wc = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c.data(), wc.data(), a, wa.data(), add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input and output is null"); + value_type* a = nullptr; + value_type* c = nullptr; + + auto wa = ublas::to_strides_v; + auto wc = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c, wc.data(), a, wa.data(), add_one), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if output is null"); + auto a = vector_t(ublas::product_v); + value_type* c = nullptr; + + auto wa = ublas::to_strides_v; + auto wc = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c, wc.data(), a.data(), wa.data(), add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input stride is null"); + auto a = vector_t(ublas::product_v); + auto c = vector_t(ublas::product_v); + + std::size_t* wa = nullptr; + auto wc = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c.data(), wc.data(), a.data(), wa, add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if input stride is null"); + auto a = vector_t(ublas::product_v); + auto c = vector_t(ublas::product_v); + + std::size_t* wc = nullptr; + auto wa = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::transform( rank, n.data(), c.data(), wc, a.data(), wa.data(), add_one ), std::runtime_error ); + } + { + BOOST_TEST_CHECKPOINT("if extents is null"); + auto a = vector_t(ublas::product_v); + auto c = vector_t(ublas::product_v); + + std::size_t* m = nullptr; + auto wa = ublas::to_strides_v; + auto wc = ublas::to_strides_v; + + BOOST_REQUIRE_THROW( ublas::transform( rank, m, c.data(), wc.data(), a.data(), wa.data(), add_one ), std::runtime_error ); + } + } + } + + } + + }); + +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_access_operator.cpp b/test/tensor/extents/test_extents_access_operator.cpp new file mode 100644 index 000000000..9d9edb8a5 --- /dev/null +++ b/test/tensor/extents/test_extents_access_operator.cpp @@ -0,0 +1,137 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_extents_access_operator, + *boost::unit_test::description("Validate Access Operator") + *boost::unit_test::depends_on("test_extents_size") +) + + +constexpr auto check_at(auto const& e, std::initializer_list l){ + auto i = 0ul; + for(auto const& el : l){ + BOOST_REQUIRE_EQUAL(e[i++], el); + } +}; + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_function, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("[read]boost::numeric::ublas::extents<>::operator[]") + *boost::unit_test::description("Testing the dynamic extents' read [operator[]]")) +{ + namespace ublas = boost::numeric::ublas; + + + BOOST_TEST_CONTEXT("[At Method] rank(1) dynamic extents"){ + check_at(n1, {1}); + check_at(n2, {2}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(2) dynamic extents"){ + check_at(n11, {1,1}); + check_at(n12, {1,2}); + check_at(n21, {2,1}); + check_at(n22, {2,2}); + check_at(n32, {3,2}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(3) dynamic extents"){ + check_at(n111, {1ul, 1ul, 1ul}); + check_at(n112, {1ul, 1ul, 2ul}); + check_at(n121, {1ul, 2ul, 1ul}); + check_at(n123, {1ul, 2ul, 3ul}); + check_at(n211, {2ul, 1ul, 1ul}); + check_at(n213, {2ul, 1ul, 3ul}); + check_at(n321, {3ul, 2ul, 1ul}); + check_at(n432, {4ul, 3ul, 2ul}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(4) dynamic extents"){ + check_at(n1111, {1ul, 1ul, 1ul, 1ul}); + check_at(n4231, {4ul, 2ul, 3ul, 1ul}); + } + +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_function, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("[read]boost::numeric::ublas::extents::operator[]") + *boost::unit_test::description("Testing the static rank extents' read [operator[]]")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[At Method] rank(1) static rank extents"){ + check_at(n1, {1}); + check_at(n2, {2}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(2) static rank extents"){ + check_at(n11, {1,1}); + check_at(n12, {1,2}); + check_at(n21, {2,1}); + check_at(n22, {2,2}); + check_at(n32, {3,2}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(3) static rank extents"){ + check_at(n111, {1ul, 1ul, 1ul}); + check_at(n112, {1ul, 1ul, 2ul}); + check_at(n121, {1ul, 2ul, 1ul}); + check_at(n123, {1ul, 2ul, 3ul}); + check_at(n211, {2ul, 1ul, 1ul}); + check_at(n213, {2ul, 1ul, 3ul}); + check_at(n321, {3ul, 2ul, 1ul}); + check_at(n432, {4ul, 3ul, 2ul}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(4) static rank extents"){ + check_at(n1111, {1ul, 1ul, 1ul, 1ul}); + check_at(n4231, {4ul, 2ul, 3ul, 1ul}); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_function, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("[read]boost::numeric::ublas::extents<...>::operator[]") + *boost::unit_test::description("Testing the static extents' read [operator[]]")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[At Method] rank(2) static extents"){ + check_at(n11, {1,1}); + check_at(n12, {1,2}); + check_at(n21, {2,1}); + check_at(n22, {2,2}); + check_at(n32, {3,2}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(3) static extents"){ + check_at(n111, {1ul, 1ul, 1ul}); + check_at(n112, {1ul, 1ul, 2ul}); + check_at(n121, {1ul, 2ul, 1ul}); + check_at(n123, {1ul, 2ul, 3ul}); + check_at(n211, {2ul, 1ul, 1ul}); + check_at(n213, {2ul, 1ul, 3ul}); + check_at(n321, {3ul, 2ul, 1ul}); + check_at(n432, {4ul, 3ul, 2ul}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(4) static extents"){ + check_at(n1111, {1ul, 1ul, 1ul, 1ul}); + check_at(n4231, {4ul, 2ul, 3ul, 1ul}); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_assignment_operator.cpp b/test/tensor/extents/test_extents_assignment_operator.cpp new file mode 100644 index 000000000..ec4c6c1e3 --- /dev/null +++ b/test/tensor/extents/test_extents_assignment_operator.cpp @@ -0,0 +1,112 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_extents_assignement_operator, + *boost::unit_test::description("Validate extents operator=(...)") + *boost::unit_test::depends_on("test_extents_constructor") +) + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("boost::numeric::ublas::extents<>::operator=(...)") + *boost::unit_test::description("Testing dynamic extents assignment operator")) +{ + namespace ublas = boost::numeric::ublas; + using extents_type = ublas::extents<>; + + BOOST_TEST_CONTEXT("[Dynamic Extents Assignment Operator] copy extents"){ + auto e = extents_type(); + BOOST_REQUIRE ( ublas::empty(e)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 0ul); + + e = n4231; + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE_EQUAL ( e[0], 4ul); + BOOST_REQUIRE_EQUAL ( e[1], 2ul); + BOOST_REQUIRE_EQUAL ( e[2], 3ul); + BOOST_REQUIRE_EQUAL ( e[3], 1ul); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents Assignment Operator] copy extents"){ + auto temp = n4231; + + auto e = extents_type(); + BOOST_REQUIRE ( ublas::empty(e)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 0ul); + + e = std::move(temp); + BOOST_REQUIRE ( ublas::empty(temp)); + BOOST_REQUIRE_EQUAL ( ublas::size(temp), 0ul); + + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE_EQUAL ( e[0], 4ul); + BOOST_REQUIRE_EQUAL ( e[1], 2ul); + BOOST_REQUIRE_EQUAL ( e[2], 3ul); + BOOST_REQUIRE_EQUAL ( e[3], 1ul); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + } + +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("boost::numeric::ublas::extents::operator=(...)") + *boost::unit_test::description("Testing static_rank extents assignment operator")) +{ + namespace ublas = boost::numeric::ublas; + using extents_type = ublas::extents<4>; + + BOOST_TEST_CONTEXT("[Static Rank Extents Assignment Operator] copy extents"){ + auto e = extents_type(); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + + e = n4231; + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE_EQUAL ( e[0], 4ul); + BOOST_REQUIRE_EQUAL ( e[1], 2ul); + BOOST_REQUIRE_EQUAL ( e[2], 3ul); + BOOST_REQUIRE_EQUAL ( e[3], 1ul); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents Assignment Operator] copy extents"){ + auto temp = n4231; + + auto e = extents_type(); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + + e = std::move(temp); + BOOST_REQUIRE (!ublas::empty(temp)); + BOOST_REQUIRE_EQUAL ( ublas::size(temp), 4ul); + + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE_EQUAL ( e[0], 4ul); + BOOST_REQUIRE_EQUAL ( e[1], 2ul); + BOOST_REQUIRE_EQUAL ( e[2], 3ul); + BOOST_REQUIRE_EQUAL ( e[3], 1ul); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + } + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_at.cpp b/test/tensor/extents/test_extents_at.cpp new file mode 100644 index 000000000..6a387d481 --- /dev/null +++ b/test/tensor/extents/test_extents_at.cpp @@ -0,0 +1,136 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_extents_at, + *boost::unit_test::description("Validate At Method") + *boost::unit_test::depends_on("test_extents_size") +) + +constexpr auto check_at(auto const& e, std::initializer_list l){ + auto i = 0ul; + for(auto const& el : l){ + BOOST_REQUIRE_EQUAL(e.at(i++), el); + } +}; + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_function, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("[read]boost::numeric::ublas::extents<>::at") + *boost::unit_test::description("Testing the dynamic extents' read [at] method")) +{ + namespace ublas = boost::numeric::ublas; + + + BOOST_TEST_CONTEXT("[At Method] rank(1) dynamic extents"){ + check_at(n1, {1}); + check_at(n2, {2}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(2) dynamic extents"){ + check_at(n11, {1,1}); + check_at(n12, {1,2}); + check_at(n21, {2,1}); + check_at(n22, {2,2}); + check_at(n32, {3,2}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(3) dynamic extents"){ + check_at(n111, {1ul, 1ul, 1ul}); + check_at(n112, {1ul, 1ul, 2ul}); + check_at(n121, {1ul, 2ul, 1ul}); + check_at(n123, {1ul, 2ul, 3ul}); + check_at(n211, {2ul, 1ul, 1ul}); + check_at(n213, {2ul, 1ul, 3ul}); + check_at(n321, {3ul, 2ul, 1ul}); + check_at(n432, {4ul, 3ul, 2ul}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(4) dynamic extents"){ + check_at(n1111, {1ul, 1ul, 1ul, 1ul}); + check_at(n4231, {4ul, 2ul, 3ul, 1ul}); + } + +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_function, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("[read]boost::numeric::ublas::extents::at") + *boost::unit_test::description("Testing the static rank extents' read [at] method")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[At Method] rank(1) static rank extents"){ + check_at(n1, {1}); + check_at(n2, {2}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(2) static rank extents"){ + check_at(n11, {1,1}); + check_at(n12, {1,2}); + check_at(n21, {2,1}); + check_at(n22, {2,2}); + check_at(n32, {3,2}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(3) static rank extents"){ + check_at(n111, {1ul, 1ul, 1ul}); + check_at(n112, {1ul, 1ul, 2ul}); + check_at(n121, {1ul, 2ul, 1ul}); + check_at(n123, {1ul, 2ul, 3ul}); + check_at(n211, {2ul, 1ul, 1ul}); + check_at(n213, {2ul, 1ul, 3ul}); + check_at(n321, {3ul, 2ul, 1ul}); + check_at(n432, {4ul, 3ul, 2ul}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(4) static rank extents"){ + check_at(n1111, {1ul, 1ul, 1ul, 1ul}); + check_at(n4231, {4ul, 2ul, 3ul, 1ul}); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_function, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("[read]boost::numeric::ublas::extents<...>::at") + *boost::unit_test::description("Testing the static extents' read [at] method")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[At Method] rank(2) static extents"){ + check_at(n11, {1,1}); + check_at(n12, {1,2}); + check_at(n21, {2,1}); + check_at(n22, {2,2}); + check_at(n32, {3,2}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(3) static extents"){ + check_at(n111, {1ul, 1ul, 1ul}); + check_at(n112, {1ul, 1ul, 2ul}); + check_at(n121, {1ul, 2ul, 1ul}); + check_at(n123, {1ul, 2ul, 3ul}); + check_at(n211, {2ul, 1ul, 1ul}); + check_at(n213, {2ul, 1ul, 3ul}); + check_at(n321, {3ul, 2ul, 1ul}); + check_at(n432, {4ul, 3ul, 2ul}); + } + + BOOST_TEST_CONTEXT("[At Method] rank(4) static extents"){ + check_at(n1111, {1ul, 1ul, 1ul, 1ul}); + check_at(n4231, {4ul, 2ul, 3ul, 1ul}); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_comparision.cpp b/test/tensor/extents/test_extents_comparision.cpp new file mode 100644 index 000000000..e6858a262 --- /dev/null +++ b/test/tensor/extents/test_extents_comparision.cpp @@ -0,0 +1,219 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#include +#include "../fixture_utility.hpp" + + +BOOST_AUTO_TEST_SUITE(test_extents_compare, + *boost::unit_test::description("Validate extents' comparision operator/function") +) + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("cmp_equality") + *boost::unit_test::description("Testing equality comparision for the dynamic extents")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(0) dynamic extents"){ + BOOST_CHECK( n == n ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(1) dynamic extents"){ + BOOST_CHECK( n1 == n1 ); + BOOST_CHECK( n2 == n2 ); + + BOOST_CHECK( n1 != n2 ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(2) dynamic extents"){ + BOOST_CHECK( n11 == n11 ); + BOOST_CHECK( n12 == n12 ); + BOOST_CHECK( n21 == n21 ); + BOOST_CHECK( n22 == n22 ); + BOOST_CHECK( n32 == n32 ); + + BOOST_CHECK( n11 != n12 ); + BOOST_CHECK( n12 != n21 ); + BOOST_CHECK( n21 != n22 ); + BOOST_CHECK( n22 != n32 ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(3) dynamic extents"){ + BOOST_CHECK( n111 == n111 ); + BOOST_CHECK( n112 == n112 ); + BOOST_CHECK( n121 == n121 ); + BOOST_CHECK( n123 == n123 ); + BOOST_CHECK( n211 == n211 ); + BOOST_CHECK( n213 == n213 ); + BOOST_CHECK( n321 == n321 ); + BOOST_CHECK( n432 == n432 ); + + BOOST_CHECK( n111 != n112 ); + BOOST_CHECK( n112 != n121 ); + BOOST_CHECK( n121 != n123 ); + BOOST_CHECK( n123 != n211 ); + BOOST_CHECK( n211 != n213 ); + BOOST_CHECK( n213 != n321 ); + BOOST_CHECK( n321 != n432 ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(4) dynamic extents"){ + BOOST_CHECK( n1111 == n1111 ); + BOOST_CHECK( n4231 == n4231 ); + + BOOST_CHECK( n1111 != n4231 ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] different rank dynamic extents"){ + BOOST_CHECK( n != n1 ); + BOOST_CHECK( n1 != n11 ); + BOOST_CHECK( n11 != n111 ); + BOOST_CHECK( n111 != n1111 ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("cmp_equality") + *boost::unit_test::description("Testing equality comparision for the static rank extents")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(0) extents"){ + BOOST_CHECK( n == n ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(1) extents"){ + BOOST_CHECK( n1 == n1 ); + BOOST_CHECK( n2 == n2 ); + + BOOST_CHECK( n1 != n2 ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(2) extents"){ + BOOST_CHECK( n11 == n11 ); + BOOST_CHECK( n12 == n12 ); + BOOST_CHECK( n21 == n21 ); + BOOST_CHECK( n22 == n22 ); + BOOST_CHECK( n32 == n32 ); + + BOOST_CHECK( n11 != n12 ); + BOOST_CHECK( n12 != n21 ); + BOOST_CHECK( n21 != n22 ); + BOOST_CHECK( n22 != n32 ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(3) extents"){ + BOOST_CHECK( n111 == n111 ); + BOOST_CHECK( n112 == n112 ); + BOOST_CHECK( n121 == n121 ); + BOOST_CHECK( n123 == n123 ); + BOOST_CHECK( n211 == n211 ); + BOOST_CHECK( n213 == n213 ); + BOOST_CHECK( n321 == n321 ); + BOOST_CHECK( n432 == n432 ); + + BOOST_CHECK( n111 != n112 ); + BOOST_CHECK( n112 != n121 ); + BOOST_CHECK( n121 != n123 ); + BOOST_CHECK( n123 != n211 ); + BOOST_CHECK( n211 != n213 ); + BOOST_CHECK( n213 != n321 ); + BOOST_CHECK( n321 != n432 ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(4) extents"){ + BOOST_CHECK( n1111 == n1111 ); + BOOST_CHECK( n4231 == n4231 ); + + BOOST_CHECK( n1111 != n4231 ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] different static rank extents"){ + BOOST_CHECK( n != n1 ); + BOOST_CHECK( n1 != n11 ); + BOOST_CHECK( n11 != n111 ); + BOOST_CHECK( n111 != n1111 ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("cmp_equality") + *boost::unit_test::description("Testing equality comparision for the static extents")) +{ + namespace ublas = boost::numeric::ublas; + + + BOOST_TEST_CONTEXT("[Static Extents] rank(0) static extents"){ + BOOST_CHECK( n_type{} == n_type{} ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(1) static extents"){ + BOOST_CHECK( n1 == n1 ); + BOOST_CHECK( n2 == n2 ); + + BOOST_CHECK( n1 != n2 ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(2) static extents"){ + BOOST_CHECK( n11 == n11 ); + BOOST_CHECK( n12 == n12 ); + BOOST_CHECK( n21 == n21 ); + BOOST_CHECK( n22 == n22 ); + BOOST_CHECK( n32 == n32 ); + + BOOST_CHECK( n11 != n12 ); + BOOST_CHECK( n12 != n21 ); + BOOST_CHECK( n21 != n22 ); + BOOST_CHECK( n22 != n32 ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(3) static extents"){ + BOOST_CHECK( n111 == n111 ); + BOOST_CHECK( n112 == n112 ); + BOOST_CHECK( n121 == n121 ); + BOOST_CHECK( n123 == n123 ); + BOOST_CHECK( n211 == n211 ); + BOOST_CHECK( n213 == n213 ); + BOOST_CHECK( n321 == n321 ); + BOOST_CHECK( n432 == n432 ); + + BOOST_CHECK( n111 != n112 ); + BOOST_CHECK( n112 != n121 ); + BOOST_CHECK( n121 != n123 ); + BOOST_CHECK( n123 != n211 ); + BOOST_CHECK( n211 != n213 ); + BOOST_CHECK( n213 != n321 ); + BOOST_CHECK( n321 != n432 ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(4) static extents"){ + BOOST_CHECK( n1111 == n1111 ); + BOOST_CHECK( n4231 == n4231 ); + + BOOST_CHECK( n1111 != n4231 ); + } + + BOOST_TEST_CONTEXT("[Static Extents] different rank static extents"){ + BOOST_CHECK( n_type{} != n1 ); + BOOST_CHECK( n1 != n11 ); + BOOST_CHECK( n11 != n111 ); + BOOST_CHECK( n111 != n1111 ); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_construction.cpp b/test/tensor/extents/test_extents_construction.cpp new file mode 100644 index 000000000..25edcf452 --- /dev/null +++ b/test/tensor/extents/test_extents_construction.cpp @@ -0,0 +1,255 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_extents_constructor, + *boost::unit_test::description("Validate constructor") + *boost::unit_test::depends_on("test_extents_empty") + *boost::unit_test::depends_on("test_extents_size") + *boost::unit_test::depends_on("test_extents_at") + *boost::unit_test::depends_on("test_extents_access_operator") +) + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("boost::numeric::ublas::extents<>(...)") + *boost::unit_test::description("Testing dynamic extents construction")) +{ + namespace ublas = boost::numeric::ublas; + using extents_type = ublas::extents<>; + + BOOST_TEST_CONTEXT("[Dynamic Extents Constructor] default constructor"){ + auto e = extents_type(); + BOOST_REQUIRE_EQUAL (ublas::size(e), 0ul); + BOOST_REQUIRE (ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(0), std::out_of_range); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents Constructor] construction using base type"){ + using extents_base_type = typename extents_type::base_type; + extents_base_type vec {1,2,3,4,5}; + auto e = extents_type(std::move(vec)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 5ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 1ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 4ul); + BOOST_REQUIRE_EQUAL (e[4], 5ul); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents Constructor] construction using initilizer list"){ + auto e = extents_type{1,2,3,4,5}; + BOOST_REQUIRE_EQUAL ( ublas::size(e), 5ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 1ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 4ul); + BOOST_REQUIRE_EQUAL (e[4], 5ul); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents Constructor] construction using iterator"){ + std::array arr {1,2,3,4,5}; + auto e = extents_type(arr.begin(), arr.end()); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 5ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 1ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 4ul); + BOOST_REQUIRE_EQUAL (e[4], 5ul); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents Constructor] copy constructor"){ + auto e = extents_type(n4231); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 4ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 1ul); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents Constructor] move constructor"){ + auto temp = extents_type(n4231); + auto e = extents_type(std::move(temp)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 4ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 1ul); + BOOST_REQUIRE_EQUAL ( ublas::size(temp), 0ul); + BOOST_REQUIRE ( ublas::empty(temp)); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents Constructor] invalid construction"){ + BOOST_CHECK_THROW( (extents_type{1, 1, 0}), std::invalid_argument); + BOOST_CHECK_THROW( (extents_type{1, 0 }), std::invalid_argument); + BOOST_CHECK_THROW( (extents_type{0 }), std::invalid_argument); + BOOST_CHECK_THROW( (extents_type{0, 1 }), std::invalid_argument); + } + +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("boost::numeric::ublas::extents<>(...)") + *boost::unit_test::description("Testing static_rank extents construction")) +{ + namespace ublas = boost::numeric::ublas; + + using extents_type = ublas::extents<4>; + + BOOST_TEST_CONTEXT("[Static Rank Extents Constructor] default constructor"){ + auto e = extents_type(); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_NO_THROW((void)e.at(0)); + BOOST_CHECK_NO_THROW((void)e.at(1)); + BOOST_CHECK_NO_THROW((void)e.at(2)); + BOOST_CHECK_NO_THROW((void)e.at(3)); + BOOST_CHECK_THROW ((void)e.at(4), std::out_of_range); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents Constructor] construction using base type"){ + using extents_base_type = typename extents_type::base_type; + extents_base_type arr {1,2,3,4}; + auto e = extents_type(std::move(arr)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 1ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 4ul); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents Constructor] construction using initilizer list"){ + auto e = extents_type{1,2,3,4}; + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 1ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 4ul); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents Constructor] construction using iterator"){ + std::array arr {1,2,3,4}; + auto e = extents_type(arr.begin(), arr.end()); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 1ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 4ul); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents Constructor] copy constructor"){ + auto e = extents_type(n4231); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 4ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 1ul); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents Constructor] move constructor"){ + auto temp = extents_type(n4231); + auto e = extents_type(std::move(temp)); + BOOST_REQUIRE_EQUAL ( ublas::size(e), 4ul); + BOOST_REQUIRE (!ublas::empty(e)); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 4ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 1ul); + BOOST_REQUIRE_EQUAL ( ublas::size(temp), 4ul); + BOOST_REQUIRE (!ublas::empty(temp)); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents Constructor] invalid construction"){ + BOOST_CHECK_THROW( (extents_type{1, 1, 0 }), std::length_error); + BOOST_CHECK_THROW( (extents_type{1, 1, 1, 1, 1}), std::length_error); + BOOST_CHECK_THROW( (extents_type{1, 1, 0, 1 }), std::invalid_argument); + BOOST_CHECK_THROW( (extents_type{0, 1, 0, 1 }), std::invalid_argument); + } + +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("boost::numeric::ublas::extents<>(...)") + *boost::unit_test::description("Testing static extents construction")) +{ + namespace ublas = boost::numeric::ublas; + + using extents_type = ublas::extents<4,2,3,1>; + + BOOST_TEST_CONTEXT("[Static Rank Extents Constructor] default constructor"){ + auto e = extents_type(); + BOOST_REQUIRE_EQUAL ( ublas::size_v, 4ul); + BOOST_REQUIRE (!ublas::empty_v); + BOOST_REQUIRE_EQUAL (e[0], 4ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 1ul); + BOOST_CHECK_THROW ((void)e.at(4), std::out_of_range); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents Constructor] copy constructor"){ + auto e = extents_type(n4231); + BOOST_REQUIRE_EQUAL ( ublas::size_v, 4ul); + BOOST_REQUIRE (!ublas::empty_v); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 4ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 1ul); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents Constructor] move constructor"){ + auto temp = extents_type(n4231); + auto e = extents_type(std::move(temp)); + BOOST_REQUIRE_EQUAL ( ublas::size_v, 4ul); + BOOST_REQUIRE (!ublas::empty_v); + BOOST_CHECK_THROW ((void)e.at(5), std::out_of_range); + BOOST_REQUIRE_EQUAL (e[0], 4ul); + BOOST_REQUIRE_EQUAL (e[1], 2ul); + BOOST_REQUIRE_EQUAL (e[2], 3ul); + BOOST_REQUIRE_EQUAL (e[3], 1ul); + + BOOST_REQUIRE_EQUAL ( ublas::size_v, 4ul); + BOOST_REQUIRE (!ublas::empty_v); + BOOST_REQUIRE_EQUAL (temp[0], 4ul); + BOOST_REQUIRE_EQUAL (temp[1], 2ul); + BOOST_REQUIRE_EQUAL (temp[2], 3ul); + BOOST_REQUIRE_EQUAL (temp[3], 1ul); + } + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_empty.cpp b/test/tensor/extents/test_extents_empty.cpp new file mode 100644 index 000000000..3c8432295 --- /dev/null +++ b/test/tensor/extents/test_extents_empty.cpp @@ -0,0 +1,141 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_extents_empty, * boost::unit_test::description("Validate Empty Function and Trait")) + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_function, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("boost::numeric::ublas::empty(extents_base const&)") + *boost::unit_test::description("Testing free function [empty] for dynamic extents")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Empty Free Function] rank(0) dynamic extents"){ + BOOST_REQUIRE( ublas::empty(n )); + } + + BOOST_TEST_CONTEXT("[Empty Free Function] rank(1) dynamic extents"){ + BOOST_REQUIRE(!ublas::empty(n1 )); + BOOST_REQUIRE(!ublas::empty(n2 )); + } + + BOOST_TEST_CONTEXT("[Empty Free Function] rank(2) dynamic extents"){ + BOOST_REQUIRE(!ublas::empty(n11 )); + BOOST_REQUIRE(!ublas::empty(n12 )); + BOOST_REQUIRE(!ublas::empty(n21 )); + BOOST_REQUIRE(!ublas::empty(n22 )); + BOOST_REQUIRE(!ublas::empty(n32 )); + } + + BOOST_TEST_CONTEXT("[Empty Free Function] rank(3) dynamic extents"){ + BOOST_REQUIRE(!ublas::empty(n111 )); + BOOST_REQUIRE(!ublas::empty(n112 )); + BOOST_REQUIRE(!ublas::empty(n121 )); + BOOST_REQUIRE(!ublas::empty(n123 )); + BOOST_REQUIRE(!ublas::empty(n211 )); + BOOST_REQUIRE(!ublas::empty(n213 )); + BOOST_REQUIRE(!ublas::empty(n321 )); + BOOST_REQUIRE(!ublas::empty(n432 )); + } + + BOOST_TEST_CONTEXT("[Empty Free Function] rank(4) dynamic extents"){ + BOOST_REQUIRE(!ublas::empty(n1111)); + BOOST_REQUIRE(!ublas::empty(n4231)); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_function, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("boost::numeric::ublas::empty(extents_base const&)") + *boost::unit_test::description("Testing free function [empty] for static rank extents")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Empty Free Function] rank(0) static rank extents"){ + BOOST_REQUIRE( ublas::empty(n )); + } + + BOOST_TEST_CONTEXT("[Empty Free Function] rank(1) static rank extents"){ + BOOST_REQUIRE(!ublas::empty(n1 )); + BOOST_REQUIRE(!ublas::empty(n2 )); + } + + BOOST_TEST_CONTEXT("[Empty Free Function] rank(2) static rank extents"){ + BOOST_REQUIRE(!ublas::empty(n11 )); + BOOST_REQUIRE(!ublas::empty(n12 )); + BOOST_REQUIRE(!ublas::empty(n21 )); + BOOST_REQUIRE(!ublas::empty(n22 )); + BOOST_REQUIRE(!ublas::empty(n32 )); + } + + BOOST_TEST_CONTEXT("[Empty Free Function] rank(3) static rank extents"){ + BOOST_REQUIRE(!ublas::empty(n111 )); + BOOST_REQUIRE(!ublas::empty(n112 )); + BOOST_REQUIRE(!ublas::empty(n121 )); + BOOST_REQUIRE(!ublas::empty(n123 )); + BOOST_REQUIRE(!ublas::empty(n211 )); + BOOST_REQUIRE(!ublas::empty(n213 )); + BOOST_REQUIRE(!ublas::empty(n321 )); + BOOST_REQUIRE(!ublas::empty(n432 )); + } + + BOOST_TEST_CONTEXT("[Empty Free Function] rank(4) static rank extents"){ + BOOST_REQUIRE(!ublas::empty(n1111)); + BOOST_REQUIRE(!ublas::empty(n4231)); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_trait, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("boost::numeric::ublas::empty_v>") + *boost::unit_test::description("Testing trait [empty_v] for static extents")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Empty Trait] rank(0) static rank extents"){ + BOOST_REQUIRE( ublas::empty_v); + } + + BOOST_TEST_CONTEXT("[Empty Trait] rank(1) static extents"){ + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + } + + BOOST_TEST_CONTEXT("[Empty Trait] rank(2) static extents"){ + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + } + + BOOST_TEST_CONTEXT("[Empty Trait] rank(3) static extents"){ + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + } + + BOOST_TEST_CONTEXT("[Empty Trait] rank(4) static extents"){ + BOOST_REQUIRE(!ublas::empty_v); + BOOST_REQUIRE(!ublas::empty_v); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_is_matrix.cpp b/test/tensor/extents/test_extents_is_matrix.cpp new file mode 100644 index 000000000..d2dddf8cb --- /dev/null +++ b/test/tensor/extents/test_extents_is_matrix.cpp @@ -0,0 +1,142 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#include +#include "../fixture_utility.hpp" + + +BOOST_AUTO_TEST_SUITE(test_extents_is_matrix, + *boost::unit_test::description("Validate extents' is_matrix functions/traits") +) + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("is_matrix(extents<>)") + *boost::unit_test::description("Testing if dynamic extents is matrix or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(0) dynamic extents"){ + BOOST_CHECK( !ublas::is_matrix(n) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(1) dynamic extents"){ + BOOST_CHECK( ublas::is_matrix(n1) ); + BOOST_CHECK( ublas::is_matrix(n2) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(2) dynamic extents"){ + BOOST_CHECK( ublas::is_matrix(n11) ); + BOOST_CHECK( ublas::is_matrix(n12) ); + BOOST_CHECK( ublas::is_matrix(n21) ); + BOOST_CHECK( ublas::is_matrix(n22) ); + BOOST_CHECK( ublas::is_matrix(n32) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(3) dynamic extents"){ + BOOST_CHECK( ublas::is_matrix(n111) ); + BOOST_CHECK( !ublas::is_matrix(n112) ); + BOOST_CHECK( ublas::is_matrix(n121) ); + BOOST_CHECK( !ublas::is_matrix(n123) ); + BOOST_CHECK( ublas::is_matrix(n211) ); + BOOST_CHECK( !ublas::is_matrix(n213) ); + BOOST_CHECK( ublas::is_matrix(n321) ); + BOOST_CHECK( !ublas::is_matrix(n432) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(4) dynamic extents"){ + BOOST_CHECK( ublas::is_matrix(n1111) ); + BOOST_CHECK( !ublas::is_matrix(n4231) ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("is_matrix(extents)") + *boost::unit_test::description("Testing if static rank extents is matrix or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(0) extents"){ + BOOST_CHECK( !ublas::is_matrix(n) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(1) extents"){ + BOOST_CHECK( ublas::is_matrix(n1) ); + BOOST_CHECK( ublas::is_matrix(n2) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(2) extents"){ + BOOST_CHECK( ublas::is_matrix(n11) ); + BOOST_CHECK( ublas::is_matrix(n12) ); + BOOST_CHECK( ublas::is_matrix(n21) ); + BOOST_CHECK( ublas::is_matrix(n22) ); + BOOST_CHECK( ublas::is_matrix(n32) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(3) extents"){ + BOOST_CHECK( ublas::is_matrix(n111) ); + BOOST_CHECK( !ublas::is_matrix(n112) ); + BOOST_CHECK( ublas::is_matrix(n121) ); + BOOST_CHECK( !ublas::is_matrix(n123) ); + BOOST_CHECK( ublas::is_matrix(n211) ); + BOOST_CHECK( !ublas::is_matrix(n213) ); + BOOST_CHECK( ublas::is_matrix(n321) ); + BOOST_CHECK( !ublas::is_matrix(n432) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(4) extents"){ + BOOST_CHECK( ublas::is_matrix(n1111) ); + BOOST_CHECK( !ublas::is_matrix(n4231) ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("is_matrix_v>") + *boost::unit_test::description("Testing if static extents is matrix or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Static Extents] rank(0) static extents"){ + BOOST_CHECK( !ublas::is_matrix_v< n_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(1) static extents"){ + BOOST_CHECK( ublas::is_matrix_v< n1_type > ); + BOOST_CHECK( ublas::is_matrix_v< n2_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(2) static extents"){ + BOOST_CHECK( ublas::is_matrix_v< n11_type > ); + BOOST_CHECK( ublas::is_matrix_v< n12_type > ); + BOOST_CHECK( ublas::is_matrix_v< n21_type > ); + BOOST_CHECK( ublas::is_matrix_v< n22_type > ); + BOOST_CHECK( ublas::is_matrix_v< n32_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(3) static extents"){ + BOOST_CHECK( ublas::is_matrix_v< n111_type > ); + BOOST_CHECK( !ublas::is_matrix_v< n112_type > ); + BOOST_CHECK( ublas::is_matrix_v< n121_type > ); + BOOST_CHECK( !ublas::is_matrix_v< n123_type > ); + BOOST_CHECK( ublas::is_matrix_v< n211_type > ); + BOOST_CHECK( !ublas::is_matrix_v< n213_type > ); + BOOST_CHECK( ublas::is_matrix_v< n321_type > ); + BOOST_CHECK( !ublas::is_matrix_v< n432_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(4) static extents"){ + BOOST_CHECK( ublas::is_matrix_v< n1111_type > ); + BOOST_CHECK( !ublas::is_matrix_v< n4231_type > ); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_is_scalar.cpp b/test/tensor/extents/test_extents_is_scalar.cpp new file mode 100644 index 000000000..e3ddfaf29 --- /dev/null +++ b/test/tensor/extents/test_extents_is_scalar.cpp @@ -0,0 +1,142 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#include +#include "../fixture_utility.hpp" + + +BOOST_AUTO_TEST_SUITE(test_extents_is_scalar, + *boost::unit_test::description("Validate extents' is_scalar functions/traits") +) + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("is_scalar(extents<>)") + *boost::unit_test::description("Testing if dynamic extents is scalar or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(0) dynamic extents"){ + BOOST_CHECK( !ublas::is_scalar(n) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(1) dynamic extents"){ + BOOST_CHECK( ublas::is_scalar(n1) ); + BOOST_CHECK( !ublas::is_scalar(n2) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(2) dynamic extents"){ + BOOST_CHECK( ublas::is_scalar(n11) ); + BOOST_CHECK( !ublas::is_scalar(n12) ); + BOOST_CHECK( !ublas::is_scalar(n21) ); + BOOST_CHECK( !ublas::is_scalar(n22) ); + BOOST_CHECK( !ublas::is_scalar(n32) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(3) dynamic extents"){ + BOOST_CHECK( ublas::is_scalar(n111) ); + BOOST_CHECK( !ublas::is_scalar(n112) ); + BOOST_CHECK( !ublas::is_scalar(n121) ); + BOOST_CHECK( !ublas::is_scalar(n123) ); + BOOST_CHECK( !ublas::is_scalar(n211) ); + BOOST_CHECK( !ublas::is_scalar(n213) ); + BOOST_CHECK( !ublas::is_scalar(n321) ); + BOOST_CHECK( !ublas::is_scalar(n432) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(4) dynamic extents"){ + BOOST_CHECK( ublas::is_scalar(n1111) ); + BOOST_CHECK( !ublas::is_scalar(n4231) ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("is_scalar(extents)") + *boost::unit_test::description("Testing if static rank extents is scalar or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(0) extents"){ + BOOST_CHECK( !ublas::is_scalar(n) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(1) extents"){ + BOOST_CHECK( ublas::is_scalar(n1) ); + BOOST_CHECK( !ublas::is_scalar(n2) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(2) extents"){ + BOOST_CHECK( ublas::is_scalar(n11) ); + BOOST_CHECK( !ublas::is_scalar(n12) ); + BOOST_CHECK( !ublas::is_scalar(n21) ); + BOOST_CHECK( !ublas::is_scalar(n22) ); + BOOST_CHECK( !ublas::is_scalar(n32) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(3) extents"){ + BOOST_CHECK( ublas::is_scalar(n111) ); + BOOST_CHECK( !ublas::is_scalar(n112) ); + BOOST_CHECK( !ublas::is_scalar(n121) ); + BOOST_CHECK( !ublas::is_scalar(n123) ); + BOOST_CHECK( !ublas::is_scalar(n211) ); + BOOST_CHECK( !ublas::is_scalar(n213) ); + BOOST_CHECK( !ublas::is_scalar(n321) ); + BOOST_CHECK( !ublas::is_scalar(n432) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(4) extents"){ + BOOST_CHECK( ublas::is_scalar(n1111) ); + BOOST_CHECK( !ublas::is_scalar(n4231) ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("is_scalar_v>") + *boost::unit_test::description("Testing if static extents is scalar or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Static Extents] rank(0) static extents"){ + BOOST_CHECK( !ublas::is_scalar_v< n_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(1) static extents"){ + BOOST_CHECK( ublas::is_scalar_v< n1_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n2_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(2) static extents"){ + BOOST_CHECK( ublas::is_scalar_v< n11_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n12_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n21_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n22_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n32_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(3) static extents"){ + BOOST_CHECK( ublas::is_scalar_v< n111_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n112_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n121_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n123_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n211_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n213_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n321_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n432_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(4) static extents"){ + BOOST_CHECK( ublas::is_scalar_v< n1111_type > ); + BOOST_CHECK( !ublas::is_scalar_v< n4231_type > ); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_is_tensor.cpp b/test/tensor/extents/test_extents_is_tensor.cpp new file mode 100644 index 000000000..e132682e4 --- /dev/null +++ b/test/tensor/extents/test_extents_is_tensor.cpp @@ -0,0 +1,142 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#include +#include "../fixture_utility.hpp" + + +BOOST_AUTO_TEST_SUITE(test_extents_is_tensor, + *boost::unit_test::description("Validate extents' is_tensor functions/traits") +) + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("is_tensor(extents<>)") + *boost::unit_test::description("Testing if dynamic extents is tensor or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(0) dynamic extents"){ + BOOST_CHECK( !ublas::is_tensor(n) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(1) dynamic extents"){ + BOOST_CHECK( !ublas::is_tensor(n1) ); + BOOST_CHECK( !ublas::is_tensor(n2) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(2) dynamic extents"){ + BOOST_CHECK( !ublas::is_tensor(n11) ); + BOOST_CHECK( !ublas::is_tensor(n12) ); + BOOST_CHECK( !ublas::is_tensor(n21) ); + BOOST_CHECK( !ublas::is_tensor(n22) ); + BOOST_CHECK( !ublas::is_tensor(n32) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(3) dynamic extents"){ + BOOST_CHECK( !ublas::is_tensor(n111) ); + BOOST_CHECK( ublas::is_tensor(n112) ); + BOOST_CHECK( !ublas::is_tensor(n121) ); + BOOST_CHECK( ublas::is_tensor(n123) ); + BOOST_CHECK( !ublas::is_tensor(n211) ); + BOOST_CHECK( ublas::is_tensor(n213) ); + BOOST_CHECK( !ublas::is_tensor(n321) ); + BOOST_CHECK( ublas::is_tensor(n432) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(4) dynamic extents"){ + BOOST_CHECK( !ublas::is_tensor(n1111) ); + BOOST_CHECK( ublas::is_tensor(n4231) ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("is_tensor(extents)") + *boost::unit_test::description("Testing if static rank extents is tensor or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(0) extents"){ + BOOST_CHECK( !ublas::is_tensor(n) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(1) extents"){ + BOOST_CHECK( !ublas::is_tensor(n1) ); + BOOST_CHECK( !ublas::is_tensor(n2) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(2) extents"){ + BOOST_CHECK( !ublas::is_tensor(n11) ); + BOOST_CHECK( !ublas::is_tensor(n12) ); + BOOST_CHECK( !ublas::is_tensor(n21) ); + BOOST_CHECK( !ublas::is_tensor(n22) ); + BOOST_CHECK( !ublas::is_tensor(n32) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(3) extents"){ + BOOST_CHECK( !ublas::is_tensor(n111) ); + BOOST_CHECK( ublas::is_tensor(n112) ); + BOOST_CHECK( !ublas::is_tensor(n121) ); + BOOST_CHECK( ublas::is_tensor(n123) ); + BOOST_CHECK( !ublas::is_tensor(n211) ); + BOOST_CHECK( ublas::is_tensor(n213) ); + BOOST_CHECK( !ublas::is_tensor(n321) ); + BOOST_CHECK( ublas::is_tensor(n432) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(4) extents"){ + BOOST_CHECK( !ublas::is_tensor(n1111) ); + BOOST_CHECK( ublas::is_tensor(n4231) ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("is_tensor_v>") + *boost::unit_test::description("Testing if static extents is tensor or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Static Extents] rank(0) static extents"){ + BOOST_CHECK( !ublas::is_tensor_v< n_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(1) static extents"){ + BOOST_CHECK( !ublas::is_tensor_v< n1_type > ); + BOOST_CHECK( !ublas::is_tensor_v< n2_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(2) static extents"){ + BOOST_CHECK( !ublas::is_tensor_v< n11_type > ); + BOOST_CHECK( !ublas::is_tensor_v< n12_type > ); + BOOST_CHECK( !ublas::is_tensor_v< n21_type > ); + BOOST_CHECK( !ublas::is_tensor_v< n22_type > ); + BOOST_CHECK( !ublas::is_tensor_v< n32_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(3) static extents"){ + BOOST_CHECK( !ublas::is_tensor_v< n111_type > ); + BOOST_CHECK( ublas::is_tensor_v< n112_type > ); + BOOST_CHECK( !ublas::is_tensor_v< n121_type > ); + BOOST_CHECK( ublas::is_tensor_v< n123_type > ); + BOOST_CHECK( !ublas::is_tensor_v< n211_type > ); + BOOST_CHECK( ublas::is_tensor_v< n213_type > ); + BOOST_CHECK( !ublas::is_tensor_v< n321_type > ); + BOOST_CHECK( ublas::is_tensor_v< n432_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(4) static extents"){ + BOOST_CHECK( !ublas::is_tensor_v< n1111_type > ); + BOOST_CHECK( ublas::is_tensor_v< n4231_type > ); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_is_valid.cpp b/test/tensor/extents/test_extents_is_valid.cpp new file mode 100644 index 000000000..ea9fe2512 --- /dev/null +++ b/test/tensor/extents/test_extents_is_valid.cpp @@ -0,0 +1,145 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#include +#include "../fixture_utility.hpp" + + +BOOST_AUTO_TEST_SUITE(test_extents_is_valid, + *boost::unit_test::description("Validate extents' is_valid functions/traits") +) + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("is_valid(extents<>)") + *boost::unit_test::description("Testing if dynamic extents is valid or not")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(0) dynamic extents"){ + BOOST_CHECK( ublas::is_valid(n) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(1) dynamic extents"){ + BOOST_CHECK( ublas::is_valid(n1) ); + BOOST_CHECK( ublas::is_valid(n2) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(2) dynamic extents"){ + BOOST_CHECK( ublas::is_valid(n11) ); + BOOST_CHECK( ublas::is_valid(n12) ); + BOOST_CHECK( ublas::is_valid(n21) ); + BOOST_CHECK( ublas::is_valid(n22) ); + BOOST_CHECK( ublas::is_valid(n32) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(3) dynamic extents"){ + BOOST_CHECK( ublas::is_valid(n111) ); + BOOST_CHECK( ublas::is_valid(n112) ); + BOOST_CHECK( ublas::is_valid(n121) ); + BOOST_CHECK( ublas::is_valid(n123) ); + BOOST_CHECK( ublas::is_valid(n211) ); + BOOST_CHECK( ublas::is_valid(n213) ); + BOOST_CHECK( ublas::is_valid(n321) ); + BOOST_CHECK( ublas::is_valid(n432) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(4) dynamic extents"){ + BOOST_CHECK( ublas::is_valid(n1111) ); + BOOST_CHECK( ublas::is_valid(n4231) ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("is_valid(extents)") + *boost::unit_test::description("Testing if static rank extents is valid or not")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(0) extents"){ + BOOST_CHECK( ublas::is_valid(n) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(1) extents"){ + BOOST_CHECK( ublas::is_valid(n1) ); + BOOST_CHECK( ublas::is_valid(n2) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(2) extents"){ + BOOST_CHECK( ublas::is_valid(n11) ); + BOOST_CHECK( ublas::is_valid(n12) ); + BOOST_CHECK( ublas::is_valid(n21) ); + BOOST_CHECK( ublas::is_valid(n22) ); + BOOST_CHECK( ublas::is_valid(n32) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(3) extents"){ + BOOST_CHECK( ublas::is_valid(n111) ); + BOOST_CHECK( ublas::is_valid(n112) ); + BOOST_CHECK( ublas::is_valid(n121) ); + BOOST_CHECK( ublas::is_valid(n123) ); + BOOST_CHECK( ublas::is_valid(n211) ); + BOOST_CHECK( ublas::is_valid(n213) ); + BOOST_CHECK( ublas::is_valid(n321) ); + BOOST_CHECK( ublas::is_valid(n432) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(4) extents"){ + BOOST_CHECK( ublas::is_valid(n1111) ); + BOOST_CHECK( ublas::is_valid(n4231) ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("is_valid_v>") + *boost::unit_test::description("Testing if static extents is valid or not")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Static Extents] rank(0) static extents"){ + BOOST_CHECK( ublas::is_valid_v< n_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(1) static extents"){ + BOOST_CHECK( ublas::is_valid_v< n1_type > ); + BOOST_CHECK( ublas::is_valid_v< n2_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(2) static extents"){ + BOOST_CHECK( ublas::is_valid_v< n11_type > ); + BOOST_CHECK( ublas::is_valid_v< n12_type > ); + BOOST_CHECK( ublas::is_valid_v< n21_type > ); + BOOST_CHECK( ublas::is_valid_v< n22_type > ); + BOOST_CHECK( ublas::is_valid_v< n32_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(3) static extents"){ + BOOST_CHECK( ublas::is_valid_v< n111_type > ); + BOOST_CHECK( ublas::is_valid_v< n112_type > ); + BOOST_CHECK( ublas::is_valid_v< n121_type > ); + BOOST_CHECK( ublas::is_valid_v< n123_type > ); + BOOST_CHECK( ublas::is_valid_v< n211_type > ); + BOOST_CHECK( ublas::is_valid_v< n213_type > ); + BOOST_CHECK( ublas::is_valid_v< n321_type > ); + BOOST_CHECK( ublas::is_valid_v< n432_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(4) static extents"){ + BOOST_CHECK( ublas::is_valid_v< n1111_type > ); + BOOST_CHECK( ublas::is_valid_v< n4231_type > ); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_is_vector.cpp b/test/tensor/extents/test_extents_is_vector.cpp new file mode 100644 index 000000000..d67d5387b --- /dev/null +++ b/test/tensor/extents/test_extents_is_vector.cpp @@ -0,0 +1,142 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#include +#include "../fixture_utility.hpp" + + +BOOST_AUTO_TEST_SUITE(test_extents_is_vector_functions, + *boost::unit_test::description("Validate extents' is_vector functions/traits") +) + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("is_vector(extents<>)") + *boost::unit_test::description("Testing if dynamic extents is vector or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(0) dynamic extents"){ + BOOST_CHECK( !ublas::is_vector(n) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(1) dynamic extents"){ + BOOST_CHECK( ublas::is_vector(n1) ); + BOOST_CHECK( ublas::is_vector(n2) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(2) dynamic extents"){ + BOOST_CHECK( ublas::is_vector(n11) ); + BOOST_CHECK( ublas::is_vector(n12) ); + BOOST_CHECK( ublas::is_vector(n21) ); + BOOST_CHECK( !ublas::is_vector(n22) ); + BOOST_CHECK( !ublas::is_vector(n32) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(3) dynamic extents"){ + BOOST_CHECK( ublas::is_vector(n111) ); + BOOST_CHECK( !ublas::is_vector(n112) ); + BOOST_CHECK( ublas::is_vector(n121) ); + BOOST_CHECK( !ublas::is_vector(n123) ); + BOOST_CHECK( ublas::is_vector(n211) ); + BOOST_CHECK( !ublas::is_vector(n213) ); + BOOST_CHECK( !ublas::is_vector(n321) ); + BOOST_CHECK( !ublas::is_vector(n432) ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(4) dynamic extents"){ + BOOST_CHECK( ublas::is_vector(n1111) ); + BOOST_CHECK( !ublas::is_vector(n4231) ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("is_vector(extents)") + *boost::unit_test::description("Testing if static rank extents is vector or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(0) extents"){ + BOOST_CHECK( !ublas::is_vector(n) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(1) extents"){ + BOOST_CHECK( ublas::is_vector(n1) ); + BOOST_CHECK( ublas::is_vector(n2) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(2) extents"){ + BOOST_CHECK( ublas::is_vector(n11) ); + BOOST_CHECK( ublas::is_vector(n12) ); + BOOST_CHECK( ublas::is_vector(n21) ); + BOOST_CHECK( !ublas::is_vector(n22) ); + BOOST_CHECK( !ublas::is_vector(n32) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(3) extents"){ + BOOST_CHECK( ublas::is_vector(n111) ); + BOOST_CHECK( !ublas::is_vector(n112) ); + BOOST_CHECK( ublas::is_vector(n121) ); + BOOST_CHECK( !ublas::is_vector(n123) ); + BOOST_CHECK( ublas::is_vector(n211) ); + BOOST_CHECK( !ublas::is_vector(n213) ); + BOOST_CHECK( !ublas::is_vector(n321) ); + BOOST_CHECK( !ublas::is_vector(n432) ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(4) extents"){ + BOOST_CHECK( ublas::is_vector(n1111) ); + BOOST_CHECK( !ublas::is_vector(n4231) ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("is_vector_v>") + *boost::unit_test::description("Testing if static extents is vector or not")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Static Extents] rank(0) static extents"){ + BOOST_CHECK( !ublas::is_vector_v< n_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(1) static extents"){ + BOOST_CHECK( ublas::is_vector_v< n1_type > ); + BOOST_CHECK( ublas::is_vector_v< n2_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(2) static extents"){ + BOOST_CHECK( ublas::is_vector_v< n11_type > ); + BOOST_CHECK( ublas::is_vector_v< n12_type > ); + BOOST_CHECK( ublas::is_vector_v< n21_type > ); + BOOST_CHECK( !ublas::is_vector_v< n22_type > ); + BOOST_CHECK( !ublas::is_vector_v< n32_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(3) static extents"){ + BOOST_CHECK( ublas::is_vector_v< n111_type > ); + BOOST_CHECK( !ublas::is_vector_v< n112_type > ); + BOOST_CHECK( ublas::is_vector_v< n121_type > ); + BOOST_CHECK( !ublas::is_vector_v< n123_type > ); + BOOST_CHECK( ublas::is_vector_v< n211_type > ); + BOOST_CHECK( !ublas::is_vector_v< n213_type > ); + BOOST_CHECK( !ublas::is_vector_v< n321_type > ); + BOOST_CHECK( !ublas::is_vector_v< n432_type > ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(4) static extents"){ + BOOST_CHECK( ublas::is_vector_v< n1111_type > ); + BOOST_CHECK( !ublas::is_vector_v< n4231_type > ); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_product.cpp b/test/tensor/extents/test_extents_product.cpp new file mode 100644 index 000000000..9a609e6b8 --- /dev/null +++ b/test/tensor/extents/test_extents_product.cpp @@ -0,0 +1,145 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + +#include +#include "../fixture_utility.hpp" + + +BOOST_AUTO_TEST_SUITE(test_extents_product, + *boost::unit_test::description("Validate extents' product functions/traits") +) + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("product(extents<>)") + *boost::unit_test::description("Testing the accumulated product of elements of the dynamic extents")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(0) dynamic extents"){ + BOOST_CHECK_EQUAL( ublas::product(n), 0ul ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(1) dynamic extents"){ + BOOST_CHECK_EQUAL( ublas::product(n1), 1ul ); + BOOST_CHECK_EQUAL( ublas::product(n2), 2ul ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(2) dynamic extents"){ + BOOST_CHECK_EQUAL( ublas::product(n11), 1ul ); + BOOST_CHECK_EQUAL( ublas::product(n12), 2ul ); + BOOST_CHECK_EQUAL( ublas::product(n21), 2ul ); + BOOST_CHECK_EQUAL( ublas::product(n22), 4ul ); + BOOST_CHECK_EQUAL( ublas::product(n32), 6ul ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(3) dynamic extents"){ + BOOST_CHECK_EQUAL( ublas::product(n111), 1ul ); + BOOST_CHECK_EQUAL( ublas::product(n112), 2ul ); + BOOST_CHECK_EQUAL( ublas::product(n121), 2ul ); + BOOST_CHECK_EQUAL( ublas::product(n123), 6ul ); + BOOST_CHECK_EQUAL( ublas::product(n211), 2ul ); + BOOST_CHECK_EQUAL( ublas::product(n213), 6ul ); + BOOST_CHECK_EQUAL( ublas::product(n321), 6ul ); + BOOST_CHECK_EQUAL( ublas::product(n432), 24ul ); + } + + BOOST_TEST_CONTEXT("[Dynamic Extents] rank(4) dynamic extents"){ + BOOST_CHECK_EQUAL( ublas::product(n1111), 1ul ); + BOOST_CHECK_EQUAL( ublas::product(n4231), 24ul ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("product(extents)") + *boost::unit_test::description("Testing the accumulated product of elements of the static rank extents")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(0) extents"){ + BOOST_CHECK_EQUAL( ublas::product(n), 0ul ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(1) extents"){ + BOOST_CHECK_EQUAL( ublas::product(n1), 1ul ); + BOOST_CHECK_EQUAL( ublas::product(n2), 2ul ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(2) extents"){ + BOOST_CHECK_EQUAL( ublas::product(n11), 1ul ); + BOOST_CHECK_EQUAL( ublas::product(n12), 2ul ); + BOOST_CHECK_EQUAL( ublas::product(n21), 2ul ); + BOOST_CHECK_EQUAL( ublas::product(n22), 4ul ); + BOOST_CHECK_EQUAL( ublas::product(n32), 6ul ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(3) extents"){ + BOOST_CHECK_EQUAL( ublas::product(n111), 1ul ); + BOOST_CHECK_EQUAL( ublas::product(n112), 2ul ); + BOOST_CHECK_EQUAL( ublas::product(n121), 2ul ); + BOOST_CHECK_EQUAL( ublas::product(n123), 6ul ); + BOOST_CHECK_EQUAL( ublas::product(n211), 2ul ); + BOOST_CHECK_EQUAL( ublas::product(n213), 6ul ); + BOOST_CHECK_EQUAL( ublas::product(n321), 6ul ); + BOOST_CHECK_EQUAL( ublas::product(n432), 24ul ); + } + + BOOST_TEST_CONTEXT("[Static Rank Extents] static rank(4) extents"){ + BOOST_CHECK_EQUAL( ublas::product(n1111), 1ul ); + BOOST_CHECK_EQUAL( ublas::product(n4231), 24ul ); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("product_v>") + *boost::unit_test::description("Testing the accumulated product of elements of the static extents")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Static Extents] rank(0) static extents"){ + BOOST_CHECK_EQUAL( ublas::product_v< n_type >, 0ul ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(1) static extents"){ + BOOST_CHECK_EQUAL( ublas::product_v< n1_type >, 1ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n2_type >, 2ul ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(2) static extents"){ + BOOST_CHECK_EQUAL( ublas::product_v< n11_type >, 1ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n12_type >, 2ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n21_type >, 2ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n22_type >, 4ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n32_type >, 6ul ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(3) static extents"){ + BOOST_CHECK_EQUAL( ublas::product_v< n111_type >, 1ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n112_type >, 2ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n121_type >, 2ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n123_type >, 6ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n211_type >, 2ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n213_type >, 6ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n321_type >, 6ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n432_type >, 24ul ); + } + + BOOST_TEST_CONTEXT("[Static Extents] rank(4) static extents"){ + BOOST_CHECK_EQUAL( ublas::product_v< n1111_type >, 1ul ); + BOOST_CHECK_EQUAL( ublas::product_v< n4231_type >, 24ul ); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/extents/test_extents_size.cpp b/test/tensor/extents/test_extents_size.cpp new file mode 100644 index 000000000..2c2def3f5 --- /dev/null +++ b/test/tensor/extents/test_extents_size.cpp @@ -0,0 +1,141 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_extents_size, * boost::unit_test::description("Validate Size Function and Trait")) + + +BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_function, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("boost::numeric::ublas::size(extents_base const&)") + *boost::unit_test::description("Testing free function [size] for dynamic extents")) +{ + namespace ublas = boost::numeric::ublas; + BOOST_TEST_CONTEXT("[Size Free Function] rank(0) dynamic extents"){ + BOOST_REQUIRE_EQUAL(ublas::size(n ), 0ul); + } + + BOOST_TEST_CONTEXT("[Size Free Function] rank(1) dynamic extents"){ + BOOST_REQUIRE_EQUAL(ublas::size(n1 ), 1ul); + BOOST_REQUIRE_EQUAL(ublas::size(n2 ), 1ul); + } + + BOOST_TEST_CONTEXT("[Size Free Function] rank(2) dynamic extents"){ + BOOST_REQUIRE_EQUAL(ublas::size(n11 ), 2ul); + BOOST_REQUIRE_EQUAL(ublas::size(n12 ), 2ul); + BOOST_REQUIRE_EQUAL(ublas::size(n21 ), 2ul); + BOOST_REQUIRE_EQUAL(ublas::size(n22 ), 2ul); + BOOST_REQUIRE_EQUAL(ublas::size(n32 ), 2ul); + } + + BOOST_TEST_CONTEXT("[Size Free Function] rank(3) dynamic extents"){ + BOOST_REQUIRE_EQUAL(ublas::size(n111 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n112 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n121 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n123 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n211 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n213 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n321 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n432 ), 3ul); + } + + BOOST_TEST_CONTEXT("[Size Free Function] rank(4) dynamic extents"){ + BOOST_REQUIRE_EQUAL(ublas::size(n1111), 4ul); + BOOST_REQUIRE_EQUAL(ublas::size(n4231), 4ul); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_function, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("boost::numeric::ublas::size(extents_base const&)") + *boost::unit_test::description("Testing free function [size] for static rank extents")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Size Free Function] rank(0) static rank extents"){ + BOOST_REQUIRE_EQUAL(ublas::size(n ), 0ul); + } + + BOOST_TEST_CONTEXT("[Size Free Function] rank(1) static rank extents"){ + BOOST_REQUIRE_EQUAL(ublas::size(n1 ), 1ul); + BOOST_REQUIRE_EQUAL(ublas::size(n2 ), 1ul); + } + + BOOST_TEST_CONTEXT("[Size Free Function] rank(2) static rank extents"){ + BOOST_REQUIRE_EQUAL(ublas::size(n11 ), 2ul); + BOOST_REQUIRE_EQUAL(ublas::size(n12 ), 2ul); + BOOST_REQUIRE_EQUAL(ublas::size(n21 ), 2ul); + BOOST_REQUIRE_EQUAL(ublas::size(n22 ), 2ul); + BOOST_REQUIRE_EQUAL(ublas::size(n32 ), 2ul); + } + + BOOST_TEST_CONTEXT("[Size Free Function] rank(3) static rank extents"){ + BOOST_REQUIRE_EQUAL(ublas::size(n111 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n112 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n121 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n123 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n211 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n213 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n321 ), 3ul); + BOOST_REQUIRE_EQUAL(ublas::size(n432 ), 3ul); + } + + BOOST_TEST_CONTEXT("[Size Free Function] rank(4) static rank extents"){ + BOOST_REQUIRE_EQUAL(ublas::size(n1111), 4ul); + BOOST_REQUIRE_EQUAL(ublas::size(n4231), 4ul); + } +} + +BOOST_FIXTURE_TEST_CASE(test_extents_static_trait, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("boost::numeric::ublas::size_v>") + *boost::unit_test::description("Testing trait [size_v] for static extents")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Size Trait] rank(0) static rank extents"){ + BOOST_REQUIRE_EQUAL(ublas::size_v, 0ul); + } + + BOOST_TEST_CONTEXT("[Size Trait] rank(1) static extents"){ + BOOST_REQUIRE_EQUAL(ublas::size_v, 1ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 1ul); + } + + BOOST_TEST_CONTEXT("[Size Trait] rank(2) static extents"){ + BOOST_REQUIRE_EQUAL(ublas::size_v, 2ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 2ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 2ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 2ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 2ul); + } + + BOOST_TEST_CONTEXT("[Size Trait] rank(3) static extents"){ + BOOST_REQUIRE_EQUAL(ublas::size_v, 3ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 3ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 3ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 3ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 3ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 3ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 3ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 3ul); + } + + BOOST_TEST_CONTEXT("[Size Trait] rank(4) static extents"){ + BOOST_REQUIRE_EQUAL(ublas::size_v, 4ul); + BOOST_REQUIRE_EQUAL(ublas::size_v, 4ul); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/fixture_utility.hpp b/test/tensor/fixture_utility.hpp new file mode 100644 index 000000000..dcfa2a749 --- /dev/null +++ b/test/tensor/fixture_utility.hpp @@ -0,0 +1,365 @@ +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TEST_TENSOR_FIXTURE_UTILITY_HPP +#define BOOST_UBLAS_TEST_TENSOR_FIXTURE_UTILITY_HPP + +#include +#include +#include "utility.hpp" +#include +#include + +namespace boost::numeric::ublas{ + + template + struct fixture_extents_dynamic{ + + using extents_type = extents_core; + using base_type = std::vector; + + extents_core const n{}; + + extents_core const n1{1}; + extents_core const n2{2}; + + extents_core const n11{1, 1}; + extents_core const n12{1, 2}; + extents_core const n21{2, 1}; + extents_core const n22{2, 2}; + extents_core const n32{3, 2}; + + extents_core const n111{1, 1, 1}; + extents_core const n112{1, 1, 2}; + extents_core const n121{1, 2, 1}; + extents_core const n123{1, 2, 3}; + extents_core const n211{2, 1, 1}; + extents_core const n213{2, 1, 3}; + extents_core const n321{3, 2, 1}; + extents_core const n432{4, 3, 2}; + + extents_core const n1111{1, 1, 1, 1}; + extents_core const n4231{4, 2, 3, 1}; + + base_type const collection{ + n, + n1, n2, + n11, n12, n21, n22, n32, + n111, n112, n121, n123, n211, n213, n321, n432, + n1111, n4231 + }; + + template + static auto make_tensor(extents_type e, Args&&... args){ + return tensor_type(std::move(e), std::forward(args)...); + } + }; + + template + struct fixture_extents_static_rank{ + constexpr static extents_core n{}; + + constexpr static extents_core n1{1}; + constexpr static extents_core n2{2}; + + constexpr static extents_core n11{1, 1}; + constexpr static extents_core n12{1, 2}; + constexpr static extents_core n21{2, 1}; + constexpr static extents_core n22{2, 2}; + constexpr static extents_core n32{3, 2}; + + constexpr static extents_core n111{1, 1, 1}; + constexpr static extents_core n112{1, 1, 2}; + constexpr static extents_core n121{1, 2, 1}; + constexpr static extents_core n123{1, 2, 3}; + constexpr static extents_core n211{2, 1, 1}; + constexpr static extents_core n213{2, 1, 3}; + constexpr static extents_core n321{3, 2, 1}; + constexpr static extents_core n432{4, 3, 2}; + + constexpr static extents_core n1111{1, 1, 1, 1}; + constexpr static extents_core n4231{4, 2, 3, 1}; + + constexpr static std::tuple collection{ + n, + n1, n2, + n11, n12, n21, n22, n32, + n111, n112, n121, n123, n211, n213, n321, n432, + n1111, n4231 + }; + + using tuple_type = decltype(collection); + + constexpr static auto size = std::tuple_size_v; + }; + + template + struct fixture_extents_static{ + using n_type = extents_core; + + using n1_type = extents_core; + using n2_type = extents_core; + + using n11_type = extents_core; + using n12_type = extents_core; + using n21_type = extents_core; + using n22_type = extents_core; + using n32_type = extents_core; + + using n111_type = extents_core; + using n112_type = extents_core; + using n121_type = extents_core; + using n123_type = extents_core; + using n211_type = extents_core; + using n213_type = extents_core; + using n321_type = extents_core; + using n432_type = extents_core; + + using n1111_type = extents_core; + using n4231_type = extents_core; + + constexpr static n1_type n1{}; + constexpr static n2_type n2{}; + + constexpr static n11_type n11{}; + constexpr static n12_type n12{}; + constexpr static n21_type n21{}; + constexpr static n22_type n22{}; + constexpr static n32_type n32{}; + + constexpr static n111_type n111{}; + constexpr static n112_type n112{}; + constexpr static n121_type n121{}; + constexpr static n123_type n123{}; + constexpr static n211_type n211{}; + constexpr static n213_type n213{}; + constexpr static n321_type n321{}; + constexpr static n432_type n432{}; + + constexpr static n1111_type n1111{}; + constexpr static n4231_type n4231{}; + + + using tuple_type = std::tuple< + n_type, + n1_type, n2_type, + n11_type, n12_type, n21_type, n22_type, n32_type, + n111_type, n112_type, n121_type, n123_type, n211_type, n213_type, n321_type, n432_type, + n1111_type, n4231_type + >; + + tuple_type const collection{}; + + constexpr static auto size = std::tuple_size_v; + + }; + + template + struct fixture_tensor_dynamic{ + private: + fixture_extents_dynamic const m_fixture{}; + public: + using tensor_type = tensor_dynamic; + using base_type = std::vector; + + tensor_type const t2 { m_fixture.n2 }; + + tensor_type const t11 { m_fixture.n11 }; + tensor_type const t12 { m_fixture.n12 }; + tensor_type const t21 { m_fixture.n21 }; + tensor_type const t22 { m_fixture.n22 }; + tensor_type const t32 { m_fixture.n32 }; + + tensor_type const t111 { m_fixture.n111 }; + tensor_type const t112 { m_fixture.n112 }; + tensor_type const t121 { m_fixture.n121 }; + tensor_type const t123 { m_fixture.n123 }; + tensor_type const t211 { m_fixture.n211 }; + tensor_type const t213 { m_fixture.n213 }; + tensor_type const t321 { m_fixture.n321 }; + tensor_type const t432 { m_fixture.n432 }; + + tensor_type const t1111 { m_fixture.n1111 }; + tensor_type const t4231 { m_fixture.n4231 }; + + base_type const collection{ + t2, + t11, t12, t21, t22, t32, + t111, t112, t121, t123, t211, t213, t321, t432, + t1111, t4231 + }; + }; + + template + using tuple_fixture_tensor_dynamic = fixture_tensor_dynamic; + + template + struct fixture_tensor_static_rank{ + private: + constexpr static fixture_extents_static_rank m_fixture{}; + public: + template + using tensor_type = tensor_static_rank; + + tensor_type<1> const t2 { m_fixture.n2 }; + + tensor_type<2> const t11 { m_fixture.n11 }; + tensor_type<2> const t12 { m_fixture.n12 }; + tensor_type<2> const t21 { m_fixture.n21 }; + tensor_type<2> const t22 { m_fixture.n22 }; + tensor_type<2> const t32 { m_fixture.n32 }; + + tensor_type<3> const t111 { m_fixture.n111 }; + tensor_type<3> const t112 { m_fixture.n112 }; + tensor_type<3> const t121 { m_fixture.n121 }; + tensor_type<3> const t123 { m_fixture.n123 }; + tensor_type<3> const t211 { m_fixture.n211 }; + tensor_type<3> const t213 { m_fixture.n213 }; + tensor_type<3> const t321 { m_fixture.n321 }; + tensor_type<3> const t432 { m_fixture.n432 }; + + tensor_type<4> const t1111 { m_fixture.n1111 }; + tensor_type<4> const t4231 { m_fixture.n4231 }; + + using tuple_type = std::tuple< + tensor_type<1> const&, + tensor_type<2> const&, tensor_type<2> const&, tensor_type<2> const&, tensor_type<2> const&, tensor_type<2> const&, + tensor_type<3> const&, tensor_type<3> const&, tensor_type<3> const&, tensor_type<3> const&, tensor_type<3> const&, + tensor_type<3> const&, tensor_type<3> const&, tensor_type<3> const&, + tensor_type<4> const&, tensor_type<4> const& + >; + + tuple_type collection{ + t2, + t11, t12, t21, t22, t32, + t111, t112, t121, t123, t211, t213, t321, t432, + t1111, t4231 + }; + + constexpr static auto size = std::tuple_size_v; + }; + + template + using tuple_fixture_tensor_static_rank = fixture_tensor_static_rank; + + template + struct fixture_tensor_static{ + + template + using tensor_type = tensor_static; + using fixture_type = fixture_extents_static; + + using t2_type = tensor_type; + + using t11_type = tensor_type; + using t12_type = tensor_type; + using t21_type = tensor_type; + using t22_type = tensor_type; + using t32_type = tensor_type; + + using t111_type = tensor_type; + using t112_type = tensor_type; + using t121_type = tensor_type; + using t123_type = tensor_type; + using t211_type = tensor_type; + using t213_type = tensor_type; + using t321_type = tensor_type; + using t432_type = tensor_type; + + using t1111_type = tensor_type; + using t4231_type = tensor_type; + + // t2_type const t2{}; + + t11_type const t11{}; + t12_type const t12{}; + t21_type const t21{}; + t22_type const t22{}; + t32_type const t32{}; + + t111_type const t111{}; + t112_type const t112{}; + t121_type const t121{}; + t123_type const t123{}; + t211_type const t211{}; + t213_type const t213{}; + t321_type const t321{}; + t432_type const t432{}; + + t1111_type const t1111{}; + t4231_type const t4231{}; + + + using tuple_type = std::tuple< + // t2_type const&, + t11_type const&, t12_type const&, t21_type const&, t22_type const&, t32_type const&, + t111_type const&, t112_type const&, t121_type const&, t123_type const&, t211_type const&, t213_type const&, t321_type const&, t432_type const&, + t1111_type const&, t4231_type const& + >; + + tuple_type collection{ + // t2, + t11, t12, t21, t22, t32, + t111, t112, t121, t123, t211, t213, t321, t432, + t1111, t4231 + }; + + constexpr static auto size = std::tuple_size_v; + }; + + template + using tuple_fixture_tensor_static = fixture_tensor_static; + + namespace detail{ + template + struct is_tuple : std::false_type{}; + + template + struct is_tuple< std::tuple > : std::true_type{}; + + template + inline static constexpr auto is_tuple_v = is_tuple< std::decay_t >::value; + + template + concept HasTuple = requires{ + typename std::decay_t::tuple_type; + requires is_tuple_v< typename std::decay_t::tuple_type >; + }; + + } + + template + constexpr auto for_each_fixture(FixtureType&& fixture, FnType&& fn){ + for_each_in_tuple(fixture.collection, std::forward(fn)); + } + + template + constexpr auto for_each_fixture(fixture_extents_dynamic const& fixture, FnType&& fn){ + std::size_t i{}; + for(auto const& el : fixture.collection){ + std::invoke(fn, i, el); + ++i; + } + } + + template + constexpr auto for_each_fixture(fixture_tensor_dynamic const& fixture, FnType&& fn){ + std::size_t i{}; + for(auto const& el : fixture.collection){ + std::invoke(fn, i, el); + ++i; + } + } + +} // namespace boost::numeric::ublas + +#endif // BOOST_UBLAS_TEST_TENSOR_FIXTURE_UTILITY_HPP \ No newline at end of file diff --git a/test/tensor/functions/test_functions_inner.cpp b/test/tensor/functions/test_functions_inner.cpp new file mode 100644 index 000000000..c43b90f56 --- /dev/null +++ b/test/tensor/functions/test_functions_inner.cpp @@ -0,0 +1,100 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_functions_inner, + * boost::unit_test::description("Validate Inner Product") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("inner_prod") + *boost::unit_test::description("Testing the inner product for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + auto const rank = a.rank(); + + if(rank <= 1ul) return; + + auto b = a; + a = value_type{2}; + b = value_type{1}; + + BOOST_TEST_CONTEXT("[Dynamic Inner Product] tensor with rank("<< rank <<")"){ + + 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_TEST_DECORATOR( + *boost::unit_test::label("inner_prod") + *boost::unit_test::description("Testing the inner product for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + + constexpr auto rank = a.rank(); + + if constexpr (rank > 1ul) { + + auto b = a; + a = value_type{2}; + b = value_type{1}; + + + BOOST_TEST_CONTEXT("[Static Rank Inner Product] tensor with rank("<< rank <<")"){ + + 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_AUTO_TEST_SUITE_END() diff --git a/test/tensor/functions/test_functions_matrix.cpp b/test/tensor/functions/test_functions_matrix.cpp new file mode 100644 index 000000000..2fa0ac6ff --- /dev/null +++ b/test/tensor/functions/test_functions_matrix.cpp @@ -0,0 +1,115 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include + +BOOST_AUTO_TEST_SUITE(test_functions_matrix, + * boost::unit_test::description("Validate Matrix Product") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("matrix_prod") + *boost::unit_test::description("Testing the matrix product for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using inner_t = inner_type_t; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + using matrix_type = typename tensor_type::matrix_type; + + auto const rank = a.rank(); + + if(rank <= 1ul) return; + + a = value_type{2}; + + BOOST_TEST_CONTEXT("[Dynamic Tensor Matrix Product] tensor with rank("<< rank <<")"){ + + for(auto m = 0u; m < rank; ++m){ + auto const em = a.size(m); + + auto b = matrix_type ( em, em, 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( static_cast< inner_t >(em) ) * a[i] ); + + } + + } + }); + + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("matrix_prod") + *boost::unit_test::description("Testing the matrix product for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using inner_t = inner_type_t; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + using matrix_type = typename tensor_type::matrix_type; + + constexpr auto rank = a.rank(); + + if constexpr (rank > 1ul) { + + a = value_type{2}; + + BOOST_TEST_CONTEXT("[Static Rank Tensor Matrix Product] tensor with rank("<< rank <<")"){ + + for(auto m = 0u; m < rank; ++m){ + auto const em = a.size(m); + + auto b = matrix_type ( em, em, 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( static_cast< inner_t >(em) ) * a[i] ); + + } + + } + } + + }); + + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/functions/test_functions_norm.cpp b/test/tensor/functions/test_functions_norm.cpp new file mode 100644 index 000000000..248794cc2 --- /dev/null +++ b/test/tensor/functions/test_functions_norm.cpp @@ -0,0 +1,102 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_functions_norm, + * boost::unit_test::description("Validate Norm Function") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("norm_fn") + *boost::unit_test::description("Testing the norm function for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::cpp_std_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + auto const rank = a.rank(); + + if(rank <= 1ul) return; + + ublas::iota(a, value_type{1}); + + BOOST_TEST_CONTEXT("[Dynamic Norm Function] tensor with rank("<< rank <<")"){ + auto c = ublas::inner_prod(a, a); + auto r = std::inner_product(a.begin(),a.end(), a.begin(),value_type(0)); + + tensor_type var = (a+a)/value_type{2}; + auto r2 = ublas::norm( var ); + + BOOST_CHECK_EQUAL( c , r ); + BOOST_CHECK_EQUAL( std::sqrt( c ) , r2 ); + + } + }); + + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("norm_fn") + *boost::unit_test::description("Testing the norm function for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::cpp_std_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + + constexpr auto rank = a.rank(); + + if constexpr (rank > 1ul) { + + ublas::iota(a, value_type{1}); + + BOOST_TEST_CONTEXT("[Static Rank Norm Function] tensor with rank("<< rank <<")"){ + + auto c = ublas::inner_prod(a, a); + auto r = std::inner_product(a.begin(),a.end(), a.begin(),value_type(0)); + + tensor_type var = (a+a)/value_type{2}; + auto r2 = ublas::norm( var ); + + BOOST_CHECK_EQUAL( c , r ); + BOOST_CHECK_EQUAL( std::sqrt( c ) , r2 ); + + } + } + + }); + + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/functions/test_functions_outer.cpp b/test/tensor/functions/test_functions_outer.cpp new file mode 100644 index 000000000..76c97ad8b --- /dev/null +++ b/test/tensor/functions/test_functions_outer.cpp @@ -0,0 +1,109 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_functions_outer, + * boost::unit_test::description("Validate Outer Product") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("outer_prod") + *boost::unit_test::description("Testing the outer product for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [&self](auto /*id*/, auto a){ + auto const a_rank = a.rank(); + + if(a_rank <= 1ul) return; + + a = value_type{2}; + + ublas::for_each_fixture(self, [&a, a_rank](auto /*id*/, auto b){ + auto const b_rank = b.rank(); + if(b_rank <= 1ul) return; + + b = value_type{1}; + + BOOST_TEST_CONTEXT("[Dynamic Outer Product] tensor with left rank("<< a_rank <<") : right rank (" << b_rank << ")"){ + + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + + } + }); + }); + + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("outer_prod") + *boost::unit_test::description("Testing the outer product for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [&self](auto /*id*/, auto a){ + static constexpr auto a_rank = a.rank(); + + if constexpr(a_rank > 1ul){ + a = value_type{2}; + + ublas::for_each_fixture(self, [&a](auto /*id*/, auto b){ + constexpr auto b_rank = b.rank(); + + if constexpr(b_rank > 1ul){ + b = value_type{1}; + + BOOST_TEST_CONTEXT("[Static Rank Outer Product] tensor with left rank("<< a_rank <<") : right rank (" << b_rank << ")"){ + + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + + } + } + + }); + } + + }); + + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/functions/test_functions_real_imag_conj.cpp b/test/tensor/functions/test_functions_real_imag_conj.cpp new file mode 100644 index 000000000..650bf18f7 --- /dev/null +++ b/test/tensor/functions/test_functions_real_imag_conj.cpp @@ -0,0 +1,265 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_functions_real_imag_conj, + * boost::unit_test::description("Validate Real, Imaginary, and Conjugate Product") +) + +template +struct rebind_tensor; + +template +using rebind_tensor_t = typename rebind_tensor::type; + +template +struct rebind_tensor, T> +{ + using type = boost::numeric::ublas::tensor_dynamic; +}; + +template +struct rebind_tensor, T> +{ + using type = boost::numeric::ublas::tensor_static_rank; +}; + +template +struct rebind_tensor, T> +{ + using type = boost::numeric::ublas::tensor_static; +}; + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("real_imag_conj_fn") + *boost::unit_test::description("Testing the real, imag, and conj for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::cpp_basic_std_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + using complex_t = std::complex; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type const& t){ + using complex_tensor_t = rebind_tensor_t; + auto const rank = t.rank(); + + if(rank < 1ul) return; + auto const& n = t.extents(); + + BOOST_TEST_CONTEXT("[Dynamic RIC(1)] tensor with rank("<< rank <<")"){ + auto a = t; + ublas::iota(a, value_type{0}); + auto r0 = a; + auto r00 = complex_tensor_t(n); + + 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_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r1.begin(), r1.end()); + + 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_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r2.begin(), r2.end()); + + complex_tensor_t 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_EQUAL_COLLECTIONS(r00.begin(), r00.end(), r3.begin(), r3.end()); + + } + + BOOST_TEST_CONTEXT("[Dynamic RIC(2)] tensor with rank("<< rank <<")"){ + auto a = complex_tensor_t(n); + ublas::iota(a, value_type{0}); + + auto r0 = t; + auto r00 = complex_tensor_t(n); + + complex_tensor_t b = (a+a) / complex_t( 2,2 ); + tensor_type r1 = ublas::real( (a+a) / complex_t( 2,2 ) ); + std::transform( b.begin(), b.end(), r0.begin(), [](auto const& l){ return std::real( l ); } ); + BOOST_CHECK_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r1.begin(), r1.end()); + + tensor_type r2 = ublas::imag( (a+a) / complex_t( 2,2 ) ); + std::transform( b.begin(), b.end(), r0.begin(), [](auto const& l){ return std::imag( l ); } ); + BOOST_CHECK_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r2.begin(), r2.end()); + + complex_tensor_t r3 = ublas::conj( (a+a) / complex_t( 2,2 ) ); + std::transform( b.begin(), b.end(), r00.begin(), [](auto const& l){ return std::conj( l ); } ); + BOOST_CHECK_EQUAL_COLLECTIONS(r00.begin(), r00.end(), r3.begin(), r3.end()); + + } + }); + + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("real_imag_conj_fn") + *boost::unit_test::description("Testing the real, imag, and conj for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::cpp_basic_std_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + using complex_t = std::complex; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type const& t){ + using complex_tensor_t = rebind_tensor_t; + using extents_type = typename tensor_type::extents_type; + + auto const& n = t.extents(); + constexpr auto rank = std::tuple_size_v; + + if constexpr (rank > 0ul) { + + BOOST_TEST_CONTEXT("[Static Rank RIC(1)] tensor with rank("<< rank <<")"){ + auto a = t; + ublas::iota(a, value_type{0}); + auto r0 = a; + auto r00 = complex_tensor_t(n); + + 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_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r1.begin(), r1.end()); + + 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_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r2.begin(), r2.end()); + + complex_tensor_t 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_EQUAL_COLLECTIONS(r00.begin(), r00.end(), r3.begin(), r3.end()); + + } + + BOOST_TEST_CONTEXT("[Static Rank RIC(2)] tensor with rank("<< rank <<")"){ + auto a = complex_tensor_t(n); + ublas::iota(a, value_type{0}); + + auto r0 = t; + auto r00 = complex_tensor_t(n); + + complex_tensor_t b = (a+a) / complex_t( 2,2 ); + tensor_type r1 = ublas::real( (a+a) / complex_t( 2,2 ) ); + std::transform( b.begin(), b.end(), r0.begin(), [](auto const& l){ return std::real( l ); } ); + BOOST_CHECK_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r1.begin(), r1.end()); + + tensor_type r2 = ublas::imag( (a+a) / complex_t( 2,2 ) ); + std::transform( b.begin(), b.end(), r0.begin(), [](auto const& l){ return std::imag( l ); } ); + BOOST_CHECK_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r2.begin(), r2.end()); + + complex_tensor_t r3 = ublas::conj( (a+a) / complex_t( 2,2 ) ); + std::transform( b.begin(), b.end(), r00.begin(), [](auto const& l){ return std::conj( l ); } ); + BOOST_CHECK_EQUAL_COLLECTIONS(r00.begin(), r00.end(), r3.begin(), r3.end()); + + } + } + + }); + + +} + +// TODO: Add support for static tensor and then enable this test +// BOOST_TEST_DECORATOR( +// *boost::unit_test::label("real_imag_conj_fn") +// *boost::unit_test::description("Testing the real, imag, and conj for static tensor") +// ) +// BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, +// TestTupleType, +// boost::numeric::ublas::cpp_basic_std_types, +// boost::numeric::ublas::tuple_fixture_tensor_static +// ) +// { +// namespace ublas = boost::numeric::ublas; +// using value_type = typename TestTupleType::first_type; +// using fixture_t = ublas::tuple_fixture_tensor_static; +// using complex_t = std::complex; + +// auto const& self = static_cast(*this); + +// ublas::for_each_fixture(self, [](auto /*id*/, tensor_type const& t){ +// using complex_tensor_t = rebind_tensor_t; +// using extents_type = typename tensor_type::extents_type; + +// constexpr auto rank = ublas::size_v; + +// if constexpr (rank > 1ul) { + +// BOOST_TEST_CONTEXT("[Static RIC(1)] tensor with rank("<< rank <<")"){ +// auto a = t; +// ublas::iota(a, value_type{0}); +// auto r0 = a; +// auto r00 = complex_tensor_t(); + +// 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_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r1.begin(), r1.end()); + +// 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_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r2.begin(), r2.end()); + +// complex_tensor_t 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_EQUAL_COLLECTIONS(r00.begin(), r00.end(), r3.begin(), r3.end()); + +// } + +// BOOST_TEST_CONTEXT("[Static RIC(2)] tensor with rank("<< rank <<")"){ +// auto a = complex_tensor_t(); +// ublas::iota(a, value_type{0}); + +// auto r0 = t; +// auto r00 = complex_tensor_t(); + +// complex_tensor_t b = (a+a) / complex_t( 2,2 ); +// tensor_type r1 = ublas::real( (a+a) / complex_t( 2,2 ) ); +// std::transform( b.begin(), b.end(), r0.begin(), [](auto const& l){ return std::real( l ); } ); +// BOOST_CHECK_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r1.begin(), r1.end()); + +// tensor_type r2 = ublas::imag( (a+a) / complex_t( 2,2 ) ); +// std::transform( b.begin(), b.end(), r0.begin(), [](auto const& l){ return std::imag( l ); } ); +// BOOST_CHECK_EQUAL_COLLECTIONS(r0.begin(), r0.end(), r2.begin(), r2.end()); + +// complex_tensor_t r3 = ublas::conj( (a+a) / complex_t( 2,2 ) ); +// std::transform( b.begin(), b.end(), r00.begin(), [](auto const& l){ return std::conj( l ); } ); +// BOOST_CHECK_EQUAL_COLLECTIONS(r00.begin(), r00.end(), r3.begin(), r3.end()); + +// } +// } + +// }); + + +// } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/functions/test_functions_tensor.cpp b/test/tensor/functions/test_functions_tensor.cpp new file mode 100644 index 000000000..c68efdd10 --- /dev/null +++ b/test/tensor/functions/test_functions_tensor.cpp @@ -0,0 +1,127 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_functions_tensor, + * boost::unit_test::description("Validate Tensor Product") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("tensor_prod") + *boost::unit_test::description("Testing the tensor product for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using inner_t = inner_type_t; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + auto const rank = a.rank(); + + if(rank <= 1ul) return; + + auto b = tensor_type{a.extents(), value_type{3}}; + + a = value_type{2}; + + BOOST_TEST_CONTEXT("[Dynamic Tensor Product] tensor with rank("<< rank <<")"){ + + // the number of contractions is changed. + for( auto q = 0ul; q <= rank; ++q) { // rank + + auto phi = std::vector ( 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 *= value_type{ static_cast< inner_t >( a.size(phi.at(i)-1) ) }; + + for(auto i = 0ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); + + } + + } + }); + + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("tensor_prod") + *boost::unit_test::description("Testing the tensor product for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using inner_t = inner_type_t; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + + static constexpr auto rank = a.rank(); + + if constexpr (rank > 1ul) { + + auto b = tensor_type(a.extents()); + a = value_type{2}; + b = value_type{3}; + + BOOST_TEST_CONTEXT("[Static Rank Tensor Product] tensor with rank("<< rank <<")"){ + + static_for_each([&](IType /*id*/){ + constexpr auto q = IType::value; + + auto phi = std::array (); + + 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 *= value_type{ static_cast< inner_t >( a.size(phi.at(i)-1) ) }; + + for(auto i = 0ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); + + }); + + } + } + + }); + + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/functions/test_functions_tensor_permutation.cpp b/test/tensor/functions/test_functions_tensor_permutation.cpp new file mode 100644 index 000000000..0bc3a81e7 --- /dev/null +++ b/test/tensor/functions/test_functions_tensor_permutation.cpp @@ -0,0 +1,170 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_functions_tensor_permutation, + * boost::unit_test::description("Validate Tensor Product with Permutation") +) + + +constexpr auto compute_factorial(std::size_t const& p) noexcept{ + std::size_t f = 1ul; + for(std::size_t i = 1u; i <= p; ++i) + f *= i; + return f; +} + +constexpr auto permute_extents(auto const& pi, auto const& na){ + namespace ublas = boost::numeric::ublas; + using extents_type = std::decay_t< decltype(na) >; + + auto nb_base = na.base(); + assert(pi.size() == ublas::size(na)); + for(auto j = 0u; j < pi.size(); ++j) + nb_base[pi[j]-1] = na[j]; + return extents_type(nb_base); +}; + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("tensor_prod_permutation") + *boost::unit_test::description("Testing the tensor product with permutation for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using inner_t = inner_type_t; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + auto const pa = a.rank(); + + if(pa <= 1ul) return; + + BOOST_TEST_CONTEXT("[Dynamic Tensor Product Permutation] tensor with rank("<< pa <<")"){ + + auto const& na = a.extents(); + auto pi = std::vector(pa); + auto fac = compute_factorial(pa); + std::iota( pi.begin(), pi.end(), 1ul ); + + 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 ( q ); // concatenation for a + auto phib = std::vector ( 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 *= value_type( static_cast< inner_t >( na.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_TEST_DECORATOR( + *boost::unit_test::label("tensor_prod_permutation") + *boost::unit_test::description("Testing the tensor product with permutation for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using inner_t = inner_type_t; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + + constexpr auto rank = a.rank(); + + if constexpr (rank > 1ul) { + + BOOST_TEST_CONTEXT("[Static Rank Tensor Product Permutation] tensor with rank("<< rank <<")"){ + auto const& na = a.extents(); + auto pi = std::array(); + auto fac = compute_factorial(rank); + std::iota( pi.begin(), pi.end(), 1ul ); + + for(auto f = 0ul; f < fac; ++f){ + + auto nb = permute_extents( pi, na ); + auto b = tensor_type(nb); + b = value_type{3}; + + // the number of contractions is changed. + static_for_each([&](IType /*id*/){ + constexpr auto q = IType::value; + + auto phia = std::array (); // concatenation for a + auto phib = std::array (); // 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 *= value_type( static_cast< inner_t >( na.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_AUTO_TEST_SUITE_END() diff --git a/test/tensor/functions/test_functions_trans.cpp b/test/tensor/functions/test_functions_trans.cpp new file mode 100644 index 000000000..c0db0cc30 --- /dev/null +++ b/test/tensor/functions/test_functions_trans.cpp @@ -0,0 +1,163 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_functions_transpose, + * boost::unit_test::description("Validate Tensor Transpose") +) + + +constexpr auto compute_factorial(std::size_t const& p) noexcept{ + std::size_t f = 1ul; + for(std::size_t i = 1u; i <= p; ++i) + f *= i; + return f; +} + +constexpr auto inverse(auto const& pi) noexcept{ + auto pi_inv = pi; + for(auto j = 0u; j < pi.size(); ++j) + pi_inv[pi[j]-1] = j+1; + return pi_inv; +} + +constexpr auto permute_extents(auto const& pi, auto const& na){ + namespace ublas = boost::numeric::ublas; + using extents_type = std::decay_t< decltype(na) >; + + auto nb_base = na.base(); + assert(pi.size() == ublas::size(na)); + for(auto j = 0u; j < pi.size(); ++j) + nb_base[pi[j]-1] = na[j]; + return extents_type(nb_base); +}; + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("tensor_trans") + *boost::unit_test::description("Testing the tensor transpose for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + auto const rank = a.rank(); + + if(rank <= 1ul) return; + + BOOST_TEST_CONTEXT("[Dynamic Tensor Transpose] tensor with rank("<< rank <<")"){ + + ublas::iota(a,value_type{0}); + auto const p = rank; + auto aref = a; + + auto pi = std::vector(p); + std::iota(pi.begin(), pi.end(), 1); + + a = ublas::trans( a, pi ); + BOOST_CHECK_EQUAL_COLLECTIONS(a.begin(), a.end(), aref.begin(), aref.end()); + + + auto const factorial = compute_factorial(p); + auto i = 0ul; + + for(; i < factorial - 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_EQUAL_COLLECTIONS(a.begin(), a.end(), aref.begin(), aref.end()); + + } + }); + + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("tensor_trans") + *boost::unit_test::description("Testing the tensor transpose for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, auto a){ + constexpr auto rank = a.rank(); + + if constexpr (rank > 1ul){ + + BOOST_TEST_CONTEXT("[Static Rank Tensor Transpose] tensor with rank("<< rank <<")"){ + + ublas::iota(a,value_type{0}); + constexpr auto p = rank; + auto aref = a; + + auto pi = std::array(); + std::iota(pi.begin(), pi.end(), 1); + + a = ublas::trans( a, pi ); + BOOST_CHECK_EQUAL_COLLECTIONS(a.begin(), a.end(), aref.begin(), aref.end()); + + + auto const factorial = compute_factorial(p); + auto i = 0ul; + + for(; i < factorial - 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_EQUAL_COLLECTIONS(a.begin(), a.end(), aref.begin(), aref.end()); + + } + } + + }); + + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/functions/test_functions_vector.cpp b/test/tensor/functions/test_functions_vector.cpp new file mode 100644 index 000000000..2a28ec318 --- /dev/null +++ b/test/tensor/functions/test_functions_vector.cpp @@ -0,0 +1,163 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include + +BOOST_AUTO_TEST_SUITE(test_functions_vector, + * boost::unit_test::description("Validate Vector Product") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("vector_prod") + *boost::unit_test::description("Testing the vector product for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using inner_t = inner_type_t; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + using vector_type = typename tensor_type::vector_type; + + auto const rank = a.rank(); + + if(rank == 0ul) return; + + a = value_type{2}; + + BOOST_TEST_CONTEXT("[Dynamic Tensor Vector Product] tensor with rank("<< rank <<")"){ + + for(auto m = 0u; m < rank; ++m){ + auto const em = a.size(m); + + auto b = vector_type (em, 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( static_cast< inner_t >(em) ) * a[i] ); + + } + + } + }); + + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("vector_prod") + *boost::unit_test::description("Testing the vector product for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using inner_t = inner_type_t; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ + using vector_type = typename tensor_type::vector_type; + + constexpr auto rank = a.rank(); + + if constexpr (rank > 0ul) { + + a = value_type{2}; + + BOOST_TEST_CONTEXT("[Static Rank Tensor Vector Product] tensor with rank("<< rank <<")"){ + + for(auto m = 0u; m < rank; ++m){ + auto const em = a.size(m); + + auto b = vector_type (em, 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( static_cast< inner_t >(em) ) * a[i] ); + + } + + } + } + + }); + + +} + +// TODO: Add product support for static tensor and enable this test +// BOOST_TEST_DECORATOR( +// *boost::unit_test::label("vector_prod") +// *boost::unit_test::description("Testing the vector product for static tensor") +// ) +// BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, +// TestTupleType, +// boost::numeric::ublas::test_types, +// boost::numeric::ublas::tuple_fixture_tensor_static +// ) +// { +// namespace ublas = boost::numeric::ublas; +// using value_type = typename TestTupleType::first_type; +// using inner_t = inner_type_t; +// using fixture_t = ublas::tuple_fixture_tensor_static; + +// auto const& self = static_cast(*this); + +// ublas::for_each_fixture(self, [](auto /*id*/, tensor_type a){ +// using vector_type = typename tensor_type::vector_type; + +// constexpr auto rank = a.rank(); + +// if constexpr (rank > 0ul) { + +// a = value_type{2}; + +// BOOST_TEST_CONTEXT("[Static Tensor Vector Product] tensor with rank("<< rank <<")"){ + +// for(auto m = 0u; m < rank; ++m){ +// auto const em = a.size(m); + +// auto b = vector_type (em, 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( static_cast< inner_t >(em) ) * a[i] ); + +// } + +// } +// } + +// }); +// } + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/multiplication/test_multiplication_inner.cpp b/test/tensor/multiplication/test_multiplication_inner.cpp new file mode 100644 index 000000000..6088f8d88 --- /dev/null +++ b/test/tensor/multiplication/test_multiplication_inner.cpp @@ -0,0 +1,146 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(test_multiplication_inner, + *boost::unit_test::description("Validate Inner Product") +) + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("inner_product") + *boost::unit_test::description("Testing inner product for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_dynamic; + using vector_t = std::vector; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& n){ + auto const rank = ublas::size(n); + auto const p = ublas::product(n); + + if(rank < 2ul) return; + + BOOST_TEST_CONTEXT("[Inner Product Dynamic Tensor] testing for rank(" << rank << ")"){ + auto a = vector_t(p, value_type{2}); + auto b = vector_t(p, value_type{3}); + auto w = ublas::to_strides(n,layout_type{}); + + auto c = ublas::inner(rank, 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_TEST_DECORATOR( + *boost::unit_test::label("inner_product") + *boost::unit_test::description("Testing inner product for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static_rank; + using vector_t = std::vector; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& n){ + constexpr auto rank = std::tuple_size_v; + auto const p = ublas::product(n); + + if constexpr(rank >= 2ul){ + BOOST_TEST_CONTEXT("[Inner Product Static Rank Tensor] testing for rank(" << rank << ")"){ + auto a = vector_t(p, value_type{2}); + auto b = vector_t(p, value_type{3}); + auto w = ublas::to_strides(n,layout_type{}); + + auto c = ublas::inner(rank, 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 ); + } + } + + }); +} + +// FIXME: temp fix to the invalid computation of static strides, +// rempve this after the fix +template +constexpr auto get_strides(std::array const& temp) noexcept{ + namespace ublas = boost::numeric::ublas; + using extents_type = ublas::extents_core; + auto n = extents_type{temp}; + return ublas::to_strides(n, L{}); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("inner_product") + *boost::unit_test::description("Testing inner product for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& n){ + constexpr auto rank = ublas::size_v; + constexpr auto p = ublas::product_v; + + if constexpr(rank >= 2ul){ + BOOST_TEST_CONTEXT("[Inner Product Static Tensor] testing for rank(" << rank << ")"){ + auto a = std::array(); + std::fill(a.begin(), a.end(), value_type{2}); + auto b = std::array(); + std::fill(a.begin(), a.end(), value_type{3}); + + // FIXME: remove after the fix + auto w = get_strides(ublas::to_array_v); + + auto c = ublas::inner(rank, 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_AUTO_TEST_SUITE_END() diff --git a/test/tensor/multiplication/test_multiplication_mtm.cpp b/test/tensor/multiplication/test_multiplication_mtm.cpp new file mode 100644 index 000000000..19238d7a6 --- /dev/null +++ b/test/tensor/multiplication/test_multiplication_mtm.cpp @@ -0,0 +1,190 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(test_multiplication_mtm, + *boost::unit_test::description("Validate Matrix Times Matrix") +) + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("mtm") + *boost::unit_test::description("Testing mtm for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_dynamic; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + auto const rank = ublas::size(na); + auto const p = ublas::product(na); + + if(rank != 2ul) return; + + BOOST_TEST_CONTEXT("[MTM Dynamic Tensor] testing for m(" << na[0] << "), n(" << na[1] <<")"){ + auto a = vector_t (p, value_type{2}); + auto wa = ublas::to_strides(na,layout_type{}); + + auto nb = extents_type {na[1],na[0]}; + auto wb = ublas::to_strides(nb,layout_type{}); + auto b = vector_t (ublas::product(nb), value_type{1} ); + + auto nc = extents_type {na[0],nb[1]}; + auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t (ublas::product(nc)); + + + ublas::detail::recursive::mtm( + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data() + ); + + auto v = value_type{ static_cast(na[1]) }*a[0]; + BOOST_CHECK(std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v;})); + } + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("mtm") + *boost::unit_test::description("Testing mtm for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static_rank; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + constexpr auto rank = std::tuple_size_v; + auto const p = ublas::product(na); + + if constexpr (rank == 2ul){ + + BOOST_TEST_CONTEXT("[MTM Static Rank Tensor] testing for m(" << na[0] << "), n(" << na[1] <<")"){ + auto a = vector_t (p, value_type{2}); + auto wa = ublas::to_strides(na,layout_type{}); + + auto nb = extents_type {na[1],na[0]}; + auto wb = ublas::to_strides(nb,layout_type{}); + auto b = vector_t (ublas::product(nb), value_type{1} ); + + auto nc = extents_type {na[0],nb[1]}; + auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t (ublas::product(nc)); + + + ublas::detail::recursive::mtm( + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data() + ); + + auto v = value_type{ static_cast(na[1]) }*a[0]; + BOOST_CHECK(std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v;})); + } + } + + }); +} + +// FIXME: temp fix to the invalid computation of static strides, +// rempve this after the fix +template +constexpr auto get_strides(std::array const& temp) noexcept{ + namespace ublas = boost::numeric::ublas; + using extents_type = ublas::extents_core; + auto n = extents_type{temp}; + return ublas::to_strides(n, L{}); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("mtm") + *boost::unit_test::description("Testing mtm for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& /*na*/){ + using extents_value_type = typename extents_type::value_type; + constexpr auto rank = ublas::size_v; + constexpr auto const p = ublas::product_v; + + if constexpr (rank == 2ul){ + + constexpr auto na = ublas::to_array_v; + + BOOST_TEST_CONTEXT("[MTM Static Rank Tensor] testing for m(" << na[0] << "), n(" << na[1] <<"), k(" << na[1] <<")"){ + auto a = std::array(); + std::fill(a.begin(), a.end(), value_type{2}); + auto wa = get_strides(na); + + using nb_type = ublas::extents_core, ublas::get_v >; + auto nb = ublas::to_array_v; + auto wb = get_strides(nb); + auto b = std::array>(); + std::fill(b.begin(), b.end(), value_type{1}); + + using nc_type = ublas::extents_core, ublas::get_v >; + auto nc = ublas::to_array_v; + auto wc = get_strides(nc); + auto c = std::array>(); + + ublas::detail::recursive::mtm( + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data() + ); + + auto v = value_type{ static_cast(na[1]) }*a[0]; + BOOST_CHECK(std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v;})); + } + + } + + }); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/test/tensor/multiplication/test_multiplication_mtv.cpp b/test/tensor/multiplication/test_multiplication_mtv.cpp new file mode 100644 index 000000000..272407ff4 --- /dev/null +++ b/test/tensor/multiplication/test_multiplication_mtv.cpp @@ -0,0 +1,232 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(test_multiplication_mtv, + *boost::unit_test::description("Validate Matrix Times Vector") +) + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("mtv") + *boost::unit_test::description("Testing mtv for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_dynamic; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + auto const rank = ublas::size(na); + auto const p = ublas::product(na); + using base_t = typename extents_type::base_type; + + if(rank != 2ul) return; + + auto a = vector_t(p, value_type{2}); + auto wa = ublas::to_strides(na, layout_type{}); + + for(std::size_t m = 0ul; m < rank; ++m){ + BOOST_TEST_CONTEXT("[MTV Dynamic Tensor] testing for m(" << m << ") and n(" << p << ")"){ + auto nb = extents_type {na[m], std::size_t{1}}; + auto b = vector_t(ublas::product(nb), value_type{1} ); + + auto nc_base = base_t(std::max(std::size_t{rank - 1u}, std::size_t{2}), 1); + for(std::size_t i = 0ul, j = 0ul; i < rank; ++i){ + if(i != m) nc_base[j++] = na[i]; + } + + auto nc = extents_type (std::move(nc_base)); + auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t (ublas::product(nc), value_type{0}); + + ublas::detail::recursive::mtv( + m, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data()); + + auto v = value_type{static_cast(na[m])}; + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); + } + } + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("mtv") + *boost::unit_test::description("Testing mtv for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static_rank; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + constexpr auto rank = std::tuple_size_v; + auto const p = ublas::product(na); + using extents_value_type = typename extents_type::value_type; + + if constexpr (rank == 2ul){ + constexpr auto nc_rank = std::max(std::size_t{rank - 1u}, std::size_t{2}); + using nc_extents_type = ublas::extents_core; + using base_t = typename nc_extents_type::base_type; + auto a = vector_t(p, value_type{2}); + auto wa = ublas::to_strides(na, layout_type{}); + + for(std::size_t m = 0ul; m < rank; ++m){ + BOOST_TEST_CONTEXT("[MTV Static Rank Tensor] testing for m(" << m << ") and n(" << p << ")"){ + auto nb = extents_type {na[m], std::size_t{1}}; + auto b = vector_t(ublas::product(nb), value_type{1} ); + + auto nc_base = base_t{}; + std::fill(std::begin(nc_base), std::end(nc_base), 1ul); + + for(std::size_t i = 0ul, j = 0ul; i < rank; ++i){ + if(i != m) nc_base[j++] = na[i]; + } + + auto nc = nc_extents_type (std::move(nc_base)); + auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t (ublas::product(nc), value_type{0}); + + ublas::detail::recursive::mtv( + m, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data()); + + auto v = value_type{static_cast(na[m])}; + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); + } + } + } + + }); +} + +template +constexpr auto generate_result_extents() noexcept{ + namespace ublas = boost::numeric::ublas; + using value_type = typename E::value_type; + constexpr auto sz = std::max( std::size_t{N - 1ul}, std::size_t{2} ); + + constexpr auto helper = [](std::index_sequence){ + constexpr auto process_arr = []{ + std::array temp; + constexpr auto n = ublas::to_array_v; + std::fill(std::begin(temp), std::end(temp), value_type{1}); + auto j = 0ul; + for(auto i = 0ul; i < N; ++i){ + if(i != M) temp[j++] = n[i]; + } + return temp; + }; + constexpr auto arr = process_arr(); + return ublas::extents_core{}; + }; + return helper(std::make_index_sequence{}); +} +// FIXME: temp fix to the invalid computation of static strides, +// rempve this after the fix +template +constexpr auto get_strides(std::array const& temp) noexcept{ + namespace ublas = boost::numeric::ublas; + using extents_type = ublas::extents_core; + auto n = extents_type{temp}; + return ublas::to_strides(n, L{}); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("mtv") + *boost::unit_test::description("Testing mtv for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& /*na*/){ + using extents_value_type = typename extents_type::value_type; + static constexpr auto rank = ublas::size_v; + static constexpr auto p = ublas::product_v; + + if constexpr (rank == 2ul){ + auto na = ublas::to_array_v; + + auto a = std::array(); + std::fill(std::begin(a), std::end(a), value_type{2}); + // FIXME: use strides_v after the fix + auto wa = get_strides(na); + + static_for_each([&wa, &a](IType /*id*/){ + constexpr auto na = ublas::to_array_v; + constexpr std::size_t m = IType::value; + + BOOST_TEST_CONTEXT("[MTV Static Tensor] testing for m(" << m << ") and n(" << p << ")"){ + using nb_type = ublas::extents_core; + auto b = std::array >{}; + std::fill(std::begin(b), std::end(b), value_type{1}); + + using nc_type = decltype( generate_result_extents() ); + auto nc = ublas::to_array_v; + // FIXME: use strides_v after the fix + auto wc = get_strides(nc); + auto c = std::array >(); + std::fill(std::begin(c), std::end(c), value_type{0}); + + ublas::detail::recursive::mtv( + m, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data()); + + auto v = value_type{static_cast(na[m])}; + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); + } + }); + } + + }); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/test/tensor/multiplication/test_multiplication_outer.cpp b/test/tensor/multiplication/test_multiplication_outer.cpp new file mode 100644 index 000000000..78e37f41c --- /dev/null +++ b/test/tensor/multiplication/test_multiplication_outer.cpp @@ -0,0 +1,222 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include +#include +#include + +BOOST_AUTO_TEST_SUITE(test_multiplication_outer, + *boost::unit_test::description("Validate Outer Product") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("inner_product") + *boost::unit_test::description("Testing outer product for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_dynamic; + using vector_t = std::vector; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [&self](auto /*id*/, extents_type const& na){ + + using base_t = typename extents_type::base_type; + + auto const a_rank = ublas::size(na); + auto const ap = ublas::product(na); + + if(a_rank < 2ul) return; + + auto a = vector_t(ap, value_type{2}); + auto wa = ublas::to_strides(na,layout_type{}); + + ublas::for_each_fixture(self, [&](auto /*id*/, extents_type const& nb) { + auto const b_rank = ublas::size(nb); + auto const bp = ublas::product(nb); + + if(b_rank < 2ul) return; + + auto b = vector_t(bp, value_type{3}); + auto wb = ublas::to_strides(nb,layout_type{}); + + BOOST_TEST_CONTEXT("[Outer Product Dynamic Tensor] testing for outer rank(" << a_rank << ") : inner rank(" << b_rank << ")"){ + + auto const c_rank = a_rank + b_rank; + auto nc_base = base_t(c_rank); + + auto it = std::copy(ublas::begin(na), ublas::end(na), nc_base.begin()); + std::copy(ublas::begin(nb), ublas::end(nb), it); + + auto nc = extents_type(std::move(nc_base)); + auto const cp = ublas::product(nc); + auto c = vector_t(cp); + auto wc = ublas::to_strides(nc,layout_type{}); + + ublas::outer(c.data(), c_rank, nc.data(), wc.data(), + a.data(), a_rank, na.data(), wa.data(), + b.data(), b_rank, nb.data(), wb.data()); + for(auto const& cc : c) + BOOST_REQUIRE_EQUAL( cc , a[0]*b[0] ); + } + }); + + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("inner_product") + *boost::unit_test::description("Testing outer product for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static_rank; + using vector_t = std::vector; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [&self](auto /*id*/, outer_extents_type const& na){ + + using extents_value_type = typename outer_extents_type::value_type; + + static constexpr auto a_rank = std::tuple_size_v; + auto const ap = ublas::product(na); + + if constexpr(a_rank >= 2ul){ + auto a = vector_t(ap, value_type{2}); + auto wa = ublas::to_strides(na,layout_type{}); + + ublas::for_each_fixture(self, [&a, &wa, &na](auto /*id*/, inner_extents_type const& nb) { + constexpr auto b_rank = std::tuple_size_v; + auto const bp = ublas::product(nb); + + if constexpr(b_rank >= 2ul){ + auto b = vector_t(bp, value_type{3}); + auto wb = ublas::to_strides(nb,layout_type{}); + + BOOST_TEST_CONTEXT("[Outer Product Statc Rank Tensor] testing for outer rank(" << a_rank << ") : inner rank(" << b_rank << ")"){ + + constexpr auto const c_rank = a_rank + b_rank; + using nc_type = ublas::extents_core; + auto nc_base = typename nc_type::base_type(); + + auto it = std::copy(ublas::begin(na), ublas::end(na), nc_base.begin()); + std::copy(ublas::begin(nb), ublas::end(nb), it); + + auto nc = nc_type(nc_base); + auto const cp = ublas::product(nc); + auto c = vector_t(cp); + auto wc = ublas::to_strides(nc,layout_type{}); + + ublas::outer(c.data(), c_rank, nc.data(), wc.data(), + a.data(), a_rank, na.data(), wa.data(), + b.data(), b_rank, nb.data(), wb.data()); + for(auto const& cc : c) + BOOST_REQUIRE_EQUAL( cc , a[0]*b[0] ); + } + } + + }); + } + + + }); +} + +// FIXME: temp fix to the invalid computation of static strides, +// rempve this after the fix +template +constexpr auto get_strides(std::array const& temp) noexcept{ + namespace ublas = boost::numeric::ublas; + using extents_type = ublas::extents_core; + auto n = extents_type{temp}; + return ublas::to_strides(n, L{}); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("inner_product") + *boost::unit_test::description("Testing outer product for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [&self](auto /*id*/, outer_extents_type const& na){ + + static constexpr auto a_rank = ublas::size_v; + static constexpr auto ap = ublas::product_v; + + if constexpr(a_rank >= 2ul){ + auto a = std::array(); + std::fill(a.begin(), a.end(), value_type{2}); + + auto wa = get_strides(ublas::to_array_v); + + ublas::for_each_fixture(self, [&a, &wa, &na](auto /*id*/, inner_extents_type const& nb) { + constexpr auto b_rank = ublas::size_v; + constexpr auto bp = ublas::product_v; + + if constexpr(b_rank >= 2ul){ + auto b = std::array(); + std::fill(b.begin(), b.end(), value_type{3}); + + auto wb = get_strides(ublas::to_array_v); + + BOOST_TEST_CONTEXT("[Outer Product Statc Rank Tensor] testing for outer rank(" << a_rank << ") : inner rank(" << b_rank << ")"){ + + constexpr auto const c_rank = a_rank + b_rank; + using nc_type = ublas::cat_t; + + constexpr auto cp = ublas::product_v; + auto c = std::array(); + constexpr auto nc = ublas::to_array_v; + auto wc = get_strides(nc); + + ublas::outer(c.data(), c_rank, nc.data(), wc.data(), + a.data(), a_rank, na.data(), wa.data(), + b.data(), b_rank, nb.data(), wb.data()); + for(auto const& cc : c) + BOOST_REQUIRE_EQUAL( cc , a[0]*b[0] ); + } + } + + }); + } + + + }); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/multiplication/test_multiplication_ttm.cpp b/test/tensor/multiplication/test_multiplication_ttm.cpp new file mode 100644 index 000000000..36cf4993a --- /dev/null +++ b/test/tensor/multiplication/test_multiplication_ttm.cpp @@ -0,0 +1,196 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(test_multiplication_ttm, + *boost::unit_test::description("Validate Tensor Times Matrix") +) + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttm") + *boost::unit_test::description("Testing ttm for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_dynamic; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + auto const rank = ublas::size(na); + auto const p = ublas::product(na); + + if (rank <= 1ul) return; + + BOOST_TEST_CONTEXT("[TTM Dynamic Tensor] testing for rank(" << rank << ")"){ + auto a = vector_t(p, value_type{2}); + auto wa = ublas::to_strides(na,layout_type{}); + for(auto m = std::size_t{0}; m < rank; ++m){ + const auto nb = extents_type {na[m], na[m] }; + const auto b = vector_t (ublas::product(nb), value_type{1} ); + const auto wb = ublas::to_strides(nb,layout_type{}); + + const auto& nc = na; + const auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t (ublas::product(nc), value_type{0}); + + ublas::ttm(m+1, rank, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + + auto v = value_type{ static_cast(na[m]) }; + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); + } + } + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttm") + *boost::unit_test::description("Testing ttm for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static_rank; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + constexpr auto rank = std::tuple_size_v; + auto const p = ublas::product(na); + using extents_value_type = typename extents_type::value_type; + + if constexpr (rank > 1ul){ + + BOOST_TEST_CONTEXT("[TTM Static Rank Tensor] testing for rank(" << rank << ")"){ + auto a = vector_t(p, value_type{2}); + auto wa = ublas::to_strides(na,layout_type{}); + for(auto m = std::size_t{0}; m < rank; ++m){ + using nb_type = ublas::extents_core< extents_value_type, 2ul >; + const auto nb = nb_type{na[m], na[m]}; + const auto b = vector_t(ublas::product(nb), value_type{1} ); + const auto wb = ublas::to_strides(nb,layout_type{}); + + const auto& nc = na; + const auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t(ublas::product(nc), value_type{0}); + + ublas::ttm(m+1, rank, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + + auto v = value_type{ static_cast(na[m]) }; + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); + } + } + } + + }); +} + +// FIXME: temp fix to the invalid computation of static strides, +// rempve this after the fix +template +constexpr auto get_strides(std::array const& temp) noexcept{ + namespace ublas = boost::numeric::ublas; + using extents_type = ublas::extents_core; + auto n = extents_type{temp}; + return ublas::to_strides(n, L{}); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttm") + *boost::unit_test::description("Testing ttm for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& /*na*/){ + using extents_value_type = typename extents_type::value_type; + static constexpr auto rank = ublas::size_v; + static constexpr auto p = ublas::product_v; + + if constexpr (rank > 1ul){ + + BOOST_TEST_CONTEXT("[TTM Static Rank Tensor] testing for rank(" << rank << ")"){ + + auto na = ublas::to_array_v; + + auto a = std::array(); + std::fill(a.begin(), a.end(), value_type{2}); + auto wa = get_strides(na); + + static_for_each([&a, &wa](IType /*id*/){ + constexpr auto na = ublas::to_array_v; + constexpr auto m = IType::value; + + using nb_type = ublas::extents_core; + auto nb = ublas::to_array_v; + auto wb = get_strides(nb); + auto b = std::array>(); + std::fill(b.begin(), b.end(), value_type{1}); + + auto nc = na; + auto wc = wa;; + auto c = std::array>(); + + ublas::ttm(m+1, rank, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + auto v = value_type{ static_cast(na[m]) }; + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); + }); + } + + } + + }); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/test/tensor/multiplication/test_multiplication_ttt.cpp b/test/tensor/multiplication/test_multiplication_ttt.cpp new file mode 100644 index 000000000..1644f3523 --- /dev/null +++ b/test/tensor/multiplication/test_multiplication_ttt.cpp @@ -0,0 +1,284 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(test_tensor_ttt, + *boost::unit_test::description("Validate Tensor Times Tensor") +) + +constexpr auto calculate_nc_base(auto& out, auto const& na, auto const& nb, std::size_t r, std::size_t s) noexcept{ + using namespace boost::numeric::ublas; + using namespace std; + auto it = std::copy(begin(na), begin(na) + r, out.begin()); + std::copy(begin(nb), begin(nb) + s, it); +}; + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttt") + *boost::unit_test::description("Testing ttt for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_dynamic; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + auto const rank = ublas::size(na); + auto const p = ublas::product(na); + using extents_base_t = typename extents_type::base_type; + + if(rank <= 1ul) return; + + constexpr auto one = std::size_t{1}; + constexpr auto two = std::size_t{2}; + + BOOST_TEST_CONTEXT("[TTT Dynamic Tensor] testing for rank(" << rank << ")"){ + + auto wa = ublas::to_strides(na,layout_type{}); + auto a = vector_t(p, value_type{2}); + auto pa = rank; + + auto const& nb = na; + auto wb = ublas::to_strides(nb,layout_type{}); + auto b = vector_t(ublas::product(nb), value_type{3}); + auto pb = ublas::size(nb); + + // the number of contractions is changed. + for(auto q = std::size_t{0}; q <= pa; ++q) { + + auto r = pa - q; + auto s = pb - q; + + auto pc = r+s > 0 ? std::max(std::size_t{r+s},two) : two; + + auto nc_base = extents_base_t(pc, 1ul); + calculate_nc_base(nc_base, na, nb, r, s); + + auto nc = extents_type ( std::move(nc_base) ); + auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t ( ublas::product(nc), value_type{0} ); + + 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 = one; + for(auto i = r; i < pa; ++i) + acc *= na[i]; + + auto v = value_type{ static_cast(acc) }*a[0]*b[0]; + + BOOST_CHECK( std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v; } ) ); + + } + } + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttt") + *boost::unit_test::description("Testing ttt for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static_rank; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + static constexpr auto rank = ublas::size_v; + auto const p = ublas::product(na); + using extents_value_type = typename extents_type::value_type; + + if constexpr(rank > 1ul){ + + static constexpr auto one = std::size_t{1}; + static constexpr auto two = std::size_t{2}; + + auto wa = ublas::to_strides(na,layout_type{}); + auto a = vector_t(p, value_type{2}); + static constexpr auto pa = rank; + + auto const& nb = na; + auto wb = ublas::to_strides(nb,layout_type{}); + auto b = vector_t(ublas::product(nb), value_type{3}); + static constexpr auto pb = ublas::size_v; + + BOOST_TEST_CONTEXT("[TTT Static Rank Tensor] testing for rank(" << rank << ")"){ + + static_for_each([&wa, &a, &na, &nb, &wb, &b](IType /*id*/){ + constexpr auto q = IType::value; + constexpr auto r = pa - q; + constexpr auto s = pb - q; + + constexpr auto pc = r+s > 0 ? std::max(std::size_t{r+s},two) : two; + + using nc_type = ublas::extents_core; + auto nc_base = typename nc_type::base_type{}; + std::fill(nc_base.begin(), nc_base.end(), 1ul); + calculate_nc_base(nc_base, na, nb, r, s); + + auto nc = extents_type ( nc_base ); + auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t ( ublas::product(nc), value_type{0} ); + + 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 = one; + for(auto i = r; i < pa; ++i) + acc *= na[i]; + + auto v = value_type{ static_cast(acc) }*a[0]*b[0]; + + BOOST_CHECK( std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v; } ) ); + }); + } + } + + }); +} + +template +constexpr auto compute_nc() noexcept{ + namespace ublas = boost::numeric::ublas; + using value_type = typename E1::value_type; + constexpr auto pc = r+s > std::size_t{0} ? std::max(std::size_t{r+s}, std::size_t{2}) : std::size_t{2}; + + constexpr auto helper = [](std::index_sequence){ + constexpr auto helper1 = []{ + std::array temp; + constexpr auto na = ublas::to_array_v; + constexpr auto nb = ublas::to_array_v; + std::fill(std::begin(temp), std::end(temp), value_type{1}); + calculate_nc_base(temp, na, nb, r, s); + return temp; + }; + constexpr auto arr = helper1(); + return ublas::extents_core{}; + }; + return helper(std::make_index_sequence{}); +} + +// FIXME: temp fix to the invalid computation of static strides, +// rempve this after the fix +template +constexpr auto get_strides(std::array const& temp) noexcept{ + namespace ublas = boost::numeric::ublas; + using extents_type = ublas::extents_core; + auto n = extents_type{temp}; + return ublas::to_strides(n, L{}); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttt") + *boost::unit_test::description("Testing ttt for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + static constexpr auto rank = ublas::size_v; + static constexpr auto p = ublas::product_v; + + if constexpr(rank > 1ul){ + + static constexpr auto one = std::size_t{1}; + + // FIXME: remove after the fix + auto wa = get_strides(ublas::to_array_v); + auto a = std::array(); + std::fill(a.begin(), a.end(), value_type{1}); + static constexpr auto pa = rank; + + auto const& nb = na; + using nb_type = decltype(nb); + + // FIXME: remove after the fix + auto wb = get_strides(ublas::to_array_v); + auto b = std::array>(); + std::fill(b.begin(), b.end(), value_type{3}); + + static constexpr auto pb = ublas::size_v; + + BOOST_TEST_CONTEXT("[TTT Static Rank Tensor] testing for rank(" << rank << ")"){ + + static_for_each([&wa, &a, &nb, &wb, &b, &na](IType /*id*/){ + constexpr auto q = IType::value; + constexpr auto r = pa - q; + constexpr auto s = pb - q; + + auto nc = compute_nc(); + using nc_type = decltype(nc); + + // FIXME: remove after the fix + auto wc = get_strides(ublas::to_array_v); + auto c = std::array>(); + std::fill(c.begin(), c.end(), value_type{0}); + + 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 = one; + for(auto i = r; i < pa; ++i) + acc *= na[i]; + + auto v = value_type{ static_cast(acc) }*a[0]*b[0]; + + BOOST_CHECK( std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v; } ) ); + }); + } + } + + }); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/test/tensor/multiplication/test_multiplication_ttt_permutation.cpp b/test/tensor/multiplication/test_multiplication_ttt_permutation.cpp new file mode 100644 index 000000000..46c9b6052 --- /dev/null +++ b/test/tensor/multiplication/test_multiplication_ttt_permutation.cpp @@ -0,0 +1,238 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(test_tensor_ttt_permutation, + *boost::unit_test::description("Validate Tensor Times Tensor With Permuation") +) + + +constexpr auto compute_factorial(std::size_t const& p) noexcept{ + std::size_t f = 1ul; + for(std::size_t i = 1u; i <= p; ++i) + f *= i; + return f; +} + + +constexpr auto compute_inverse_permutation(auto const& pi) noexcept{ + auto pi_inv = pi; + for(auto j = 0u; j < pi.size(); ++j) + pi_inv[pi[j]-1] = j+1; + return pi_inv; +} + +constexpr auto permute_extents(auto const& pi, auto const& na){ + namespace ublas = boost::numeric::ublas; + using extents_type = std::decay_t< decltype(na) >; + + auto nb_base = na.base(); + assert(pi.size() == ublas::size(na)); + for(auto j = 0u; j < pi.size(); ++j) + nb_base[j] = na[pi[j]-1]; + return extents_type(nb_base); +}; + +constexpr auto calculate_nc(auto& out, auto const& pia, auto const& pib_inv, auto const& na, auto const& nb, std::size_t r, std::size_t s){ + for(auto j = 0u; j < r; ++j) + out[j] = na[pia[j]-1]; + + for(auto j = 0u; j < s; ++j) + out[r+j] = nb[ pib_inv[j]-1 ]; +}; + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttt") + *boost::unit_test::description("Testing ttt for dynamic tensor with permutation") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_dynamic; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + auto const rank = ublas::size(na); + auto const p = ublas::product(na); + using extents_base_t = typename extents_type::base_type; + + if(rank <= 1ul) return; + + constexpr auto one = std::size_t{1}; + constexpr auto two = std::size_t{2}; + + BOOST_TEST_CONTEXT("[Permutated TTT Dynamic Tensor] testing for rank(" << rank << ")"){ + auto wa = ublas::to_strides(na,layout_type{}); + auto a = vector_t(p, value_type{2}); + auto pa = rank; + auto pia = std::vector(pa); + std::iota( pia.begin(), pia.end(), one ); + + 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 = ublas::to_strides(nb,layout_type{}); + auto b = vector_t(ublas::product(nb), value_type{3}); + auto pb = ublas::size(nb); + + // the number of contractions is changed. + for(auto q = std::size_t{0}; q <= pa; ++q) { + + auto r = pa - q; + auto s = pb - q; + + auto pc = r+s > 0 ? std::max(std::size_t{r+s},two) : two; + + auto nc_base = extents_base_t(pc,one); + + calculate_nc(nc_base, pia, pib_inv, na, nb, r, s); + + auto nc = extents_type ( nc_base ); + auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t ( ublas::product(nc), 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 = one; + for(auto j = r; j < pa; ++j) + acc *= na[pia[j]-1]; + + auto v = value_type{ static_cast(acc) } * a[0] * b[0]; + + BOOST_CHECK( std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v; } ) ); + + } + + std::next_permutation(pib.begin(), pib.end()); + pib_inv = compute_inverse_permutation(pib); + } + } + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttt") + *boost::unit_test::description("Testing ttt for static rank tensor with permutation") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static_rank; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + constexpr auto const rank = std::tuple_size_v; + auto const p = ublas::product(na); + using extents_value_type = typename extents_type::value_type; + + if constexpr(rank > 1ul){ + + static constexpr auto one = std::size_t{1}; + static constexpr auto two = std::size_t{2}; + + BOOST_TEST_CONTEXT("[Permutated TTT Static Rank Tensor] testing for rank(" << rank << ")"){ + auto wa = ublas::to_strides(na,layout_type{}); + auto a = vector_t(p, value_type{2}); + static constexpr auto pa = rank; + auto pia = std::vector(pa); + std::iota( pia.begin(), pia.end(), one ); + + 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 = ublas::to_strides(nb,layout_type{}); + auto b = vector_t(ublas::product(nb), value_type{3}); + static constexpr auto pb = std::tuple_size_v; + + // the number of contractions is changed. + static_for_each([&a, &pia, &pib_inv, &nb, &wb, &b, &na, &wa](IType /*id*/){ + constexpr auto q = IType::value; + constexpr auto r = pa - q; + constexpr auto s = pb - q; + + constexpr auto pc = r+s > 0ul ? std::max(std::size_t{r+s},two) : two; + using nc_type = ublas::extents_core< extents_value_type, pc >; + using nc_base_type = typename nc_type::base_type; + auto nc_base = nc_base_type(); + std::fill(nc_base.begin(), nc_base.end(), one); + + calculate_nc(nc_base, pia, pib_inv, na, nb, r, s); + + auto nc = nc_type ( nc_base ); + auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t ( ublas::product(nc), 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 = one; + for(auto j = r; j < pa; ++j) + acc *= na[pia[j]-1]; + + auto v = value_type{ static_cast(acc) } * a[0] * b[0]; + + BOOST_CHECK( std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v; } ) ); + }); + + std::next_permutation(pib.begin(), pib.end()); + pib_inv = compute_inverse_permutation(pib); + } + } + } + + }); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/test/tensor/multiplication/test_multiplication_ttv.cpp b/test/tensor/multiplication/test_multiplication_ttv.cpp new file mode 100644 index 000000000..5dec7d5d5 --- /dev/null +++ b/test/tensor/multiplication/test_multiplication_ttv.cpp @@ -0,0 +1,235 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(test_multiplication_ttv, + *boost::unit_test::description("Validate Tensor Times Vector") +) + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttv") + *boost::unit_test::description("Testing ttv for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_dynamic; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + auto const rank = ublas::size(na); + auto const p = ublas::product(na); + using base_t = typename extents_type::base_type; + + BOOST_TEST_CONTEXT("[TTV Dynamic Tensor] testing for rank(" << rank << ")"){ + auto a = vector_t(p, value_type{2}); + auto wa = ublas::to_strides(na,layout_type{}); + for(std::size_t m = 0ul; m < rank; ++m){ + auto b = vector_t (na[m], value_type{1} ); + auto nb = extents_type {na[m],1ul}; + auto wb = ublas::to_strides(nb,layout_type{}); + auto const nc_rank = std::max(std::size_t{rank-1u}, std::size_t{2}); + auto nc_base = base_t(nc_rank,1ul); + + for(std::size_t i = 0ul, j = 0ul; i < rank; ++i) + if(i != m) + nc_base[j++] = na[i]; + + auto nc = extents_type (std::move(nc_base)); + auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t (ublas::product(nc), value_type{0}); + + ublas::ttv(m+1, rank, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + auto v = value_type{ static_cast(na[m]) }; + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); + } + } + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttv") + *boost::unit_test::description("Testing ttv for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static_rank; + using vector_t = std::vector; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& na){ + constexpr auto rank = std::tuple_size_v; + auto const p = ublas::product(na); + using extents_value_type = typename extents_type::value_type; + + if constexpr(rank > 0ul){ + constexpr auto nc_rank = std::max(std::size_t{rank - 1u}, std::size_t{2}); + using nc_extents_type = ublas::extents_core; + using nb_extents_type = ublas::extents_core; + using base_t = typename nc_extents_type::base_type; + BOOST_TEST_CONTEXT("[TTV Static Rank Tensor] testing for rank(" << rank << ")"){ + auto a = vector_t(p, value_type{2}); + auto wa = ublas::to_strides(na,layout_type{}); + for(std::size_t m = 0ul; m < rank; ++m){ + auto b = vector_t (na[m], value_type{1}); + auto nb = nb_extents_type {na[m],1ul}; + auto wb = ublas::to_strides(nb,layout_type{}); + auto nc_base = base_t(); + std::fill(nc_base.begin(), nc_base.end(), 1ul); + + for(std::size_t i = 0ul, j = 0ul; i < rank; ++i) + if(i != m) nc_base[j++] = na[i]; + + auto nc = nc_extents_type (std::move(nc_base)); + auto wc = ublas::to_strides(nc,layout_type{}); + auto c = vector_t (ublas::product(nc), value_type{0}); + + ublas::ttv(m+1, rank, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + auto v = value_type{ static_cast(na[m]) }; + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); + } + } + } + + }); +} + +template +constexpr auto generate_result_extents() noexcept{ + namespace ublas = boost::numeric::ublas; + using value_type = typename E::value_type; + constexpr auto sz = std::max( std::size_t{N - 1ul}, std::size_t{2} ); + + + constexpr auto helper = [](std::index_sequence){ + constexpr auto process_arr = []{ + std::array temp; + constexpr auto n = ublas::to_array_v; + std::fill(std::begin(temp), std::end(temp), value_type{1}); + for(std::size_t i = 0ul, j = 0ul; i < N; ++i){ + if(i != M) temp[j++] = n[i]; + } + return temp; + }; + constexpr auto arr = process_arr(); + return ublas::extents_core{}; + }; + return helper(std::make_index_sequence{}); +} + +// FIXME: temp fix to the invalid computation of static strides, +// rempve this after the fix +template +constexpr auto get_strides(std::array const& temp) noexcept{ + namespace ublas = boost::numeric::ublas; + using extents_type = ublas::extents_core; + auto n = extents_type{temp}; + return ublas::to_strides(n, L{}); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("ttv") + *boost::unit_test::description("Testing ttv for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_extents_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::fixture_extents_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = ublas::fixture_extents_static; + using inner_t = inner_type_t; + + auto const& self = static_cast(*this); + + ublas::for_each_fixture(self, [](auto /*id*/, extents_type const& /*na*/){ + using extents_value_type = typename extents_type::value_type; + static constexpr auto rank = ublas::size_v; + static constexpr auto p = ublas::product_v; + + if constexpr (rank > 0ul){ + + BOOST_TEST_CONTEXT("[TTV Static Tensor] testing for rank(" << rank << ")"){ + + auto na = ublas::to_array_v; + auto a = std::array(); + std::fill(std::begin(a), std::end(a), value_type{2}); + // FIXME: use strides_v after the fix + auto wa = get_strides(na); + + static_for_each([&a, &wa](IType /*id*/){ + + constexpr auto na = ublas::to_array_v; + constexpr auto m = IType::value; + + using nb_type = ublas::extents_core; + auto b = std::array>(); + std::fill(std::begin(b), std::end(b), value_type{1}); + constexpr auto nb = ublas::to_array_v; + + // FIXME: use strides_v after the fix + auto wb = get_strides(nb); + + using nc_type = decltype(generate_result_extents()); + constexpr auto nc = ublas::to_array_v; + + // FIXME: use strides_v after the fix + auto wc = get_strides(nc); + auto c = std::array >(); + std::fill(std::begin(c), std::end(c), value_type{0}); + + ublas::ttv(m+1, rank, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + auto v = value_type{ static_cast(na[m]) }; + BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); + }); + } + } + + }); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/test/tensor/tensor/test_tensor_access_operator.cpp b/test/tensor/tensor/test_tensor_access_operator.cpp new file mode 100644 index 000000000..828fd7ae9 --- /dev/null +++ b/test/tensor/tensor/test_tensor_access_operator.cpp @@ -0,0 +1,385 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_access_operator, + *boost::unit_test::description("Validate Access Operator") + *boost::unit_test::depends_on("test_extents_size") +) + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_dynamic::operator()/operator[]") + *boost::unit_test::description("Testing the dynamic tensor's read/write [operator()/operator[]] for single-dimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic_single_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check = [](auto t){ + auto const sz = t.size(); + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < sz; ++i, v += value_type(1)){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") dynamic tensor operator()(" << i << ") = " << v); + t(i) = v; + BOOST_REQUIRE_EQUAL(t(i), v); + + auto w = v + value_type(1); + BOOST_TEST_CHECKPOINT("[operator[]] rank("<< rank <<") dynamic tensor operator[](" << i << ") = " << w); + t[i] = w; + BOOST_REQUIRE_EQUAL(t[i], w); + } + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check](auto /*id*/, auto const& t){ + check(t); + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_dynamic::operator()/operator[]") + *boost::unit_test::description("Testing the dynamic tensor's read/write [operator()] for multidimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic_multi_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check1 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") dynamic tensor operator()(" << i << ") = " << v); + t(i) = v; + BOOST_REQUIRE_EQUAL(t(i), v); + v += value_type(1); + } + }; + + constexpr auto check2 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") dynamic tensor operator()(" << i <<", "<< j << ") = " << v); + t(i,j) = v; + BOOST_REQUIRE_EQUAL(t(i,j), v); + v += value_type(1); + } + } + BOOST_CHECK_THROW((void)t.at(0,0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t.at(0,0,0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t(0,0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t(0,0,0,0), std::invalid_argument); + }; + + constexpr auto check3 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") dynamic tensor operator()(" << i <<", "<< j <<", "<< k << ") = " << v); + t(i,j,k) = v; + BOOST_REQUIRE_EQUAL(t(i,j,k), v); + v += value_type(1); + } + } + } + BOOST_CHECK_THROW((void)t.at(0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t.at(0,0,0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t(0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t(0,0,0,0), std::invalid_argument); + }; + + constexpr auto check4 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + for(auto l = 0ul; l < t.size(3); ++l){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") dynamic tensor operator()(" << i <<", "<< j <<", "<< k <<", "<< l << ") = " << v); + t(i,j,k,l) = v; + BOOST_REQUIRE_EQUAL(t(i,j,k,l), v); + v += value_type(1); + } + } + } + } + + BOOST_CHECK_THROW((void)t.at(0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t.at(0,0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t.at(0,0,0,0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t(0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t(0,0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t(0,0,0,0,0), std::invalid_argument); + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check1, &check2, &check3, &check4](auto /*id*/, auto const& t){ + 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); + else assert(false && "Not Implemented"); + + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_static_rank::operator()/operator[]") + *boost::unit_test::description("Testing the static rank tensor's read/write [operator()/operator[]] for single-dimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank_single_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check = [](auto t){ + auto const sz = t.size(); + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < sz; ++i, v += value_type(1)){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") static rank tensor operator()(" << i << ") = " << v); + t(i) = v; + BOOST_REQUIRE_EQUAL(t(i), v); + + auto w = v + value_type(1); + BOOST_TEST_CHECKPOINT("[operator[]] rank("<< rank <<") static rank tensor operator[](" << i << ") = " << w); + t[i] = w; + BOOST_REQUIRE_EQUAL(t[i], w); + } + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check](auto /*id*/, auto const& t){ + check(t); + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_static_rank::operator()/operator[]") + *boost::unit_test::description("Testing the static rank tensor's read/write [operator()] for multidimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank_multi_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check1 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + BOOST_TEST_CHECKPOINT("[operator()] static rank("<< rank <<") rank tensor operator()(" << i << ") = " << v); + t(i) = v; + BOOST_REQUIRE_EQUAL(t(i), v); + v += value_type(1); + } + }; + + constexpr auto check2 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + BOOST_TEST_CHECKPOINT("[operator()] static rank("<< rank <<") rank tensor operator()(" << i <<", "<< j << ") = " << v); + t(i,j) = v; + BOOST_REQUIRE_EQUAL(t(i,j), v); + v += value_type(1); + } + } + }; + + constexpr auto check3 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + BOOST_TEST_CHECKPOINT("[operator()] static rank("<< rank <<") rank tensor operator()(" << i <<", "<< j <<", "<< k << ") = " << v); + t(i,j,k) = v; + BOOST_REQUIRE_EQUAL(t(i,j,k), v); + v += value_type(1); + } + } + } + }; + + constexpr auto check4 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + for(auto l = 0ul; l < t.size(3); ++l){ + BOOST_TEST_CHECKPOINT("[operator()] static rank("<< rank <<") rank tensor operator()(" << i <<", "<< j <<", "<< k <<", "<< l << ") = " << v); + t(i,j,k,l) = v; + BOOST_REQUIRE_EQUAL(t(i,j,k,l), v); + v += value_type(1); + } + } + } + } + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check1, &check2, &check3, &check4](auto /*id*/, TensorType const& t){ + constexpr auto e = typename TensorType::extents_type{}; + if constexpr(ublas::size(e) == 1) check1(t); + else if constexpr(ublas::size(e) == 2) check2(t); + else if constexpr(ublas::size(e) == 3) check3(t); + else if constexpr(ublas::size(e) == 4) check4(t); + else assert(false && "Not Implemented"); + + }); +} + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_static::operator()/operator[]") + *boost::unit_test::description("Testing the static tensor's read/write [operator()/operator[]] for single-dimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_single_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_static; + + constexpr auto check = [](auto t){ + auto const sz = t.size(); + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < sz; ++i, v += value_type(1)){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") static tensor operator()(" << i << ") = " << v); + t(i) = v; + BOOST_REQUIRE_EQUAL(t(i), v); + + auto w = v + value_type(1); + BOOST_TEST_CHECKPOINT("[operator[]] rank("<< rank <<") static tensor operator[](" << i << ") = " << w); + t[i] = w; + BOOST_REQUIRE_EQUAL(t[i], w); + } + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check](auto /*id*/, auto const& t){ + check(t); + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_static::operator()/operator[]") + *boost::unit_test::description("Testing the static tensor's read/write [operator()] for multidimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_multi_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_static; + + constexpr auto check1 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") static tensor operator()(" << i << ") = " << v); + t(i) = v; + BOOST_REQUIRE_EQUAL(t(i), v); + v += value_type(1); + } + }; + + constexpr auto check2 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") static tensor operator()(" << i <<", "<< j << ") = " << v); + t(i,j) = v; + BOOST_REQUIRE_EQUAL(t(i,j), v); + v += value_type(1); + } + } + }; + + constexpr auto check3 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") static tensor operator()(" << i <<", "<< j <<", "<< k << ") = " << v); + t(i,j,k) = v; + BOOST_REQUIRE_EQUAL(t(i,j,k), v); + v += value_type(1); + } + } + } + }; + + constexpr auto check4 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + for(auto l = 0ul; l < t.size(3); ++l){ + BOOST_TEST_CHECKPOINT("[operator()] rank("<< rank <<") static tensor operator()(" << i <<", "<< j <<", "<< k <<", "<< l << ") = " << v); + t(i,j,k,l) = v; + BOOST_REQUIRE_EQUAL(t(i,j,k,l), v); + v += value_type(1); + } + } + } + } + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check1, &check2, &check3, &check4](auto /*id*/, TensorType const& t){ + using extents_type = typename TensorType::extents_type; + if constexpr(ublas::size_v == 1) check1(t); + else if constexpr(ublas::size_v == 2) check2(t); + else if constexpr(ublas::size_v == 3) check3(t); + else if constexpr(ublas::size_v == 4) check4(t); + else assert(false && "Not Implemented"); + }); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_assignment_operator.cpp b/test/tensor/tensor/test_tensor_assignment_operator.cpp new file mode 100644 index 000000000..2f630bfd4 --- /dev/null +++ b/test/tensor/tensor/test_tensor_assignment_operator.cpp @@ -0,0 +1,422 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(test_tensor_assignment_operator, + *boost::unit_test::description("Validate tensor operator=(...)") + *boost::unit_test::depends_on("test_tensor_constructor") +) + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_dynamic::operator=(...)") + *boost::unit_test::description("Testing dynamic tensor operator=(...)") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using tensor_t = ublas::tensor_dynamic; + using strides_t = typename tensor_t::strides_type; + using fixture_type = boost::numeric::ublas::tuple_fixture_tensor_dynamic; + + // FIXME: Enable this test after the expressions are fixed + // BOOST_TEST_CONTEXT("[Dynamic Tensor Assignment Operator] assigning tensor expression"){ + + // auto const e = fixture_type::t32.extents(); + + // auto const a = tensor_t(e, value_type(1)); + // BOOST_REQUIRE_EQUAL ( a.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( a.rank(), 2ul); + // BOOST_REQUIRE (!a.empty()); + + // auto const three = value_type(3); + // auto const expr = a + three * a; + + // auto t = tensor_t(e); + // t = expr; + + // BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + // BOOST_REQUIRE (!t.empty()); + // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // BOOST_CHECK_THROW ( (void)t.at(0,1,1), std::invalid_argument); + // BOOST_CHECK_THROW ( (void)t.at(0,1,2), std::invalid_argument); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + // BOOST_REQUIRE ( t.extents() == e ); + // auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Expression Assignment] testing tensor element(" << i << ") = " < ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t), std::end(t), std::begin(o), std::end(o)); + } + + BOOST_TEST_CONTEXT("[Dynamic Tensor Move Assignment Operator] moving tensor"){ + auto const& e = fixture_type::t32.extents(); + auto o = tensor_t(e, value_type(1)); + BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE (!o.empty()); + + auto t = tensor_t(); + t = std::move(o); + + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + BOOST_REQUIRE_EQUAL ( o.size(), 0ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 0ul); + BOOST_REQUIRE ( o.empty()); + + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(0,1,1), std::invalid_argument); + BOOST_CHECK_THROW ( (void)t.at(0,1,2), std::invalid_argument); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Move constructor] testing tensor element(" << i << ") = " < ? strides_t{1, 4, 8, 24ul} : strides_t{6ul, 3ul, 1ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + for(auto const& v : t){ + BOOST_REQUIRE_EQUAL(v, value_type(1)); + } + } + +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_static_rank::operator=(...)") + *boost::unit_test::description("Testing static rank tensor operator=(...)") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using tensor_t = ublas::tensor_static_rank; + using strides_t = typename tensor_t::strides_type; + using fixture_type = boost::numeric::ublas::tuple_fixture_tensor_static_rank; + + BOOST_TEST_CONTEXT("[Static Rank Tensor Assingment Operator] assigning default value"){ + auto const e = fixture_type::t32.extents(); + auto t = tensor_t(e); + t = value_type(1); + + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + for(auto const& v : t){ + BOOST_REQUIRE_EQUAL(v, value_type(1)); + } + } + + // FIXME: Enable this test after the expressions are fixed + // BOOST_TEST_CONTEXT("[Static Rank Tensor Assignment Operator] assigning tensor expression"){ + + // auto const e = fixture_type::t32.extents(); + + // auto a = tensor_t(e); + // a = value_type(1); + // BOOST_REQUIRE_EQUAL ( a.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( a.rank(), 2ul); + // BOOST_REQUIRE (!a.empty()); + + // auto const three = value_type(3); + // auto const expr = a + three * a; + + // auto t = tensor_t(e); + // t = expr; + + // BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + // BOOST_REQUIRE (!t.empty()); + // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + // BOOST_REQUIRE ( t.extents() == e ); + // auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Expression Assignment] testing tensor element(" << i << ") = " < ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t), std::end(t), std::begin(o), std::end(o)); + } + + BOOST_TEST_CONTEXT("[Static Rank Tensor Move Assignment Operator] moving tensor"){ + auto const& e = fixture_type::t32.extents(); + auto o = tensor_t(e); + o = value_type(1); + + BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE (!o.empty()); + + auto t = tensor_t(); + t = std::move(o); + + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + BOOST_REQUIRE_EQUAL ( o.size(), 0ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE ( o.empty()); + + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Move constructor] testing tensor element(" << i << ") = " < +){ + namespace ublas = boost::numeric::ublas; + using fixture_type = boost::numeric::ublas::tuple_fixture_tensor_static; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using tensor_t = typename fixture_type::t32_type; + using shape_t = typename tensor_t::extents_type; + using strides_t = typename tensor_t::strides_type; + + BOOST_TEST_CONTEXT("[Static Tensor Assingment Operator] assigning default value"){ + auto t = tensor_t(); + t = value_type(1); + + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == shape_t{} ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + for(auto const& v : t){ + BOOST_REQUIRE_EQUAL(v, value_type(1)); + } + } + + // FIXME: Enable this test after the expressions are fixed + // BOOST_TEST_CONTEXT("[Static Tensor Assignment Operator] assigning tensor expression"){ + + // auto const a = tensor_t(value_type(1)); + // BOOST_REQUIRE_EQUAL ( a.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( a.rank(), 2ul); + // BOOST_REQUIRE (!a.empty()); + + // auto const three = value_type(3); + // auto const expr = a + three * a; + + // auto t = tensor_t(); + // t = expr; + + // BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + // BOOST_REQUIRE (!t.empty()); + // // TODO: Enable after adding bounds checking to static tensor + // // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + // BOOST_REQUIRE ( t.extents() == shape_t{} ); + // auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Expression Assignment] testing tensor element(" << i << ") = " < ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t), std::end(t), std::begin(o), std::end(o)); + } + + BOOST_TEST_CONTEXT("[Static Tensor Move Assignment Operator] moving tensor"){ + + auto const o = tensor_t(value_type(1)); + BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE (!o.empty()); + + auto t = tensor_t(); + t = std::move(o); + + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE (!o.empty()); + + // TODO: Enable after adding bounds checking to static tensor + // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == shape_t{} ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Move constructor] testing tensor element(" << i << ") = " < +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_at, + *boost::unit_test::description("Validate At Method") + *boost::unit_test::depends_on("test_extents_size") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_dynamic::at(i)") + *boost::unit_test::description("Testing the dynamic tensor's read/write [at] method for single-dimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic_single_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check = [](auto t){ + auto const sz = t.size(); + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < sz; ++i, v += value_type(1)){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") dynamic tensor at(" << i << ") = " << v); + t.at(i) = v; + BOOST_REQUIRE_EQUAL(t.at(i), v); + } + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check](auto /*id*/, auto const& t){ + check(t); + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_dynamic::at(i)") + *boost::unit_test::description("Testing the dynamic tensor's read/write [at] method for multidimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic_multi_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check1 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") dynamic tensor at(" << i << ") = " << v); + t.at(i) = v; + BOOST_REQUIRE_EQUAL(t.at(i), v); + v += value_type(1); + } + }; + + constexpr auto check2 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") dynamic tensor at(" << i <<", "<< j << ") = " << v); + t.at(i,j) = v; + BOOST_REQUIRE_EQUAL(t.at(i,j), v); + v += value_type(1); + } + } + + BOOST_CHECK_THROW((void)t.at(0,0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t.at(0,0,0,0), std::invalid_argument); + }; + + constexpr auto check3 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") dynamic tensor at(" << i <<", "<< j <<", "<< k << ") = " << v); + t.at(i,j,k) = v; + BOOST_REQUIRE_EQUAL(t.at(i,j,k), v); + v += value_type(1); + } + } + } + BOOST_CHECK_THROW((void)t.at(0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t.at(0,0,0,0), std::invalid_argument); + }; + + constexpr auto check4 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + for(auto l = 0ul; l < t.size(3); ++l){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") dynamic tensor at(" << i <<", "<< j <<", "<< k <<", "<< l << ") = " << v); + t.at(i,j,k,l) = v; + BOOST_REQUIRE_EQUAL(t.at(i,j,k,l), v); + v += value_type(1); + } + } + } + } + BOOST_CHECK_THROW((void)t.at(0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t.at(0,0,0), std::invalid_argument); + BOOST_CHECK_THROW((void)t.at(0,0,0,0,0), std::invalid_argument); + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check1, &check2, &check3, &check4](auto /*id*/, auto const& t){ + 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); + else assert(false && "Not Implemented"); + + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_static_rank::at(i)") + *boost::unit_test::description("Testing the static rank tensor's read/write [at] method for single-dimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank_single_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check = [](auto t){ + auto const sz = t.size(); + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < sz; ++i, v += value_type(1)){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") static rank tensor at(" << i << ") = " << v); + t.at(i) = v; + BOOST_REQUIRE_EQUAL(t.at(i), v); + } + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check](auto /*id*/, auto const& t){ + check(t); + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_static_rank::at(i)") + *boost::unit_test::description("Testing the static rank tensor's read/write [at] method for multidimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank_multi_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check1 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + BOOST_TEST_CHECKPOINT("[At Method] static rank("<< rank <<") rank tensor at(" << i << ") = " << v); + t.at(i) = v; + BOOST_REQUIRE_EQUAL(t.at(i), v); + v += value_type(1); + } + }; + + constexpr auto check2 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + BOOST_TEST_CHECKPOINT("[At Method] static rank("<< rank <<") rank tensor at(" << i <<", "<< j << ") = " << v); + t.at(i,j) = v; + BOOST_REQUIRE_EQUAL(t.at(i,j), v); + v += value_type(1); + } + } + }; + + constexpr auto check3 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + BOOST_TEST_CHECKPOINT("[At Method] static rank("<< rank <<") rank tensor at(" << i <<", "<< j <<", "<< k << ") = " << v); + t.at(i,j,k) = v; + BOOST_REQUIRE_EQUAL(t.at(i,j,k), v); + v += value_type(1); + } + } + } + }; + + constexpr auto check4 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + for(auto l = 0ul; l < t.size(3); ++l){ + BOOST_TEST_CHECKPOINT("[At Method] static rank("<< rank <<") rank tensor at(" << i <<", "<< j <<", "<< k <<", "<< l << ") = " << v); + t.at(i,j,k,l) = v; + BOOST_REQUIRE_EQUAL(t.at(i,j,k,l), v); + v += value_type(1); + } + } + } + } + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check1, &check2, &check3, &check4](auto /*id*/, TensorType const& t){ + constexpr auto e = typename TensorType::extents_type{}; + if constexpr(ublas::size(e) == 1) check1(t); + else if constexpr(ublas::size(e) == 2) check2(t); + else if constexpr(ublas::size(e) == 3) check3(t); + else if constexpr(ublas::size(e) == 4) check4(t); + else assert(false && "Not Implemented"); + + }); +} + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_static::at(i)") + *boost::unit_test::description("Testing the static tensor's read/write [at] method for single-dimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_single_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_static; + + constexpr auto check = [](auto t){ + auto const sz = t.size(); + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < sz; ++i, v += value_type(1)){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") static tensor at(" << i << ") = " << v); + t.at(i) = v; + BOOST_REQUIRE_EQUAL(t.at(i), v); + } + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check](auto /*id*/, auto const& t){ + check(t); + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_static::at(i)") + *boost::unit_test::description("Testing the static tensor's read/write [at] method for multidimensional") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_multi_dim, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_type = ublas::tuple_fixture_tensor_static; + + constexpr auto check1 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") static tensor at(" << i << ") = " << v); + t.at(i) = v; + BOOST_REQUIRE_EQUAL(t.at(i), v); + v += value_type(1); + } + }; + + constexpr auto check2 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") static tensor at(" << i <<", "<< j << ") = " << v); + t.at(i,j) = v; + BOOST_REQUIRE_EQUAL(t.at(i,j), v); + v += value_type(1); + } + } + }; + + constexpr auto check3 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") static tensor at(" << i <<", "<< j <<", "<< k << ") = " << v); + t.at(i,j,k) = v; + BOOST_REQUIRE_EQUAL(t.at(i,j,k), v); + v += value_type(1); + } + } + } + }; + + constexpr auto check4 = [](auto t){ + auto const rank = t.rank(); + value_type v{}; + for(auto i = 0ul; i < t.size(0); ++i){ + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto k = 0ul; k < t.size(2); ++k){ + for(auto l = 0ul; l < t.size(3); ++l){ + BOOST_TEST_CHECKPOINT("[At Method] rank("<< rank <<") static tensor at(" << i <<", "<< j <<", "<< k <<", "<< l << ") = " << v); + t.at(i,j,k,l) = v; + BOOST_REQUIRE_EQUAL(t.at(i,j,k,l), v); + v += value_type(1); + } + } + } + } + }; + + auto const self = static_cast(*this); + ublas::for_each_fixture(self, [&check1, &check2, &check3, &check4](auto /*id*/, TensorType const& t){ + using extents_type = typename TensorType::extents_type; + if constexpr(ublas::size_v == 1) check1(t); + else if constexpr(ublas::size_v == 2) check2(t); + else if constexpr(ublas::size_v == 3) check3(t); + else if constexpr(ublas::size_v == 4) check4(t); + else assert(false && "Not Implemented"); + }); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_binary_expression.cpp b/test/tensor/tensor/test_tensor_binary_expression.cpp new file mode 100644 index 000000000..3bb1b436c --- /dev/null +++ b/test/tensor/tensor/test_tensor_binary_expression.cpp @@ -0,0 +1,222 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_binary_expression, + * boost::unit_test::description("Validate Binary Expression") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("unary_expr") + *boost::unit_test::description("Testing the binary expr for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto uplus1 = [](auto const& a){ return a + value_type{1}; }; + constexpr auto uplus2 = [](auto const& a){ return a + value_type{2}; }; + constexpr auto bplus = std::plus {}; + constexpr auto bminus = std::minus{}; + + constexpr auto check = [uplus1,uplus2,bplus,bminus](auto /*id*/, tensor_t t){ + auto v = value_type{}; + + BOOST_TEST_CONTEXT("[Dynamic Tensor Binary Expr] rank("<< t.rank() <<") dynamic tensor"){ + + ublas::iota(t,v); + + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, tensor_t > ) ); + + 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( uexpr1, uexpr2, bplus ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, tensor_t > ) ); + + + 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( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) ); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("unary_expr") + *boost::unit_test::description("Testing the binary expr for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto uplus1 = [](auto const& a){ return a + value_type{1}; }; + constexpr auto uplus2 = [](auto const& a){ return a + value_type{2}; }; + constexpr auto bplus = std::plus {}; + constexpr auto bminus = std::minus{}; + + constexpr auto check = [uplus1,uplus2,bplus,bminus](auto /*id*/, tensor_t t){ + auto v = value_type{}; + + BOOST_TEST_CONTEXT("[Static Rank Tensor Binary Expr] static rank("<< t.rank() <<") tensor"){ + + ublas::iota(t,v); + + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, tensor_t > ) ); + + 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( uexpr1, uexpr2, bplus ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, tensor_t > ) ); + + + 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( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) ); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("unary_expr") + *boost::unit_test::description("Testing the binary expr for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static; + + constexpr auto uplus1 = [](auto const& a){ return a + value_type{1}; }; + constexpr auto uplus2 = [](auto const& a){ return a + value_type{2}; }; + constexpr auto bplus = std::plus {}; + constexpr auto bminus = std::minus{}; + + constexpr auto check = [uplus1,uplus2,bplus,bminus](auto /*id*/, tensor_t t){ + auto v = value_type{}; + + BOOST_TEST_CONTEXT("[Static Tensor Binary Expr] rank("<< t.rank() <<") static tensor"){ + + ublas::iota(t,v); + + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, tensor_t > ) ); + + 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( uexpr1, uexpr2, bplus ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, tensor_t > ) ); + + + 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( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) ); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_comparision.cpp b/test/tensor/tensor/test_tensor_comparision.cpp new file mode 100644 index 000000000..062de426d --- /dev/null +++ b/test/tensor/tensor/test_tensor_comparision.cpp @@ -0,0 +1,162 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_comparision, + * boost::unit_test::description("Validate Comparision Operators/Functions") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("compare_tensor") + *boost::unit_test::description("Testing the dynamic tensor's comparision operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check = [](auto /*id*/, auto t1){ + auto v = value_type{}; + BOOST_TEST_CONTEXT("[Comparision Operator] rank("<< t1.rank() <<") dynamic tensor"){ + auto t2 = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + value_type{2}); + + BOOST_CHECK(t1 == t1); + BOOST_CHECK(t1 != t2); + + if(t1.empty()) return; + + // One cannot tell which complex number is greater or less. + if constexpr(!ublas::is_complex_v){ + BOOST_CHECK(!(t1 < t1)); + BOOST_CHECK(!(t1 > t1)); + BOOST_CHECK( t1 < t2 ); + BOOST_CHECK( t2 > t1 ); + BOOST_CHECK( t1 <= t1 ); + BOOST_CHECK( t1 >= t1 ); + BOOST_CHECK( t1 <= t2 ); + BOOST_CHECK( t2 >= t1 ); + BOOST_CHECK( t2 >= t2 ); + BOOST_CHECK( t2 >= t1 ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("compare_tensor") + *boost::unit_test::description("Testing the static rank tensor's comparision operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check = [](auto /*id*/, auto t1){ + auto v = value_type{}; + BOOST_TEST_CONTEXT("[Comparision Operator] static rank("<< t1.rank() <<") tensor"){ + auto t2 = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + value_type{2}); + + BOOST_CHECK(t1 == t1); + BOOST_CHECK(t1 != t2); + + if(t1.empty()) return; + + // One cannot tell which complex number is greater or less. + if constexpr(!ublas::is_complex_v){ + BOOST_CHECK(!(t1 < t1)); + BOOST_CHECK(!(t1 > t1)); + BOOST_CHECK( t1 < t2 ); + BOOST_CHECK( t2 > t1 ); + BOOST_CHECK( t1 <= t1 ); + BOOST_CHECK( t1 >= t1 ); + BOOST_CHECK( t1 <= t2 ); + BOOST_CHECK( t2 >= t1 ); + BOOST_CHECK( t2 >= t2 ); + BOOST_CHECK( t2 >= t1 ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("compare_tensor") + *boost::unit_test::description("Testing the static tensor's comparision operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static; + + constexpr auto check = [](auto /*id*/, auto t1){ + auto v = value_type{}; + BOOST_TEST_CONTEXT("[Comparision Operator] rank("<< t1.rank() <<") static tensor"){ + auto t2 = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + value_type{2}); + + BOOST_CHECK(t1 == t1); + BOOST_CHECK(t1 != t2); + + if(t1.empty()) return; + + // One cannot tell which complex number is greater or less. + if constexpr(!ublas::is_complex_v){ + BOOST_CHECK(!(t1 < t1)); + BOOST_CHECK(!(t1 > t1)); + BOOST_CHECK( t1 < t2 ); + BOOST_CHECK( t2 > t1 ); + BOOST_CHECK( t1 <= t1 ); + BOOST_CHECK( t1 >= t1 ); + BOOST_CHECK( t1 <= t2 ); + BOOST_CHECK( t2 >= t1 ); + BOOST_CHECK( t2 >= t2 ); + BOOST_CHECK( t2 >= t1 ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_comparision_with_scalar.cpp b/test/tensor/tensor/test_tensor_comparision_with_scalar.cpp new file mode 100644 index 000000000..6ab0353dc --- /dev/null +++ b/test/tensor/tensor/test_tensor_comparision_with_scalar.cpp @@ -0,0 +1,292 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_comparision_with_scalar, + * boost::unit_test::description("Validate Comparision Operators/Functions With Scalar") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("compare_tensor") + *boost::unit_test::description("Testing the dynamic tensor's comparision operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check = [](auto /*id*/, auto t1){ + BOOST_TEST_CONTEXT("[Comparision Operator] rank("<< t1.rank() <<") dynamic tensor"){ + auto const one = value_type{1}; + auto const two = value_type{2}; + auto const three = value_type{3}; + auto const five = value_type{5}; + auto const six = value_type{6}; + + auto t2 = t1; + auto t3 = t1; + + t1 = two; + t2 = one; + t3 = three; + + BOOST_CHECK(t1 == t1); + BOOST_CHECK(t1 != t2); + + t2 = three; + + + if(t1.empty()) return; + + // One cannot tell which complex number is greater or less. + if constexpr(!ublas::is_complex_v){ + BOOST_CHECK( !(t1 < two) ); + BOOST_CHECK( !(t1 > two) ); + BOOST_CHECK( (t1 >= two) ); + BOOST_CHECK( (t1 <= two) ); + BOOST_CHECK( (t1 == two) ); + BOOST_CHECK( (t1 != three) ); + + BOOST_CHECK( !(two > t1)); + BOOST_CHECK( !(two < t1)); + BOOST_CHECK( (two <= t1) ); + BOOST_CHECK( (two >= t1) ); + BOOST_CHECK( (two == t1) ); + BOOST_CHECK( (three != t1) ); + + BOOST_CHECK( !( t1+three < five)); + BOOST_CHECK( !( t1+three > five)); + BOOST_CHECK( ( t1+three >= five) ); + BOOST_CHECK( ( t1+three <= five) ); + BOOST_CHECK( ( t1+three == five) ); + BOOST_CHECK( ( t1+three != six) ); + + + BOOST_CHECK( !( five > t1+three)); + BOOST_CHECK( !( five < t1+three)); + BOOST_CHECK( ( five >= t1+three) ); + BOOST_CHECK( ( five <= t1+three) ); + BOOST_CHECK( ( five == t1+three) ); + BOOST_CHECK( ( six != t1+three) ); + + + BOOST_CHECK( !( t1+t3 < five)); + BOOST_CHECK( !( t1+t3 > five)); + BOOST_CHECK( ( t1+t3 >= five) ); + BOOST_CHECK( ( t1+t3 <= five) ); + BOOST_CHECK( ( t1+t3 == five) ); + BOOST_CHECK( ( t1+t3 != six) ); + + + BOOST_CHECK( !( five > t1+t3)); + BOOST_CHECK( !( five < t1+t3)); + BOOST_CHECK( ( five >= t1+t3) ); + BOOST_CHECK( ( five <= t1+t3) ); + BOOST_CHECK( ( five == t1+t3) ); + BOOST_CHECK( ( six != t1+t3) ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("compare_tensor") + *boost::unit_test::description("Testing the static rank tensor's comparision operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check = [](auto /*id*/, auto t1){ + BOOST_TEST_CONTEXT("[Comparision Operator] static rank("<< t1.rank() <<") tensor"){ + auto const one = value_type{1}; + auto const two = value_type{2}; + auto const three = value_type{3}; + auto const five = value_type{5}; + auto const six = value_type{6}; + + auto t2 = t1; + auto t3 = t1; + + t1 = two; + t2 = one; + t3 = three; + + BOOST_CHECK(t1 == t1); + BOOST_CHECK(t1 != t2); + + t2 = three; + + if(t1.empty()) return; + + // One cannot tell which complex number is greater or less. + if constexpr(!ublas::is_complex_v){ + BOOST_CHECK( !(t1 < two) ); + BOOST_CHECK( !(t1 > two) ); + BOOST_CHECK( (t1 >= two) ); + BOOST_CHECK( (t1 <= two) ); + BOOST_CHECK( (t1 == two) ); + BOOST_CHECK( (t1 != three) ); + + BOOST_CHECK( !(two > t1)); + BOOST_CHECK( !(two < t1)); + BOOST_CHECK( (two <= t1) ); + BOOST_CHECK( (two >= t1) ); + BOOST_CHECK( (two == t1) ); + BOOST_CHECK( (three != t1) ); + + BOOST_CHECK( !( t1+three < five)); + BOOST_CHECK( !( t1+three > five)); + BOOST_CHECK( ( t1+three >= five) ); + BOOST_CHECK( ( t1+three <= five) ); + BOOST_CHECK( ( t1+three == five) ); + BOOST_CHECK( ( t1+three != six) ); + + + BOOST_CHECK( !( five > t1+three)); + BOOST_CHECK( !( five < t1+three)); + BOOST_CHECK( ( five >= t1+three) ); + BOOST_CHECK( ( five <= t1+three) ); + BOOST_CHECK( ( five == t1+three) ); + BOOST_CHECK( ( six != t1+three) ); + + + BOOST_CHECK( !( t1+t3 < five)); + BOOST_CHECK( !( t1+t3 > five)); + BOOST_CHECK( ( t1+t3 >= five) ); + BOOST_CHECK( ( t1+t3 <= five) ); + BOOST_CHECK( ( t1+t3 == five) ); + BOOST_CHECK( ( t1+t3 != six) ); + + + BOOST_CHECK( !( five > t1+t3)); + BOOST_CHECK( !( five < t1+t3)); + BOOST_CHECK( ( five >= t1+t3) ); + BOOST_CHECK( ( five <= t1+t3) ); + BOOST_CHECK( ( five == t1+t3) ); + BOOST_CHECK( ( six != t1+t3) ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("compare_tensor") + *boost::unit_test::description("Testing the static tensor's comparision operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static; + + constexpr auto check = [](auto /*id*/, auto t1){ + BOOST_TEST_CONTEXT("[Comparision Operator] rank("<< t1.rank() <<") static tensor"){ + auto const one = value_type{1}; + auto const two = value_type{2}; + auto const three = value_type{3}; + auto const five = value_type{5}; + auto const six = value_type{6}; + + auto t2 = t1; + auto t3 = t1; + + t1 = two; + t2 = one; + t3 = three; + + BOOST_CHECK(t1 == t1); + BOOST_CHECK(t1 != t2); + + t2 = three; + + if(t1.empty()) return; + + // One cannot tell which complex number is greater or less. + if constexpr(!ublas::is_complex_v){ + BOOST_CHECK( !(t1 < two) ); + BOOST_CHECK( !(t1 > two) ); + BOOST_CHECK( (t1 >= two) ); + BOOST_CHECK( (t1 <= two) ); + BOOST_CHECK( (t1 == two) ); + BOOST_CHECK( (t1 != three) ); + + BOOST_CHECK( !(two > t1)); + BOOST_CHECK( !(two < t1)); + BOOST_CHECK( (two <= t1) ); + BOOST_CHECK( (two >= t1) ); + BOOST_CHECK( (two == t1) ); + BOOST_CHECK( (three != t1) ); + + BOOST_CHECK( !( t1+three < five)); + BOOST_CHECK( !( t1+three > five)); + BOOST_CHECK( ( t1+three >= five) ); + BOOST_CHECK( ( t1+three <= five) ); + BOOST_CHECK( ( t1+three == five) ); + BOOST_CHECK( ( t1+three != six) ); + + + BOOST_CHECK( !( five > t1+three)); + BOOST_CHECK( !( five < t1+three)); + BOOST_CHECK( ( five >= t1+three) ); + BOOST_CHECK( ( five <= t1+three) ); + BOOST_CHECK( ( five == t1+three) ); + BOOST_CHECK( ( six != t1+three) ); + + + BOOST_CHECK( !( t1+t3 < five)); + BOOST_CHECK( !( t1+t3 > five)); + BOOST_CHECK( ( t1+t3 >= five) ); + BOOST_CHECK( ( t1+t3 <= five) ); + BOOST_CHECK( ( t1+t3 == five) ); + BOOST_CHECK( ( t1+t3 != six) ); + + + BOOST_CHECK( !( five > t1+t3)); + BOOST_CHECK( !( five < t1+t3)); + BOOST_CHECK( ( five >= t1+t3) ); + BOOST_CHECK( ( five <= t1+t3) ); + BOOST_CHECK( ( five == t1+t3) ); + BOOST_CHECK( ( six != t1+t3) ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_comparision_with_tensor_expression.cpp b/test/tensor/tensor/test_tensor_comparision_with_tensor_expression.cpp new file mode 100644 index 000000000..f96d5e774 --- /dev/null +++ b/test/tensor/tensor/test_tensor_comparision_with_tensor_expression.cpp @@ -0,0 +1,180 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_comparision_with_tensor_expression, + * boost::unit_test::description("Validate Comparision Operators/Functions With Tensor Expression") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("compare_tensor") + *boost::unit_test::description("Testing the dynamic tensor's comparision operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check = [](auto /*id*/, auto t1){ + auto v = value_type{}; + BOOST_TEST_CONTEXT("[Comparision Operator] rank("<< t1.rank() <<") dynamic tensor"){ + auto t2 = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + value_type{2}); + + BOOST_CHECK(t1 == t1); + BOOST_CHECK(t1 != t2); + + if(t1.empty()) return; + + auto const two = value_type(2); + auto const three = value_type(3); + + // One cannot tell which complex number is greater or less. + if constexpr(!ublas::is_complex_v){ + BOOST_CHECK( !(t1 < t1) ); + BOOST_CHECK( !(t1 > t1) ); + BOOST_CHECK( t1 < (t2 + t1) ); + BOOST_CHECK( (t2 + t1) > t1 ); + BOOST_CHECK( t1 <= (t1 + t1) ); + BOOST_CHECK( (t1 + t2) >= t1 ); + BOOST_CHECK( (t2 + t2 + two) >= t1 ); + BOOST_CHECK( (two * t2) > t1 ); + BOOST_CHECK( t1 < (two * t2)); + BOOST_CHECK( (two * t2) > t1 ); + BOOST_CHECK( (two * t2) >= t2 ); + BOOST_CHECK( t2 <= (two * t2)); + BOOST_CHECK( (three * t2) >= t1 ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("compare_tensor") + *boost::unit_test::description("Testing the static rank tensor's comparision operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check = [](auto /*id*/, auto t1){ + auto v = value_type{}; + BOOST_TEST_CONTEXT("[Comparision Operator] static rank("<< t1.rank() <<") tensor"){ + auto t2 = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + value_type{2}); + + BOOST_CHECK(t1 == t1); + BOOST_CHECK(t1 != t2); + + if(t1.empty()) return; + + auto const two = value_type(2); + auto const three = value_type(3); + + // One cannot tell which complex number is greater or less. + if constexpr(!ublas::is_complex_v){ + BOOST_CHECK( !(t1 < t1) ); + BOOST_CHECK( !(t1 > t1) ); + BOOST_CHECK( t1 < (t2 + t1) ); + BOOST_CHECK( (t2 + t1) > t1 ); + BOOST_CHECK( t1 <= (t1 + t1) ); + BOOST_CHECK( (t1 + t2) >= t1 ); + BOOST_CHECK( (t2 + t2 + two) >= t1 ); + BOOST_CHECK( (two * t2) > t1 ); + BOOST_CHECK( t1 < (two * t2)); + BOOST_CHECK( (two * t2) > t1 ); + BOOST_CHECK( (two * t2) >= t2 ); + BOOST_CHECK( t2 <= (two * t2)); + BOOST_CHECK( (three * t2) >= t1 ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("compare_tensor") + *boost::unit_test::description("Testing the static tensor's comparision operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static; + + constexpr auto check = [](auto /*id*/, auto t1){ + auto v = value_type{}; + BOOST_TEST_CONTEXT("[Comparision Operator] rank("<< t1.rank() <<") static tensor"){ + auto t2 = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + value_type{2}); + + BOOST_CHECK(t1 == t1); + BOOST_CHECK(t1 != t2); + + if(t1.empty()) return; + + auto const two = value_type(2); + auto const three = value_type(3); + + // One cannot tell which complex number is greater or less. + if constexpr(!ublas::is_complex_v){ + BOOST_CHECK( !(t1 < t1) ); + BOOST_CHECK( !(t1 > t1) ); + BOOST_CHECK( t1 < (t2 + t1) ); + BOOST_CHECK( (t2 + t1) > t1 ); + BOOST_CHECK( t1 <= (t1 + t1) ); + BOOST_CHECK( (t1 + t2) >= t1 ); + BOOST_CHECK( (t2 + t2 + two) >= t1 ); + BOOST_CHECK( (two * t2) > t1 ); + BOOST_CHECK( t1 < (two * t2)); + BOOST_CHECK( (two * t2) > t1 ); + BOOST_CHECK( (two * t2) >= t2 ); + BOOST_CHECK( t2 <= (two * t2)); + BOOST_CHECK( (three * t2) >= t1 ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_construction.cpp b/test/tensor/tensor/test_tensor_construction.cpp new file mode 100644 index 000000000..59b794a06 --- /dev/null +++ b/test/tensor/tensor/test_tensor_construction.cpp @@ -0,0 +1,989 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" +#include +#include + +BOOST_AUTO_TEST_SUITE(test_tensor_constructor, + *boost::unit_test::description("Validate tensor constructor") + *boost::unit_test::depends_on("test_tensor_empty") + *boost::unit_test::depends_on("test_tensor_size") + *boost::unit_test::depends_on("test_tensor_at") + *boost::unit_test::depends_on("test_tensor_access_operator") +) + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::tensor_dynamic(...)") + *boost::unit_test::description("Testing dynamic tensor construction") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +){ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using tensor_t = ublas::tensor_dynamic; + using shape_t = typename tensor_t::extents_type; + using strides_t = typename tensor_t::strides_type; + using fixture_type = boost::numeric::ublas::tuple_fixture_tensor_dynamic; + + BOOST_TEST_CONTEXT("[Dynamic Tensor Construction] default constructor"){ + auto const t = tensor_t{}; + BOOST_REQUIRE_EQUAL (t.size(), 0ul); + BOOST_REQUIRE_EQUAL (t.rank(), 0ul); + BOOST_REQUIRE (t.empty()); + BOOST_CHECK_THROW ((void)t.at(0), std::out_of_range); + } + + BOOST_TEST_CONTEXT("[Dynamic Tensor Construction] construction using variadic integral arguments"){ + auto const t = tensor_t(1,2,3); + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 3ul); + BOOST_REQUIRE (!t.empty()); + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_NO_THROW( (void)t.at(0,1,1)); + BOOST_CHECK_NO_THROW( (void)t.at(0,1,2)); + BOOST_CHECK_THROW ( (void)t.at(7ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(1,2,3), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == (shape_t{1ul,2ul,3ul}) ); + auto const strides = (std::is_same_v ? strides_t{1,1,2} : strides_t{6, 3, 1}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + } + + BOOST_TEST_CONTEXT("[Dynamic Tensor Construction] construction using extents"){ + auto const e = fixture_type::t4231.extents(); + auto const t = tensor_t(e); + BOOST_REQUIRE_EQUAL ( t.size(), 24ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 4ul); + BOOST_REQUIRE (!t.empty()); + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(0,1,1), std::invalid_argument); + BOOST_CHECK_THROW ( (void)t.at(0,1,2), std::invalid_argument); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2,3,4), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 4, 8, 24ul} : strides_t{6ul, 3ul, 1ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + } + + BOOST_TEST_CONTEXT("[Dynamic Tensor Construction] construction using extents and default value"){ + auto const e = fixture_type::t4231.extents(); + auto const t = tensor_t(e, value_type(1)); + BOOST_REQUIRE_EQUAL ( t.size(), 24ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 4ul); + BOOST_REQUIRE (!t.empty()); + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(0,1,1), std::invalid_argument); + BOOST_CHECK_THROW ( (void)t.at(0,1,2), std::invalid_argument); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2,3,4), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 4, 8, 24ul} : strides_t{6ul, 3ul, 1ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + for(auto const& v : t){ + BOOST_REQUIRE_EQUAL(v, value_type(1)); + } + } + + BOOST_TEST_CONTEXT("[Dynamic Tensor Construction] construction using extents and container"){ + using container_type = typename tensor_t::container_type; + auto const c = container_type{ + value_type(1), value_type(2), + value_type(3), value_type(4), + value_type(5), value_type(6) + }; + auto const e = fixture_type::t32.extents(); + auto const t = tensor_t(e, c); + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(0,1,1), std::invalid_argument); + BOOST_CHECK_THROW ( (void)t.at(0,1,2), std::invalid_argument); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t), std::end(t), std::begin(c), std::end(c)); + } + + // TODO: Enable after fixing the issue #116 + // BOOST_TEST_CONTEXT("[Dynamic Tensor Construction] construction using other layout"){ + // using other_layout = std::conditional_t< + // std::is_same_v, + // ublas::layout::last_order, + // ublas::layout::first_order + // >; + + // auto const e = fixture_type::t32.extents(); + // auto const o = ublas::tensor_dynamic(e, value_type(1)); + // BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + // BOOST_REQUIRE (!o.empty()); + + // auto const t = tensor_t(o); + // BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + // BOOST_REQUIRE (!t.empty()); + + // } + + // FIXME: Enable this tests after the tensor expression is fixed + // BOOST_TEST_CONTEXT("[Dynamic Tensor Construction] construction using tensor expression"){ + + // auto const e = fixture_type::t32.extents(); + + // auto const a = tensor_t(e, value_type(1)); + // BOOST_REQUIRE_EQUAL ( a.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( a.rank(), 2ul); + // BOOST_REQUIRE (!a.empty()); + + // auto const three = value_type(3); + // auto const expr = a + three * a; + // auto const t = tensor_t(expr); + + // BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + // BOOST_REQUIRE (!t.empty()); + // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // BOOST_CHECK_THROW ( (void)t.at(0,1,1), std::invalid_argument); + // BOOST_CHECK_THROW ( (void)t.at(0,1,2), std::invalid_argument); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + // BOOST_REQUIRE ( t.extents() == e ); + // auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Expression Constructor] Testing tensor element(" << i << ") = " < ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Matrix Constructor] testing tensor element(" << i << ") = " < ? strides_t{1, 1} : strides_t{1ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Vector Constructor] testing tensor element(" << i << ") = " < ? strides_t{1, 3} : strides_t{2ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Matrix Expression Constructor] testing tensor element(" << i << ") = " < ? strides_t{1, 1} : strides_t{1ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Vector Expression Constructor] testing tensor element(" << i << ") = " < ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t), std::end(t), std::begin(o), std::end(o)); + } + + BOOST_TEST_CONTEXT("[Dynamic Tensor Move Construction] move constructing tensor"){ + auto const& e = fixture_type::t32.extents(); + auto o = tensor_t(e, value_type(1)); + BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE (!o.empty()); + + auto const t = tensor_t(std::move(o)); + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + BOOST_REQUIRE_EQUAL ( o.size(), 0ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 0ul); + BOOST_REQUIRE ( o.empty()); + + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(0,1,1), std::invalid_argument); + BOOST_CHECK_THROW ( (void)t.at(0,1,2), std::invalid_argument); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Move constructor] testing tensor element(" << i << ") = " < +){ + namespace ublas = boost::numeric::ublas; + + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = boost::numeric::ublas::tuple_fixture_tensor_static_rank; + + + BOOST_TEST_CONTEXT("[Static Rank Tensor Construction] default constructor"){ + using tensor_t = ublas::tensor_static_rank; + auto const t = tensor_t(); + BOOST_REQUIRE_EQUAL (t.size(), 0ul); + BOOST_REQUIRE_EQUAL (t.rank(), 3ul); + BOOST_REQUIRE (t.empty()); + BOOST_CHECK_THROW ((void)t.at(0), std::out_of_range); + } + + BOOST_TEST_CONTEXT("[Static Rank Tensor Construction] construction using variadic integral arguments"){ + using tensor_t = ublas::tensor_static_rank; + using shape_t = typename tensor_t::extents_type; + using strides_t = typename tensor_t::strides_type; + + auto const t = tensor_t(1,2,3); + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 3ul); + BOOST_REQUIRE (!t.empty()); + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_NO_THROW( (void)t.at(0,1,1)); + BOOST_CHECK_NO_THROW( (void)t.at(0,1,2)); + BOOST_CHECK_THROW ( (void)t.at(7ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(1,2,3), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == (shape_t{1ul,2ul,3ul}) ); + auto const strides = (std::is_same_v ? strides_t{1,1,2} : strides_t{6, 3, 1}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + } + + BOOST_TEST_CONTEXT("[Static Rank Tensor Construction] construction using extents"){ + using tensor_t = ublas::tensor_static_rank; + using strides_t = typename tensor_t::strides_type; + + auto const e = fixture_type::t4231.extents(); + auto const t = tensor_t(e); + BOOST_REQUIRE_EQUAL ( t.size(), 24ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 4ul); + BOOST_REQUIRE (!t.empty()); + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2,3,4), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 4, 8, 24ul} : strides_t{6ul, 3ul, 1ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + } + + BOOST_TEST_CONTEXT("[Static Rank Tensor Construction] construction using extents and container"){ + using tensor_t = ublas::tensor_static_rank; + using strides_t = typename tensor_t::strides_type; + using container_type = typename tensor_t::container_type; + + auto const c = container_type{ + value_type(1), value_type(2), + value_type(3), value_type(4), + value_type(5), value_type(6) + }; + auto const e = fixture_type::t32.extents(); + auto const t = tensor_t(e, c); + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t), std::end(t), std::begin(c), std::end(c)); + } + + // TODO: Enable after fixing the issue #116 + // BOOST_TEST_CONTEXT("[Static Rank Tensor Construction] construction using other layout"){ + // using other_layout = std::conditional_t< + // std::is_same_v, + // ublas::layout::last_order, + // ublas::layout::first_order + // >; + + // auto const e = fixture_type::t32.extents(); + // auto const o = ublas::tensor_static_rank(e, value_type(1)); + // BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + // BOOST_REQUIRE (!o.empty()); + + // auto const t = tensor_t(o); + // BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + // BOOST_REQUIRE (!t.empty()); + + // } + + // FIXME: Enable this tests after the tensor expression is fixed + // BOOST_TEST_CONTEXT("[Static Rank Tensor Construction] construction using tensor expression"){ + + // using tensor_t = ublas::tensor_static_rank; + // using strides_t = typename tensor_t::strides_type; + + // auto const e = fixture_type::t32.extents(); + + // auto a = tensor_t(e); + // a = value_type(1); + + // BOOST_REQUIRE_EQUAL ( a.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( a.rank(), 2ul); + // BOOST_REQUIRE (!a.empty()); + + // auto const three = value_type(3); + // auto const expr = a + three * a; + // auto const t = tensor_t(expr); + + // BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + // BOOST_REQUIRE (!t.empty()); + // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + // BOOST_REQUIRE ( t.extents() == e ); + // auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Expression Constructor] Testing tensor element(" << i << ") = " <; + using strides_t = typename tensor_t::strides_type; + + using matrix_type = typename tensor_t::matrix_type; + auto const e = fixture_type::t32.extents(); + auto const a = matrix_type(e[0], e[1], value_type(1)); + BOOST_REQUIRE_EQUAL ( a.size1(), e[0]); + BOOST_REQUIRE_EQUAL ( a.size2(), e[1]); + + auto const t = tensor_t(a); + + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Matrix Constructor] testing tensor element(" << i << ") = " <; + using strides_t = typename tensor_t::strides_type; + + using vector_type = typename tensor_t::vector_type; + auto const e = fixture_type::t2.extents(); + auto const a = vector_type(e[0], value_type(1)); + BOOST_REQUIRE_EQUAL ( a.size(), e[0]); + + auto const t = tensor_t(a); + + BOOST_CHECK_NO_THROW( (void)t.at(1ul)); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == fixture_type::t21.extents() ); + auto const strides = (std::is_same_v ? strides_t{1, 1} : strides_t{1ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Vector Constructor] testing tensor element(" << i << ") = " <; + // using strides_t = typename tensor_t::strides_type; + + // using matrix_type = typename tensor_t::matrix_type; + // auto const e = fixture_type::t32.extents(); + // auto const a = matrix_type(e[0], e[1], value_type(1)); + // BOOST_REQUIRE_EQUAL ( a.size1(), e[0]); + // BOOST_REQUIRE_EQUAL ( a.size2(), e[1]); + + // auto const three = value_type(3); + // auto const expr = a + three * a; + + // auto const t = tensor_t(expr); + + // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + // BOOST_REQUIRE ( t.extents() == e ); + // auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Matrix Expression Constructor] testing tensor element(" << i << ") = " <; + // using strides_t = typename tensor_t::strides_type; + + // using vector_type = typename tensor_t::vector_type; + // auto const e = fixture_type::t2.extents(); + // auto const a = vector_type(e[0], value_type(1)); + // BOOST_REQUIRE_EQUAL ( a.size(), e[0]); + + // auto const three = value_type(3); + // auto const expr = a + three * a; + // auto const t = tensor_t(expr); + + // BOOST_CHECK_NO_THROW( (void)t.at(1ul)); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + + // BOOST_REQUIRE ( t.extents() == fixture_type::t21.extents() ); + // auto const strides = (std::is_same_v ? strides_t{1, 1} : strides_t{1ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Vector Expression Constructor] testing tensor element(" << i << ") = " <; + using strides_t = typename tensor_t::strides_type; + + auto o = fixture_type::t32; + o = value_type(1); + BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE (!o.empty()); + + auto const t = tensor_t(o); + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == o.extents() ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t), std::end(t), std::begin(o), std::end(o)); + } + + BOOST_TEST_CONTEXT("[Static Rank Tensor Move Construction] move constructing tensor"){ + using tensor_t = ublas::tensor_static_rank; + using strides_t = typename tensor_t::strides_type; + + auto const& e = fixture_type::t32.extents(); + auto o = tensor_t(e); + o = value_type(1); + + BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE (!o.empty()); + + auto const t = tensor_t(std::move(o)); + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + BOOST_REQUIRE_EQUAL ( o.size(), 0ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE ( o.empty()); + + BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == e ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Move constructor] testing tensor element(" << i << ") = " < +){ + namespace ublas = boost::numeric::ublas; + + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using fixture_type = boost::numeric::ublas::tuple_fixture_tensor_static; + + + BOOST_TEST_CONTEXT("[Static Tensor Construction] default constructor"){ + using tensor_t = ublas::tensor_static,layout_type>; + auto const t = tensor_t{}; + BOOST_REQUIRE_EQUAL ( t.size(), 1ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 3ul); + BOOST_REQUIRE (!t.empty()); + + // TODO: Enable afte adding bounds checking + // BOOST_CHECK_NO_THROW( (void)t.at(0)); + // BOOST_CHECK_THROW ( (void)t.at(1), std::out_of_range); + } + + BOOST_TEST_CONTEXT("[Static Tensor Construction] construction using container"){ + using tensor_t = typename fixture_type::t32_type; + using shape_t = typename tensor_t::extents_type; + using strides_t = typename tensor_t::strides_type; + using container_type = typename tensor_t::container_type; + + auto const c = container_type{ + value_type(1), value_type(2), + value_type(3), value_type(4), + value_type(5), value_type(6) + }; + + auto const t = tensor_t(c); + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + + // TODO: Enable afte adding bounds checking + // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == shape_t{} ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t), std::end(t), std::begin(c), std::end(c)); + } + + BOOST_TEST_CONTEXT("[Static Tensor Construction] construction using default value"){ + using tensor_t = typename fixture_type::t32_type; + using shape_t = typename tensor_t::extents_type; + using strides_t = typename tensor_t::strides_type; + + auto const t = tensor_t(value_type(1)); + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + + // TODO: Enable afte adding bounds checking + // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == shape_t{} ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Default Value Constructed] testing tensor element(" << i << ") = " <, + // ublas::layout::last_order, + // ublas::layout::first_order + // >; + + // auto const e = fixture_type::t32.extents(); + // auto const o = ublas::tensor_static(e, value_type(1)); + // BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + // BOOST_REQUIRE (!o.empty()); + + // auto const t = tensor_t(o); + // BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + // BOOST_REQUIRE (!t.empty()); + + // } + + // FIXME: Enable this tests after the tensor expression is fixed + // BOOST_TEST_CONTEXT("[Static Tensor Construction] construction using tensor expression"){ + + // using tensor_t = typename fixture_type::t32_type; + // using shape_t = typename tensor_t::extents_type; + // using strides_t = typename tensor_t::strides_type; + + // auto a = tensor_t(value_type(1)); + + // BOOST_REQUIRE_EQUAL ( a.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( a.rank(), 2ul); + // BOOST_REQUIRE (!a.empty()); + + // auto const three = value_type(3); + // auto const expr = a + three * a; + // auto const t = tensor_t(expr); + + // BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + // BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + // BOOST_REQUIRE (!t.empty()); + // // TODO: Enable it after adding out of bound check to static tensor + // // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + // BOOST_REQUIRE ( t.extents() == shape_t{} ); + // auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Expression Constructor] Testing tensor element(" << i << ") = " < ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Matrix Constructor] testing tensor element(" << i << ") = " < ? strides_t{1, 1} : strides_t{1ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const one = value_type(1); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Vector Constructor] testing tensor element(" << i << ") = " < ? strides_t{1, 3} : strides_t{2ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Matrix Expression Constructor] testing tensor element(" << i << ") = " < ? strides_t{1, 1} : strides_t{1ul, 1ul}); + // BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + // auto const four = value_type(4); + // for(auto i = 0ul; i < t.size(); ++i){ + // BOOST_TEST_CHECKPOINT("[Tensor Legacy uBLAS Vector Expression Constructor] testing tensor element(" << i << ") = " < ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t), std::end(t), std::begin(o), std::end(o)); + } + + BOOST_TEST_CONTEXT("[Static Tensor Move Construction] move constructing tensor"){ + using tensor_t = typename fixture_type::t32_type; + using strides_t = typename tensor_t::strides_type; + + auto o = tensor_t(value_type(1)); + + BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE (!o.empty()); + + auto const t = tensor_t(std::move(o)); + BOOST_REQUIRE_EQUAL ( t.size(), 6ul); + BOOST_REQUIRE_EQUAL ( t.rank(), 2ul); + BOOST_REQUIRE (!t.empty()); + BOOST_REQUIRE_EQUAL ( o.size(), 6ul); + BOOST_REQUIRE_EQUAL ( o.rank(), 2ul); + BOOST_REQUIRE (!o.empty()); + // TODO: Enable afte adding bounds checking + // BOOST_CHECK_NO_THROW( (void)t.at(3ul)); + // BOOST_CHECK_THROW ( (void)t.at(25ul), std::out_of_range); + // BOOST_CHECK_THROW ( (void)t.at(5,2), std::out_of_range); + + BOOST_REQUIRE ( t.extents() == o.extents() ); + auto const strides = (std::is_same_v ? strides_t{1, 3} : strides_t{2ul, 1ul}); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(t.strides()), std::end(t.strides()), std::begin(strides), std::end(strides)); + + auto const one = value_type(1); + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Tensor Move constructor] testing tensor element(" << i << ") = " < +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_empty, * boost::unit_test::description("Validate Empty Method")) + + +BOOST_FIXTURE_TEST_CASE(test_tensor_dynamic, + boost::numeric::ublas::fixture_tensor_dynamic, + *boost::unit_test::label("boost::numeric::ublas::tensor_dynamic::empty") + *boost::unit_test::description("Testing the dynamic tensor's [empty] method")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Empty Method] rank(1) dynamic tensor"){ + BOOST_REQUIRE(!t2.empty() ); + } + + BOOST_TEST_CONTEXT("[Empty Method] rank(2) dynamic tensor"){ + BOOST_REQUIRE(!t11.empty() ); + BOOST_REQUIRE(!t12.empty() ); + BOOST_REQUIRE(!t21.empty() ); + BOOST_REQUIRE(!t22.empty() ); + BOOST_REQUIRE(!t32.empty() ); + } + + BOOST_TEST_CONTEXT("[Empty Method] rank(3) dynamic tensor"){ + BOOST_REQUIRE(!t111.empty() ); + BOOST_REQUIRE(!t112.empty() ); + BOOST_REQUIRE(!t121.empty() ); + BOOST_REQUIRE(!t123.empty() ); + BOOST_REQUIRE(!t211.empty() ); + BOOST_REQUIRE(!t213.empty() ); + BOOST_REQUIRE(!t321.empty() ); + BOOST_REQUIRE(!t432.empty() ); + } + + BOOST_TEST_CONTEXT("[Empty Method] rank(4) dynamic tensor"){ + BOOST_REQUIRE(!t1111.empty()); + BOOST_REQUIRE(!t4231.empty()); + } + +} + +BOOST_FIXTURE_TEST_CASE(test_tensor_static_rank, + boost::numeric::ublas::fixture_tensor_static_rank, + *boost::unit_test::label("boost::numeric::ublas::tensor_static_rank::empty") + *boost::unit_test::description("Testing the static rank tensor's [empty] method")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Empty Method] rank(1) static_rank tensor"){ + BOOST_REQUIRE(!t2.empty() ); + } + + BOOST_TEST_CONTEXT("[Empty Method] rank(2) static_rank tensor"){ + BOOST_REQUIRE(!t11.empty() ); + BOOST_REQUIRE(!t12.empty() ); + BOOST_REQUIRE(!t21.empty() ); + BOOST_REQUIRE(!t22.empty() ); + BOOST_REQUIRE(!t32.empty() ); + } + + BOOST_TEST_CONTEXT("[Empty Method] rank(3) static_rank tensor"){ + BOOST_REQUIRE(!t111.empty() ); + BOOST_REQUIRE(!t112.empty() ); + BOOST_REQUIRE(!t121.empty() ); + BOOST_REQUIRE(!t123.empty() ); + BOOST_REQUIRE(!t211.empty() ); + BOOST_REQUIRE(!t213.empty() ); + BOOST_REQUIRE(!t321.empty() ); + BOOST_REQUIRE(!t432.empty() ); + } + + BOOST_TEST_CONTEXT("[Empty Method] rank(4) static_rank tensor"){ + BOOST_REQUIRE(!t1111.empty()); + BOOST_REQUIRE(!t4231.empty()); + } + +} + +BOOST_FIXTURE_TEST_CASE(test_tensor_static, + boost::numeric::ublas::fixture_tensor_static, + *boost::unit_test::label("boost::numeric::ublas::tensor_static::empty") + *boost::unit_test::description("Testing the static tensor's [empty] method")) +{ + namespace ublas = boost::numeric::ublas; + + // BOOST_TEST_CONTEXT("[Empty Method] rank(1) static tensor"){ + // BOOST_REQUIRE(!t2.empty() ); + // } + + BOOST_TEST_CONTEXT("[Empty Method] rank(2) static tensor"){ + BOOST_REQUIRE(!t11.empty() ); + BOOST_REQUIRE(!t12.empty() ); + BOOST_REQUIRE(!t21.empty() ); + BOOST_REQUIRE(!t22.empty() ); + BOOST_REQUIRE(!t32.empty() ); + } + + BOOST_TEST_CONTEXT("[Empty Method] rank(3) static tensor"){ + BOOST_REQUIRE(!t111.empty() ); + BOOST_REQUIRE(!t112.empty() ); + BOOST_REQUIRE(!t121.empty() ); + BOOST_REQUIRE(!t123.empty() ); + BOOST_REQUIRE(!t211.empty() ); + BOOST_REQUIRE(!t213.empty() ); + BOOST_REQUIRE(!t321.empty() ); + BOOST_REQUIRE(!t432.empty() ); + } + + BOOST_TEST_CONTEXT("[Empty Method] rank(4) static tensor"){ + BOOST_REQUIRE(!t1111.empty()); + BOOST_REQUIRE(!t4231.empty()); + } + +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_expression_access.cpp b/test/tensor/tensor/test_tensor_expression_access.cpp new file mode 100644 index 000000000..def21daee --- /dev/null +++ b/test/tensor/tensor/test_tensor_expression_access.cpp @@ -0,0 +1,123 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_expression_access, + * boost::unit_test::description("Validate Expression access") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("access_expr") + *boost::unit_test::description("Testing the access for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check = [](auto /*id*/, tensor_t t){ + auto v = value_type{}; + using expr_t = typename tensor_t::super_type; + + BOOST_TEST_CONTEXT("[Dynamic Tensor Expr Access] rank("<< t.rank() <<") dynamic tensor"){ + + ublas::iota(t,v); + auto const& expr = static_cast(t); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Dynamic Tensor Expr Access] testing tensor element(" << i << ") = " <(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("access_expr") + *boost::unit_test::description("Testing the access for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check = [](auto /*id*/, tensor_t t){ + auto v = value_type{}; + using expr_t = typename tensor_t::super_type; + + BOOST_TEST_CONTEXT("[Static Rank Tensor Expr Access] static rank("<< t.rank() <<") tensor"){ + + ublas::iota(t,v); + auto const& expr = static_cast(t); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Static Rank Tensor Expr Access] testing tensor element(" << i << ") = " <(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("access_expr") + *boost::unit_test::description("Testing the access for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static; + + constexpr auto check = [](auto /*id*/, tensor_t t){ + auto v = value_type{}; + using expr_t = typename tensor_t::super_type; + + BOOST_TEST_CONTEXT("[Static Tensor Expr Access] rank("<< t.rank() <<") static tensor"){ + + ublas::iota(t,v); + auto const& expr = static_cast(t); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_TEST_CHECKPOINT("[Static Tensor Expr Access] testing tensor element(" << i << ") = " <(*this); + ublas::for_each_fixture(self, check); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_expression_evaluation_all_extents_equal.cpp b/test/tensor/tensor/test_tensor_expression_evaluation_all_extents_equal.cpp new file mode 100644 index 000000000..0015ab7ae --- /dev/null +++ b/test/tensor/tensor/test_tensor_expression_evaluation_all_extents_equal.cpp @@ -0,0 +1,312 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_expression_evaluation_all_extents_equal, + * boost::unit_test::description("Validate Expression Evaluation's All Extents Equal") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("expr_eval_all_extents") + *boost::unit_test::description("Testing the expression evaluation's all extents equal for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto uplus1 = [](auto const& a){return a + value_type(1); }; + constexpr auto uplus2 = [](auto const& a){return value_type(2) + a; }; + constexpr auto bplus = std::plus {}; + constexpr auto bminus = std::minus{}; + + constexpr auto check_same_tensor = [uplus1, uplus2, bplus, bminus](auto /*id*/, tensor_t t){ + auto v = value_type{}; + + BOOST_TEST_CONTEXT("[Check All Extents(With Same Dynamic Tensor)] rank("<< t.rank() <<") dynamic tensor"){ + + ublas::iota(t,v); + auto const& e = t.extents(); + + BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); + + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); + } + }; + + auto check_different_tensor = [uplus1, uplus2, bplus, bminus, this](auto i, tensor_t t1){ + auto const size = this->collection.size(); + + if(i >= size - 1ul) + return; + + auto v = value_type{}; + auto t2 = this->collection[i + 1ul]; + + BOOST_TEST_CONTEXT("[Check All Extents(With Different Dynamic Tensor)] rank("<< t1.rank() << ", "<< t2.rank() <<") dynamic tensor"){ + + ublas::iota(t1,v); + ublas::iota(t2,v + value_type{1}); + + 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( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( 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( 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( 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( 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( t1, bexpr_bexpr_uexpr3, bplus ); + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); + } + }; + + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [check_same_tensor, &check_different_tensor](auto id, auto const& t){ + std::invoke(check_same_tensor, id, t); + std::invoke(check_different_tensor, id, t); + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("expr_eval_all_extents") + *boost::unit_test::description("Testing the expression evaluation's all extents equal for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + static constexpr auto fixture_size = fixture_t::size; + + + constexpr auto uplus1 = [](auto const& a){return a + value_type(1); }; + constexpr auto uplus2 = [](auto const& a){return value_type(2) + a; }; + constexpr auto bplus = std::plus {}; + constexpr auto bminus = std::minus{}; + + constexpr auto check_same_tensor = [uplus1, uplus2, bplus, bminus](auto /*id*/, tensor_t t){ + auto v = value_type{}; + + BOOST_TEST_CONTEXT("[Check All Extents(With Same Static Rank Tensor)] static rank("<< t.rank() <<") tensor"){ + + ublas::iota(t,v); + auto const& e = t.extents(); + + BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); + + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); + } + }; + + auto check_different_tensor = [uplus1, uplus2, bplus, bminus, this](IType /*id*/, tensor_t t1){ + + constexpr std::size_t i = IType::value; + + if constexpr(i < fixture_size - 1ul){ + + auto v = value_type{}; + auto t2 = std::get( this->collection ); + + if constexpr(t1.rank() == t2.rank()){ + + BOOST_TEST_CONTEXT("[Check All Extents(With Different Static Rank Tensor)] static rank("<< t1.rank() << ", "<< t2.rank() <<") tensor"){ + + ublas::iota(t1,v); + ublas::iota(t2,v + value_type{1}); + + 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( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( 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( 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( 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( 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( t1, bexpr_bexpr_uexpr3, bplus ); + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); + } + } + + } + + }; + + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [check_same_tensor, &check_different_tensor](auto id, auto const& t){ + std::invoke(check_same_tensor, id, t); + std::invoke(check_different_tensor, id, t); + }); +} + +// FIXME: Enable after the strides computation is fixed [ issue #119 ] +// BOOST_TEST_DECORATOR( +// *boost::unit_test::label("expr_eval_all_extents") +// *boost::unit_test::description("Testing the expression evaluation's all extents equal for static tensor") +// ) +// BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, +// TestTupleType, +// boost::numeric::ublas::test_types, +// boost::numeric::ublas::tuple_fixture_tensor_static +// ) +// { +// namespace ublas = boost::numeric::ublas; +// using value_type = typename TestTupleType::first_type; +// using fixture_t = ublas::tuple_fixture_tensor_static; + +// constexpr auto uplus1 = [](auto const& a){return a + value_type(1); }; +// constexpr auto uplus2 = [](auto const& a){return value_type(2) + a; }; +// constexpr auto bplus = std::plus {}; +// constexpr auto bminus = std::minus{}; + +// constexpr auto check_same_tensor = [uplus1, uplus2, bplus, bminus](auto /*id*/, tensor_t t){ +// auto v = value_type{}; + +// BOOST_TEST_CONTEXT("[Check All Extents(With same Tensor)] rank("<< t.rank() <<") dynamic tensor"){ + +// ublas::iota(t,v); +// auto const& e = t.extents(); + +// BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); + +// // uexpr1 = t+1 +// // uexpr2 = 2+t +// auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); +// auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); + +// BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); +// } +// }; + +// auto const& self = static_cast(*this); +// ublas::for_each_fixture(self, check_same_tensor); +// } + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_expression_evaluation_retrieve_extents.cpp b/test/tensor/tensor/test_tensor_expression_evaluation_retrieve_extents.cpp new file mode 100644 index 000000000..c76a13c26 --- /dev/null +++ b/test/tensor/tensor/test_tensor_expression_evaluation_retrieve_extents.cpp @@ -0,0 +1,300 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_expression_evaluation_retrieve_extents, + * boost::unit_test::description("Validate Expression Evaluation's Retrive Extents") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("expr_eval_retrive_extents") + *boost::unit_test::description("Testing the expression evaluation's retrive extents for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto uplus1 = [](auto const& a){return a + value_type(1); }; + constexpr auto uplus2 = [](auto const& a){return value_type(2) + a; }; + constexpr auto bplus = std::plus {}; + constexpr auto bminus = std::minus{}; + + constexpr auto equal_range = [](auto const& l, auto const& r){ + BOOST_CHECK_EQUAL_COLLECTIONS(ublas::begin(l), ublas::end(l), ublas::begin(r), ublas::end(r)); + }; + + constexpr auto check_same_tensor = [uplus1, uplus2, bplus, bminus, equal_range](auto /*id*/, tensor_t t){ + auto v = value_type{}; + + BOOST_TEST_CONTEXT("[Retrive Extents(With Same Dynamic Tensor)] rank("<< t.rank() <<") dynamic tensor"){ + + ublas::iota(t,v); + auto const& e = t.extents(); + + equal_range(ublas::detail::retrieve_extents( t ), e); + + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + + equal_range( ublas::detail::retrieve_extents( uexpr1 ), e ); + equal_range( ublas::detail::retrieve_extents( uexpr2 ), e ); + + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + + equal_range( 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( bexpr_uexpr, t, bminus ); + + equal_range( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ), e ); + } + }; + + auto check_different_tensor = [uplus1, uplus2, bplus, bminus, equal_range, this](auto i, tensor_t t1){ + auto const size = this->collection.size(); + + if(i >= size - 1ul) + return; + + auto v = value_type{}; + auto t2 = this->collection[i + 1ul]; + + BOOST_TEST_CONTEXT("[Retrive Extents(With Different Dynamic Tensor)] rank("<< t1.rank() << ", "<< t2.rank() <<") dynamic tensor"){ + + ublas::iota(t1,v); + ublas::iota(t2,v + value_type{1}); + + 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( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + + equal_range( ublas::detail::retrieve_extents( t1 ), ublas::detail::retrieve_extents( uexpr1 ) ); + equal_range( 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( uexpr1, uexpr2, bplus ); + + equal_range( 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( bexpr_uexpr, t2, bminus ); + + equal_range( 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( t2, bexpr_uexpr, bminus ); + + equal_range( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ), ublas::detail::retrieve_extents(t2) ); + } + }; + + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [check_same_tensor, &check_different_tensor](auto id, auto const& t){ + std::invoke(check_same_tensor, id, t); + std::invoke(check_different_tensor, id, t); + }); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("expr_eval_retrive_extents") + *boost::unit_test::description("Testing the expression evaluation's retrive extents for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + static constexpr auto fixture_size = fixture_t::size; + + + constexpr auto uplus1 = [](auto const& a){return a + value_type(1); }; + constexpr auto uplus2 = [](auto const& a){return value_type(2) + a; }; + constexpr auto bplus = std::plus {}; + constexpr auto bminus = std::minus{}; + + constexpr auto equal_range = [](auto const& l, auto const& r){ + BOOST_CHECK_EQUAL_COLLECTIONS(ublas::begin(l), ublas::end(l), ublas::begin(r), ublas::end(r)); + }; + + constexpr auto check_same_tensor = [uplus1, uplus2, bplus, bminus, equal_range](auto /*id*/, tensor_t t){ + auto v = value_type{}; + + BOOST_TEST_CONTEXT("[Retrive Extents(With Same Static Rank Tensor)] static rank("<< t.rank() <<") tensor"){ + + ublas::iota(t,v); + auto const& e = t.extents(); + + equal_range(ublas::detail::retrieve_extents( t ), e); + + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + + equal_range( ublas::detail::retrieve_extents( uexpr1 ), e ); + equal_range( ublas::detail::retrieve_extents( uexpr2 ), e ); + + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + + equal_range( 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( bexpr_uexpr, t, bminus ); + + equal_range( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ), e ); + } + }; + + auto check_different_tensor = [uplus1, uplus2, bplus, bminus, equal_range, this](IType /*id*/, tensor_t t1){ + + constexpr std::size_t i = IType::value; + + if constexpr(i < fixture_size - 1ul){ + + auto v = value_type{}; + auto t2 = std::get( this->collection ); + + if constexpr(t1.rank() == t2.rank()){ + + BOOST_TEST_CONTEXT("[Retrive Extents(With Different Static Rank Tensor)] static rank("<< t1.rank() << ", "<< t2.rank() <<") tensor"){ + + ublas::iota(t1,v); + ublas::iota(t2,v + value_type{1}); + + 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( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression( t2, uplus2 ); + + equal_range( ublas::detail::retrieve_extents( t1 ), ublas::detail::retrieve_extents( uexpr1 ) ); + equal_range( 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( uexpr1, uexpr2, bplus ); + + equal_range( 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( bexpr_uexpr, t2, bminus ); + + equal_range( 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( t2, bexpr_uexpr, bminus ); + + equal_range( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ), ublas::detail::retrieve_extents(t2) ); + } + } + + } + + }; + + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, [check_same_tensor, &check_different_tensor](auto id, auto const& t){ + std::invoke(check_same_tensor, id, t); + std::invoke(check_different_tensor, id, t); + }); +} + +// FIXME: Enable after the strides computation is fixed [ issue #119 ] +// BOOST_TEST_DECORATOR( +// *boost::unit_test::label("expr_eval_retrive_extents") +// *boost::unit_test::description("Testing the expression evaluation's retrive extents for static tensor") +// ) +// BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, +// TestTupleType, +// boost::numeric::ublas::test_types, +// boost::numeric::ublas::tuple_fixture_tensor_static +// ) +// { +// namespace ublas = boost::numeric::ublas; +// using value_type = typename TestTupleType::first_type; +// using fixture_t = ublas::tuple_fixture_tensor_static; + +// constexpr auto uplus1 = [](auto const& a){return a + value_type(1); }; +// constexpr auto uplus2 = [](auto const& a){return value_type(2) + a; }; +// constexpr auto bplus = std::plus {}; +// constexpr auto bminus = std::minus{}; + +// constexpr auto equal_range = [](auto const& l, auto const& r){ +// BOOST_CHECK_EQUAL_COLLECTIONS(ublas::begin(l), ublas::end(l), ublas::begin(r), ublas::end(r)); +// }; + +// constexpr auto check_same_tensor = [uplus1, uplus2, bplus, bminus, equal_range](auto /*id*/, tensor_t t){ +// auto v = value_type{}; + +// BOOST_TEST_CONTEXT("[Retrive Extents(With Same Static Tensor)] rank("<< t.rank() <<") static tensor"){ + +// ublas::iota(t,v); +// auto const& e = t.extents(); + +// equal_range(ublas::detail::retrieve_extents( t ), e); + +// // uexpr1 = t+1 +// // uexpr2 = 2+t +// auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); +// auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); + +// equal_range( ublas::detail::retrieve_extents( uexpr1 ), e ); +// equal_range( ublas::detail::retrieve_extents( uexpr2 ), e ); + +// // bexpr_uexpr = (t+1) + (2+t) +// auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( uexpr1, uexpr2, bplus ); + +// equal_range( 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( bexpr_uexpr, t, bminus ); + +// equal_range( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ), e ); +// } +// }; + +// auto const& self = static_cast(*this); +// ublas::for_each_fixture(self, check_same_tensor); +// } + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_operator_arithmetic_assignment.cpp b/test/tensor/tensor/test_tensor_operator_arithmetic_assignment.cpp new file mode 100644 index 000000000..2794bbd0e --- /dev/null +++ b/test/tensor/tensor/test_tensor_operator_arithmetic_assignment.cpp @@ -0,0 +1,291 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_assign_arithmetic, + * boost::unit_test::description("Validate Assignment of Arithmetic Operations") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("op_assignement") + *boost::unit_test::description("Testing the dynamic tensor's assingment of arithmetic result") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check = [](auto /*id*/, tensor_t t1){ + auto v = value_type{}; + auto one = value_type{1}; + auto two = value_type{2}; + auto three = value_type{3}; + auto four = value_type{4}; + if(t1.rank() == 0ul) return; + + BOOST_TEST_CONTEXT("[Arithmatic Assignment] rank("<< t1.rank() <<") dynamic tensor"){ + auto t2 = t1; + auto r = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + two); + + r = t1 + two; + r += t1; + r += two; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), two*t1(i) + four ); + + r = two + t1; + r += t1; + r += two; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), two*t1(i) + four ); + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), two*t1(i) + four ); + + r = (t1-two); + r += t1; + r -= two; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), two*t1(i) - four ); + + r = (t1*two); + r *= three; + r *= t1; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), two*three*t1(i)*t1(i) ); + + r = (t2*two); + r /= two; + r /= t2; + r *= t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), (t2(i)*two) / (two*t2(i)) * t2(i) ); + + r = (t2/two+one); + r /= (two/t2+one); + r /= t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), (t2(i)/two+one) / (two/t2(i)+one) / t2(i) ); + + tensor_t q = -r; + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( q(i), -r(i) ); + + tensor_t p = +r; + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( p(i), r(i) ); + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("op_assignement") + *boost::unit_test::description("Testing the static rank tensor's assingment of arithmetic result") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check = [](auto /*id*/, tensor_t t1){ + auto v = value_type{}; + auto one = value_type{1}; + auto two = value_type{2}; + auto three = value_type{3}; + auto four = value_type{4}; + if constexpr(t1.rank() > 0ul){ + + BOOST_TEST_CONTEXT("[Arithmatic Assignment] static rank("<< t1.rank() <<") tensor"){ + auto t2 = t1; + auto r = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + two); + + r = t1 + two; + r += t1; + r += two; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), two*t1(i) + four ); + + r = two + t1; + r += t1; + r += two; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), two*t1(i) + four ); + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), two*t1(i) + four ); + + r = (t1-two); + r += t1; + r -= two; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), two*t1(i) - four ); + + r = (t1*two); + r *= three; + r *= t1; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), two*three*t1(i)*t1(i) ); + + r = (t2*two); + r /= two; + r /= t2; + r *= t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), (t2(i)*two) / (two*t2(i)) * t2(i) ); + + r = (t2/two+one); + r /= (two/t2+one); + r /= t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), (t2(i)/two+one) / (two/t2(i)+one) / t2(i) ); + + tensor_t q = -r; + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( q(i), -r(i) ); + + tensor_t p = +r; + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( p(i), r(i) ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +// FIXME: Enable after the strides computation is fixed [ issue #119 ] +// BOOST_TEST_DECORATOR( +// *boost::unit_test::label("op_assignement") +// *boost::unit_test::description("Testing the static tensor's assingment of arithmetic result") +// ) +// BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, +// TestTupleType, +// boost::numeric::ublas::test_types, +// boost::numeric::ublas::tuple_fixture_tensor_static +// ) +// { +// namespace ublas = boost::numeric::ublas; +// using value_type = typename TestTupleType::first_type; +// using fixture_t = ublas::tuple_fixture_tensor_static; + +// constexpr auto check = [](auto /*id*/, tensor_t t1){ +// auto v = value_type{}; +// auto one = value_type{1}; +// auto two = value_type{2}; +// auto three = value_type{3}; +// auto four = value_type{4}; +// if constexpr (t1.rank() > 0ul){ + +// BOOST_TEST_CONTEXT("[Arithmatic Assignment] rank("<< t1.rank() <<") static tensor"){ +// auto t2 = t1; +// auto r = t1; + +// ublas::iota(t1, v); +// ublas::iota(t2, v + two); + +// r = t1 + two; +// r += t1; +// r += two; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), two*t1(i) + four ); + +// r = two + t1; +// r += t1; +// r += two; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), two*t1(i) + four ); + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), two*t1(i) + four ); + +// r = (t1-two); +// r += t1; +// r -= two; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), two*t1(i) - four ); + +// r = (t1*two); +// r *= three; +// r *= t1; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), two*three*t1(i)*t1(i) ); + +// r = (t2*two); +// r /= two; +// r /= t2; +// r *= t2; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), (t2(i)*two) / (two*t2(i)) * t2(i) ); + +// r = (t2/two+one); +// r /= (two/t2+one); +// r /= t2; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), (t2(i)/two+one) / (two/t2(i)+one) / t2(i) ); + +// tensor_t q = -r; +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( q(i), -r(i) ); + +// tensor_t p = +r; +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( p(i), r(i) ); +// } +// } +// }; + +// auto const& self = static_cast(*this); +// ublas::for_each_fixture(self, check); +// } + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_operator_arithmetic_binary.cpp b/test/tensor/tensor/test_tensor_operator_arithmetic_binary.cpp new file mode 100644 index 000000000..bf8a31cf0 --- /dev/null +++ b/test/tensor/tensor/test_tensor_operator_arithmetic_binary.cpp @@ -0,0 +1,223 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_binary_arithmetic, + * boost::unit_test::description("Validate Binary Arithmetic Operators/Functions") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("binary_op") + *boost::unit_test::description("Testing the dynamic tensor's binary operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check = [](auto /*id*/, auto t1){ + auto v = value_type{}; + auto one = value_type{1}; + auto three = value_type{3}; + auto four = value_type{4}; + + if (t1.rank() <= 1ul) return; + + BOOST_TEST_CONTEXT("[Binary Operator] rank("<< t1.rank() <<") dynamic tensor"){ + auto t2 = t1; + auto r = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + value_type{2}); + + r = t1 + t1 + t1 + t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), three*t1(i) + t2(i) ); + + + r = t2 / (t1+three) * (t1+one) - t2; // r = ( t2/ ((t+3)*(t+1)) ) - t2 + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), t2(i) / (t1(i)+three)*(t1(i)+one) - t2(i) ); + + r = three+t2 / (t1+three) * (t1+one) * t1 - t2; // r = 3+( t2/ ((t+3)*(t+1)*t) ) - t2 + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), three+t2(i) / (t1(i)+three)*(t1(i)+one)*t1(i) - t2(i) ); + + r = t2 - t1 + t2 - t1; + + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), four ); + + + r = t1 * t1 * t1 * t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), t1(i)*t1(i)*t1(i)*t2(i) ); + + r = (t2/t2) * (t2/t2); + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), one ); + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("binary_op") + *boost::unit_test::description("Testing the static rank tensor's binary operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check = [](auto /*id*/, auto t1){ + if constexpr(t1.rank() > 1ul){ + auto v = value_type{}; + auto one = value_type{1}; + auto three = value_type{3}; + auto four = value_type{4}; + + BOOST_TEST_CONTEXT("[Binary Operator] static rank("<< t1.rank() <<") tensor"){ + auto t2 = t1; + auto r = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + value_type{2}); + + r = t1 + t1 + t1 + t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), three*t1(i) + t2(i) ); + + + r = t2 / (t1+three) * (t1+one) - t2; // r = ( t2/ ((t+3)*(t+1)) ) - t2 + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), t2(i) / (t1(i)+three)*(t1(i)+one) - t2(i) ); + + r = three+t2 / (t1+three) * (t1+one) * t1 - t2; // r = 3+( t2/ ((t+3)*(t+1)*t) ) - t2 + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), three+t2(i) / (t1(i)+three)*(t1(i)+one)*t1(i) - t2(i) ); + + r = t2 - t1 + t2 - t1; + + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), four ); + + + r = t1 * t1 * t1 * t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), t1(i)*t1(i)*t1(i)*t2(i) ); + + r = (t2/t2) * (t2/t2); + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), one ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +// FIXME: Enable after the strides computation is fixed [ issue #119 ] +// BOOST_TEST_DECORATOR( +// *boost::unit_test::label("binary_op") +// *boost::unit_test::description("Testing the static tensor's binary operators") +// ) +// BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, +// TestTupleType, +// boost::numeric::ublas::test_types, +// boost::numeric::ublas::tuple_fixture_tensor_static +// ) +// { +// namespace ublas = boost::numeric::ublas; +// using value_type = typename TestTupleType::first_type; +// using fixture_t = ublas::tuple_fixture_tensor_static; + +// constexpr auto check = [](auto /*id*/, auto t1){ +// auto v = value_type{}; +// auto one = value_type{1}; +// auto three = value_type{3}; +// auto four = value_type{4}; +// if constexpr(t1.rank() > 0ul){ + +// BOOST_TEST_CONTEXT("[Binary Operator] rank("<< t1.rank() <<") static tensor"){ +// auto t2 = t1; +// auto r = t1; + +// ublas::iota(t1, v); +// ublas::iota(t2, v + value_type{2}); + +// r = t1 + t1 + t1 + t2; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), three*t1(i) + t2(i) ); + + +// r = t2 / (t1+three) * (t1+one) - t2; // r = ( t2/ ((t+3)*(t+1)) ) - t2 + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), t2(i) / (t1(i)+three)*(t1(i)+one) - t2(i) ); + +// r = three+t2 / (t1+three) * (t1+one) * t1 - t2; // r = 3+( t2/ ((t+3)*(t+1)*t) ) - t2 + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), three+t2(i) / (t1(i)+three)*(t1(i)+one)*t1(i) - t2(i) ); + +// r = t2 - t1 + t2 - t1; + +// for(auto i = 0ul; i < r.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), four ); + + +// r = t1 * t1 * t1 * t2; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), t1(i)*t1(i)*t1(i)*t2(i) ); + +// r = (t2/t2) * (t2/t2); + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r(i), one ); +// } +// } +// }; + +// auto const& self = static_cast(*this); +// ublas::for_each_fixture(self, check); +// } + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_operator_arithmetic_unary.cpp b/test/tensor/tensor/test_tensor_operator_arithmetic_unary.cpp new file mode 100644 index 000000000..0277b88f4 --- /dev/null +++ b/test/tensor/tensor/test_tensor_operator_arithmetic_unary.cpp @@ -0,0 +1,216 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_unary_arithmetic, + * boost::unit_test::description("Validate Binary Arithmetic Operators/Functions") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("unary_op") + *boost::unit_test::description("Testing the dynamic tensor's unary operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto check = [](auto /*id*/, tensor_t t1){ + auto v = value_type{}; + auto one = value_type{1}; + auto two = value_type{2}; + auto three = value_type{3}; + auto four = value_type{4}; + if(t1.rank() == 0ul) return; + + BOOST_TEST_CONTEXT("[Unary Operator] rank("<< t1.rank() <<") dynamic tensor"){ + auto t2 = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + two); + + tensor_t r1 = t1 + two + t1 + two; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r1(i), two*t1(i) + four ); + + tensor_t r2 = two + t1 + two + t1; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r2(i), two*t1(i) + four ); + + tensor_t r3 = (t1-two) + (t1-two); + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r3(i), two*t1(i) - four ); + + tensor_t r4 = (t1*two) * (three*t1); + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r4(i), two*three*t1(i)*t1(i) ); + + tensor_t r5 = (t2*two) / (two*t2) * t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r5(i), (t2(i)*two) / (two*t2(i)) * t2(i) ); + + tensor_t r6 = (t2/two+one) / (two/t2+one) / t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r6(i), (t2(i)/two+one) / (two/t2(i)+one) / t2(i) ); + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("unary_op") + *boost::unit_test::description("Testing the static rank tensor's unary operators") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto check = [](auto /*id*/, tensor_t t1){ + auto v = value_type{}; + auto one = value_type{1}; + auto two = value_type{2}; + auto three = value_type{3}; + auto four = value_type{4}; + if constexpr(t1.rank() > 0ul){ + + BOOST_TEST_CONTEXT("[Unary Operator] static rank("<< t1.rank() <<") tensor"){ + auto t2 = t1; + + ublas::iota(t1, v); + ublas::iota(t2, v + two); + + tensor_t r1 = t1 + two + t1 + two; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r1(i), two*t1(i) + four ); + + tensor_t r2 = two + t1 + two + t1; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r2(i), two*t1(i) + four ); + + tensor_t r3 = (t1-two) + (t1-two); + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r3(i), two*t1(i) - four ); + + tensor_t r4 = (t1*two) * (three*t1); + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r4(i), two*three*t1(i)*t1(i) ); + + tensor_t r5 = (t2*two) / (two*t2) * t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r5(i), (t2(i)*two) / (two*t2(i)) * t2(i) ); + + tensor_t r6 = (t2/two+one) / (two/t2+one) / t2; + + for(auto i = 0ul; i < t1.size(); ++i) + BOOST_CHECK_EQUAL ( r6(i), (t2(i)/two+one) / (two/t2(i)+one) / t2(i) ); + } + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +// FIXME: Enable after the strides computation is fixed [ issue #119 ] +// BOOST_TEST_DECORATOR( +// *boost::unit_test::label("unary_op") +// *boost::unit_test::description("Testing the static tensor's unary operators") +// ) +// BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, +// TestTupleType, +// boost::numeric::ublas::test_types, +// boost::numeric::ublas::tuple_fixture_tensor_static +// ) +// { +// namespace ublas = boost::numeric::ublas; +// using value_type = typename TestTupleType::first_type; +// using fixture_t = ublas::tuple_fixture_tensor_static; + +// constexpr auto check = [](auto /*id*/, tensor_t t1){ +// auto v = value_type{}; +// auto one = value_type{1}; +// auto two = value_type{2}; +// auto three = value_type{3}; +// auto four = value_type{4}; +// if constexpr(t1.rank() > 0ul){ + +// BOOST_TEST_CONTEXT("[Unary Operator] rank("<< t1.rank() <<") static tensor"){ +// tensor_t t2; + +// ublas::iota(t1, v); +// ublas::iota(t2, v + two); + +// tensor_t r1 = t1 + two + t1 + two; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r1(i), two*t1(i) + four ); + +// tensor_t r2 = two + t1 + two + t1; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r2(i), two*t1(i) + four ); + +// tensor_t r3 = (t1-two) + (t1-two); + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r3(i), two*t1(i) - four ); + +// tensor_t r4 = (t1*two) * (three*t1); + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r4(i), two*three*t1(i)*t1(i) ); + +// tensor_t r5 = (t2*two) / (two*t2) * t2; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r5(i), (t2(i)*two) / (two*t2(i)) * t2(i) ); + +// tensor_t r6 = (t2/two+one) / (two/t2+one) / t2; + +// for(auto i = 0ul; i < t1.size(); ++i) +// BOOST_CHECK_EQUAL ( r6(i), (t2(i)/two+one) / (two/t2(i)+one) / t2(i) ); +// } +// } +// }; + +// auto const& self = static_cast(*this); +// ublas::for_each_fixture(self, check); +// } + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_size.cpp b/test/tensor/tensor/test_tensor_size.cpp new file mode 100644 index 000000000..ac9beaeab --- /dev/null +++ b/test/tensor/tensor/test_tensor_size.cpp @@ -0,0 +1,130 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_size, * boost::unit_test::description("Validate Size Function and Trait")) + +BOOST_FIXTURE_TEST_CASE(test_tensor_dynamic, + boost::numeric::ublas::fixture_tensor_dynamic, + *boost::unit_test::label("boost::numeric::ublas::tensor_dynamic::size") + *boost::unit_test::description("Testing the dynamic tensor's [size] method")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Size Method] rank(1) dynamic tensor"){ + BOOST_REQUIRE_EQUAL(t2.size() , 2ul); + } + + BOOST_TEST_CONTEXT("[Size Method] rank(2) dynamic tensor"){ + BOOST_REQUIRE_EQUAL(t11.size() , 1ul); + BOOST_REQUIRE_EQUAL(t12.size() , 2ul); + BOOST_REQUIRE_EQUAL(t21.size() , 2ul); + BOOST_REQUIRE_EQUAL(t22.size() , 4ul); + BOOST_REQUIRE_EQUAL(t32.size() , 6ul); + } + + BOOST_TEST_CONTEXT("[Size Method] rank(3) dynamic tensor"){ + BOOST_REQUIRE_EQUAL(t111.size() , 1ul); + BOOST_REQUIRE_EQUAL(t112.size() , 2ul); + BOOST_REQUIRE_EQUAL(t121.size() , 2ul); + BOOST_REQUIRE_EQUAL(t123.size() , 6ul); + BOOST_REQUIRE_EQUAL(t211.size() , 2ul); + BOOST_REQUIRE_EQUAL(t213.size() , 6ul); + BOOST_REQUIRE_EQUAL(t321.size() , 6ul); + BOOST_REQUIRE_EQUAL(t432.size() , 24ul); + } + + BOOST_TEST_CONTEXT("[Size Method] rank(4) dynamic tensor"){ + BOOST_REQUIRE_EQUAL(t1111.size(), 1ul); + BOOST_REQUIRE_EQUAL(t4231.size(), 24ul); + } + +} + +BOOST_FIXTURE_TEST_CASE(test_tensor_static_rank, + boost::numeric::ublas::fixture_tensor_static_rank, + *boost::unit_test::label("boost::numeric::ublas::tensor_static_rank::size") + *boost::unit_test::description("Testing the static rank tensor's [size] method")) +{ + namespace ublas = boost::numeric::ublas; + + BOOST_TEST_CONTEXT("[Size Method] rank(1) static_rank tensor"){ + BOOST_REQUIRE_EQUAL(t2.size() , 2ul); + } + + BOOST_TEST_CONTEXT("[Size Method] rank(2) static_rank tensor"){ + BOOST_REQUIRE_EQUAL(t11.size() , 1ul); + BOOST_REQUIRE_EQUAL(t12.size() , 2ul); + BOOST_REQUIRE_EQUAL(t21.size() , 2ul); + BOOST_REQUIRE_EQUAL(t22.size() , 4ul); + BOOST_REQUIRE_EQUAL(t32.size() , 6ul); + } + + BOOST_TEST_CONTEXT("[Size Method] rank(3) static_rank tensor"){ + BOOST_REQUIRE_EQUAL(t111.size() , 1ul); + BOOST_REQUIRE_EQUAL(t112.size() , 2ul); + BOOST_REQUIRE_EQUAL(t121.size() , 2ul); + BOOST_REQUIRE_EQUAL(t123.size() , 6ul); + BOOST_REQUIRE_EQUAL(t211.size() , 2ul); + BOOST_REQUIRE_EQUAL(t213.size() , 6ul); + BOOST_REQUIRE_EQUAL(t321.size() , 6ul); + BOOST_REQUIRE_EQUAL(t432.size() , 24ul); + } + + BOOST_TEST_CONTEXT("[Size Method] rank(4) static_rank tensor"){ + BOOST_REQUIRE_EQUAL(t1111.size(), 1ul); + BOOST_REQUIRE_EQUAL(t4231.size(), 24ul); + } + +} + +BOOST_FIXTURE_TEST_CASE(test_tensor_static, + boost::numeric::ublas::fixture_tensor_static, + *boost::unit_test::label("boost::numeric::ublas::tensor_static::size") + *boost::unit_test::description("Testing the static tensor's [size] method")) +{ + namespace ublas = boost::numeric::ublas; + + // BOOST_TEST_CONTEXT("[Size Method] rank(1) static tensor"){ + // BOOST_REQUIRE_EQUAL(t2.size() , 2ul); + // } + + BOOST_TEST_CONTEXT("[Size Method] rank(2) static tensor"){ + BOOST_REQUIRE_EQUAL(t11.size() , 1ul); + BOOST_REQUIRE_EQUAL(t12.size() , 2ul); + BOOST_REQUIRE_EQUAL(t21.size() , 2ul); + BOOST_REQUIRE_EQUAL(t22.size() , 4ul); + BOOST_REQUIRE_EQUAL(t32.size() , 6ul); + } + + BOOST_TEST_CONTEXT("[Size Method] rank(3) static tensor"){ + BOOST_REQUIRE_EQUAL(t111.size() , 1ul); + BOOST_REQUIRE_EQUAL(t112.size() , 2ul); + BOOST_REQUIRE_EQUAL(t121.size() , 2ul); + BOOST_REQUIRE_EQUAL(t123.size() , 6ul); + BOOST_REQUIRE_EQUAL(t211.size() , 2ul); + BOOST_REQUIRE_EQUAL(t213.size() , 6ul); + BOOST_REQUIRE_EQUAL(t321.size() , 6ul); + BOOST_REQUIRE_EQUAL(t432.size() , 24ul); + } + + BOOST_TEST_CONTEXT("[Size Method] rank(4) static tensor"){ + BOOST_REQUIRE_EQUAL(t1111.size(), 1ul); + BOOST_REQUIRE_EQUAL(t4231.size(), 24ul); + } + +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/tensor/test_tensor_unary_expression.cpp b/test/tensor/tensor/test_tensor_unary_expression.cpp new file mode 100644 index 000000000..789f8de7d --- /dev/null +++ b/test/tensor/tensor/test_tensor_unary_expression.cpp @@ -0,0 +1,168 @@ +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + +#include +#include "../fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_tensor_unary_expression, + * boost::unit_test::description("Validate Unary Expression") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("unary_expr") + *boost::unit_test::description("Testing the unary expr for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; + + constexpr auto uplus1 = [](auto const& a){ return a + value_type{1}; }; + + constexpr auto check = [uplus1](auto /*id*/, tensor_t t){ + auto v = value_type{}; + + BOOST_TEST_CONTEXT("[Dynamic Tensor Unary Expr] rank("<< t.rank() <<") dynamic tensor"){ + + ublas::iota(t,v); + + const auto uexpr = ublas::detail::make_unary_tensor_expression( 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( 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_t > ) ); + + 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_t > ) ); + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("unary_expr") + *boost::unit_test::description("Testing the unary expr for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; + + constexpr auto uplus1 = [](auto const& a){ return a + value_type{1}; }; + + constexpr auto check = [uplus1](auto /*id*/, tensor_t t){ + auto v = value_type{}; + + BOOST_TEST_CONTEXT("[Static Rank Tensor Unary Expr] static rank("<< t.rank() <<") tensor"){ + + ublas::iota(t,v); + + const auto uexpr = ublas::detail::make_unary_tensor_expression( 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( 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_t > ) ); + + 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_t > ) ); + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("unary_expr") + *boost::unit_test::description("Testing the unary expr for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +) +{ + namespace ublas = boost::numeric::ublas; + using value_type = typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static; + + constexpr auto uplus1 = [](auto const& a){ return a + value_type{1}; }; + + constexpr auto check = [uplus1](auto /*id*/, tensor_t t){ + auto v = value_type{}; + + BOOST_TEST_CONTEXT("[Static Tensor Unary Expr] rank("<< t.rank() <<") static tensor"){ + + ublas::iota(t,v); + + const auto uexpr = ublas::detail::make_unary_tensor_expression( 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( 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_t > ) ); + + 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_t > ) ); + } + }; + + auto const& self = static_cast(*this); + ublas::for_each_fixture(self, check); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_algorithms.cpp b/test/tensor/test_algorithms.cpp deleted file mode 100644 index 477ee1e0c..000000000 --- a/test/tensor/test_algorithms.cpp +++ /dev/null @@ -1,565 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#include -#include -#include -#include -#include -#include "utility.hpp" - -#include - - -BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms/*, - * boost::unit_test::depends_on("test_shape_dynamic") * boost::unit_test::depends_on("test_strides")*/ - ) - -// BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms) - - -using test_types = zip>::with_t; -using test_types2 = std::tuple>; - -struct fixture -{ - using extents_t = boost::numeric::ublas::extents<>; - const std::vector extents = - { - extents_t{1,1}, // 1 - extents_t{1,2}, // 2 - extents_t{2,1}, // 3 - extents_t{2,3}, // 4 - extents_t{2,3,1}, // 5 - extents_t{4,1,3}, // 6 - extents_t{1,2,3}, // 7 - extents_t{4,2,3}, // 8 - extents_t{4,2,3,5} - }; -}; - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_types2, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = value; - using vector_t = std::vector; - - - constexpr auto first_order = ublas::layout::first_order{}; - constexpr auto last_order = ublas::layout::last_order {}; - - - for(auto const& n : extents) { - - auto a = vector_t(product(n)); - auto b = vector_t(product(n)); - auto c = vector_t(product(n)); - - auto wa = ublas::to_strides(n,first_order); - auto wb = ublas::to_strides(n,last_order ); - auto wc = ublas::to_strides(n,first_order); - - auto v = value_type{}; - for(auto i = 0ul; i < a.size(); ++i, v+=1){ - a[i]=v; - } - - ublas::copy( ublas::size(n), n.data(), b.data(), wb.data(), a.data(), wa.data() ); - ublas::copy( ublas::size(n), 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] ); - - std::size_t const*const p0 = nullptr; - value_type* c0 = nullptr; - - BOOST_CHECK_THROW( ublas::copy( ublas::size(n), p0, c.data(), wc.data(), b.data(), wb.data() ), std::runtime_error ); - BOOST_CHECK_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), p0, b.data(), wb.data() ), std::runtime_error ); - BOOST_CHECK_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc.data(), b.data(), p0 ), std::runtime_error ); - BOOST_CHECK_THROW( ublas::copy( ublas::size(n), n.data(), c0, wc.data(), b.data(), wb.data() ), std::runtime_error ); - } -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy_exceptions, value, test_types2, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = value; - using vector_t = std::vector; - constexpr auto first_order = ublas::layout::first_order{}; - - - for(auto const& n : extents) { - - value_type* a = nullptr; - auto c = vector_t(ublas::product(n)); - - auto wa = ublas::to_strides(n,first_order); - auto wc = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc.data(), a, wa.data() ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - value_type* a = nullptr; - value_type* c = nullptr; - - auto wa = ublas::to_strides(n,first_order); - auto wc = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c, wc.data(), a, wa.data() ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto a = vector_t(product(n)); - value_type* c = nullptr; - - auto wa = ublas::to_strides(n,first_order); - auto wc = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c, wc.data(), a.data(), wa.data() ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto a = vector_t(product(n)); - auto c = vector_t(product(n)); - - - size_t* wa = nullptr; - auto wc = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc.data(), a.data(), wa ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto a = vector_t(product(n)); - auto c = vector_t(product(n)); - - - - size_t* wc = nullptr; - auto wa = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), n.data(), c.data(), wc, a.data(), wa.data() ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto a = vector_t(product(n)); - auto c = vector_t(product(n)); - - size_t* m = nullptr; - auto wa = ublas::to_strides(n,first_order); - auto wc = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::copy( ublas::size(n), m, c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); - - } -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform, value, test_types2, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = value; - using vector_t = std::vector; - - constexpr auto first_order = ublas::layout::first_order{}; - constexpr auto last_order = ublas::layout::last_order {}; - - - for(auto const& n : extents) { - - auto a = vector_t(ublas::product(n)); - auto b = vector_t(ublas::product(n)); - auto c = vector_t(ublas::product(n)); - - auto wa = ublas::to_strides(n,first_order); - auto wb = ublas::to_strides(n,last_order ); - auto wc = ublas::to_strides(n,first_order); - - auto v = value_type{}; - for(auto i = 0ul; i < a.size(); ++i, v+=1){ - a[i]=v; - } - - ublas::transform( ublas::size(n), n.data(), b.data(), wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ); - ublas::transform( ublas::size(n), n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a - value_type(1);} ); - - auto zero = std::size_t{0}; - ublas::transform(zero, n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a + value_type(1);} ); - - value_type* c0 = nullptr; - const std::size_t* s0 = nullptr; - std::size_t const*const p0 = nullptr; - - BOOST_CHECK_THROW(ublas::transform( ublas::size(n), n.data(), c0, wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); - BOOST_CHECK_THROW(ublas::transform( ublas::size(n), n.data(), b.data(), s0, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); - BOOST_CHECK_THROW(ublas::transform( ublas::size(n), p0, b.data(), wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error); - - - for(auto i = 1ul; i < c.size(); ++i) - BOOST_CHECK_EQUAL( c[i], a[i] ); - - } -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform_exceptions, value, test_types2, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = value; - using vector_t = std::vector; - - constexpr auto first_order = ublas::layout::first_order{}; - - for(auto const& n : extents) { - - value_type* a = nullptr; - auto c = vector_t(ublas::product(n)); - - auto wa = ublas::to_strides(n,first_order); - auto wc = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), n.data(), c.data(), wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - value_type* a = nullptr; - value_type* c = nullptr; - - auto wa = ublas::to_strides(n,first_order); - auto wc = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), n.data(), c, wc.data(), a, wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto a = vector_t(ublas::product(n)); - value_type* c = nullptr; - - auto wa = ublas::to_strides(n,first_order); - auto wc = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), n.data(), c, wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto a = vector_t(product(n)); - auto c = vector_t(product(n)); - - size_t* wa = nullptr; - auto wc = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), n.data(), c.data(), wc.data(), a.data(), wa, [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto a = vector_t(ublas::product(n)); - auto c = vector_t(ublas::product(n)); - - size_t* wc = nullptr; - auto wa = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), n.data(), c.data(), wc, a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } - - for(auto const& n : extents) { - - auto a = vector_t(product(n)); - auto c = vector_t(product(n)); - - size_t* m = nullptr; - auto wa = ublas::to_strides(n,first_order); - auto wc = ublas::to_strides(n,first_order); - - BOOST_REQUIRE_THROW( ublas::transform( ublas::size(n), m, c.data(), wc.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ), std::runtime_error ); - - } -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, test_types2, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = value; - using vector_t = std::vector; - - constexpr auto first_order = ublas::layout::first_order{}; - - - for(auto const& n : extents) { - - auto const s = ublas::product(n); - - auto a = vector_t(ublas::product(n)); - auto wa = ublas::to_strides(n,first_order); - - - auto v = value_type{}; - for(auto i = 0ul; i < a.size(); ++i, v+=value_type(1)){ - a[i]=v; - } - - auto acc = ublas::accumulate( ublas::size(n), n.data(), a.data(), wa.data(), v); - - auto sum = std::div(s*(s+1),2).quot; - - BOOST_CHECK_EQUAL( acc, value_type( static_cast< inner_type_t >( sum ) ) ); - - auto zero = std::size_t{0}; - (void)ublas::accumulate(zero, n.data(), a.data(), wa.data(),v); - - value_type* c0 = nullptr; - std::size_t const*const p0 = nullptr; - - BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), n.data(), c0, wa.data(), v), std::runtime_error); - BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), n.data(), a.data(), p0, v), std::runtime_error); - BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), p0, a.data(), wa.data(), v), std::runtime_error); - - - auto acc2 = ublas::accumulate( ublas::size(n), n.data(), a.data(), wa.data(), v, - [](auto const& l, auto const& r){return l + r; }); - - BOOST_CHECK_EQUAL( acc2, value_type( static_cast< inner_type_t >( sum ) ) ); - - (void)ublas::accumulate(zero, n.data(), a.data(), wa.data(), v, [](auto const& l, auto const& r){return l + r; }); - - BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), n.data(), c0, wa.data(), v,[](auto const& l, auto const& r){return l + r; }), std::runtime_error); - BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), n.data(), a.data(), p0, v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); - BOOST_CHECK_THROW((void)ublas::accumulate( ublas::size(n), p0, a.data(), wa.data(),v, [](auto const& l, auto const& r){return l + r; }), std::runtime_error); - - } -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate_exceptions, value, test_types2, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = value; - using vector_t = std::vector; - constexpr auto first_order = ublas::layout::first_order{}; - - - for(auto const& n : extents) { - value_type* a = nullptr; - auto wa = ublas::to_strides(n,first_order); - BOOST_REQUIRE_THROW( (void)ublas::accumulate( ublas::size(n), n.data(), a, wa.data(), value_type{0} ), std::runtime_error ); - - } - - for(auto const& n : extents) { - value_type* a = nullptr; - auto wa = ublas::to_strides(n,first_order); - BOOST_REQUIRE_THROW( (void)ublas::accumulate( ublas::size(n), n.data(), a, wa.data(), value_type{0},[](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); - } - - for(auto const& n : extents) { - auto a = vector_t(product(n)); - auto wa = ublas::to_strides(n,first_order); - size_t p = 0u; - BOOST_CHECK_EQUAL ( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0} ), value_type{0} ); - } - - for(auto const& n : extents) { - auto a = vector_t(product(n)); - auto wa = ublas::to_strides(n,first_order); - size_t p = 0u; - BOOST_CHECK_EQUAL( ublas::accumulate( p, n.data(), a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), value_type{0} ); - } - - for(auto const& n : extents) { - auto a = vector_t(product(n)); - size_t* wa = nullptr; - BOOST_REQUIRE_THROW( (void)ublas::accumulate( ublas::size(n), n.data(), a.data(), wa, value_type{0} ), std::runtime_error ); - } - - for(auto const& n : extents) { - auto a = vector_t(product(n)); - auto wa = ublas::to_strides(n,first_order); - size_t* m = nullptr; - BOOST_REQUIRE_THROW( (void)ublas::accumulate( ublas::size(n), m, a.data(), wa.data(), value_type{0}, [](value_type const& a,value_type const& b){ return a + b;} ), std::runtime_error ); - } - -} - - -template -void init(std::vector& a) -{ - auto v = V(1); - for(auto i = 0u; i < a.size(); ++i, ++v){ - a[i] = v; - } -} - -template -void init(std::vector>& a) -{ - auto v = std::complex(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 ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; -// using layout_t = typename value::second_type; - using vector_t = std::vector; - using base_t = typename extents_t::base_type; - using permutation_type = std::vector; - - constexpr auto first_order = ublas::layout::first_order{}; - - - for(auto const& n : extents) { - - auto p = ublas::size(n); - auto s = ublas::product(n); - - auto pi = permutation_type(p); - auto a = vector_t(s); - auto b1 = vector_t(s); - auto b2 = vector_t(s); - auto c1 = vector_t(s); - auto c2 = vector_t(s); - - auto wa = ublas::to_strides(n,first_order); - - init(a); - - // so wie last-order. - for(auto i = std::size_t{0}, j = p; i < ublas::size(n); ++i, --j) - pi[i] = j; - - auto nc_base = base_t(p); - for(auto i = 0u; i < p; ++i) - nc_base[pi[i]-1] = n[i]; - - auto nc = extents_t(std::move(nc_base)); - - auto wc = ublas::to_strides(nc,first_order); - auto wc_pi = base_t(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) - for(auto i = 0ul; i < s; ++i) - BOOST_CHECK_EQUAL( c1[i], c2[i] ); - - - auto nb_base = base_t(p); - for(auto i = 0u; i < p; ++i) - nb_base[pi[i]-1] = nc[i]; - - auto nb = extents_t(std::move(nb_base)); - - auto wb = ublas::to_strides(nb,first_order); - auto wb_pi = base_t(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) - 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] ); - - auto zero = std::size_t{0}; - ublas::trans( zero, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() ); - ublas::trans( zero, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() ); - - value_type *c0 = nullptr; - std::size_t const*const s0 = nullptr; - - BOOST_CHECK_THROW(ublas::trans( p, n.data(), pi.data(), c0, wc.data(), a.data(), wa.data()), std::runtime_error); - BOOST_CHECK_THROW(ublas::trans( p, s0, pi.data(), c2.data(),wc.data(), a.data(), wa.data()), std::runtime_error); - BOOST_CHECK_THROW(ublas::trans( p, n.data(), pi.data(), c2.data(), s0, a.data(), wa.data()), std::runtime_error); - BOOST_CHECK_THROW(ublas::trans( p, n.data(), s0, c2.data(), wc.data(), a.data(), wa.data()), std::runtime_error); - - } -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans_exceptions, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_t = typename value::second_type; - using vector_t = std::vector; - using permutation_type = std::vector; - - constexpr auto layout = layout_t{}; - - std::size_t* nnullptr = nullptr; - value_type * anullptr = nullptr; - - for(auto const& n : extents) { - auto p = ublas::size(n); - auto s = ublas::product(n); - auto pi = permutation_type(p); - auto a = vector_t(s); - auto c = vector_t(s); - auto wa = ublas::to_strides(n,layout); - auto wc = ublas::to_strides(n,layout); - if(p>1){ - BOOST_REQUIRE_THROW( ublas::trans( p, nnullptr, pi.data(), c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); - BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , nnullptr , c.data(), wc.data(), a.data(), wa.data() ), std::runtime_error ); - BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), c.data(), nnullptr , a.data(), nnullptr ), std::runtime_error ); - BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), c.data(), wc.data(), a.data(), nnullptr ), std::runtime_error ); - BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), c.data(), nnullptr , a.data(), wa.data() ), std::runtime_error ); - BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), anullptr, wc.data(), anullptr, wa.data() ), std::runtime_error ); - BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), c.data(), wc.data(), anullptr, wa.data() ), std::runtime_error ); - BOOST_REQUIRE_THROW( ublas::trans( p, n.data() , pi.data(), anullptr, wc.data(), a.data(), wa.data() ), std::runtime_error ); - } - - // ublas::trans( p, n.data(), pi.data(), c.data(), wc.data(), a.data(), wa.data() ); - } - -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_einstein_notation.cpp b/test/tensor/test_einstein_notation.cpp index 400011a7c..5953c83c7 100644 --- a/test/tensor/test_einstein_notation.cpp +++ b/test/tensor/test_einstein_notation.cpp @@ -1,6 +1,6 @@ // -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -9,138 +9,360 @@ // The authors gratefully acknowledge the support of // Google and Fraunhofer IOSB, Ettlingen, Germany // -// And we acknowledge the support from all contributors. - -#include #include +#include "fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_einstein_notation, + * boost::unit_test::description("Validate Einstien Notation") +) + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("einstien_notation") + *boost::unit_test::description("Testing the einstien notation for dynamic tensor") +) +BOOST_AUTO_TEST_CASE_TEMPLATE(test_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types +) +{ + namespace ublas = boost::numeric::ublas; + namespace index = ublas::index; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using inner_t = inner_type_t; + using tensor_t = ublas::tensor_dynamic; + + BOOST_TEST_CONTEXT("[Dynamic Tensor Einstien Notation] tensor with LHS[5, 3] : RHS[3, 4]"){ + + auto A = tensor_t(5,3); + auto B = tensor_t{3,4}; + + for(auto j = 0u; j < A.size(1); ++j){ + for(auto i = 0u; i < A.size(0); ++i){ + A.at( i,j ) = value_type{ static_cast< inner_t >(i+1) }; + } + } + for(auto j = 0u; j < B.size(1); ++j){ + for(auto i = 0u; i < B.size(0); ++i){ + B.at( i,j ) = value_type{ static_cast< inner_t >(i+1) }; + } + } -#include -#include + auto AB = A(index::_,index::_e) * B(index::_e,index::_); + for(auto j = 0u; j < AB.size(1); ++j){ + for(auto i = 0u; i < AB.size(0); ++i){ + auto e0 = B.size(0); + auto sum = std::div(e0 * ( e0 + 1 ), 2); + auto quot = value_type{ static_cast(sum.quot) }; + BOOST_CHECK_EQUAL( AB.at(i,j) , A.at(i,0)*quot ); + } + } -#include "utility.hpp" + } -BOOST_AUTO_TEST_SUITE ( test_einstein_notation/*, - *boost::unit_test::depends_on("test_multi_index") */) + BOOST_TEST_CONTEXT("[Dynamic Tensor Einstien Notation] tensor with LHS[4, 5, 3] : RHS[3, 4, 2]"){ + + auto A = tensor_t{4,5,3}; + auto B = tensor_t{3,4,2}; + + for(auto k = 0u; k < A.size(2); ++k){ + for(auto j = 0u; j < A.size(1); ++j){ + for(auto i = 0u; i < A.size(0); ++i){ + A.at( i,j,k ) = value_type{ static_cast< inner_t >(i+1) }; + } + } + } + for(auto k = 0u; k < B.size(2); ++k){ + for(auto j = 0u; j < B.size(1); ++j){ + for(auto i = 0u; i < B.size(0); ++i){ + B.at( i,j,k ) = value_type{ static_cast< inner_t >(i+1) }; + } + } + } -using test_types = zip>::with_t; + auto AB = A(index::_d,index::_,index::_f) * B(index::_f,index::_d,index::_); -//using test_types = zip::with_t; + auto const nf = ( B.size(0) * (B.size(0)+1) / 2 ); + auto const nd = ( A.size(0) * (A.size(0)+1) / 2 ); -BOOST_AUTO_TEST_CASE_TEMPLATE( test_einstein_multiplication, value, test_types ) -{ - namespace ublas = boost::numeric::ublas; - - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using tensor_t = ublas::tensor_dynamic; - // NOLINTNEXTLINE(google-build-using-namespace) - using namespace boost::numeric::ublas::index; - - { - auto A = tensor_t(5,3); - auto B = tensor_t{3,4}; - // auto C = tensor_t{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_t( static_cast< inner_type_t >(i+1) ); - } - } + for(auto j = 0u; j < AB.size(1); ++j){ + for(auto i = 0u; i < AB.size(0); ++i){ + auto const rhs = value_type{ static_cast< inner_t >(nf * nd) }; + BOOST_CHECK_EQUAL( AB.at( i,j ) , rhs ); + } + } - 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_t( static_cast< inner_type_t >(i+1) ); - } } - auto AB = A(_,_e) * B(_e,_); + BOOST_TEST_CONTEXT("[Dynamic Tensor Einstien Notation] tensor with LHS[4, 3] : RHS[3, 4, 2]"){ + + auto A = tensor_t{4,3}; + auto B = tensor_t{3,4,2}; - // std::cout << "A = " << A << std::endl; - // std::cout << "B = " << B << std::endl; - // std::cout << "AB = " << AB << std::endl; + for(auto j = 0u; j < A.size(1); ++j){ + for(auto i = 0u; i < A.size(0); ++i){ + A.at( i,j ) = value_type{ static_cast< inner_t >(i+1) }; + } + } - for(auto j = 0u; j < AB.extents().at(1); ++j){ - for(auto i = 0u; i < AB.extents().at(0); ++i){ - auto e0 = B.extents().at(0); - auto sum = std::div(e0*(e0+1),2); - auto quot = value_t(sum.quot); - BOOST_CHECK_EQUAL( AB.at(i,j) , A.at(i,0)*quot ); - } - } - } + for(auto k = 0u; k < B.size(2); ++k){ + for(auto j = 0u; j < B.size(1); ++j){ + for(auto i = 0u; i < B.size(0); ++i){ + B.at( i,j,k ) = value_type{ static_cast< inner_t >(i+1) }; + } + } + } + + auto AB = A(index::_d,index::_f) * B(index::_f,index::_d,index::_); - { - auto A = tensor_t{4,5,3}; - auto B = tensor_t{3,4,2}; + // n*(n+1)/2; + auto const nf = ( B.size(0) * (B.size(0)+1) / 2 ); + auto const nd = ( A.size(0) * (A.size(0)+1) / 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_t( static_cast< inner_type_t >(i+1) ); + for(auto i = 0u; i < AB.size(0); ++i){ + auto const rhs = value_type{ static_cast< inner_t >(nf * nd) }; + BOOST_CHECK_EQUAL ( AB.at( i ) , rhs ); } - } + } +} - 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_t( static_cast< inner_type_t >(i+1) ); +BOOST_TEST_DECORATOR( + *boost::unit_test::label("einstien_notation") + *boost::unit_test::description("Testing the einstien notation for static rank tensor") +) +BOOST_AUTO_TEST_CASE_TEMPLATE(test_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types +) +{ + namespace ublas = boost::numeric::ublas; + namespace index = ublas::index; + using value_type = typename TestTupleType::first_type; + using layout_type = typename TestTupleType::second_type; + using inner_t = inner_type_t; + using tensor2_t = ublas::tensor_static_rank; + using tensor3_t = ublas::tensor_static_rank; + + BOOST_TEST_CONTEXT("[Static Rank Tensor Einstien Notation] tensor with LHS[5, 3] : RHS[3, 4]"){ + + auto A = tensor2_t(5,3); + auto B = tensor2_t(3,4); + + for(auto j = 0u; j < A.size(1); ++j){ + for(auto i = 0u; i < A.size(0); ++i){ + A.at( i,j ) = value_type{ static_cast< inner_t >(i+1) }; + } + } + + for(auto j = 0u; j < B.size(1); ++j){ + for(auto i = 0u; i < B.size(0); ++i){ + B.at( i,j ) = value_type{ static_cast< inner_t >(i+1) }; + } } - } - } - auto AB = A(_d,_,_f) * B(_f,_d,_); + auto AB = A(index::_,index::_e) * B(index::_e,index::_); - // 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.size(1); ++j){ + for(auto i = 0u; i < AB.size(0); ++i){ + auto e0 = B.size(0); + auto sum = std::div(e0 * ( e0 + 1 ), 2); + auto quot = value_type{ static_cast(sum.quot) }; + BOOST_CHECK_EQUAL( AB.at(i,j) , A.at(i,0)*quot ); + } + } - 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_t( static_cast< inner_type_t >(nf * nd) ) ); - } } - } + BOOST_TEST_CONTEXT("[Static Rank Tensor Einstien Notation] tensor with LHS[4, 5, 3] : RHS[3, 4, 2]"){ + + auto A = tensor3_t(4,5,3); + auto B = tensor3_t(3,4,2); + + for(auto k = 0u; k < A.size(2); ++k){ + for(auto j = 0u; j < A.size(1); ++j){ + for(auto i = 0u; i < A.size(0); ++i){ + A.at( i,j,k ) = value_type{ static_cast< inner_t >(i+1) }; + } + } + } - { - auto A = tensor_t{{4,3}}; - auto B = tensor_t{3,4,2}; + for(auto k = 0u; k < B.size(2); ++k){ + for(auto j = 0u; j < B.size(1); ++j){ + for(auto i = 0u; i < B.size(0); ++i){ + B.at( i,j,k ) = value_type{ static_cast< inner_t >(i+1) }; + } + } + } - 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_t( static_cast< inner_type_t >(i+1) ); - } - } + auto AB = A(index::_d,index::_,index::_f) * B(index::_f,index::_d,index::_); + auto const nf = ( B.size(0) * (B.size(0)+1) / 2 ); + auto const nd = ( A.size(0) * (A.size(0)+1) / 2 ); - 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_t( static_cast< inner_type_t >(i+1) ); + for(auto j = 0u; j < AB.size(1); ++j){ + for(auto i = 0u; i < AB.size(0); ++i){ + auto const rhs = value_type{ static_cast< inner_t >(nf * nd) }; + BOOST_CHECK_EQUAL( AB.at( i,j ) , rhs ); + } } - } + } - auto AB = A(_d,_f) * B(_f,_d,_); + // FIXME: Enable this test after the issue #121 has been fixed. + // BOOST_TEST_CONTEXT("[Static Rank Tensor Einstien Notation] tensor with LHS[4, 3] : RHS[3, 4, 2]"){ + + // auto A = tensor2_t(4,3); + // auto B = tensor3_t(3,4,2); - // 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 < A.size(1); ++j){ + // for(auto i = 0u; i < A.size(0); ++i){ + // A.at( i,j ) = value_type{ static_cast< inner_t >(i+1) }; + // } + // } - for(auto i = 0u; i < AB.extents().at(0); ++i){ - BOOST_CHECK_EQUAL ( AB.at( i ) , value_t( static_cast< inner_type_t >(nf * nd) ) ); - } - } + // for(auto k = 0u; k < B.size(2); ++k){ + // for(auto j = 0u; j < B.size(1); ++j){ + // for(auto i = 0u; i < B.size(0); ++i){ + // B.at( i,j,k ) = value_type{ static_cast< inner_t >(i+1) }; + // } + // } + // } + + // auto AB = A(index::_d,index::_f) * B(index::_f,index::_d,index::_); + + // // n*(n+1)/2; + // auto const nf = ( B.size(0) * (B.size(0)+1) / 2 ); + // auto const nd = ( A.size(0) * (A.size(0)+1) / 2 ); + + // for(auto i = 0u; i < AB.size(0); ++i){ + // auto const rhs = value_type{ static_cast< inner_t >(nf * nd) }; + // BOOST_CHECK_EQUAL ( AB.at( i ) , rhs ); + // } + + // } } +// TODO: Add support of static tensor product then enable it. +// BOOST_TEST_DECORATOR( +// *boost::unit_test::label("einstien_notation") +// *boost::unit_test::description("Testing the einstien notation for static tensor") +// ) +// BOOST_AUTO_TEST_CASE_TEMPLATE(test_tensor_static, +// TestTupleType, +// boost::numeric::ublas::test_types +// ) +// { +// namespace ublas = boost::numeric::ublas; +// namespace index = ublas::index; +// using value_type = typename TestTupleType::first_type; +// using layout_type = typename TestTupleType::second_type; +// using inner_t = inner_type_t; + +// BOOST_TEST_CONTEXT("[Static Tensor Einstien Notation] tensor with LHS[5, 3] : RHS[3, 4]"){ + +// auto A = ublas::tensor_static, layout_type>(); +// auto B = ublas::tensor_static, layout_type>(); + +// for(auto j = 0u; j < A.size(1); ++j){ +// for(auto i = 0u; i < A.size(0); ++i){ +// A.at( i,j ) = value_type{ static_cast< inner_t >(i+1) }; +// } +// } + +// for(auto j = 0u; j < B.size(1); ++j){ +// for(auto i = 0u; i < B.size(0); ++i){ +// B.at( i,j ) = value_type{ static_cast< inner_t >(i+1) }; +// } +// } + +// auto AB = A(index::_,index::_e) * B(index::_e,index::_); + +// for(auto j = 0u; j < AB.size(1); ++j){ +// for(auto i = 0u; i < AB.size(0); ++i){ +// auto e0 = B.size(0); +// auto sum = std::div(e0 * ( e0 + 1 ), 2); +// auto quot = value_type{ static_cast(sum.quot) }; +// BOOST_CHECK_EQUAL( AB.at(i,j) , A.at(i,0)*quot ); +// } +// } + +// } + +// BOOST_TEST_CONTEXT("[Static Einstien Notation] tensor with LHS[4, 5, 3] : RHS[3, 4, 2]"){ + +// auto A = ublas::tensor_static, layout_type>(); +// auto B = ublas::tensor_static, layout_type>(); + +// for(auto k = 0u; k < A.size(2); ++k){ +// for(auto j = 0u; j < A.size(1); ++j){ +// for(auto i = 0u; i < A.size(0); ++i){ +// A.at( i,j,k ) = value_type{ static_cast< inner_t >(i+1) }; +// } +// } +// } + +// for(auto k = 0u; k < B.size(2); ++k){ +// for(auto j = 0u; j < B.size(1); ++j){ +// for(auto i = 0u; i < B.size(0); ++i){ +// B.at( i,j,k ) = value_type{ static_cast< inner_t >(i+1) }; +// } +// } +// } + +// auto AB = A(index::_d,index::_,index::_f) * B(index::_f,index::_d,index::_); + +// auto const nf = ( B.size(0) * (B.size(0)+1) / 2 ); +// auto const nd = ( A.size(0) * (A.size(0)+1) / 2 ); + +// for(auto j = 0u; j < AB.size(1); ++j){ +// for(auto i = 0u; i < AB.size(0); ++i){ +// auto const rhs = value_type{ static_cast< inner_t >(nf * nd) }; +// BOOST_CHECK_EQUAL( AB.at( i,j ) , rhs ); +// } +// } + +// } + +// // BOOST_TEST_CONTEXT("[Static Einstien Notation] tensor with LHS[4, 3] : RHS[3, 4, 2]"){ + +// // auto A = ublas::tensor_static, layout_type>(); +// // auto B = ublas::tensor_static, layout_type>(); + +// // for(auto j = 0u; j < A.size(1); ++j){ +// // for(auto i = 0u; i < A.size(0); ++i){ +// // A.at( i,j ) = value_type{ static_cast< inner_t >(i+1) }; +// // } +// // } + + +// // for(auto k = 0u; k < B.size(2); ++k){ +// // for(auto j = 0u; j < B.size(1); ++j){ +// // for(auto i = 0u; i < B.size(0); ++i){ +// // B.at( i,j,k ) = value_type{ static_cast< inner_t >(i+1) }; +// // } +// // } +// // } + +// // auto AB = A(index::_d,index::_f) * B(index::_f,index::_d,index::_); + +// // // n*(n+1)/2; +// // auto const nf = ( B.size(0) * (B.size(0)+1) / 2 ); +// // auto const nd = ( A.size(0) * (A.size(0)+1) / 2 ); + +// // for(auto i = 0u; i < AB.size(0); ++i){ +// // auto const rhs = value_type{ static_cast< inner_t >(nf * nd) }; +// // BOOST_CHECK_EQUAL ( AB.at( i ) , rhs ); +// // } + +// // } +// } + + BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_expression.cpp b/test/tensor/test_expression.cpp deleted file mode 100644 index 3d884e72c..000000000 --- a/test/tensor/test_expression.cpp +++ /dev/null @@ -1,183 +0,0 @@ -// 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 -#include -#include -#include -#include "utility.hpp" - -#include -#include - - - -using test_types = zip>::with_t; - - -struct fixture -{ - using extents_type = boost::numeric::ublas::extents<>; - - const std::vector 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 - }; -}; - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_access, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using tensor_t = ublas::tensor_dynamic; - using expression_t = typename tensor_t::super_type; - - - for(auto const& e : extents) { - - if(!ublas::is_valid(e)){ - continue; - } - - auto v = value_t{}; - auto t = tensor_t(e); - - for(auto& tt: t){ tt = v; v+=value_t{1}; } - const auto& tensor_expression_const = static_cast( 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) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using tensor_t = ublas::tensor_dynamic; - - auto uplus1 = [](auto const& a){ return a+value_t{1}; }; - //auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_t(1) ); - - for(auto const& e : extents) { - - auto t = tensor_t(e); - auto v = value_t{}; - for(auto& tt: t) { tt = v; v+=value_t{1}; } - - const auto uexpr = ublas::detail::make_unary_tensor_expression( 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( 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_t > ) ); - - 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_t > ) ); - - - } -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_expression, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using tensor_t = ublas::tensor_dynamic; - - auto uplus1 = [](auto const& a){ return a+value_t{1}; }; - auto uplus2 = [](auto const& a){ return a+value_t{2}; }; - //auto uplus1 = std::bind( std::plus{}, std::placeholders::_1, value_t(1) ); - //auto uplus2 = std::bind( std::plus{}, std::placeholders::_1, value_t(2) ); - auto bplus = std::plus {}; - auto bminus = std::minus{}; - - for(auto const& e : extents) { - - auto t = tensor_t(e); - auto v = value_t{}; - for(auto& tt: t){ tt = v; v+=value_t{1}; } - - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( t, uplus2 ); - - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, tensor_t > ) ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, tensor_t > ) ); - - 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( uexpr1, uexpr2, bplus ); - - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, tensor_t > ) ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, tensor_t > ) ); - - - 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( bexpr_uexpr, t, bminus ); - - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, tensor_t > ) ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, tensor_t > ) ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) ); - BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) ); - - for(auto i = 0ul; i < t.size(); ++i){ - BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) ); - } - - } - - -} diff --git a/test/tensor/test_expression_evaluation.cpp b/test/tensor/test_expression_evaluation.cpp deleted file mode 100644 index 5863aa963..000000000 --- a/test/tensor/test_expression_evaluation.cpp +++ /dev/null @@ -1,244 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - - - -#include -#include -#include -#include -#include "utility.hpp" -#include - -#include - -BOOST_AUTO_TEST_SUITE(test_tensor_expression) -using test_types = zip>::with_t; - -struct fixture -{ - using extents_t = boost::numeric::ublas::extents<>; - - const std::vector extents = - { -// extents_t{}, // 0 - - extents_t{1,1}, // 1 - extents_t{1,2}, // 2 - extents_t{2,1}, // 3 - - extents_t{2,3}, // 4 - extents_t{2,3,1}, // 5 - extents_t{1,2,3}, // 6 - extents_t{1,1,2,3}, // 7 - extents_t{1,2,3,1,1}, // 8 - - extents_t{4,2,3}, // 9 - extents_t{4,2,1,3}, // 10 - extents_t{4,2,1,3,1}, // 11 - extents_t{1,4,2,1,3,1} // 12 - }; -}; - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_retrieve_extents, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using tensor_t = ublas::tensor_dynamic; - - auto uplus1 = [](auto const& a){ return a + value_t(1); }; - auto uplus2 = [](auto const& a){ return value_t(2) + a; }; - auto bplus = std::plus {}; - auto bminus = std::minus{}; - - for(auto const& e : extents) { - - auto t = tensor_t(e); - auto v = value_t{}; - for(auto& tt: t){ tt = v; v+=value_t{1}; } - - - BOOST_CHECK( ublas::detail::retrieve_extents( t ) == e ); - - - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( 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_t{}; - - auto t1 = tensor_t(extents[i]); - for(auto& tt: t1){ tt = v; v+=value_t{1}; } - - auto t2 = tensor_t(extents[i+1]); - for(auto& tt: t2){ tt = v; v+=value_t{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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( 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( 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) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using tensor_t = ublas::tensor_dynamic; - - auto uplus1 = [](auto const& a){ return a + value_t(1); }; - auto uplus2 = [](auto const& a){ return value_t(2) + a; }; - auto bplus = std::plus {}; - auto bminus = std::minus{}; - - for(auto const& e : extents) { - - auto t = tensor_t(e); - auto v = value_t{}; - for(auto& tt: t){ tt = v; v+=value_t{1}; } - - - BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); - - - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( 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_t{}; - - auto t1 = tensor_t(extents[i]); - for(auto& tt: t1){ tt = v; v+=value_t{1}; } - - auto t2 = tensor_t(extents[i+1]); - for(auto& tt: t2){ tt = v; v+=value_t{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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( 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( 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( 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( 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( t1, bexpr_bexpr_uexpr3, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); - - } -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_extents_dynamic.cpp b/test/tensor/test_extents_dynamic.cpp deleted file mode 100644 index fe4761b88..000000000 --- a/test/tensor/test_extents_dynamic.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// -// Copyright (c) 2018 Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#include -#include - -BOOST_AUTO_TEST_SUITE ( test_extents_dynamic ) - - -struct fixture -{ - using extents = boost::numeric::ublas::extents<>; - -// static inline auto n = extents{}; - static inline auto n1 = extents{1}; - static inline auto n2 = extents{2}; - static inline auto n11 = extents{1,1}; - static inline auto n12 = extents{1,2}; - static inline auto n21 = extents{2,1}; - static inline auto n22 = extents{2,2}; - static inline auto n32 = extents{3,2}; - static inline auto n111 = extents{1,1,1}; - static inline auto n211 = extents{2,1,1}; - static inline auto n121 = extents{1,2,1}; - static inline auto n112 = extents{1,1,2}; - static inline auto n123 = extents{1,2,3}; - static inline auto n321 = extents{3,2,1}; - static inline auto n213 = extents{2,1,3}; - static inline auto n432 = extents{4,3,2}; -}; - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_empty, - fixture, - *boost::unit_test::label("dynamic_extents") *boost::unit_test::label("empty")) -{ - namespace ublas = boost::numeric::ublas; - -// BOOST_CHECK( ublas::empty(n )); - BOOST_CHECK(!ublas::empty(n1 )); - BOOST_CHECK(!ublas::empty(n2 )); - BOOST_CHECK(!ublas::empty(n11 )); - BOOST_CHECK(!ublas::empty(n12 )); - BOOST_CHECK(!ublas::empty(n21 )); - BOOST_CHECK(!ublas::empty(n22 )); - BOOST_CHECK(!ublas::empty(n32 )); - BOOST_CHECK(!ublas::empty(n111)); - BOOST_CHECK(!ublas::empty(n211)); - BOOST_CHECK(!ublas::empty(n121)); - BOOST_CHECK(!ublas::empty(n112)); - BOOST_CHECK(!ublas::empty(n123)); - BOOST_CHECK(!ublas::empty(n321)); - BOOST_CHECK(!ublas::empty(n213)); - BOOST_CHECK(!ublas::empty(n432)); - - BOOST_CHECK_THROW( extents({1,1,0}), std::invalid_argument); - BOOST_CHECK_THROW( extents({1,0}) , std::invalid_argument); - BOOST_CHECK_THROW( extents({0} ) , std::invalid_argument); - BOOST_CHECK_THROW( extents({0,1}) , std::invalid_argument); -} - - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_size, - fixture, - *boost::unit_test::label("dynamic_extents") *boost::unit_test::label("size")) -{ - namespace ublas = boost::numeric::ublas; - - -// BOOST_CHECK_EQUAL(ublas::size(n ),0); - BOOST_CHECK_EQUAL(ublas::size(n1 ),1); - BOOST_CHECK_EQUAL(ublas::size(n2 ),1); - BOOST_CHECK_EQUAL(ublas::size(n11 ),2); - BOOST_CHECK_EQUAL(ublas::size(n12 ),2); - BOOST_CHECK_EQUAL(ublas::size(n21 ),2); - BOOST_CHECK_EQUAL(ublas::size(n22 ),2); - BOOST_CHECK_EQUAL(ublas::size(n32 ),2); - BOOST_CHECK_EQUAL(ublas::size(n111),3); - BOOST_CHECK_EQUAL(ublas::size(n211),3); - BOOST_CHECK_EQUAL(ublas::size(n121),3); - BOOST_CHECK_EQUAL(ublas::size(n112),3); - BOOST_CHECK_EQUAL(ublas::size(n123),3); - BOOST_CHECK_EQUAL(ublas::size(n321),3); - BOOST_CHECK_EQUAL(ublas::size(n213),3); - BOOST_CHECK_EQUAL(ublas::size(n432),3); -} - - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_at_read, - fixture, - *boost::unit_test::label("dynamic_extents") *boost::unit_test::label("at_read")) -{ - BOOST_CHECK_EQUAL(n1 .at(0),1); - BOOST_CHECK_EQUAL(n2 .at(0),2); - - BOOST_CHECK_EQUAL(n11 .at(0),1); - BOOST_CHECK_EQUAL(n11 .at(1),1); - - BOOST_CHECK_EQUAL(n12 .at(0),1); - BOOST_CHECK_EQUAL(n12 .at(1),2); - - BOOST_CHECK_EQUAL(n21 .at(0),2); - BOOST_CHECK_EQUAL(n21 .at(1),1); - - BOOST_CHECK_EQUAL(n22 .at(0),2); - BOOST_CHECK_EQUAL(n22 .at(1),2); - - BOOST_CHECK_EQUAL(n32 .at(0),3); - BOOST_CHECK_EQUAL(n32 .at(1),2); - - BOOST_CHECK_EQUAL(n432.at(0),4); - BOOST_CHECK_EQUAL(n432.at(1),3); - BOOST_CHECK_EQUAL(n432.at(2),2); - - -// BOOST_CHECK_THROW( (void)n .at(0), std::out_of_range); - BOOST_CHECK_THROW( (void)n32.at(2), std::out_of_range); - BOOST_CHECK_THROW( (void)n32.at(5), std::out_of_range); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_at_write, - fixture, - *boost::unit_test::label("dynamic_extents") *boost::unit_test::label("at_write")) -{ - auto n3 = extents{1}; - n3 = extents{3}; - BOOST_CHECK_EQUAL(n3.at(0),3); - - auto n34 = extents{1,1}; - n34 = extents{3,4}; - BOOST_CHECK_EQUAL(n34.at(0),3); - BOOST_CHECK_EQUAL(n34.at(1),4); - - - auto n345 = extents{1,1,1}; - n345 = extents{3,4,5}; - BOOST_CHECK_EQUAL(n345.at(0),3); - BOOST_CHECK_EQUAL(n345.at(1),4); - BOOST_CHECK_EQUAL(n345.at(2),5); - - - auto n5432 = extents{1,1,1,1}; - n5432 = extents{5,4,3,2}; - BOOST_CHECK_EQUAL(n5432.at(0),5); - BOOST_CHECK_EQUAL(n5432.at(1),4); - BOOST_CHECK_EQUAL(n5432.at(2),3); - BOOST_CHECK_EQUAL(n5432.at(3),2); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_operator_access_read, - fixture, - *boost::unit_test::label("dynamic_extents") *boost::unit_test::label("operator_access_read")) -{ - BOOST_CHECK_EQUAL(n1 [0],1); - BOOST_CHECK_EQUAL(n2 [0],2); - - BOOST_CHECK_EQUAL(n11 [0],1); - BOOST_CHECK_EQUAL(n11 [1],1); - - BOOST_CHECK_EQUAL(n12 [0],1); - BOOST_CHECK_EQUAL(n12 [1],2); - - BOOST_CHECK_EQUAL(n21 [0],2); - BOOST_CHECK_EQUAL(n21 [1],1); - - BOOST_CHECK_EQUAL(n22 [0],2); - BOOST_CHECK_EQUAL(n22 [1],2); - - BOOST_CHECK_EQUAL(n32 [0],3); - BOOST_CHECK_EQUAL(n32 [1],2); - - BOOST_CHECK_EQUAL(n432[0],4); - BOOST_CHECK_EQUAL(n432[1],3); - BOOST_CHECK_EQUAL(n432[2],2); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_extents_dynamic_rank_static.cpp b/test/tensor/test_extents_dynamic_rank_static.cpp deleted file mode 100644 index c7d4a6a9d..000000000 --- a/test/tensor/test_extents_dynamic_rank_static.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// -// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com -// -// 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 -#include - -BOOST_AUTO_TEST_SUITE ( test_shape_dynamic_static_rank ) - - -struct fixture -{ - template - using shape_t = boost::numeric::ublas::extents; - -// static inline auto n = shape_t<0>{}; - static inline auto n1 = shape_t<1>{1}; - static inline auto n2 = shape_t<1>{2}; - static inline auto n11 = shape_t<2>{1,1}; - static inline auto n12 = shape_t<2>{1,2}; - static inline auto n21 = shape_t<2>{2,1}; - static inline auto n22 = shape_t<2>{2,2}; - static inline auto n32 = shape_t<2>{3,2}; - static inline auto n111 = shape_t<3>{1,1,1}; - static inline auto n211 = shape_t<3>{2,1,1}; - static inline auto n121 = shape_t<3>{1,2,1}; - static inline auto n112 = shape_t<3>{1,1,2}; - static inline auto n123 = shape_t<3>{1,2,3}; - static inline auto n321 = shape_t<3>{3,2,1}; - static inline auto n213 = shape_t<3>{2,1,3}; - static inline auto n432 = shape_t<3>{4,3,2}; -}; - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_static_empty, - fixture, - *boost::unit_test::label("dynamic_extents_rank_static") *boost::unit_test::label("empty")) -{ - namespace ublas = boost::numeric::ublas; -// BOOST_CHECK( ublas::empty(n )); - BOOST_CHECK(!ublas::empty(n1 )); - BOOST_CHECK(!ublas::empty(n2 )); - BOOST_CHECK(!ublas::empty(n11 )); - BOOST_CHECK(!ublas::empty(n12 )); - BOOST_CHECK(!ublas::empty(n21 )); - BOOST_CHECK(!ublas::empty(n22 )); - BOOST_CHECK(!ublas::empty(n32 )); - BOOST_CHECK(!ublas::empty(n111)); - BOOST_CHECK(!ublas::empty(n211)); - BOOST_CHECK(!ublas::empty(n121)); - BOOST_CHECK(!ublas::empty(n112)); - BOOST_CHECK(!ublas::empty(n123)); - BOOST_CHECK(!ublas::empty(n321)); - BOOST_CHECK(!ublas::empty(n213)); - BOOST_CHECK(!ublas::empty(n432)); - - BOOST_CHECK_THROW( shape_t<3>({1,1,0}), std::invalid_argument); - BOOST_CHECK_THROW( shape_t<2>({1,0}), std::invalid_argument); - BOOST_CHECK_THROW( shape_t<1>({0} ), std::invalid_argument); - BOOST_CHECK_THROW( shape_t<2>({0,1}), std::invalid_argument); -} - - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_static_size, - fixture, - *boost::unit_test::label("dynamic_extents_rank_static") *boost::unit_test::label("size")) -{ - namespace ublas = boost::numeric::ublas; - -// BOOST_CHECK_EQUAL(ublas::size(n ),0); - BOOST_CHECK_EQUAL(ublas::size(n1 ),1); - BOOST_CHECK_EQUAL(ublas::size(n2 ),1); - BOOST_CHECK_EQUAL(ublas::size(n11 ),2); - BOOST_CHECK_EQUAL(ublas::size(n12 ),2); - BOOST_CHECK_EQUAL(ublas::size(n21 ),2); - BOOST_CHECK_EQUAL(ublas::size(n22 ),2); - BOOST_CHECK_EQUAL(ublas::size(n32 ),2); - BOOST_CHECK_EQUAL(ublas::size(n111),3); - BOOST_CHECK_EQUAL(ublas::size(n211),3); - BOOST_CHECK_EQUAL(ublas::size(n121),3); - BOOST_CHECK_EQUAL(ublas::size(n112),3); - BOOST_CHECK_EQUAL(ublas::size(n123),3); - BOOST_CHECK_EQUAL(ublas::size(n321),3); - BOOST_CHECK_EQUAL(ublas::size(n213),3); - BOOST_CHECK_EQUAL(ublas::size(n432),3); -} - - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_static_at_read, - fixture, - *boost::unit_test::label("dynamic_extents_rank_static") *boost::unit_test::label("at_read")) -{ - BOOST_CHECK_EQUAL(n1 .at(0),1); - BOOST_CHECK_EQUAL(n2 .at(0),2); - - BOOST_CHECK_EQUAL(n11 .at(0),1); - BOOST_CHECK_EQUAL(n11 .at(1),1); - - BOOST_CHECK_EQUAL(n12 .at(0),1); - BOOST_CHECK_EQUAL(n12 .at(1),2); - - BOOST_CHECK_EQUAL(n21 .at(0),2); - BOOST_CHECK_EQUAL(n21 .at(1),1); - - BOOST_CHECK_EQUAL(n22 .at(0),2); - BOOST_CHECK_EQUAL(n22 .at(1),2); - - BOOST_CHECK_EQUAL(n32 .at(0),3); - BOOST_CHECK_EQUAL(n32 .at(1),2); - - BOOST_CHECK_EQUAL(n432.at(0),4); - BOOST_CHECK_EQUAL(n432.at(1),3); - BOOST_CHECK_EQUAL(n432.at(2),2); - - -// BOOST_CHECK_THROW( (void)n .at(0), std::out_of_range); - BOOST_CHECK_THROW( (void)n32.at(2), std::out_of_range); - BOOST_CHECK_THROW( (void)n32.at(5), std::out_of_range); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_static_operator_access_read, - fixture, - *boost::unit_test::label("dynamic_extents_rank_static") *boost::unit_test::label("operator_access_read")) -{ - BOOST_CHECK_EQUAL(n1 [0],1); - BOOST_CHECK_EQUAL(n2 [0],2); - - BOOST_CHECK_EQUAL(n11 [0],1); - BOOST_CHECK_EQUAL(n11 [1],1); - - BOOST_CHECK_EQUAL(n12 [0],1); - BOOST_CHECK_EQUAL(n12 [1],2); - - BOOST_CHECK_EQUAL(n21 [0],2); - BOOST_CHECK_EQUAL(n21 [1],1); - - BOOST_CHECK_EQUAL(n22 [0],2); - BOOST_CHECK_EQUAL(n22 [1],2); - - BOOST_CHECK_EQUAL(n32 [0],3); - BOOST_CHECK_EQUAL(n32 [1],2); - - BOOST_CHECK_EQUAL(n432[0],4); - BOOST_CHECK_EQUAL(n432[1],3); - BOOST_CHECK_EQUAL(n432[2],2); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_extents_functions.cpp b/test/tensor/test_extents_functions.cpp deleted file mode 100644 index 868afd26e..000000000 --- a/test/tensor/test_extents_functions.cpp +++ /dev/null @@ -1,634 +0,0 @@ -// -// Copyright (c) 2020, Cem Bassoy, cem.bassoy@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#include -#include - -#include -#include - - - -BOOST_AUTO_TEST_SUITE(test_shape_functions) - -struct fixture_extents_dynamic_rank -{ - using shape_t = boost::numeric::ublas::extents<>; - - static inline auto n = shape_t{}; - static inline auto n1 = shape_t{1}; - static inline auto n2 = shape_t{2}; - static inline auto n11 = shape_t{1,1}; - static inline auto n12 = shape_t{1,2}; - static inline auto n21 = shape_t{2,1}; - static inline auto n22 = shape_t{2,2}; - static inline auto n32 = shape_t{3,2}; - static inline auto n111 = shape_t{1,1,1}; - static inline auto n211 = shape_t{2,1,1}; - static inline auto n121 = shape_t{1,2,1}; - static inline auto n112 = shape_t{1,1,2}; - static inline auto n123 = shape_t{1,2,3}; - static inline auto n321 = shape_t{3,2,1}; - static inline auto n213 = shape_t{2,1,3}; - static inline auto n432 = shape_t{4,3,2}; -}; - -struct fixture_extents_static_rank -{ - template - using extents_static_rank = boost::numeric::ublas::extents; - - static constexpr inline auto n = extents_static_rank<0>{}; - static constexpr inline auto n1 = extents_static_rank<1>{1}; - static constexpr inline auto n2 = extents_static_rank<1>{2}; - static constexpr inline auto n11 = extents_static_rank<2>{{1,1}}; - static constexpr inline auto n12 = extents_static_rank<2>{{1,2}}; - static constexpr inline auto n21 = extents_static_rank<2>{{2,1}}; - static constexpr inline auto n22 = extents_static_rank<2>{{2,2}}; - static constexpr inline auto n32 = extents_static_rank<2>{{3,2}}; - static constexpr inline auto n111 = extents_static_rank<3>{{1,1,1}}; - static constexpr inline auto n211 = extents_static_rank<3>{{2,1,1}}; - static constexpr inline auto n121 = extents_static_rank<3>{{1,2,1}}; - static constexpr inline auto n112 = extents_static_rank<3>{{1,1,2}}; - static constexpr inline auto n123 = extents_static_rank<3>{{1,2,3}}; - static constexpr inline auto n321 = extents_static_rank<3>{{3,2,1}}; - static constexpr inline auto n213 = extents_static_rank<3>{{2,1,3}}; - static constexpr inline auto n432 = extents_static_rank<3>{{4,3,2}}; - - static constexpr inline auto tuple = std::make_tuple( n,n1,n2,n11,n12,n21,n22,n32,n111,n211,n121,n112,n123,n321,n213,n432 ); - -}; - - - -struct fixture_extents_static -{ - template - using extents_static = boost::numeric::ublas::extents; - - static inline auto n = extents_static<> {}; - static inline auto n1 = extents_static<1> {}; - static inline auto n2 = extents_static<2> {}; - static inline auto n11 = extents_static<1,1> {}; - static inline auto n12 = extents_static<1,2> {}; - static inline auto n21 = extents_static<2,1> {}; - static inline auto n22 = extents_static<2,2> {}; - static inline auto n32 = extents_static<3,2> {}; - static inline auto n111 = extents_static<1,1,1> {}; - static inline auto n211 = extents_static<2,1,1> {}; - static inline auto n121 = extents_static<1,2,1> {}; - static inline auto n112 = extents_static<1,1,2> {}; - static inline auto n123 = extents_static<1,2,3> {}; - static inline auto n321 = extents_static<3,2,1> {}; - static inline auto n213 = extents_static<2,1,3> {}; - static inline auto n432 = extents_static<4,3,2> {}; - - - -}; - - - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_is_scalar, - fixture_extents_dynamic_rank, - *boost::unit_test::label("extents_dynamic_rank") - *boost::unit_test::label("is_scalar")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_scalar( n )); - BOOST_CHECK ( ub::is_scalar( n1 )); - BOOST_CHECK ( !ub::is_scalar( n2 )); - BOOST_CHECK ( ub::is_scalar( n11 )); - BOOST_CHECK ( !ub::is_scalar( n12 )); - BOOST_CHECK ( !ub::is_scalar( n21 )); - BOOST_CHECK ( !ub::is_scalar( n22 )); - BOOST_CHECK ( !ub::is_scalar( n32 )); - BOOST_CHECK ( ub::is_scalar( n111 )); - BOOST_CHECK ( !ub::is_scalar( n211 )); - BOOST_CHECK ( !ub::is_scalar( n121 )); - BOOST_CHECK ( !ub::is_scalar( n112 )); - BOOST_CHECK ( !ub::is_scalar( n123 )); - BOOST_CHECK ( !ub::is_scalar( n321 )); - BOOST_CHECK ( !ub::is_scalar( n213 )); - BOOST_CHECK ( !ub::is_scalar( n432 )); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_is_scalar, - fixture_extents_static_rank, - *boost::unit_test::label("extents_static_rank") - *boost::unit_test::label("is_scalar")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_scalar( n )); - BOOST_CHECK ( ub::is_scalar( n1 )); - BOOST_CHECK ( !ub::is_scalar( n2 )); - BOOST_CHECK ( ub::is_scalar( n11 )); - BOOST_CHECK ( !ub::is_scalar( n12 )); - BOOST_CHECK ( !ub::is_scalar( n21 )); - BOOST_CHECK ( !ub::is_scalar( n22 )); - BOOST_CHECK ( !ub::is_scalar( n32 )); - BOOST_CHECK ( ub::is_scalar( n111 )); - BOOST_CHECK ( !ub::is_scalar( n211 )); - BOOST_CHECK ( !ub::is_scalar( n121 )); - BOOST_CHECK ( !ub::is_scalar( n112 )); - BOOST_CHECK ( !ub::is_scalar( n123 )); - BOOST_CHECK ( !ub::is_scalar( n321 )); - BOOST_CHECK ( !ub::is_scalar( n213 )); - BOOST_CHECK ( !ub::is_scalar( n432 )); - -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_is_scalar, - fixture_extents_static, - *boost::unit_test::label("extents_static") - *boost::unit_test::label("is_scalar")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_scalar( n )); -//FIXME: BOOST_CHECK ( ub::is_scalar( n1 )); - BOOST_CHECK ( !ub::is_scalar( n2 )); - BOOST_CHECK ( ub::is_scalar( n11 )); - BOOST_CHECK ( !ub::is_scalar( n12 )); - BOOST_CHECK ( !ub::is_scalar( n21 )); - BOOST_CHECK ( !ub::is_scalar( n22 )); - BOOST_CHECK ( !ub::is_scalar( n32 )); - BOOST_CHECK ( ub::is_scalar( n111 )); - BOOST_CHECK ( !ub::is_scalar( n211 )); - BOOST_CHECK ( !ub::is_scalar( n121 )); - BOOST_CHECK ( !ub::is_scalar( n112 )); - BOOST_CHECK ( !ub::is_scalar( n123 )); - BOOST_CHECK ( !ub::is_scalar( n321 )); - BOOST_CHECK ( !ub::is_scalar( n213 )); - BOOST_CHECK ( !ub::is_scalar( n432 )); - -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_is_vector, - fixture_extents_dynamic_rank, - *boost::unit_test::label("extents_dynamic_rank") - *boost::unit_test::label("is_vector")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_vector( n )); - BOOST_CHECK ( ub::is_vector( n1 )); - BOOST_CHECK ( ub::is_vector( n2 )); - BOOST_CHECK ( ub::is_vector( n11 )); - BOOST_CHECK ( ub::is_vector( n12 )); - BOOST_CHECK ( ub::is_vector( n21 )); - BOOST_CHECK ( !ub::is_vector( n22 )); - BOOST_CHECK ( !ub::is_vector( n32 )); - BOOST_CHECK ( ub::is_vector( n111 )); - BOOST_CHECK ( ub::is_vector( n211 )); - BOOST_CHECK ( ub::is_vector( n121 )); - BOOST_CHECK ( !ub::is_vector( n112 )); - BOOST_CHECK ( !ub::is_vector( n123 )); - BOOST_CHECK ( !ub::is_vector( n321 )); - BOOST_CHECK ( !ub::is_vector( n213 )); - BOOST_CHECK ( !ub::is_vector( n432 )); -} - -BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_is_vector, - fixture_extents_static_rank, - *boost::unit_test::label("extents_static_rank") - *boost::unit_test::label("is_vector")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_vector( n )); - BOOST_CHECK ( ub::is_vector( n1 )); - BOOST_CHECK ( ub::is_vector( n2 )); - BOOST_CHECK ( ub::is_vector( n11 )); - BOOST_CHECK ( ub::is_vector( n12 )); - BOOST_CHECK ( ub::is_vector( n21 )); - BOOST_CHECK ( !ub::is_vector( n22 )); - BOOST_CHECK ( !ub::is_vector( n32 )); - BOOST_CHECK ( ub::is_vector( n111 )); - BOOST_CHECK ( ub::is_vector( n211 )); - BOOST_CHECK ( ub::is_vector( n121 )); - BOOST_CHECK ( !ub::is_vector( n112 )); - BOOST_CHECK ( !ub::is_vector( n123 )); - BOOST_CHECK ( !ub::is_vector( n321 )); - BOOST_CHECK ( !ub::is_vector( n213 )); - BOOST_CHECK ( !ub::is_vector( n432 )); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_is_vector, - fixture_extents_static, - *boost::unit_test::label("extents_static") - *boost::unit_test::label("is_vector")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_vector( n1 )); -//FIXME: BOOST_CHECK ( ub::is_vector( n2 )); - BOOST_CHECK ( ub::is_vector( n11 )); - BOOST_CHECK ( ub::is_vector( n12 )); - BOOST_CHECK ( ub::is_vector( n21 )); - BOOST_CHECK ( !ub::is_vector( n22 )); - BOOST_CHECK ( !ub::is_vector( n32 )); - BOOST_CHECK ( ub::is_vector( n111 )); - BOOST_CHECK ( ub::is_vector( n211 )); - BOOST_CHECK ( ub::is_vector( n121 )); - BOOST_CHECK ( !ub::is_vector( n112 )); - BOOST_CHECK ( !ub::is_vector( n123 )); - BOOST_CHECK ( !ub::is_vector( n321 )); - BOOST_CHECK ( !ub::is_vector( n213 )); - BOOST_CHECK ( !ub::is_vector( n432 )); -} - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_is_matrix, - fixture_extents_dynamic_rank, - *boost::unit_test::label("extents_dynamic_rank") - *boost::unit_test::label("is_matrix")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_matrix( n )); - BOOST_CHECK ( ub::is_matrix( n1 )); - BOOST_CHECK ( ub::is_matrix( n2 )); - BOOST_CHECK ( ub::is_matrix( n11 )); - BOOST_CHECK ( ub::is_matrix( n12 )); - BOOST_CHECK ( ub::is_matrix( n21 )); - BOOST_CHECK ( ub::is_matrix( n22 )); - BOOST_CHECK ( ub::is_matrix( n32 )); - BOOST_CHECK ( ub::is_matrix( n111 )); - BOOST_CHECK ( ub::is_matrix( n211 )); - BOOST_CHECK ( ub::is_matrix( n121 )); - BOOST_CHECK ( !ub::is_matrix( n112 )); - BOOST_CHECK ( !ub::is_matrix( n123 )); - BOOST_CHECK ( ub::is_matrix( n321 )); - BOOST_CHECK ( !ub::is_matrix( n213 )); - BOOST_CHECK ( !ub::is_matrix( n432 )); -} - -BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_is_matrix, - fixture_extents_static_rank, - *boost::unit_test::label("extents_static_rank") - *boost::unit_test::label("is_matrix")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_matrix( n )); - BOOST_CHECK ( ub::is_matrix( n1 )); - BOOST_CHECK ( ub::is_matrix( n2 )); - BOOST_CHECK ( ub::is_matrix( n11 )); - BOOST_CHECK ( ub::is_matrix( n12 )); - BOOST_CHECK ( ub::is_matrix( n21 )); - BOOST_CHECK ( ub::is_matrix( n22 )); - BOOST_CHECK ( ub::is_matrix( n32 )); - BOOST_CHECK ( ub::is_matrix( n111 )); - BOOST_CHECK ( ub::is_matrix( n211 )); - BOOST_CHECK ( ub::is_matrix( n121 )); - BOOST_CHECK ( !ub::is_matrix( n112 )); - BOOST_CHECK ( !ub::is_matrix( n123 )); - BOOST_CHECK ( ub::is_matrix( n321 )); - BOOST_CHECK ( !ub::is_matrix( n213 )); - BOOST_CHECK ( !ub::is_matrix( n432 )); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_is_matrix, - fixture_extents_static, - *boost::unit_test::label("extents_static") - *boost::unit_test::label("is_matrix")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_matrix( n )); -//FIXME: BOOST_CHECK ( !ub::is_matrix( n1 )); - BOOST_CHECK ( !ub::is_matrix( n2 )); - BOOST_CHECK ( ub::is_matrix( n11 )); - BOOST_CHECK ( ub::is_matrix( n12 )); - BOOST_CHECK ( ub::is_matrix( n21 )); - BOOST_CHECK ( ub::is_matrix( n22 )); - BOOST_CHECK ( ub::is_matrix( n32 )); - BOOST_CHECK ( ub::is_matrix( n111 )); - BOOST_CHECK ( ub::is_matrix( n211 )); - BOOST_CHECK ( ub::is_matrix( n121 )); - BOOST_CHECK ( !ub::is_matrix( n112 )); - BOOST_CHECK ( !ub::is_matrix( n123 )); - BOOST_CHECK ( ub::is_matrix( n321 )); - BOOST_CHECK ( !ub::is_matrix( n213 )); - BOOST_CHECK ( !ub::is_matrix( n432 )); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_is_tensor, - fixture_extents_dynamic_rank, - *boost::unit_test::label("extents_dynamic_rank") - *boost::unit_test::label("is_tensor")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_tensor( n )); - BOOST_CHECK ( !ub::is_tensor( n1 )); - BOOST_CHECK ( !ub::is_tensor( n2 )); - BOOST_CHECK ( !ub::is_tensor( n11 )); - BOOST_CHECK ( !ub::is_tensor( n12 )); - BOOST_CHECK ( !ub::is_tensor( n21 )); - BOOST_CHECK ( !ub::is_tensor( n22 )); - BOOST_CHECK ( !ub::is_tensor( n32 )); - BOOST_CHECK ( !ub::is_tensor( n111 )); - BOOST_CHECK ( !ub::is_tensor( n211 )); - BOOST_CHECK ( !ub::is_tensor( n121 )); - BOOST_CHECK ( ub::is_tensor( n112 )); - BOOST_CHECK ( ub::is_tensor( n123 )); - BOOST_CHECK ( !ub::is_tensor( n321 )); - BOOST_CHECK ( ub::is_tensor( n213 )); - BOOST_CHECK ( ub::is_tensor( n432 )); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_is_tensor, - fixture_extents_static_rank, - *boost::unit_test::label("extents_static_rank") - *boost::unit_test::label("is_tensor")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_tensor( n )); - BOOST_CHECK ( !ub::is_tensor( n1 )); - BOOST_CHECK ( !ub::is_tensor( n2 )); - BOOST_CHECK ( !ub::is_tensor( n11 )); - BOOST_CHECK ( !ub::is_tensor( n12 )); - BOOST_CHECK ( !ub::is_tensor( n21 )); - BOOST_CHECK ( !ub::is_tensor( n22 )); - BOOST_CHECK ( !ub::is_tensor( n32 )); - BOOST_CHECK ( !ub::is_tensor( n111 )); - BOOST_CHECK ( !ub::is_tensor( n211 )); - BOOST_CHECK ( !ub::is_tensor( n121 )); - BOOST_CHECK ( ub::is_tensor( n112 )); - BOOST_CHECK ( ub::is_tensor( n123 )); - BOOST_CHECK ( !ub::is_tensor( n321 )); - BOOST_CHECK ( ub::is_tensor( n213 )); - BOOST_CHECK ( ub::is_tensor( n432 )); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_is_tensor, - fixture_extents_static, - *boost::unit_test::label("extents_static") - *boost::unit_test::label("is_tensor")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( !ub::is_tensor( n )); -//FIXME: BOOST_CHECK ( !ub::is_tensor( n1 )); - BOOST_CHECK ( !ub::is_tensor( n2 )); - BOOST_CHECK ( !ub::is_tensor( n11 )); - BOOST_CHECK ( !ub::is_tensor( n12 )); - BOOST_CHECK ( !ub::is_tensor( n21 )); - BOOST_CHECK ( !ub::is_tensor( n22 )); - BOOST_CHECK ( !ub::is_tensor( n32 )); - BOOST_CHECK ( !ub::is_tensor( n111 )); - BOOST_CHECK ( !ub::is_tensor( n211 )); - BOOST_CHECK ( !ub::is_tensor( n121 )); - BOOST_CHECK ( ub::is_tensor( n112 )); - BOOST_CHECK ( ub::is_tensor( n123 )); - BOOST_CHECK ( !ub::is_tensor( n321 )); - BOOST_CHECK ( ub::is_tensor( n213 )); - BOOST_CHECK ( ub::is_tensor( n432 )); -} - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_is_valid, - fixture_extents_dynamic_rank, - *boost::unit_test::label("extents_dynamic_rank") - *boost::unit_test::label("is_valid")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( ub::is_valid( n1 )); - BOOST_CHECK ( ub::is_valid( n2 )); - BOOST_CHECK ( ub::is_valid( n11 )); - BOOST_CHECK ( ub::is_valid( n12 )); - BOOST_CHECK ( ub::is_valid( n21 )); - BOOST_CHECK ( ub::is_valid( n22 )); - BOOST_CHECK ( ub::is_valid( n32 )); - BOOST_CHECK ( ub::is_valid( n111 )); - BOOST_CHECK ( ub::is_valid( n211 )); - BOOST_CHECK ( ub::is_valid( n121 )); - BOOST_CHECK ( ub::is_valid( n112 )); - BOOST_CHECK ( ub::is_valid( n123 )); - BOOST_CHECK ( ub::is_valid( n321 )); - BOOST_CHECK ( ub::is_valid( n213 )); - BOOST_CHECK ( ub::is_valid( n432 )); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_is_valid, - fixture_extents_static_rank, - *boost::unit_test::label("extents_static_rank") - *boost::unit_test::label("is_valid")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( ub::is_valid( n )); - BOOST_CHECK ( ub::is_valid( n1 )); - BOOST_CHECK ( ub::is_valid( n2 )); - BOOST_CHECK ( ub::is_valid( n11 )); - BOOST_CHECK ( ub::is_valid( n12 )); - BOOST_CHECK ( ub::is_valid( n21 )); - BOOST_CHECK ( ub::is_valid( n22 )); - BOOST_CHECK ( ub::is_valid( n32 )); - BOOST_CHECK ( ub::is_valid( n111 )); - BOOST_CHECK ( ub::is_valid( n211 )); - BOOST_CHECK ( ub::is_valid( n121 )); - BOOST_CHECK ( ub::is_valid( n112 )); - BOOST_CHECK ( ub::is_valid( n123 )); - BOOST_CHECK ( ub::is_valid( n321 )); - BOOST_CHECK ( ub::is_valid( n213 )); - BOOST_CHECK ( ub::is_valid( n432 )); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_is_valid, - fixture_extents_static, - *boost::unit_test::label("extents_static") - *boost::unit_test::label("is_valid")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK ( ub::is_valid( n )); -//FIXME: BOOST_CHECK ( ub::is_valid( n1 )); -//FIXME: BOOST_CHECK ( ub::is_valid( n2 )); - BOOST_CHECK ( ub::is_valid( n11 )); - BOOST_CHECK ( ub::is_valid( n12 )); - BOOST_CHECK ( ub::is_valid( n21 )); - BOOST_CHECK ( ub::is_valid( n22 )); - BOOST_CHECK ( ub::is_valid( n32 )); - BOOST_CHECK ( ub::is_valid( n111 )); - BOOST_CHECK ( ub::is_valid( n211 )); - BOOST_CHECK ( ub::is_valid( n121 )); - BOOST_CHECK ( ub::is_valid( n112 )); - BOOST_CHECK ( ub::is_valid( n123 )); - BOOST_CHECK ( ub::is_valid( n321 )); - BOOST_CHECK ( ub::is_valid( n213 )); - BOOST_CHECK ( ub::is_valid( n432 )); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_product, - fixture_extents_dynamic_rank, - *boost::unit_test::label("extents_dynamic_rank") - *boost::unit_test::label("product")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK_EQUAL ( ub::product( n ), 0U); - BOOST_CHECK_EQUAL ( ub::product( n1 ), 1U); - BOOST_CHECK_EQUAL ( ub::product( n2 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n11 ), 1U); - BOOST_CHECK_EQUAL ( ub::product( n12 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n21 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n22 ), 4U); - BOOST_CHECK_EQUAL ( ub::product( n32 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n111 ), 1U); - BOOST_CHECK_EQUAL ( ub::product( n211 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n121 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n112 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n123 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n321 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n213 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n432 ),24U); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_product, - fixture_extents_static_rank, - *boost::unit_test::label("extents_static_rank") - *boost::unit_test::label("product")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK_EQUAL ( ub::product( n ), 0U); - BOOST_CHECK_EQUAL ( ub::product( n1 ), 1U); - BOOST_CHECK_EQUAL ( ub::product( n2 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n11 ), 1U); - BOOST_CHECK_EQUAL ( ub::product( n12 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n21 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n22 ), 4U); - BOOST_CHECK_EQUAL ( ub::product( n32 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n111 ), 1U); - BOOST_CHECK_EQUAL ( ub::product( n211 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n121 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n112 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n123 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n321 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n213 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n432 ),24U); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_product, - fixture_extents_static, - *boost::unit_test::label("extents_static") - *boost::unit_test::label("product")) -{ - - namespace ub = boost::numeric::ublas; - BOOST_CHECK_EQUAL ( ub::product( n ), 0U); -//FIXME: BOOST_CHECK_EQUAL ( ub::product( n1 ), 1U); -//FIXME: BOOST_CHECK_EQUAL ( ub::product( n2 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n11 ), 1U); - BOOST_CHECK_EQUAL ( ub::product( n12 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n21 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n22 ), 4U); - BOOST_CHECK_EQUAL ( ub::product( n32 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n111 ), 1U); - BOOST_CHECK_EQUAL ( ub::product( n211 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n121 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n112 ), 2U); - BOOST_CHECK_EQUAL ( ub::product( n123 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n321 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n213 ), 6U); - BOOST_CHECK_EQUAL ( ub::product( n432 ),24U); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_equal, - fixture_extents_dynamic_rank, - *boost::unit_test::label("extents_dynamic_rank") - *boost::unit_test::label("equal")) -{ - BOOST_CHECK ( n == n ); - BOOST_CHECK ( n1 == n1 ); - BOOST_CHECK ( n2 == n2 ); - BOOST_CHECK ( n11 == n11 ); - BOOST_CHECK ( n12 == n12 ); - BOOST_CHECK ( n21 == n21 ); - BOOST_CHECK ( n22 == n22 ); - BOOST_CHECK ( n32 == n32 ); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_rank_equal, - fixture_extents_static_rank, - *boost::unit_test::label("extents_static_rank") - *boost::unit_test::label("equal")) -{ - BOOST_CHECK ( n == n ); - BOOST_CHECK ( n1 == n1 ); - BOOST_CHECK ( n2 == n2 ); - BOOST_CHECK ( n11 == n11 ); - BOOST_CHECK ( n12 == n12 ); - BOOST_CHECK ( n21 == n21 ); - BOOST_CHECK ( n22 == n22 ); - BOOST_CHECK ( n32 == n32 ); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_equal, - fixture_extents_static, - *boost::unit_test::label("extents_static") - *boost::unit_test::label("equal")) -{ - BOOST_CHECK ( n == n ); - BOOST_CHECK ( n1 == n1 ); - BOOST_CHECK ( n2 == n2 ); - BOOST_CHECK ( n11 == n11 ); - BOOST_CHECK ( n12 == n12 ); - BOOST_CHECK ( n21 == n21 ); - BOOST_CHECK ( n22 == n22 ); - BOOST_CHECK ( n32 == n32 ); -} - - -BOOST_FIXTURE_TEST_CASE(test_extents_dynamic_rank_not_equal, - fixture_extents_dynamic_rank, - *boost::unit_test::label("extents_dynamic_rank") - *boost::unit_test::label("not_equal")) -{ - BOOST_CHECK ( ! (n != n ) ); - BOOST_CHECK ( ! (n1 != n1) ); - BOOST_CHECK ( ! (n2 != n2) ); - BOOST_CHECK ( ! (n11 != n11) ); - BOOST_CHECK ( ! (n12 != n12) ); - BOOST_CHECK ( ! (n21 != n21) ); - BOOST_CHECK ( ! (n22 != n22) ); - BOOST_CHECK ( ! (n32 != n32) ); - BOOST_CHECK ( (n2 != n1) ); - BOOST_CHECK ( (n11 != n12) ); - BOOST_CHECK ( (n12 != n21) ); - BOOST_CHECK ( (n21 != n22) ); - BOOST_CHECK ( (n22 != n32) ); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_expression_evaluation.cpp b/test/tensor/test_fixed_rank_expression_evaluation.cpp deleted file mode 100644 index a1e06885b..000000000 --- a/test/tensor/test_fixed_rank_expression_evaluation.cpp +++ /dev/null @@ -1,287 +0,0 @@ -// -// Copyright (c) 2020, Amit Singh, amitsingh19975@gmail.com -// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - - -#include -#include -#include - -#include "utility.hpp" - -#include -#include -#include - -BOOST_AUTO_TEST_SUITE(test_tensor_static_rank_expression) - -using test_types = zip>::with_t; - - - - -struct fixture -{ - template - using extents_t = boost::numeric::ublas::extents; - - static constexpr auto extents = - std::make_tuple( -// extents_t<0> {}, - extents_t<2> {1,1}, - extents_t<2> {1,2}, - extents_t<2> {2,1}, - extents_t<2> {2,3}, - extents_t<3> {2,3,1}, - extents_t<3> {4,1,3}, - extents_t<3> {1,2,3}, - extents_t<3> {4,2,3}, - extents_t<4>{4,2,3,5} ); -}; - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_static_rank_expression_retrieve_extents, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - auto uplus1 = [](auto const& a){return a + value_t(1); }; - auto uplus2 = [](auto const& a){return value_t(2) + a; }; - auto bplus = std::plus {}; - auto bminus = std::minus{}; - - for_each_in_tuple(extents, [&](auto const& /*unused*/, auto const& e){ - - - - static constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - - - auto t = tensor_t(e); - auto v = value_t{}; - for(auto& tt: t){ tt = v; v+=value_t{1}; } - - - BOOST_CHECK( ublas::detail::retrieve_extents( t ) == e ); - - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); - - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); - - }); - - for_each_in_tuple(extents, [&](auto I, auto const& e1){ - - - if ( I >= std::tuple_size_v - 1 ){ - return; - } - - constexpr auto size1 = std::tuple_size_v>; - using tensor_type1 = ublas::tensor_static_rank; - - for_each_in_tuple(extents, [&,I](auto J, auto const& e2){ - - if( J != I + 1 ){ - return; - } - - static constexpr auto size1 = std::tuple_size_v>; - static constexpr auto size2 = std::tuple_size_v>; - using tensor_type2 = ublas::tensor_static_rank; - - auto v = value_t{}; - - tensor_type1 t1(e1); - for(auto& tt: t1){ tt = v; v+=value_t{1}; } - - tensor_type2 t2(e2); - for(auto& tt: t2){ tt = v; v+=value_t{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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 ) ); - - if constexpr( size1 == size2 ){ - // bexpr_uexpr = (t1+1) + (2+t2) - auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( 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( 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_static_rank_expression_all_extents_equal, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - auto uplus1 = [](auto const& a){return a + value_t(1); }; - auto uplus2 = [](auto const& a){return value_t(2) + a; }; - auto bplus = std::plus {}; - auto bminus = std::minus{}; - - for_each_in_tuple(extents, [&](auto const& /*unused*/, auto& e){ - static constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - - - auto t = tensor_t(e); - auto v = value_t{}; - for(auto& tt: t){ tt = v; v+=value_t{1}; } - - - BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); - - - // uexpr1 = t+1 - // uexpr2 = 2+t - auto uexpr1 = ublas::detail::make_unary_tensor_expression( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); - - BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); - - }); - - - for_each_in_tuple(extents, [&](auto I, auto& e1){ - - if ( I >= std::tuple_size_v - 1){ - return; - } - - static constexpr auto size1 = std::tuple_size_v>; - using tensor_type1 = ublas::tensor_static_rank; - - for_each_in_tuple(extents, [&](auto J, auto& e2){ - - if( J != I + 1 ){ - return; - } - - - static constexpr auto size2 = std::tuple_size_v>; - using tensor_type2 = ublas::tensor_static_rank; - - auto v = value_t{}; - - tensor_type1 t1(e1); - for(auto& tt: t1){ tt = v; v+=value_t{1}; } - - tensor_type2 t2(e2); - for(auto& tt: t2){ tt = v; v+=value_t{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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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) ) ); - - if constexpr( size1 == size2 ){ - // bexpr_uexpr = (t1+1) + (2+t2) - auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression( 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( 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( 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( 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( 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( t1, bexpr_bexpr_uexpr3, bplus ); - BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); - } - - }); - }); - -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_extents.cpp b/test/tensor/test_fixed_rank_extents.cpp deleted file mode 100644 index ac873f55c..000000000 --- a/test/tensor/test_fixed_rank_extents.cpp +++ /dev/null @@ -1,555 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#include -#include -#include - -BOOST_AUTO_TEST_SUITE ( test_extents_static_size ) - - -//*boost::unit_test::label("extents") -//*boost::unit_test::label("constructor") - -BOOST_AUTO_TEST_CASE(test_extents_static_size_ctor) -{ - namespace ub = boost::numeric::ublas; - - -// auto e = ub::extents<0>{}; - auto e11 = ub::extents<2>{1,1}; - auto e12 = ub::extents<2>{1,2}; - auto e21 = ub::extents<2>{2,1}; - auto e23 = ub::extents<2>{2,3}; - auto e231 = ub::extents<3>{2,3,1}; - auto e123 = ub::extents<3>{1,2,3}; // 6 - auto e423 = ub::extents<3>{4,2,3}; // 7 - - - BOOST_CHECK (!ub::empty(e11)); - BOOST_CHECK (!ub::empty(e12)); - BOOST_CHECK (!ub::empty(e21)); - BOOST_CHECK (!ub::empty(e23)); - BOOST_CHECK (!ub::empty(e231)); - BOOST_CHECK (!ub::empty(e123)); - BOOST_CHECK (!ub::empty(e423)); - - BOOST_CHECK ( ub::size (e11) == 2); - BOOST_CHECK ( ub::size (e12) == 2); - BOOST_CHECK ( ub::size (e21) == 2); - BOOST_CHECK ( ub::size (e23) == 2); - BOOST_CHECK ( ub::size(e231) == 3); - BOOST_CHECK ( ub::size(e123) == 3); - BOOST_CHECK ( ub::size(e423) == 3); - - - BOOST_CHECK_THROW( ub::extents<2>({1,0}), std::invalid_argument); - BOOST_CHECK_THROW( ub::extents<1>({0} ), std::invalid_argument); - BOOST_CHECK_THROW( ub::extents<2>({0,1}), std::invalid_argument); - BOOST_CHECK_THROW( ub::extents<2>({1,1,2}), std::length_error); -} - - -struct fixture { - template - using extents = boost::numeric::ublas::extents; - -// extents<0> de {}; - - extents<2> de11 {1,1}; - extents<2> de12 {1,2}; - extents<2> de21 {2,1}; - - extents<2> de23 {2,3}; - extents<3> de231 {2,3,1}; - extents<3> de123 {1,2,3}; - extents<4> de1123 {1,1,2,3}; - extents<5> de12311 {1,2,3,1,1}; - - extents<3> de423 {4,2,3}; - extents<4> de4213 {4,2,1,3}; - extents<5> de42131 {4,2,1,3,1}; - extents<6> de142131 {1,4,2,1,3,1}; - - extents<3> de141 {1,4,1}; - extents<4> de1111 {1,1,1,1}; - extents<5> de14111 {1,4,1,1,1}; - extents<6> de112111 {1,1,2,1,1,1}; - extents<6> de112311 {1,1,2,3,1,1}; -}; - -BOOST_FIXTURE_TEST_CASE(test_extents_static_size_access, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("access")) -{ - - namespace ublas = boost::numeric::ublas; - -// BOOST_REQUIRE_EQUAL(ublas::size(de), 0); -// BOOST_CHECK (ublas::empty(de) ); - - BOOST_REQUIRE_EQUAL(ublas::size(de11) , 2); - BOOST_REQUIRE_EQUAL(ublas::size(de12) , 2); - BOOST_REQUIRE_EQUAL(ublas::size(de21) , 2); - BOOST_REQUIRE_EQUAL(ublas::size(de23) , 2); - BOOST_REQUIRE_EQUAL(ublas::size(de231) , 3); - BOOST_REQUIRE_EQUAL(ublas::size(de123) , 3); - BOOST_REQUIRE_EQUAL(ublas::size(de1123) , 4); - BOOST_REQUIRE_EQUAL(ublas::size(de12311) , 5); - BOOST_REQUIRE_EQUAL(ublas::size(de423) , 3); - BOOST_REQUIRE_EQUAL(ublas::size(de4213) , 4); - BOOST_REQUIRE_EQUAL(ublas::size(de42131) , 5); - BOOST_REQUIRE_EQUAL(ublas::size(de142131), 6); - BOOST_REQUIRE_EQUAL(ublas::size(de141) , 3); - BOOST_REQUIRE_EQUAL(ublas::size(de1111) , 4); - BOOST_REQUIRE_EQUAL(ublas::size(de14111) , 5); - BOOST_REQUIRE_EQUAL(ublas::size(de112111), 6); - BOOST_REQUIRE_EQUAL(ublas::size(de112311), 6); - - - BOOST_CHECK_EQUAL(de11[0],1); - BOOST_CHECK_EQUAL(de11[1],1); - - BOOST_CHECK_EQUAL(de12[0],1); - BOOST_CHECK_EQUAL(de12[1],2); - - BOOST_CHECK_EQUAL(de21[0],2); - BOOST_CHECK_EQUAL(de21[1],1); - - BOOST_CHECK_EQUAL(de23[0],2); - BOOST_CHECK_EQUAL(de23[1],3); - - BOOST_CHECK_EQUAL(de231[0],2); - BOOST_CHECK_EQUAL(de231[1],3); - BOOST_CHECK_EQUAL(de231[2],1); - - BOOST_CHECK_EQUAL(de123[0],1); - BOOST_CHECK_EQUAL(de123[1],2); - BOOST_CHECK_EQUAL(de123[2],3); - - BOOST_CHECK_EQUAL(de1123[0],1); - BOOST_CHECK_EQUAL(de1123[1],1); - BOOST_CHECK_EQUAL(de1123[2],2); - BOOST_CHECK_EQUAL(de1123[3],3); - - BOOST_CHECK_EQUAL(de12311[0],1); - BOOST_CHECK_EQUAL(de12311[1],2); - BOOST_CHECK_EQUAL(de12311[2],3); - BOOST_CHECK_EQUAL(de12311[3],1); - BOOST_CHECK_EQUAL(de12311[4],1); - - BOOST_CHECK_EQUAL(de423[0],4); - BOOST_CHECK_EQUAL(de423[1],2); - BOOST_CHECK_EQUAL(de423[2],3); - - BOOST_CHECK_EQUAL(de4213[0],4); - BOOST_CHECK_EQUAL(de4213[1],2); - BOOST_CHECK_EQUAL(de4213[2],1); - BOOST_CHECK_EQUAL(de4213[3],3); - - BOOST_CHECK_EQUAL(de42131[0],4); - BOOST_CHECK_EQUAL(de42131[1],2); - BOOST_CHECK_EQUAL(de42131[2],1); - BOOST_CHECK_EQUAL(de42131[3],3); - BOOST_CHECK_EQUAL(de42131[4],1); - - BOOST_CHECK_EQUAL(de142131[0],1); - BOOST_CHECK_EQUAL(de142131[1],4); - BOOST_CHECK_EQUAL(de142131[2],2); - BOOST_CHECK_EQUAL(de142131[3],1); - BOOST_CHECK_EQUAL(de142131[4],3); - BOOST_CHECK_EQUAL(de142131[5],1); - - BOOST_CHECK_EQUAL(de141[0],1); - BOOST_CHECK_EQUAL(de141[1],4); - BOOST_CHECK_EQUAL(de141[2],1); - - BOOST_CHECK_EQUAL(de1111[0],1); - BOOST_CHECK_EQUAL(de1111[1],1); - BOOST_CHECK_EQUAL(de1111[2],1); - BOOST_CHECK_EQUAL(de1111[3],1); - - BOOST_CHECK_EQUAL(de14111[0],1); - BOOST_CHECK_EQUAL(de14111[1],4); - BOOST_CHECK_EQUAL(de14111[2],1); - BOOST_CHECK_EQUAL(de14111[3],1); - BOOST_CHECK_EQUAL(de14111[4],1); - - BOOST_CHECK_EQUAL(de112111[0],1); - BOOST_CHECK_EQUAL(de112111[1],1); - BOOST_CHECK_EQUAL(de112111[2],2); - BOOST_CHECK_EQUAL(de112111[3],1); - BOOST_CHECK_EQUAL(de112111[4],1); - BOOST_CHECK_EQUAL(de112111[5],1); - - BOOST_CHECK_EQUAL(de112311[0],1); - BOOST_CHECK_EQUAL(de112311[1],1); - BOOST_CHECK_EQUAL(de112311[2],2); - BOOST_CHECK_EQUAL(de112311[3],3); - BOOST_CHECK_EQUAL(de112311[4],1); - BOOST_CHECK_EQUAL(de112311[5],1); -} - -BOOST_FIXTURE_TEST_CASE(test_extents_static_size_copy_ctor, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("copy_ctor")) -{ - namespace ublas = boost::numeric::ublas; - -// auto e = de; - auto e1 = de11; - auto e12 = de12; - auto e21 = de21; - auto e23 = de23; - auto e231 = de231; - auto e123 = de123; - auto e1123 = de1123; - auto e12311 = de12311; - auto e423 = de423; - auto e4213 = de4213; - auto e42131 = de42131; - auto e142131 = de142131; - auto e141 = de141; - auto e1111 = de1111; - auto e14111 = de14111; - auto e112111 = de112111; - auto e112311 = de112311; - - -// BOOST_CHECK (ublas::empty(e) ); - -// BOOST_REQUIRE_EQUAL(ublas::size(e) , 0); - BOOST_REQUIRE_EQUAL(ublas::size(e1) , 2); - BOOST_REQUIRE_EQUAL(ublas::size(e12) , 2); - BOOST_REQUIRE_EQUAL(ublas::size(e21) , 2); - BOOST_REQUIRE_EQUAL(ublas::size(e23) , 2); - BOOST_REQUIRE_EQUAL(ublas::size(e231), 3); - BOOST_REQUIRE_EQUAL(ublas::size(e123), 3); - BOOST_REQUIRE_EQUAL(ublas::size(e1123), 4); - BOOST_REQUIRE_EQUAL(ublas::size(e12311), 5); - BOOST_REQUIRE_EQUAL(ublas::size(e423), 3); - BOOST_REQUIRE_EQUAL(ublas::size(e4213), 4); - BOOST_REQUIRE_EQUAL(ublas::size(e42131), 5); - BOOST_REQUIRE_EQUAL(ublas::size(e142131), 6); - BOOST_REQUIRE_EQUAL(ublas::size(e141), 3); - BOOST_REQUIRE_EQUAL(ublas::size(e1111), 4); - BOOST_REQUIRE_EQUAL(ublas::size(e14111), 5); - BOOST_REQUIRE_EQUAL(ublas::size(e112111), 6); - BOOST_REQUIRE_EQUAL(ublas::size(e112311), 6); - - - BOOST_CHECK_EQUAL(e1[0],1); - BOOST_CHECK_EQUAL(e1[1],1); - - BOOST_CHECK_EQUAL(e12[0],1); - BOOST_CHECK_EQUAL(e12[1],2); - - BOOST_CHECK_EQUAL(e21[0],2); - BOOST_CHECK_EQUAL(e21[1],1); - - BOOST_CHECK_EQUAL(e23[0],2); - BOOST_CHECK_EQUAL(e23[1],3); - - BOOST_CHECK_EQUAL(e231[0],2); - BOOST_CHECK_EQUAL(e231[1],3); - BOOST_CHECK_EQUAL(e231[2],1); - - BOOST_CHECK_EQUAL(e123[0],1); - BOOST_CHECK_EQUAL(e123[1],2); - BOOST_CHECK_EQUAL(e123[2],3); - - BOOST_CHECK_EQUAL(e1123[0],1); - BOOST_CHECK_EQUAL(e1123[1],1); - BOOST_CHECK_EQUAL(e1123[2],2); - BOOST_CHECK_EQUAL(e1123[3],3); - - BOOST_CHECK_EQUAL(e12311[0],1); - BOOST_CHECK_EQUAL(e12311[1],2); - BOOST_CHECK_EQUAL(e12311[2],3); - BOOST_CHECK_EQUAL(e12311[3],1); - BOOST_CHECK_EQUAL(e12311[4],1); - - BOOST_CHECK_EQUAL(e423[0],4); - BOOST_CHECK_EQUAL(e423[1],2); - BOOST_CHECK_EQUAL(e423[2],3); - - BOOST_CHECK_EQUAL(e4213[0],4); - BOOST_CHECK_EQUAL(e4213[1],2); - BOOST_CHECK_EQUAL(e4213[2],1); - BOOST_CHECK_EQUAL(e4213[3],3); - - BOOST_CHECK_EQUAL(e42131[0],4); - BOOST_CHECK_EQUAL(e42131[1],2); - BOOST_CHECK_EQUAL(e42131[2],1); - BOOST_CHECK_EQUAL(e42131[3],3); - BOOST_CHECK_EQUAL(e42131[4],1); - - BOOST_CHECK_EQUAL(e142131[0],1); - BOOST_CHECK_EQUAL(e142131[1],4); - BOOST_CHECK_EQUAL(e142131[2],2); - BOOST_CHECK_EQUAL(e142131[3],1); - BOOST_CHECK_EQUAL(e142131[4],3); - BOOST_CHECK_EQUAL(e142131[5],1); - - BOOST_CHECK_EQUAL(e141[0],1); - BOOST_CHECK_EQUAL(e141[1],4); - BOOST_CHECK_EQUAL(e141[2],1); - - BOOST_CHECK_EQUAL(e1111[0],1); - BOOST_CHECK_EQUAL(e1111[1],1); - BOOST_CHECK_EQUAL(e1111[2],1); - BOOST_CHECK_EQUAL(e1111[3],1); - - BOOST_CHECK_EQUAL(e14111[0],1); - BOOST_CHECK_EQUAL(e14111[1],4); - BOOST_CHECK_EQUAL(e14111[2],1); - BOOST_CHECK_EQUAL(e14111[3],1); - BOOST_CHECK_EQUAL(e14111[4],1); - - BOOST_CHECK_EQUAL(e112111[0],1); - BOOST_CHECK_EQUAL(e112111[1],1); - BOOST_CHECK_EQUAL(e112111[2],2); - BOOST_CHECK_EQUAL(e112111[3],1); - BOOST_CHECK_EQUAL(e112111[4],1); - BOOST_CHECK_EQUAL(e112111[5],1); - - BOOST_CHECK_EQUAL(e112311[0],1); - BOOST_CHECK_EQUAL(e112311[1],1); - BOOST_CHECK_EQUAL(e112311[2],2); - BOOST_CHECK_EQUAL(e112311[3],3); - BOOST_CHECK_EQUAL(e112311[4],1); - BOOST_CHECK_EQUAL(e112311[5],1); - -} - -BOOST_FIXTURE_TEST_CASE(test_extents_static_size_is, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("query")) -{ - namespace ublas = boost::numeric::ublas; - - -// auto e = de; - auto e11 = de11; - auto e12 = de12; - auto e21 = de21; - auto e23 = de23; - auto e231 = de231; - auto e123 = de123; - auto e1123 = de1123; - auto e12311 = de12311; - auto e423 = de423; - auto e4213 = de4213; - auto e42131 = de42131; - auto e142131 = de142131; - auto e141 = de141; - auto e1111 = de1111; - auto e14111 = de14111; - auto e112111 = de112111; - auto e112311 = de112311; - -// BOOST_CHECK( ublas::empty (e)); -// BOOST_CHECK( ! ublas::is_scalar(e)); -// BOOST_CHECK( ! ublas::is_vector(e)); -// BOOST_CHECK( ! ublas::is_matrix(e)); -// BOOST_CHECK( ! ublas::is_tensor(e)); - - BOOST_CHECK( ! ublas::empty (e11) ); - BOOST_CHECK( ublas::is_scalar(e11) ); - BOOST_CHECK( ublas::is_vector(e11) ); - BOOST_CHECK( ublas::is_matrix(e11) ); - BOOST_CHECK( ! ublas::is_tensor(e11) ); - - BOOST_CHECK( ! ublas::empty (e12) ); - BOOST_CHECK( ! ublas::is_scalar(e12) ); - BOOST_CHECK( ublas::is_vector(e12) ); - BOOST_CHECK( ublas::is_matrix(e12) ); - BOOST_CHECK( ! ublas::is_tensor(e12) ); - - BOOST_CHECK( ! ublas::empty (e21) ); - BOOST_CHECK( ! ublas::is_scalar(e21) ); - BOOST_CHECK( ublas::is_vector(e21) ); - BOOST_CHECK( ublas::is_matrix(e21) ); - BOOST_CHECK( ! ublas::is_tensor(e21) ); - - BOOST_CHECK( ! ublas::empty (e23) ); - BOOST_CHECK( ! ublas::is_scalar(e23) ); - BOOST_CHECK( ! ublas::is_vector(e23) ); - BOOST_CHECK( ublas::is_matrix(e23) ); - BOOST_CHECK( ! ublas::is_tensor(e23) ); - - BOOST_CHECK( ! ublas::empty (e231) ); - BOOST_CHECK( ! ublas::is_scalar(e231) ); - BOOST_CHECK( ! ublas::is_vector(e231) ); - BOOST_CHECK( ublas::is_matrix(e231) ); - BOOST_CHECK( ! ublas::is_tensor(e231) ); - - BOOST_CHECK( ! ublas::empty (e123) ); - BOOST_CHECK( ! ublas::is_scalar(e123) ); - BOOST_CHECK( ! ublas::is_vector(e123) ); - BOOST_CHECK( ! ublas::is_matrix(e123) ); - BOOST_CHECK( ublas::is_tensor(e123) ); - - BOOST_CHECK( ! ublas::empty (e1123) ); - BOOST_CHECK( ! ublas::is_scalar(e1123) ); - BOOST_CHECK( ! ublas::is_vector(e1123) ); - BOOST_CHECK( ! ublas::is_matrix(e1123) ); - BOOST_CHECK( ublas::is_tensor(e1123) ); - - BOOST_CHECK( ! ublas::empty (e12311) ); - BOOST_CHECK( ! ublas::is_scalar(e12311) ); - BOOST_CHECK( ! ublas::is_vector(e12311) ); - BOOST_CHECK( ! ublas::is_matrix(e12311) ); - BOOST_CHECK( ublas::is_tensor(e12311) ); - - BOOST_CHECK( ! ublas::empty (e423) ); - BOOST_CHECK( ! ublas::is_scalar(e423) ); - BOOST_CHECK( ! ublas::is_vector(e423) ); - BOOST_CHECK( ! ublas::is_matrix(e423) ); - BOOST_CHECK( ublas::is_tensor(e423) ); - - BOOST_CHECK( ! ublas::empty (e4213) ); - BOOST_CHECK( ! ublas::is_scalar(e4213) ); - BOOST_CHECK( ! ublas::is_vector(e4213) ); - BOOST_CHECK( ! ublas::is_matrix(e4213) ); - BOOST_CHECK( ublas::is_tensor(e4213) ); - - BOOST_CHECK( ! ublas::empty (e42131) ); - BOOST_CHECK( ! ublas::is_scalar(e42131) ); - BOOST_CHECK( ! ublas::is_vector(e42131) ); - BOOST_CHECK( ! ublas::is_matrix(e42131) ); - BOOST_CHECK( ublas::is_tensor(e42131) ); - - BOOST_CHECK( ! ublas::empty (e142131) ); - BOOST_CHECK( ! ublas::is_scalar(e142131) ); - BOOST_CHECK( ! ublas::is_vector(e142131) ); - BOOST_CHECK( ! ublas::is_matrix(e142131) ); - BOOST_CHECK( ublas::is_tensor(e142131) ); - - BOOST_CHECK( ! ublas::empty (e141) ); - BOOST_CHECK( ! ublas::is_scalar(e141) ); - BOOST_CHECK( ublas::is_vector(e141) ); - BOOST_CHECK( ublas::is_matrix(e141) ); - BOOST_CHECK( ! ublas::is_tensor(e141) ); - - BOOST_CHECK( ! ublas::empty (e1111) ); - BOOST_CHECK( ublas::is_scalar(e1111) ); - BOOST_CHECK( ublas::is_vector(e1111) ); - BOOST_CHECK( ublas::is_matrix(e1111) ); - BOOST_CHECK( ! ublas::is_tensor(e1111) ); - - BOOST_CHECK( ! ublas::empty (e14111) ); - BOOST_CHECK( ! ublas::is_scalar(e14111) ); - BOOST_CHECK( ublas::is_vector(e14111) ); - BOOST_CHECK( ublas::is_matrix(e14111) ); - BOOST_CHECK( ! ublas::is_tensor(e14111) ); - - BOOST_CHECK( ! ublas::empty (e112111) ); - BOOST_CHECK( ! ublas::is_scalar(e112111) ); - BOOST_CHECK( ! ublas::is_vector(e112111) ); - BOOST_CHECK( ! ublas::is_matrix(e112111) ); - BOOST_CHECK( ublas::is_tensor(e112111) ); - - BOOST_CHECK( ! ublas::empty (e112311) ); - BOOST_CHECK( ! ublas::is_scalar(e112311) ); - BOOST_CHECK( ! ublas::is_vector(e112311) ); - BOOST_CHECK( ! ublas::is_matrix(e112311) ); - BOOST_CHECK( ublas::is_tensor(e112311) ); -} - -//BOOST_FIXTURE_TEST_CASE(test_extents_static_size_squeeze, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("squeeze")) -//{ -// auto e1 = squeeze(de1); // {1,1} -// auto e2 = squeeze(de2); // {1,2} -// auto 21 = squeeze(d21); // {2,1} - -// auto e4 = squeeze(de4); // {2,3} -// auto e231 = squeeze(de231); // {2,3} -// auto e123 = squeeze(de123); // {2,3} -// auto e1123 = squeeze(de1123); // {2,3} -// auto e12311 = squeeze(de12311); // {2,3} - -// auto e423 = squeeze(de423); // {4,2,3} -// auto e4213 = squeeze(de4213); // {4,2,3} -// auto e11 = squeeze(de11); // {4,2,3} -// auto e12 = squeeze(e142131); // {4,2,3} - -// auto e141 = squeeze(de141); // {1,4} -// auto e1111 = squeeze(de1111); // {1,1} -// auto e14111 = squeeze(de14111); // {1,4} -// auto e112111 = squeeze(de112111); // {2,1} -// auto e112311 = squeeze(de112311); // {2,3} - -// BOOST_CHECK( (e1 == extents<2>{1,1}) ); -// BOOST_CHECK( (e2 == extents<2>{1,2}) ); -// BOOST_CHECK( (21 == extents<2>{2,1}) ); - -// BOOST_CHECK( (e4 == extents<2>{2,3}) ); -// BOOST_CHECK( (e231 == extents<2>{2,3}) ); -// BOOST_CHECK( (e123 == extents<2>{2,3}) ); -// BOOST_CHECK( (e1123 == extents<2>{2,3}) ); -// BOOST_CHECK( (e12311 == extents<2>{2,3}) ); - -// BOOST_CHECK( (e423 == extents<3>{4,2,3}) ); -// BOOST_CHECK( (e4213 == extents<3>{4,2,3}) ); -// BOOST_CHECK( (e11 == extents<3>{4,2,3}) ); -// BOOST_CHECK( (e12 == extents<3>{4,2,3}) ); - -// BOOST_CHECK( (e141 == extents<2>{1,4}) ); -// BOOST_CHECK( (e1111 == extents<2>{1,1}) ); -// BOOST_CHECK( (e14111 == extents<2>{1,4}) ); -// BOOST_CHECK( (e112111 == extents<2>{2,1}) ); -// BOOST_CHECK( (e112311 == extents<2>{2,3}) ); - -//} - - -BOOST_FIXTURE_TEST_CASE(test_extents_static_size_product, fixture, *boost::unit_test::label("basic_fixed_rank_extents") *boost::unit_test::label("product")) -{ - namespace ublas = boost::numeric::ublas; - -// auto e = ublas::product( de ); - auto e11 = ublas::product( de11 ); - auto e12 = ublas::product( de12 ); - auto e21 = ublas::product( de21 ); - auto e23 = ublas::product( de23 ); - auto e231 = ublas::product( de231 ); - auto e123 = ublas::product( de123 ); - auto e1123 = ublas::product( de1123 ); - auto e12311 = ublas::product( de12311 ); - auto e423 = ublas::product( de423 ); - auto e4213 = ublas::product( de4213 ); - auto e42131 = ublas::product( de42131 ); - auto e142131 = ublas::product( de142131 ); - auto e141 = ublas::product( de141 ); - auto e1111 = ublas::product( de1111 ); - auto e14111 = ublas::product( de14111 ); - auto e112111 = ublas::product( de112111 ); - auto e112311 = ublas::product( de112311 ); - -// BOOST_CHECK_EQUAL( e , 0 ); - BOOST_CHECK_EQUAL( e11 , 1 ); - BOOST_CHECK_EQUAL( e12 , 2 ); - BOOST_CHECK_EQUAL( e21 , 2 ); - BOOST_CHECK_EQUAL( e23 , 6 ); - BOOST_CHECK_EQUAL( e231 , 6 ); - BOOST_CHECK_EQUAL( e123 , 6 ); - BOOST_CHECK_EQUAL( e1123 , 6 ); - BOOST_CHECK_EQUAL( e12311 , 6 ); - BOOST_CHECK_EQUAL( e423 , 24 ); - BOOST_CHECK_EQUAL( e4213 , 24 ); - BOOST_CHECK_EQUAL( e42131 , 24 ); - BOOST_CHECK_EQUAL( e142131, 24 ); - BOOST_CHECK_EQUAL( e141 , 4 ); - BOOST_CHECK_EQUAL( e1111 , 1 ); - BOOST_CHECK_EQUAL( e14111 , 4 ); - BOOST_CHECK_EQUAL( e112111, 2 ); - BOOST_CHECK_EQUAL( e112311, 6 ); - - -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_functions.cpp b/test/tensor/test_fixed_rank_functions.cpp deleted file mode 100644 index df3d4ce80..000000000 --- a/test/tensor/test_fixed_rank_functions.cpp +++ /dev/null @@ -1,460 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// -// And we acknowledge the support from all contributors. - - -#include -#include -#include -#include -#include - -#include - -#include "utility.hpp" - -// BOOST_AUTO_TEST_SUITE ( test_tensor_functions, * boost::unit_test::depends_on("test_tensor_contraction") ) -BOOST_AUTO_TEST_SUITE ( test_tensor_extents_static_size_functions) - - -using test_types = zip>::with_t; - -//using test_types = zip::with_t; - - -struct fixture -{ - std::tuple< - boost::numeric::ublas::extents<2>, - boost::numeric::ublas::extents<2>, - boost::numeric::ublas::extents<3>, - boost::numeric::ublas::extents<3>, - boost::numeric::ublas::extents<4> - > extents_tuple{ - {1,1}, // 1 - {2,3}, // 2 - {2,3,1}, // 3 - {4,2,3}, // 4 - {4,2,3,5} // 5 - }; - - - std::vector> extents_vector = - { - {1,1}, // 1 - {2,3}, // 2 - {2,3,1}, // 3 - {4,2,3}, // 4 - {4,2,3,5} // 5 - }; - -}; - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_prod_vector, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - for_each_in_tuple(extents_tuple,[](auto const& /*unused*/, auto const& n){ - - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - using vector_t = typename tensor_t::vector_type; - auto a = tensor_t(n); - a = 2; - - for (auto m = 0u; m < ublas::size(n); ++m) { - auto b = vector_t(n[m], value_t{1}); - - auto c = ublas::prod(a, b, m + 1); - - for (auto i = 0u; i < c.size(); ++i) - BOOST_CHECK_EQUAL(c[i], value_t( static_cast< inner_type_t >(n[m]) ) * a[i]); - } - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_prod_matrix, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - for_each_in_tuple(extents_tuple,[](auto const& /*unused*/, auto const & n){ - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - using matrix_t = typename tensor_t::matrix_type; - - auto a = tensor_t(n); - a = 2; - for (auto m = 0u; m < ublas::size(n); ++m) { - - auto b = matrix_t ( n[m], n[m], value_t{1} ); - auto c = ublas::prod(a, b, m + 1); - - for (auto i = 0u; i < c.size(); ++i){ - BOOST_CHECK_EQUAL(c[i], value_t( static_cast< inner_type_t >(n[m]) ) * a[i]); - } - } - }); - -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_prod_tensor_1, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - - auto check = [&](auto const& a, auto const& b, std::index_sequence /*unused*/) - { - namespace ublas = boost::numeric::ublas; - - constexpr auto q = sizeof...(qs); - - using tensorA = std::decay_t; - using tensorB = std::decay_t; - - using extentsA = typename tensorA::extents_type; - using extentsB = typename tensorB::extents_type; - - static_assert(!ublas::is_static_v && !ublas::is_static_v ); - - constexpr auto one_of_extents_is_resizable = ublas::is_dynamic_rank_v || - ublas::is_dynamic_rank_v; - - using phi_type = std::conditional_t, - std::array >; - - auto phi = phi_type{}; - if constexpr(std::is_same_v>){ - phi.resize(q); - } - std::iota(phi.begin(), phi.end(), std::size_t{1}); - auto c = ublas::prod(a, b, phi); - - auto const& na = a.extents(); - auto acc = std::size_t{1}; - for (auto i = 0ul; i < q; ++i){ - acc *= na.at(phi.at(i)-1); - } - const auto v = value_t(acc) * a[0] * b[0]; - BOOST_CHECK( std::all_of(c.begin(),c.end(),[v](auto cc){ return cc == v;})); - }; - - - for_each_in_tuple(extents_tuple,[&](auto const& /*I*/, auto const& n){ - constexpr auto size = std::tuple_size_v>; - constexpr auto modes = std::make_index_sequence{}; - using tensor_t = ublas::tensor_static_rank; - auto a = tensor_t(n); - auto b = tensor_t(n); - a = 2; - b = 3; - for_each_in_index(modes, a,b, check ); - }); - - for_each_in_tuple(extents_tuple,[&](auto const& I, auto const& n){ - auto const& nA = n; - auto const& nB = extents_vector[I]; - constexpr auto sizeA = std::tuple_size_v>; - constexpr auto modes = std::make_index_sequence{}; - using tensorA_type = ublas::tensor_static_rank; - using tensorB_type = ublas::tensor_dynamic; - auto a = tensorA_type(nA); - auto b = tensorB_type(nB); - a = 2; - b = 3; - - for_each_in_index(modes, a,b, check ); - }); - - for_each_in_tuple(extents_tuple,[&](auto const& I, auto const& n){ - auto const& nA = extents_vector[I]; - auto const& nB = n; - constexpr auto sizeB = std::tuple_size_v>; - constexpr auto modes = std::make_index_sequence{}; - using tensor_t_1 = ublas::tensor_dynamic; - using tensor_t_2 = ublas::tensor_static_rank; - auto a = tensor_t_1(nA); - auto b = tensor_t_2(nB); - a = 2; - b = 3; - for_each_in_index(modes, a,b, check ); - - }); -} - -// TODO: -#if 0 - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_prod_tensor_2, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - constexpr auto to_array = [](std::index_sequence/*unused*/) { - return std::array{is...}; - }; - - auto compute_factorial = [](std::index_sequence/*unused*/) { - return ( 1 * ... * is ); - }; - /* - auto compute_factorial = [](auto const& p){ - auto f = 1ul; - for(auto i = 1u; i <= p; ++i) - f *= i; - return f; - }; -*/ - auto permute_extents_dynamic_rank = [](auto const& pi, auto const& na){ - auto nb = ublas::extents<>(na.begin(),na.end()); - assert(std::size(pi) == ublas::size(na)); - for(auto j = 0u; j < std::size(pi); ++j) - nb[pi[j]-1] = na[j]; - return nb; - }; - - auto permute_extents_static_rank = [](std::array const& pi, auto const& na){ - //constexpr auto size = std::tuple_size_v>; - auto na_base = na.base(); - assert(std::size(pi) == size); - for(auto j = 0u; j < std::size(pi); ++j) - na_base[pi[j]-1] = na[j]; - return ublas::extents(na_base.begin(),na_base.end()); - }; - - for_each_in_tuple(extents_tuple,[&](auto const& /*unused*/, auto const& n){ - auto const& na = n; - constexpr auto size = std::tuple_size_v>; - using tensorA_type = ublas::tensor_static_rank; - auto a = tensorA_type(na); - a = 2; - assert(a.rank() == size); - // auto const pa = a.rank(); - auto pi = to_array(std::make_index_sequence{}); - constexpr auto factorial = compute_factorial(std::make_index_sequence{}); - // auto pi = std::vector(pa); - // auto fac = compute_factorial(pa); - // std::iota(pi.begin(), pi.end(), 1); - - constexpr auto factorials = std::make_index_sequence{}; - - // for_each_in_tuple(factorials,[&](auto const& /*unused*/, auto const& /*unused*/){ - // using tensorB_type = ublas::tensor_dynamic; - // const auto nb = permute_extents_dynamic_rank(pi, na); - // const auto b = tensorB_type(nb, value_t{3}); - - // constexpr auto modes = std::make_index_sequence{}; - - // for_each_in_tuple(modes,[&](auto const& /*unused*/, auto const& /*unused*/){ - - - // const auto phia = to_array(std::make_index_sequence); - // const auto phib = std::array(q); - - // }); - - // for (auto f = 0ul; f < fac; ++f) { - // for (auto q = 0ul; q <= pa; ++q) { - - // auto phia = std::vector(q); - // auto phib = std::vector(q); - - // 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_t(1); - // for (auto i = 0ul; i < q; ++i) - // acc *= value_t( static_cast< inner_type_t >( 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()); - // } - }); - - for_each_in_tuple(extents_tuple,[&](auto const& /*unused*/, auto & /*n*/){ - // auto const& na = n; - // constexpr auto size = std::tuple_size_v>; - // using tensor_t_1 = ublas::tensor_static_rank; - // auto a = tensor_t_1(na, value_t{2}); - // auto const pa = a.rank(); - - // auto pi = std::vector(pa); - // auto fac = compute_factorial(pa); - // std::iota(pi.begin(), pi.end(), 1); - - // for (auto f = 0ul; f < fac; ++f) { - // auto nb = permute_extents_static_rank(pi, na); - - // using tensor_t_2 = ublas::tensor_static_rank; - // auto b = tensor_t_2(nb, value_t{3}); - - // for (auto q = 0ul; q <= pa; ++q) { - - // auto phia = std::vector(q); - // auto phib = std::vector(q); - - // 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_t(1); - // for (auto i = 0ul; i < q; ++i){ - // acc *= value_t( static_cast< inner_type_t >( 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()); - // } - }); - -} -#endif - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_inner_prod, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - - using dtensor_t = ublas::tensor_dynamic; - - auto const body = [&](auto const& a, auto const& b){ - auto c = ublas::inner_prod(a, b); - auto r = std::inner_product(a.begin(),a.end(), b.begin(),value_t(0)); - BOOST_CHECK_EQUAL( c , r ); - }; - - for_each_in_tuple(extents_tuple,[&](auto const& /*unused*/, auto & n){ - constexpr auto size = std::tuple_size_v>; - using stensor_t = ublas::tensor_static_rank; - auto a = stensor_t(n); - auto b = stensor_t(n); - a = 2; - b = 3; - body(a,b); - - }); - - for_each_in_tuple(extents_tuple,[&](auto const& I, auto & n){ - constexpr auto size = std::tuple_size_v>; - using stensor_t = ublas::tensor_static_rank; - auto a = stensor_t(n); - auto b = dtensor_t(extents_vector[I]); - a = 2; - b = 1; - - body(a,b); - - }); - - for_each_in_tuple(extents_tuple,[&](auto const& I, auto & n){ - constexpr auto size = std::tuple_size_v>; - using stensor_t = ublas::tensor_static_rank; - auto a = dtensor_t(extents_vector[I]); - auto b = stensor_t(n); - a = 2; - b = 1; - body(a,b); - - }); - -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_extents_static_size_outer_prod, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - for_each_in_tuple(extents_tuple,[&](auto const& /*unused*/, auto const& n1){ - constexpr auto size1 = std::tuple_size_v>; - using tensor_t_1 = ublas::tensor_static_rank; - auto a = tensor_t_1(n1); - a = 2; - for_each_in_tuple(extents_tuple,[&](auto const& /*J*/, auto const& n2){ - constexpr auto size2 = std::tuple_size_v>; - using tensor_t_2 = ublas::tensor_static_rank; - auto b = tensor_t_2(n2); - b = 1; - auto c = ublas::outer_prod(a, b); - - BOOST_CHECK ( std::all_of(c.begin(),c.end(), [&a,&b](auto cc){return cc == a[0]*b[0];}) ); - - }); - - }); - - for_each_in_tuple(extents_tuple,[&](auto const& I, auto const& /*n1*/){ - using tensor_t_1 = ublas::tensor_dynamic; - auto a = tensor_t_1(extents_vector[I]); - a = 2; - for_each_in_tuple(extents_tuple,[&](auto const& /*J*/, auto const& n2){ - constexpr auto size = std::tuple_size_v>; - using tensor_t_2 = ublas::tensor_static_rank; - auto b = tensor_t_2(n2); - b = 1; - auto c = ublas::outer_prod(a, b); - BOOST_CHECK ( std::all_of(c.begin(),c.end(), [&a,&b](auto cc){return cc == a[0]*b[0];}) ); - - -// for(auto const& cc : c) -// BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - }); - - }); - - for_each_in_tuple(extents_tuple,[&](auto const& /*unused*/, auto const& n1){ - constexpr auto size = std::tuple_size_v>; - using tensor_t_1 = ublas::tensor_static_rank; - auto a = tensor_t_1(n1); - a = 2; - for(auto const& n2 : extents_vector){ - using tensor_t_2 = ublas::tensor_dynamic; - auto b = tensor_t_2(n2); - b = 1; - auto c = ublas::outer_prod(a, b); - - BOOST_CHECK ( std::all_of(c.begin(),c.end(), [&a,&b](auto cc){return cc == a[0]*b[0];}) ); - -// for(auto const& cc : c) -// BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - } - - }); - -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_operators_arithmetic.cpp b/test/tensor/test_fixed_rank_operators_arithmetic.cpp deleted file mode 100644 index 08ef6b8f9..000000000 --- a/test/tensor/test_fixed_rank_operators_arithmetic.cpp +++ /dev/null @@ -1,238 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - - -#include - -#include -#include -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE(test_tensor_static_rank_arithmetic_operations) - -using double_extended = boost::multiprecision::cpp_bin_float_double_extended; - -using test_types = zip::with_t; - -struct fixture -{ - template - using extents_t = boost::numeric::ublas::extents; - - std::tuple< - extents_t<2>, // 1 - extents_t<2>, // 2 - extents_t<3>, // 3 - extents_t<3>, // 4 - extents_t<4> // 5 - > extents = { - extents_t<2>{1,1}, - extents_t<2>{2,3}, - extents_t<3>{4,1,3}, - extents_t<3>{4,2,3}, - extents_t<4>{4,2,3,5} - }; -}; - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) - { - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - auto t = tensor_t (e); - auto t2 = tensor_t (e); - auto r = tensor_t (e); - auto v = value_t {}; - - 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 = 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_each_in_tuple(extents,check); -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) - { - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - auto t = tensor_t (e); - auto t2 = tensor_t (e); - auto v = value_t {}; - - std::iota(t.begin(), t.end(), v); - std::iota(t2.begin(), t2.end(), v+2); - - tensor_t r1 = t + 2 + t + 2; - - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r1(i), 2*t(i) + 4 ); - - tensor_t r2 = 2 + t + 2 + t; - - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r2(i), 2*t(i) + 4 ); - - tensor_t r3 = (t-2) + (t-2); - - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r3(i), 2*t(i) - 4 ); - - tensor_t 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_t 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_t 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_each_in_tuple(extents,check); -} - - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_assign_arithmetic_operations, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) - { - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - auto t = tensor_t (e); - auto t2 = tensor_t (e); - auto r = tensor_t (e); - auto v = value_t {}; - - 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_t q = -r; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( q(i), -r(i) ); - - tensor_t p = +r; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( p(i), r(i) ); - }; - - for_each_in_tuple(extents,check); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_operators_comparison.cpp b/test/tensor/test_fixed_rank_operators_comparison.cpp deleted file mode 100644 index 59338c387..000000000 --- a/test/tensor/test_fixed_rank_operators_comparison.cpp +++ /dev/null @@ -1,197 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - - -#include -#include -#include -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE(test_tensor_static_rank_comparison) - -using double_extended = boost::multiprecision::cpp_bin_float_double_extended; - -using test_types = zip::with_t; - -struct fixture { - template - using extents_t = boost::numeric::ublas::extents; - - std::tuple< - extents_t<2>, // 1 - extents_t<2>, // 2 - extents_t<3>, // 3 - extents_t<3>, // 4 - extents_t<4> // 5 - > extents = { - extents_t<2>{1,1}, - extents_t<2>{2,3}, - extents_t<3>{4,1,3}, - extents_t<3>{4,2,3}, - extents_t<4>{4,2,3,5} - }; -}; - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - auto check = [](auto const& /*unused*/, auto& e) - { - using extents_t = std::decay_t; - using tensor_t = ublas::tensor_static_rank, layout_t>; - auto t = tensor_t (e); - auto t2 = tensor_t (e); - auto v = value_t {}; - - 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_each_in_tuple(extents,check); - -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - - for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e) { - using extents_t = std::decay_t; - using tensor_t = ublas::tensor_static_rank, layout_t>; - - auto t = tensor_t (e); - auto t2 = tensor_t (e); - auto v = value_t {}; - - 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 ); - }); - - -} - - - -//BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_scalar, value, test_types, fixture) -//{ -// namespace ublas = boost::numeric::ublas; -// using value_t = typename value::first_type; -// using layout_t = typename value::second_type; - - -// for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e) { -// using extents_t = std::decay_t; -// using tensor_t = ublas::tensor_static_rank, layout_t>; - -// BOOST_CHECK( tensor_t(e,value_t{2}) == tensor_t(e,value_t{2}) ); -// BOOST_CHECK( tensor_t(e,value_t{2}) != tensor_t(e,value_t{1}) ); - -// if(ublas::empty(e)) -// return; - -// BOOST_CHECK( !(tensor_t(e,2) < 2) ); -// BOOST_CHECK( !(tensor_t(e,2) > 2) ); -// BOOST_CHECK( (tensor_t(e,2) >= 2) ); -// BOOST_CHECK( (tensor_t(e,2) <= 2) ); -// BOOST_CHECK( (tensor_t(e,2) == 2) ); -// BOOST_CHECK( (tensor_t(e,2) != 3) ); - -// BOOST_CHECK( !(2 > tensor_t(e,2)) ); -// BOOST_CHECK( !(2 < tensor_t(e,2)) ); -// BOOST_CHECK( (2 <= tensor_t(e,2)) ); -// BOOST_CHECK( (2 >= tensor_t(e,2)) ); -// BOOST_CHECK( (2 == tensor_t(e,2)) ); -// BOOST_CHECK( (3 != tensor_t(e,2)) ); - -// BOOST_CHECK( !( tensor_t(e,2)+3 < 5) ); -// BOOST_CHECK( !( tensor_t(e,2)+3 > 5) ); -// BOOST_CHECK( ( tensor_t(e,2)+3 >= 5) ); -// BOOST_CHECK( ( tensor_t(e,2)+3 <= 5) ); -// BOOST_CHECK( ( tensor_t(e,2)+3 == 5) ); -// BOOST_CHECK( ( tensor_t(e,2)+3 != 6) ); - - -// BOOST_CHECK( !( 5 > tensor_t(e,2)+3) ); -// BOOST_CHECK( !( 5 < tensor_t(e,2)+3) ); -// BOOST_CHECK( ( 5 >= tensor_t(e,2)+3) ); -// BOOST_CHECK( ( 5 <= tensor_t(e,2)+3) ); -// BOOST_CHECK( ( 5 == tensor_t(e,2)+3) ); -// BOOST_CHECK( ( 6 != tensor_t(e,2)+3) ); - - -// BOOST_CHECK( !( tensor_t(e,2)+tensor_t(e,3) < 5) ); -// BOOST_CHECK( !( tensor_t(e,2)+tensor_t(e,3) > 5) ); -// BOOST_CHECK( ( tensor_t(e,2)+tensor_t(e,3) >= 5) ); -// BOOST_CHECK( ( tensor_t(e,2)+tensor_t(e,3) <= 5) ); -// BOOST_CHECK( ( tensor_t(e,2)+tensor_t(e,3) == 5) ); -// BOOST_CHECK( ( tensor_t(e,2)+tensor_t(e,3) != 6) ); - - -// BOOST_CHECK( !( 5 > tensor_t(e,2)+tensor_t(e,3)) ); -// BOOST_CHECK( !( 5 < tensor_t(e,2)+tensor_t(e,3)) ); -// BOOST_CHECK( ( 5 >= tensor_t(e,2)+tensor_t(e,3)) ); -// BOOST_CHECK( ( 5 <= tensor_t(e,2)+tensor_t(e,3)) ); -// BOOST_CHECK( ( 5 == tensor_t(e,2)+tensor_t(e,3)) ); -// BOOST_CHECK( ( 6 != tensor_t(e,2)+tensor_t(e,3)) ); - -// }); - -//} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_strides.cpp b/test/tensor/test_fixed_rank_strides.cpp deleted file mode 100644 index c7efd6413..000000000 --- a/test/tensor/test_fixed_rank_strides.cpp +++ /dev/null @@ -1,184 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#if 0 - -#include -#include -#include - -BOOST_AUTO_TEST_SUITE(test_fixed_rank_strides) - -using test_types = std::tuple; - -template -using strides =boost::numeric::ublas::strides,L>; - -BOOST_AUTO_TEST_CASE_TEMPLATE( test_fixed_rank_strides_ctor, value, test_types) -{ - namespace ublas = boost::numeric::ublas; -// using layout_type = value; -// constexpr auto layout = value{}; - - auto s0 = strides<0,value>{}; - auto s1 = strides<1,value>({1} ); - auto s3 = strides<1,value>({3} ); - auto s11 = strides<2,value>({1,1} ); - auto s12 = strides<2,value>({1,2} ); - auto s21 = strides<2,value>({2,1} ); - auto s23 = strides<2,value>({2,3} ); - auto s231 = strides<3,value>({2,3,1} ); - auto s123 = strides<3,value>({1,2,3} ); - auto s423 = strides<3,value>({4,2,3} ); - - BOOST_CHECK ( s0.empty()); - BOOST_CHECK (! s1.empty()); - BOOST_CHECK (! s3.empty()); - BOOST_CHECK (! s11.empty()); - BOOST_CHECK (! s12.empty()); - BOOST_CHECK (! s21.empty()); - BOOST_CHECK (! s23.empty()); - BOOST_CHECK (!s231.empty()); - BOOST_CHECK (!s123.empty()); - BOOST_CHECK (!s423.empty()); - - - BOOST_CHECK_EQUAL ( s0.size(), 0); - BOOST_CHECK_EQUAL ( s1.size(), 3); - BOOST_CHECK_EQUAL ( s3.size(), 1); - BOOST_CHECK_EQUAL ( s11.size(), 2); - BOOST_CHECK_EQUAL ( s12.size(), 2); - BOOST_CHECK_EQUAL ( s21.size(), 2); - BOOST_CHECK_EQUAL ( s23.size(), 2); - BOOST_CHECK_EQUAL ( s231.size(), 3); - BOOST_CHECK_EQUAL ( s123.size(), 3); - BOOST_CHECK_EQUAL ( s423.size(), 3); -} - - -BOOST_AUTO_TEST_CASE( test_fixed_rank_strides_ctor_access_first_order) -{ - using value = boost::numeric::ublas::layout::first_order; -// constexpr auto layout = boost::numeric::ublas::layout::first_order{}; - - auto s1 = strides<1,value>({1} ); - auto s3 = strides<1,value>({3} ); - auto s11 = strides<2,value>({1,1} ); - auto s12 = strides<2,value>({1,2} ); - auto s21 = strides<2,value>({2,1} ); - auto s23 = strides<2,value>({2,3} ); - auto s231 = strides<3,value>({2,3,1} ); - auto s213 = strides<3,value>({2,3,1} ); - auto s123 = strides<3,value>({1,2,3} ); - auto s423 = strides<3,value>({4,2,3} ); - - - BOOST_REQUIRE_EQUAL ( s1.size(),1); - BOOST_REQUIRE_EQUAL ( s3.size(),1); - BOOST_REQUIRE_EQUAL ( s11.size(),2); - BOOST_REQUIRE_EQUAL ( s12.size(),2); - BOOST_REQUIRE_EQUAL ( s21.size(),2); - BOOST_REQUIRE_EQUAL ( s23.size(),2); - BOOST_REQUIRE_EQUAL ( s231.size(),3); - BOOST_REQUIRE_EQUAL ( s213.size(),3); - BOOST_REQUIRE_EQUAL ( s123.size(),3); - BOOST_REQUIRE_EQUAL ( s423.size(),3); - - BOOST_CHECK_EQUAL ( s11[0], 1); - BOOST_CHECK_EQUAL ( s11[1], 1); - - BOOST_CHECK_EQUAL ( s12[0], 1); - BOOST_CHECK_EQUAL ( s12[1], 1); - - BOOST_CHECK_EQUAL ( s21[0], 1); - BOOST_CHECK_EQUAL ( s21[1], 1); - - BOOST_CHECK_EQUAL ( s23[0], 1); - BOOST_CHECK_EQUAL ( s23[1], 2); - - BOOST_CHECK_EQUAL ( s231[0], 1); - BOOST_CHECK_EQUAL ( s231[1], 2); - BOOST_CHECK_EQUAL ( s231[2], 6); - - BOOST_CHECK_EQUAL ( s123[0], 1); - BOOST_CHECK_EQUAL ( s123[1], 1); - BOOST_CHECK_EQUAL ( s123[2], 2); - - BOOST_CHECK_EQUAL ( s213[0], 1); - BOOST_CHECK_EQUAL ( s213[1], 2); - BOOST_CHECK_EQUAL ( s213[2], 2); - - BOOST_CHECK_EQUAL ( s423[0], 1); - BOOST_CHECK_EQUAL ( s423[1], 4); - BOOST_CHECK_EQUAL ( s423[2], 8); -} - -BOOST_AUTO_TEST_CASE( test_fixed_rank_strides_ctor_access_last_order) -{ - using value = boost::numeric::ublas::layout::first_order; - // constexpr auto layout = boost::numeric::ublas::layout::first_order{}; - - auto s1 = strides<1,value>({1} ); - auto s3 = strides<1,value>({3} ); - auto s11 = strides<2,value>({1,1} ); - auto s12 = strides<2,value>({1,2} ); - auto s21 = strides<2,value>({2,1} ); - auto s23 = strides<2,value>({2,3} ); - auto s231 = strides<3,value>({2,3,1} ); - auto s213 = strides<3,value>({2,3,1} ); - auto s123 = strides<3,value>({1,2,3} ); - auto s423 = strides<3,value>({4,2,3} ); - - BOOST_REQUIRE_EQUAL ( s1.size(),1); - BOOST_REQUIRE_EQUAL ( s3.size(),1); - BOOST_REQUIRE_EQUAL ( s11.size(),2); - BOOST_REQUIRE_EQUAL ( s12.size(),2); - BOOST_REQUIRE_EQUAL ( s21.size(),2); - BOOST_REQUIRE_EQUAL ( s23.size(),2); - BOOST_REQUIRE_EQUAL ( s231.size(),3); - BOOST_REQUIRE_EQUAL ( s213.size(),3); - BOOST_REQUIRE_EQUAL ( s123.size(),3); - BOOST_REQUIRE_EQUAL ( s423.size(),3); - - BOOST_CHECK_EQUAL ( s11[0], 1); - BOOST_CHECK_EQUAL ( s11[1], 1); - - BOOST_CHECK_EQUAL ( s12[0], 1); - BOOST_CHECK_EQUAL ( s12[1], 1); - - BOOST_CHECK_EQUAL ( s21[0], 1); - BOOST_CHECK_EQUAL ( s21[1], 1); - - BOOST_CHECK_EQUAL ( s23[0], 3); - BOOST_CHECK_EQUAL ( s23[1], 1); - - BOOST_CHECK_EQUAL ( s231[0], 3); - BOOST_CHECK_EQUAL ( s231[1], 1); - BOOST_CHECK_EQUAL ( s231[2], 1); - - BOOST_CHECK_EQUAL ( s123[0], 6); - BOOST_CHECK_EQUAL ( s123[1], 3); - BOOST_CHECK_EQUAL ( s123[2], 1); - - BOOST_CHECK_EQUAL ( s213[0], 3); - BOOST_CHECK_EQUAL ( s213[1], 3); - BOOST_CHECK_EQUAL ( s213[2], 1); - - BOOST_CHECK_EQUAL ( s423[0], 6); - BOOST_CHECK_EQUAL ( s423[1], 3); - BOOST_CHECK_EQUAL ( s423[2], 1); - -} - -BOOST_AUTO_TEST_SUITE_END() - -#endif diff --git a/test/tensor/test_fixed_rank_tensor.cpp b/test/tensor/test_fixed_rank_tensor.cpp deleted file mode 100644 index b7050c897..000000000 --- a/test/tensor/test_fixed_rank_tensor.cpp +++ /dev/null @@ -1,510 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - - -#include -#include - -#include -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE ( test_tensor_static_rank ) - -using test_types = zip>::with_t; - - -BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - auto a2 = ublas::tensor_static_rank{1,1}; - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - BOOST_CHECK_NE( a2.data() , nullptr); - - auto a3 = ublas::tensor_static_rank{2,1}; - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - BOOST_CHECK_NE( a3.data() , nullptr); - - auto a4 = ublas::tensor_static_rank{1,2}; - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - BOOST_CHECK_NE( a4.data() , nullptr); - - auto a5 = ublas::tensor_static_rank{2,1}; - BOOST_CHECK_EQUAL( a5.size() , 2 ); - BOOST_CHECK( !a5.empty() ); - BOOST_CHECK_NE( a5.data() , nullptr); - - auto a6 = ublas::tensor_static_rank{4,3,2}; - BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); - BOOST_CHECK( !a6.empty() ); - BOOST_CHECK_NE( a6.data() , nullptr); - - auto a7 = ublas::tensor_static_rank{4,1,2}; - BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); - BOOST_CHECK( !a7.empty() ); - BOOST_CHECK_NE( a7.data() , nullptr); - -} - - -struct fixture -{ - template - using extents_t = boost::numeric::ublas::extents; - - std::tuple< - extents_t<2>, // 1 - extents_t<2>, // 2 - extents_t<3>, // 3 - extents_t<3>, // 4 - extents_t<4> // 5 - > extents = { - extents_t<2>{1,1}, - extents_t<2>{2,3}, - extents_t<3>{4,1,3}, - extents_t<3>{4,2,3}, - extents_t<4>{4,2,3,5} - }; -}; - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ - constexpr auto size = std::tuple_size_v>; - auto t = ublas::tensor_static_rank{e}; - - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - if(ublas::empty(e)) { - BOOST_CHECK ( t.empty() ); - BOOST_CHECK_EQUAL ( t.data() , nullptr); - } - else{ - BOOST_CHECK ( !t.empty() ); - BOOST_CHECK_NE ( t.data() , nullptr); - } - }); - -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ - constexpr auto size = std::tuple_size_v>; - auto r = ublas::tensor_static_rank{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(ublas::empty(e)) { - 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] ); - - }); -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using other_layout_t = std::conditional_t::value, ublas::layout::last_order, ublas::layout::first_order>; - - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - using other_tensor_t = ublas::tensor_static_rank; - auto r = tensor_t(e); - other_tensor_t t = r; - tensor_t 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 ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - auto check = [](auto const& /*unused*/, auto& e) - { - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - auto r = tensor_t{e}; - auto t = std::move(r); - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - - if(ublas::empty(e)) { - BOOST_CHECK ( t.empty() ); - BOOST_CHECK_EQUAL ( t.data() , nullptr); - } - else{ - BOOST_CHECK ( !t.empty() ); - BOOST_CHECK_NE ( t.data() , nullptr); - } - - }; - - for_each_in_tuple(extents,check); -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - std::random_device device{}; - std::minstd_rand0 generator(device()); - - using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; - auto distribution = distribution_type(1,6); - - for_each_in_tuple(extents, [&](auto const& /*unused*/, auto const& e){ - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - - auto r = value_t( static_cast< inner_type_t >(distribution(generator)) ); - auto t = tensor_t(e); - t = 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) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - using container_t = typename tensor_t::container_type; - - auto a = container_t(product(e)); - auto v = value_t {}; - - for(auto& aa : a){ - aa = v; - v += value_t{1}; - } - auto t = tensor_t(e, a); - v = value_t{}; - - for(auto i = 0ul; i < t.size(); ++i, v+=value_t{1}) - BOOST_CHECK_EQUAL( t[i], v); - - }); -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_single_index_access, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - - auto t = tensor_t{e}; - auto v = value_t {}; - for(auto i = 0ul; i < t.size(); ++i, v+=value_t{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) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - auto check1 = [](const auto& t) - { - auto v = value_t{}; - for(auto k = 0ul; k < t.size(); ++k){ - BOOST_CHECK_EQUAL(t[k], v); - v+=value_t{1}; - } - }; - - auto check2 = [](const auto& t) - { - std::array k = {0,0}; - auto r = std::is_same::value ? 1 : 0; - auto q = std::is_same::value ? 1 : 0; - auto v = value_t{}; - 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_t{1}; - } - } - }; - - auto check3 = [](const auto& t) - { - std::array k = {0,0,0}; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 2 : 0; - auto o = op_type{}; - auto v = value_t{}; - 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_t{1}; - } - } - } - }; - - auto check4 = [](const auto& t) - { - static constexpr auto order = 4; - std::array k = {0,0,0,0}; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? (order-1) : 0; - auto o = op_type{}; - auto v = value_t{}; - for(k[o(r,0)] = 0ul; k[o(r,0)] < t.size(o(r,0)); ++k[o(r,0)]){ - 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_t{1}; - } - } - } - } - }; - - auto check = [check1,check2,check3,check4](auto const& /*unused*/, auto const& e) { - constexpr auto size = std::tuple_size_v>; - using tensor_t = ublas::tensor_static_rank; - auto t = tensor_t(e); - auto v = value_t {}; - for(auto i = 0ul; i < t.size(); ++i){ - t[i] = v; - v+=value_t{1}; - } - - if constexpr(size == 1) check1(t); - else if constexpr(size == 2) check2(t); - else if constexpr(size == 3) check3(t); - else if constexpr(size == 4) check4(t); - - }; - - for_each_in_tuple(extents,check); -} - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - for_each_in_tuple(extents,[&](auto const& /*unused*/, auto const& efrom){ - - using efrom_t = std::decay_t; - using tensor_t = ublas::tensor_static_rank, layout_t>; - - for_each_in_tuple(extents,[&](auto const& /*unused*/, auto& eto){ - using eto_t = std::decay_t; - - if constexpr( std::tuple_size_v == std::tuple_size_v ){ - - auto v = value_t {}; - v+=value_t{1}; - auto t = tensor_t(efrom); - t = v; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL( t[i], v ); - - auto t2 = reshape(t,eto); - for(auto i = 0ul; i < std::min(ublas::product(efrom),ublas::product(eto)); ++i) - BOOST_CHECK_EQUAL( t2[i], v ); - - BOOST_CHECK_EQUAL ( t2.size() , ublas::product(eto) ); - BOOST_CHECK_EQUAL ( t2.rank() , ublas::size (eto) ); - BOOST_CHECK ( t2.extents() == eto ); - - if(efrom != eto){ - for(auto i = product(efrom); i < t.size(); ++i) - BOOST_CHECK_EQUAL( t2[i], value_t{} ); - } - } - }); - }); -} - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_swap, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - for_each_in_tuple(extents,[&](auto const& /*unused*/, auto const& e_t){ - using e_tt = std::decay_t< decltype(e_t) >; - using tensor_t = ublas::tensor_static_rank, layout_t>; - - for_each_in_tuple(extents,[&](auto const& /*unused*/, auto& e_r){ - - using e_rt = std::decay_t< decltype(e_r) >; - - if constexpr( std::tuple_size_v == std::tuple_size_v ){ - - auto v = value_t {} + value_t{1}; - auto w = value_t {} + value_t{2}; - auto t = tensor_t(e_t); - auto r = tensor_t(e_r); - - t = v; - r = w; - - std::swap( r, t ); - - BOOST_CHECK ( std::all_of(t.begin(),t.end(),[w](auto tt){return tt == w; } ) ) ; - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e_r) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e_r) ); - BOOST_CHECK ( t.extents() == e_r ); - BOOST_CHECK ( t.strides() == ublas::to_strides(e_r,layout_t{}) ); - - BOOST_CHECK ( std::all_of(r.begin(),r.end(),[v](auto tt){return tt == v; } ) ) ; - BOOST_CHECK_EQUAL ( r.size() , ublas::product(e_t) ); - BOOST_CHECK_EQUAL ( r.rank() , ublas::size (e_t) ); - BOOST_CHECK ( r.extents() == e_t ); - BOOST_CHECK ( r.strides() == ublas::to_strides(e_t,layout_t{}) ); - - - } - }); - }); -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - - for_each_in_tuple(extents,[](auto const& /*unused*/, auto const& e){ - using et = std::decay_t< decltype(e) >; - using tensor_t = ublas::tensor_static_rank, layout_t>; - - auto v = value_t {} + value_t{1}; - auto t = tensor_t(e); - t = 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.empty()) { - BOOST_CHECK( t.data() == std::addressof( *t.begin () ) ) ; - BOOST_CHECK( t.data() == std::addressof( *t.cbegin() ) ) ; - } - }); - -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using tensor_t = ublas::tensor_static_rank; - - auto vec = std::vector(1); - BOOST_CHECK_THROW(tensor_t({5,5},vec), std::length_error); - - // Does not throw but results in a static assertion -// auto t = tensor_t{{5,5}}; -// auto i = ublas::index::index_type<4>{}; -// BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::runtime_error); - -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp b/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp deleted file mode 100644 index 5ed7a4f56..000000000 --- a/test/tensor/test_fixed_rank_tensor_matrix_vector.cpp +++ /dev/null @@ -1,472 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#include -#include -#include -#include -#include - -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE ( test_tensor_static_rank_matrix_interoperability ) - -using test_types = zip::with_t; - - -BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout = typename value::second_type; - using tensor = ublas::tensor_static_rank; - using matrix = typename tensor::matrix_type; - - auto a2 = tensor( matrix(1,1) ); - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - BOOST_CHECK_NE( a2.data() , nullptr); - - auto a3 = tensor( matrix(2,1) ); - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - BOOST_CHECK_NE( a3.data() , nullptr); - - auto a4 = tensor( matrix(1,2) ); - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - BOOST_CHECK_NE( a4.data() , nullptr); - - auto a5 = tensor( matrix(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) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_static_rank; - using vector_type = typename tensor_type::vector_type; - - auto a2 = tensor_type( vector_type(1) ); - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - BOOST_CHECK_NE( a2.data() , nullptr); - - auto a3 = tensor_type( vector_type(2) ); - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - BOOST_CHECK_NE( a3.data() , nullptr); - - auto a4 = tensor_type( vector_type(2) ); - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - BOOST_CHECK_NE( a4.data() , nullptr); - - auto a5 = tensor_type( vector_type(3) ); - BOOST_CHECK_EQUAL( a5.size() , 3 ); - BOOST_CHECK( !a5.empty() ); - BOOST_CHECK_NE( a5.data() , nullptr); -} - - -struct fixture -{ - template - using extents_type = boost::numeric::ublas::extents; - - std::tuple< - extents_type<2>, // 0 - extents_type<2>, // 1 - extents_type<2>, // 2 - extents_type<2>, // 3 - extents_type<2> // 4 - > extents = { - {1,1}, - {1,2}, - {2,1}, - {6,6}, - {9,7}, - }; -}; - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto check = [](auto const& /*unused*/, auto& e) { - constexpr auto size = std::tuple_size_v>; - using tensor = ublas::tensor_static_rank; - using matrix = typename tensor::matrix_type; - - assert(ublas::size(e)==2); - tensor t = matrix{e[0],e[1]}; - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - BOOST_CHECK ( !t.empty() ); - BOOST_CHECK_NE ( t.data() , nullptr); - }; - - for_each_in_tuple(extents,check); -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) { - constexpr auto size = std::tuple_size_v>; - using tensor = ublas::tensor_static_rank; - using vector = typename tensor::vector_type; - - assert(ublas::size(e)==2); - if(ublas::empty(e)) - return; - - tensor t = vector (product(e)); - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - BOOST_CHECK ( !t.empty() ); - BOOST_CHECK_NE ( t.data() , nullptr); - }; - - for_each_in_tuple(extents,check); -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e) { - using etype = std::decay_t; - constexpr auto size = std::tuple_size_v; - using tensor = ublas::tensor_static_rank; - using matrix = typename tensor::matrix_type; - - assert(ublas::size(e) == 2); - auto t = tensor{e[1],e[0]}; - auto r = matrix(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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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_each_in_tuple(extents,check); -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto check = [](auto const& /*unused*/, auto& e) { - constexpr auto size = std::tuple_size_v>; - using tensor_type = ublas::tensor_static_rank; - using vector_type = typename tensor_type::vector_type; - - assert(ublas::size(e) == 2); - auto t = tensor_type{e[1],e[0]}; - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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_each_in_tuple(extents,check); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) { - constexpr auto size = std::tuple_size_v>; - using tensor_type = ublas::tensor_static_rank; - using matrix_type = typename tensor_type::matrix_type; - - assert(ublas::size(e) == 2); - auto t = tensor_type{e[1],e[0]}; - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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_each_in_tuple(extents,check); -} - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto check = [](auto const& /*unused*/, auto& e) { - constexpr auto size = std::tuple_size_v>; - using tensor_type = ublas::tensor_static_rank; - using vector_type = typename tensor_type::vector_type; - - assert(ublas::size(e) == 2); - auto t = tensor_type{e[1],e[0]}; - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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_each_in_tuple(extents,check); -} - - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) { - constexpr auto size = std::tuple_size_v>; - using tensor_type = ublas::tensor_static_rank; - using matrix_type = typename tensor_type::matrix_type; - - assert(ublas::size(e) == 2); - auto t = tensor_type{e[1],e[0]}; - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , ublas::size (e) ); - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , ublas::size (e) ); - 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_each_in_tuple(extents,check); -} - - - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto check = [](auto const& /*unused*/, auto& e) { - constexpr auto size = std::tuple_size_v>; - using tensor_type = ublas::tensor_static_rank; - using vector_type = typename tensor_type::vector_type; - - assert(ublas::size(e) == 2); - auto t = tensor_type{e[1],e[0]}; - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , ublas::size (e) ); - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , ublas::size (e) ); - 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_each_in_tuple(extents,check); -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) { - constexpr auto size = std::tuple_size_v>; - using tensor = ublas::tensor_static_rank; - using matrix = typename tensor::matrix_type; - using vector = typename tensor::vector_type; - - if(product(e) <= 2) - return; - assert(ublas::size(e) == 2); - auto Q = tensor{e[0],1}; - auto A = matrix(e[0],e[1]); - auto b = vector(e[1]); - auto c = vector(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 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); - - const auto n = e[1]; - const auto ab = value(std::div(n*(n+1),2).quot); - const auto ref = ab+4*Q(0)+2*c(0); - BOOST_CHECK( std::all_of(T.begin(),T.end(), [ref](auto cc){ return ref == cc; }) ); - -// 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_each_in_tuple(extents,check); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_functions.cpp b/test/tensor/test_functions.cpp deleted file mode 100644 index c5a55048c..000000000 --- a/test/tensor/test_functions.cpp +++ /dev/null @@ -1,554 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// -// And we acknowledge the support from all contributors. - - -#include -#include -#include -#include -#include - -#include - -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE ( test_tensor_functions) - - -using test_types = zip>::with_t; - -//using test_types = zip::with_t; - - -struct fixture -{ - using dynamic_extents_type = boost::numeric::ublas::extents<>; - fixture() - : extents { - dynamic_extents_type{1,1}, // 1 - dynamic_extents_type{2,3}, // 2 - dynamic_extents_type{2,3,1}, // 3 - dynamic_extents_type{4,2,3}, // 4 - dynamic_extents_type{4,2,3,5}} // 5 - { - } - - std::vector extents; -}; - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_vector, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - 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 < ublas::size(n); ++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( static_cast< inner_type_t >(n[m]) ) * a[i] ); - - } - } - auto n = extents[4]; - auto a = tensor_type(n, value_type{2}); - auto b = vector_type(n[0], value_type{1}); - - auto empty = vector_type{}; - - BOOST_CHECK_THROW(prod(a, b, 0), std::length_error); - BOOST_CHECK_THROW(prod(a, b, 9), std::length_error); - BOOST_CHECK_THROW(prod(a, empty, 2), std::length_error); - -} - -BOOST_AUTO_TEST_CASE( test_tensor_prod_vector_exception ) -{ -// namespace ublas = boost::numeric::ublas; -// using value_type = float; -// using layout_type = ublas::layout::first_order; -// using d_tensor_type = ublas::tensor_dynamic; -// using vector_type = typename d_tensor_type::vector_type; - -// auto t1 = d_tensor_type{ublas::extents<>{},1.f}; -// auto v1 = vector_type{3,value_type{1}}; - -// BOOST_REQUIRE_THROW(prod(t1,v1,0),std::length_error); -// BOOST_REQUIRE_THROW(prod(t1,v1,1),std::length_error); -// BOOST_REQUIRE_THROW(prod(t1,v1,3),std::length_error); -} - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_matrix, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - 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 < ublas::size(n); ++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( static_cast< inner_type_t >(n[m]) ) * a[i] ); - - } - } - - auto n = extents[4]; - auto a = tensor_type(n, value_type{2}); - auto b = matrix_type(n[0], n[0], value_type{1}); - - auto empty = matrix_type{}; - - BOOST_CHECK_THROW(prod(a, b, 0), std::length_error); - BOOST_CHECK_THROW(prod(a, b, 9), std::length_error); - BOOST_CHECK_THROW(prod(a, empty, 2), std::invalid_argument); -} - -BOOST_AUTO_TEST_CASE( test_tensor_prod_matrix_exception ) -{ -// namespace ublas = boost::numeric::ublas; -// using value_type = float; -// using layout_type = ublas::layout::first_order; -// using d_extents_type = ublas::extents<>; -// using d_tensor_type = ublas::tensor_dynamic; -// using matrix_type = typename d_tensor_type::matrix_type; - -// auto t1 = d_tensor_type{d_extents_type{},1.f}; -// auto m1 = matrix_type{3,3,value_type{1}}; - - -// BOOST_REQUIRE_THROW(prod(t1,m1,0),std::length_error); -// BOOST_REQUIRE_THROW(prod(t1,m1,1),std::length_error); -// BOOST_REQUIRE_THROW(prod(t1,m1,3),std::length_error); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_1, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - // 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 ( 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 *= value_type( static_cast< inner_type_t >( 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_AUTO_TEST_CASE( test_tensor_prod_tensor_1_exception ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = float; - using layout_type = ublas::layout::first_order; - using d_extents_type = ublas::extents<>; - using d_tensor_type = ublas::tensor_dynamic; - - - std::vector phia = {1,2,3}; - std::vector phib = {1,2,3,4,5}; - - - auto t3 = d_tensor_type{d_extents_type{1,2},1.f}; - auto t4 = d_tensor_type{d_extents_type{1,2},1.f}; - BOOST_REQUIRE_THROW(prod(t3,t4,phia,phib),std::runtime_error); - - - auto t5 = d_tensor_type{d_extents_type{1,2,3,4},1.f}; - auto t6 = d_tensor_type{d_extents_type{1,2},1.f}; - BOOST_REQUIRE_THROW(prod(t5,t6,phia,phib),std::runtime_error); - - - auto t7 = d_tensor_type{d_extents_type{1,2,3,4,5},1.f}; - auto t8 = d_tensor_type{d_extents_type{1,2,3,4,5},1.f}; - BOOST_REQUIRE_THROW(prod(t7,t8,phia,phib),std::runtime_error); - - std::vector phia_2 = {1,2,3,5,4}; - std::vector phib_2 = {1,2,3,4,5}; - auto t9 = d_tensor_type{d_extents_type{1,2,3,4,5,6},1.f}; - auto t10 = d_tensor_type{d_extents_type{1,2,3,4,5,6},1.f}; - BOOST_REQUIRE_THROW(prod(t9,t10,phia_2,phib_2),std::runtime_error); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_2, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - using extents_type = typename tensor_type::extents_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_base = na.base(); - assert(pi.size() == ublas::size(na)); - for(auto j = 0u; j < pi.size(); ++j) - nb_base[pi[j]-1] = na[j]; - return extents_type(nb_base); - }; - - - // 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(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 ( q ); // concatenation for a - auto phib = std::vector ( 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 *= value_type( static_cast< inner_type_t >( 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()); - } - } - - auto phia = std::vector(3); - auto sphia = std::vector(2); - -// BOOST_CHECK_THROW(ublas::prod(tensor_type{}, tensor_type({2,1,2}), phia, phia), std::runtime_error); -// BOOST_CHECK_THROW(ublas::prod(tensor_type({1,2,3}), tensor_type(), phia, phia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type{1,2,4}, tensor_type{2,1}, phia, phia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type{1,2}, tensor_type{2,1,2}, phia, phia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type{1,2}, tensor_type{2,1,3}, sphia, phia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type{1,2}, tensor_type{2,2}, phia, sphia), std::runtime_error); - BOOST_CHECK_THROW(ublas::prod(tensor_type{1,2}, tensor_type{4,4}, sphia, phia), std::runtime_error); -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_inner_prod, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - - 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_CHECK_THROW(ublas::inner_prod(tensor_type{1,2,3}, tensor_type{1,2,3,4}), std::length_error); // rank different -// BOOST_CHECK_THROW(ublas::inner_prod(tensor_type(), tensor_type()), std::length_error); //empty tensor - BOOST_CHECK_THROW(ublas::inner_prod(tensor_type{1,2,3}, tensor_type{3,2,1}), std::length_error); // different extent -} - - -BOOST_AUTO_TEST_CASE( test_tensor_inner_prod_exception ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = float; - using layout_type = ublas::layout::first_order; - using d_extents_type = ublas::extents<>; - using d_tensor_type = ublas::tensor_dynamic; - - auto t1 = d_tensor_type{d_extents_type{1,2},1.f}; - auto t2 = d_tensor_type{d_extents_type{1,2,3},1.f}; - BOOST_REQUIRE_THROW( ublas::inner_prod(t1, t2), std::length_error); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_norm, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - - 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)); - - tensor_type var = (a+a)/value_type(2); // std::complex/int not allowed as expression is captured - auto r2 = ublas::norm( var ); - -// BOOST_CHECK_THROW(ublas::norm(tensor_type{}), std::runtime_error); - - BOOST_CHECK_EQUAL( c , r ); - BOOST_CHECK_EQUAL( std::sqrt( c ) , r2 ); - - } -} - -BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = float; - using complex_type = std::complex; - using layout_type = ublas::layout::first_order; - - using tensor_complex_type = ublas::tensor_dynamic; - using tensor_type = ublas::tensor_dynamic; - - 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( (bool) (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( (bool) (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( (bool) (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( (bool) (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( (bool) (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( (bool) (r00 == r3) ); - - - - } - - - -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_outer_prod, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - 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 -void init(std::vector& a) -{ - auto v = V(1); - for(auto i = 0u; i < a.size(); ++i, ++v){ - a[i] = v; - } -} - -template -void init(std::vector>& a) -{ - auto v = std::complex(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 ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - 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 = ublas::size(n); - auto const s = ublas::product(n); - 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(p); - std::iota(pi.begin(), pi.end(), 1); - a = ublas::trans( a, pi ); - bool res1 = a == aref; - BOOST_CHECK( res1 ); - - - 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 ); - } - bool res2 = a == aref; // it was an expression. so evaluate into bool - BOOST_CHECK( res2 ); - - } -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_main.cpp b/test/tensor/test_main.cpp new file mode 100644 index 000000000..fbcd35896 --- /dev/null +++ b/test/tensor/test_main.cpp @@ -0,0 +1,24 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// +// 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 +// Google and Fraunhofer IOSB, Ettlingen, Germany +// + + + +// #include +// #include + +#ifndef BOOST_TEST_DYN_LINK +#define BOOST_TEST_DYN_LINK +#endif +// NOLINTNEXTLINE +#define BOOST_TEST_MODULE MainTensor + +#include diff --git a/test/tensor/test_multi_index.cpp b/test/tensor/test_multi_index.cpp index fdbbac7de..cabb6f3ee 100644 --- a/test/tensor/test_multi_index.cpp +++ b/test/tensor/test_multi_index.cpp @@ -1,146 +1,228 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com // // 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. +// Google and Fraunhofer IOSB, Ettlingen, Germany // -#include -#include -#include -#include -#include - +#include #include +#include "fixture_utility.hpp" -#include "utility.hpp" - - -BOOST_AUTO_TEST_SUITE ( test_multi_index ) +BOOST_AUTO_TEST_SUITE(test_multi_index, + *boost::unit_test::description("Validate Multi-Index") +) -using test_types = zip>::with_t; +BOOST_AUTO_TEST_CASE(test_index_classes, + *boost::unit_test::label("index_value") + *boost::unit_test::description("Testing index correctness")) +{ + namespace index = boost::numeric::ublas::index; + + BOOST_CHECK_EQUAL ( index::_a.value , 1 ) ; + BOOST_CHECK_EQUAL ( index::_b.value , 2 ) ; + BOOST_CHECK_EQUAL ( index::_c.value , 3 ) ; + BOOST_CHECK_EQUAL ( index::_d.value , 4 ) ; + BOOST_CHECK_EQUAL ( index::_e.value , 5 ) ; + BOOST_CHECK_EQUAL ( index::_f.value , 6 ) ; + BOOST_CHECK_EQUAL ( index::_g.value , 7 ) ; + BOOST_CHECK_EQUAL ( index::_h.value , 8 ) ; + BOOST_CHECK_EQUAL ( index::_i.value , 9 ) ; + BOOST_CHECK_EQUAL ( index::_j.value , 10 ) ; + BOOST_CHECK_EQUAL ( index::_k.value , 11 ) ; + BOOST_CHECK_EQUAL ( index::_l.value , 12 ) ; + BOOST_CHECK_EQUAL ( index::_m.value , 13 ) ; + BOOST_CHECK_EQUAL ( index::_n.value , 14 ) ; + BOOST_CHECK_EQUAL ( index::_o.value , 15 ) ; + BOOST_CHECK_EQUAL ( index::_p.value , 16 ) ; + BOOST_CHECK_EQUAL ( index::_q.value , 17 ) ; + BOOST_CHECK_EQUAL ( index::_r.value , 18 ) ; + BOOST_CHECK_EQUAL ( index::_s.value , 19 ) ; + BOOST_CHECK_EQUAL ( index::_t.value , 20 ) ; + BOOST_CHECK_EQUAL ( index::_u.value , 21 ) ; + BOOST_CHECK_EQUAL ( index::_v.value , 22 ) ; + BOOST_CHECK_EQUAL ( index::_w.value , 23 ) ; + BOOST_CHECK_EQUAL ( index::_x.value , 24 ) ; + BOOST_CHECK_EQUAL ( index::_y.value , 25 ) ; + BOOST_CHECK_EQUAL ( index::_z.value , 26 ) ; +} -BOOST_AUTO_TEST_CASE ( test_index_classes ) +BOOST_AUTO_TEST_CASE(test_multi_index_class_construction, + *boost::unit_test::label("index_construction") + *boost::unit_test::description("Testing index construction")) { - namespace i = boost::numeric::ublas::index; - - - BOOST_CHECK_EQUAL ( i::_a.value , 1 ) ; - BOOST_CHECK_EQUAL ( i::_b.value , 2 ) ; - BOOST_CHECK_EQUAL ( i::_c.value , 3 ) ; - BOOST_CHECK_EQUAL ( i::_d.value , 4 ) ; - BOOST_CHECK_EQUAL ( i::_e.value , 5 ) ; - BOOST_CHECK_EQUAL ( i::_f.value , 6 ) ; - BOOST_CHECK_EQUAL ( i::_g.value , 7 ) ; - BOOST_CHECK_EQUAL ( i::_h.value , 8 ) ; - BOOST_CHECK_EQUAL ( i::_i.value , 9 ) ; - BOOST_CHECK_EQUAL ( i::_j.value , 10 ) ; - BOOST_CHECK_EQUAL ( i::_k.value , 11 ) ; - BOOST_CHECK_EQUAL ( i::_l.value , 12 ) ; - BOOST_CHECK_EQUAL ( i::_m.value , 13 ) ; - BOOST_CHECK_EQUAL ( i::_n.value , 14 ) ; - BOOST_CHECK_EQUAL ( i::_o.value , 15 ) ; - BOOST_CHECK_EQUAL ( i::_p.value , 16 ) ; - BOOST_CHECK_EQUAL ( i::_q.value , 17 ) ; - BOOST_CHECK_EQUAL ( i::_r.value , 18 ) ; - BOOST_CHECK_EQUAL ( i::_s.value , 19 ) ; - BOOST_CHECK_EQUAL ( i::_t.value , 20 ) ; - BOOST_CHECK_EQUAL ( i::_u.value , 21 ) ; - BOOST_CHECK_EQUAL ( i::_v.value , 22 ) ; - BOOST_CHECK_EQUAL ( i::_w.value , 23 ) ; - BOOST_CHECK_EQUAL ( i::_x.value , 24 ) ; - BOOST_CHECK_EQUAL ( i::_y.value , 25 ) ; - BOOST_CHECK_EQUAL ( i::_z.value , 26 ) ; + namespace ublas = boost::numeric::ublas; + namespace index = ublas::index; + + { + ublas::multi_index<2> idx(index::_a, index::_b); + BOOST_CHECK_EQUAL(ublas::get<0>(idx), 1ul); + BOOST_CHECK_EQUAL(ublas::get<1>(idx), 2ul); + } + { + ublas::multi_index<2> idx(index::_d, index::_c); + BOOST_CHECK_EQUAL(idx[0], 4ul); + BOOST_CHECK_EQUAL(idx[1], 3ul); + } + + } -BOOST_AUTO_TEST_CASE ( test_multi_index_class_construction ) +BOOST_TEST_DECORATOR( + *boost::unit_test::label("multi_index_class_generation") + *boost::unit_test::description("Testing multi-index generation for dynamic tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_multi_index_class_generation_tensor_dynamic, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_dynamic +) { namespace ublas = boost::numeric::ublas; - namespace i = ublas::index; + namespace index = ublas::index; + using value_type= typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_dynamic; - { - ublas::multi_index<2> ind(i::_a, i::_b); + constexpr auto check1 = [](auto t, auto idx0, auto idx1){ + BOOST_TEST_CONTEXT("[Dynamic Tensor] multi-index(" << idx0() << ", " << idx1() <<")"){ + t = value_type{2}; - BOOST_CHECK_EQUAL ( get<0>( ind ), 1 ) ; - BOOST_CHECK_EQUAL ( get<1>( ind ), 2 ) ; - } + auto a_idx = t(idx0, idx1); + BOOST_CHECK_EQUAL ( std::addressof( a_idx.first ), std::addressof( t ) ) ; - { - ublas::multi_index<2> ind(i::_d,i::_c); + BOOST_CHECK_EQUAL (std::get<0>(a_idx.second)(), idx0() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_idx.second)(), idx1() ) ; + } + }; - BOOST_CHECK_EQUAL ( ind[0] , 4 ) ; - BOOST_CHECK_EQUAL ( ind[1] , 3 ) ; - } -} + constexpr auto check2 = [](auto t, auto idx0, auto idx1, auto idx2){ + BOOST_TEST_CONTEXT("[Dynamic Tensor] multi-index(" << idx0() << ", " << idx1() << idx2() <<")"){ + t = value_type{2}; + + auto a_idx = t(idx0, idx1, idx2); + + BOOST_CHECK_EQUAL ( std::addressof( a_idx.first ), std::addressof( t ) ) ; + + BOOST_CHECK_EQUAL (std::get<0>(a_idx.second)(), idx0() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_idx.second)(), idx1() ) ; + BOOST_CHECK_EQUAL (std::get<2>(a_idx.second)(), idx2() ) ; + } + }; + + check1(fixture_t::t32, index::_a, index::_c); + check1(fixture_t::t32, index::_c, index::_a); + check2(fixture_t::t432, index::_b, index::_b, index::_a); +} -BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, test_types ) +BOOST_TEST_DECORATOR( + *boost::unit_test::label("multi_index_class_generation") + *boost::unit_test::description("Testing multi-index generation for static rank tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_multi_index_class_generation_tensor_static_rank, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static_rank +) { namespace ublas = boost::numeric::ublas; - namespace i = ublas::index; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - auto t = std::make_tuple ( - i::_a, // 0 - i::_b, // 1 - i::_c, // 2 - i::_d, // 3 - i::_e // 4 - ); + namespace index = ublas::index; - { - auto a = tensor_type(ublas::extents<>{2,3}, value_type{2}); - auto a_ind = a( std::get<0>(t), std::get<2>(t) ); + using value_type= typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static_rank; - BOOST_CHECK_EQUAL ( std::addressof( a_ind.first ), std::addressof( a ) ) ; + constexpr auto check1 = [](auto t, auto idx0, auto idx1){ + BOOST_TEST_CONTEXT("[Static Rank Tensor] multi-index(" << idx0() << ", " << idx1() <<")"){ + t = value_type{2}; - BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), i::_a() ) ; - BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), i::_c() ) ; - } + auto a_idx = t(idx0, idx1); - { - auto a = tensor_type(ublas::extents<>{2,3}, value_type{2}); - auto a_ind = a( std::get<2>(t), std::get<0>(t) ); + BOOST_CHECK_EQUAL ( std::addressof( a_idx.first ), std::addressof( t ) ) ; - BOOST_CHECK_EQUAL ( std::addressof( a_ind.first ), std::addressof( a ) ) ; + BOOST_CHECK_EQUAL (std::get<0>(a_idx.second)(), idx0() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_idx.second)(), idx1() ) ; + } + }; - BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), i::_c() ) ; - BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), i::_a() ) ; - } + constexpr auto check2 = [](auto t, auto idx0, auto idx1, auto idx2){ + BOOST_TEST_CONTEXT("[Static Rank Tensor] multi-index(" << idx0() << ", " << idx1() << idx2() <<")"){ + t = value_type{2}; - { - auto a = tensor_type(ublas::extents<>{2,3}, value_type{2}); - auto a_ind = a( std::get<2>(t), std::get<3>(t) ); + auto a_idx = t(idx0, idx1, idx2); - BOOST_CHECK_EQUAL (std::addressof( a_ind.first ), std::addressof( a ) ) ; + BOOST_CHECK_EQUAL ( std::addressof( a_idx.first ), std::addressof( t ) ) ; - BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), i::_c() ) ; - BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), i::_d() ) ; - } + BOOST_CHECK_EQUAL (std::get<0>(a_idx.second)(), idx0() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_idx.second)(), idx1() ) ; + BOOST_CHECK_EQUAL (std::get<2>(a_idx.second)(), idx2() ) ; + } + }; - { - auto a = tensor_type(ublas::extents<>{2,3,4}, value_type{2}); - auto a_ind = a( std::get<2>(t), std::get<3>(t), std::get<0>(t) ); + check1(fixture_t::t32, index::_a, index::_c); + check1(fixture_t::t32, index::_c, index::_a); + check2(fixture_t::t432, index::_b, index::_b, index::_a); - BOOST_CHECK_EQUAL (std::addressof( a_ind.first ), std::addressof( a ) ) ; +} - BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), i::_c() ) ; - BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), i::_d() ) ; - BOOST_CHECK_EQUAL (std::get<2>(a_ind.second)(), i::_a() ) ; - } +BOOST_TEST_DECORATOR( + *boost::unit_test::label("multi_index_class_generation") + *boost::unit_test::description("Testing multi-index generation for static tensor") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_multi_index_class_generation_tensor_static, + TestTupleType, + boost::numeric::ublas::test_types, + boost::numeric::ublas::tuple_fixture_tensor_static +) +{ + namespace ublas = boost::numeric::ublas; + namespace index = ublas::index; + + using value_type= typename TestTupleType::first_type; + using fixture_t = ublas::tuple_fixture_tensor_static; + + constexpr auto check1 = [](auto t, auto idx0, auto idx1){ + BOOST_TEST_CONTEXT("[Static Tensor] multi-index(" << idx0() << ", " << idx1() <<")"){ + t = value_type{2}; + + auto a_idx = t(idx0, idx1); + + BOOST_CHECK_EQUAL ( std::addressof( a_idx.first ), std::addressof( t ) ) ; + + BOOST_CHECK_EQUAL (std::get<0>(a_idx.second)(), idx0() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_idx.second)(), idx1() ) ; + } + }; + + constexpr auto check2 = [](auto t, auto idx0, auto idx1, auto idx2){ + BOOST_TEST_CONTEXT("[Static Tensor] multi-index(" << idx0() << ", " << idx1() << idx2() <<")"){ + t = value_type{2}; + + auto a_idx = t(idx0, idx1, idx2); + + BOOST_CHECK_EQUAL ( std::addressof( a_idx.first ), std::addressof( t ) ) ; + + BOOST_CHECK_EQUAL (std::get<0>(a_idx.second)(), idx0() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_idx.second)(), idx1() ) ; + BOOST_CHECK_EQUAL (std::get<2>(a_idx.second)(), idx2() ) ; + } + }; + + check1(fixture_t::t32, index::_a, index::_c); + check1(fixture_t::t32, index::_c, index::_a); + check2(fixture_t::t432, index::_b, index::_b, index::_a); } + BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_multi_index_utility.cpp b/test/tensor/test_multi_index_utility.cpp index 3cd35de9a..613d14172 100644 --- a/test/tensor/test_multi_index_utility.cpp +++ b/test/tensor/test_multi_index_utility.cpp @@ -1,52 +1,57 @@ -// Copyright (c) 2018-2019 Cem Bassoy +// +// Copyright (c) 2021, Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com // // 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. +// The authors gratefully acknowledge the support of +// Google and Fraunhofer IOSB, Ettlingen, Germany // -#include - +#include #include +#include "fixture_utility.hpp" + -BOOST_AUTO_TEST_SUITE ( test_multi_index_utility ) +BOOST_AUTO_TEST_SUITE(test_multi_index_utility, + *boost::unit_test::description("Validate Multi-Index Utility") +) -BOOST_AUTO_TEST_CASE ( test_multi_index_has_index ) +BOOST_AUTO_TEST_CASE(test_multi_index_has_index, + *boost::unit_test::label("has_index") + *boost::unit_test::description("Testing has_index trait")) { namespace ublas = boost::numeric::ublas; - namespace i = boost::numeric::ublas::index; - - { + namespace index = ublas::index; + + BOOST_TEST_CONTEXT("[Has Index] testing empty tuple"){ constexpr auto tuple = std::tuple<>{}; - constexpr auto has_a = ublas::has_index::value; - constexpr auto has_b = ublas::has_index::value; + constexpr auto has_a = ublas::has_index::value; + constexpr auto has_b = ublas::has_index::value; BOOST_CHECK( !has_a ); BOOST_CHECK( !has_b ); } - - - { - constexpr auto tuple = std::make_tuple(i::_a); - constexpr auto has_a = ublas::has_index::value; - constexpr auto has_b = ublas::has_index::value; + + BOOST_TEST_CONTEXT("[Has Index] testing tuple(_a)"){ + constexpr auto tuple = std::make_tuple(index::_a); + constexpr auto has_a = ublas::has_index::value; + constexpr auto has_b = ublas::has_index::value; BOOST_CHECK( has_a ); BOOST_CHECK( !has_b ); } - - { - constexpr auto tuple = std::make_tuple(i::_a,i::_b,i::_,i::_c,i::_d); - constexpr auto has_a = ublas::has_index::value; - constexpr auto has_b = ublas::has_index::value; - constexpr auto has_c = ublas::has_index::value; - constexpr auto has_d = ublas::has_index::value; - constexpr auto has_e = ublas::has_index::value; - constexpr auto has = ublas::has_index::value; + + BOOST_TEST_CONTEXT("[Has Index] testing tuple(_a, _b, _, _c, _d)"){ + constexpr auto tuple = std::make_tuple(index::_a,index::_b,index::_,index::_c,index::_d); + constexpr auto has_a = ublas::has_index::value; + constexpr auto has_b = ublas::has_index::value; + constexpr auto has_c = ublas::has_index::value; + constexpr auto has_d = ublas::has_index::value; + constexpr auto has_e = ublas::has_index::value; + constexpr auto has = ublas::has_index::value; BOOST_CHECK( has_a ); BOOST_CHECK( has_b ); BOOST_CHECK( has_c ); @@ -54,353 +59,316 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_has_index ) BOOST_CHECK( !has_e ); BOOST_CHECK( has ); } -} - +} -BOOST_AUTO_TEST_CASE ( test_multi_index_valid ) +BOOST_AUTO_TEST_CASE(test_multi_index_valid, + *boost::unit_test::label("is_valid") + *boost::unit_test::description("Testing if index is valid")) { namespace ublas = boost::numeric::ublas; - namespace i = ublas::index; - - { + namespace index = ublas::index; + + BOOST_TEST_CONTEXT("[Is Valid] testing empty tuple"){ constexpr auto tuple = std::tuple<>{}; constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } - - - { - constexpr auto tuple = std::make_tuple(i::_a); + + BOOST_TEST_CONTEXT("[Is Valid] testing tuple(_a)"){ + constexpr auto tuple = std::make_tuple(index::_a); constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } - { - constexpr auto tuple = std::make_tuple(i::_a,i::_,i::_b); + BOOST_TEST_CONTEXT("[Is Valid] testing tuple(_a, _, _b)"){ + constexpr auto tuple = std::make_tuple(index::_a,index::_,index::_b); constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } - { - constexpr auto tuple = std::make_tuple(i::_a,i::_,i::_b,i::_b); + BOOST_TEST_CONTEXT("[Is Valid] testing tuple(_a, _, _b, _b)"){ + constexpr auto tuple = std::make_tuple(index::_a,index::_,index::_b,index::_b); constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( !valid ); } - { - constexpr auto tuple = std::make_tuple(i::_c,i::_a,i::_,i::_b,i::_b); + BOOST_TEST_CONTEXT("[Is Valid] testing tuple(_c, _a, _, _b, _b)"){ + constexpr auto tuple = std::make_tuple(index::_c,index::_a,index::_,index::_b,index::_b); constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( !valid ); } - { - constexpr auto tuple = std::make_tuple(i::_c,i::_a,i::_,i::_b); + BOOST_TEST_CONTEXT("[Is Valid] testing tuple(_c, _a, _, _b)"){ + constexpr auto tuple = std::make_tuple(index::_c,index::_a,index::_,index::_b); constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } - { - constexpr auto tuple = std::make_tuple(i::_,i::_c,i::_a,i::_,i::_b); + BOOST_TEST_CONTEXT("[Is Valid] testing tuple(_, _c, _a, _, _b)"){ + constexpr auto tuple = std::make_tuple(index::_,index::_c,index::_a,index::_,index::_b); constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } - { - constexpr auto tuple = std::make_tuple(i::_,i::_c,i::_a,i::_,i::_b,i::_); + BOOST_TEST_CONTEXT("[Is Valid] testing tuple(_, _c, _a, _, _b, _)"){ + constexpr auto tuple = std::make_tuple(index::_,index::_c,index::_a,index::_,index::_b,index::_); constexpr auto valid = ublas::valid_multi_index::value; BOOST_CHECK( valid ); } -} - - - +} -BOOST_AUTO_TEST_CASE ( test_multi_index_number_equal_indices ) +BOOST_AUTO_TEST_CASE(test_multi_index_number_equal_indices, + *boost::unit_test::label("intersection_indices") + *boost::unit_test::description("Testing finds the intersection of indices")) { namespace ublas = boost::numeric::ublas; - namespace i = ublas::index; - - { + namespace index = ublas::index; + + BOOST_TEST_CONTEXT("[Intersection of Indices] testing empty tuple"){ constexpr auto lhs = std::tuple<>{}; constexpr auto rhs = std::tuple<>{}; constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 0 ); + BOOST_CHECK_EQUAL( num, 0ul ); } - - { - constexpr auto lhs = std::make_tuple(i::_a); + + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_a) : [RHS]tuple()"){ + constexpr auto lhs = std::make_tuple(index::_a); constexpr auto rhs = std::tuple<>{}; constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 0 ); + BOOST_CHECK_EQUAL( num, 0ul ); } - { - constexpr auto lhs = std::tuple<>{}; - constexpr auto rhs = std::make_tuple(i::_a); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_a) : [RHS]tuple(_a)"){ + constexpr auto lhs = std::make_tuple(index::_a); + constexpr auto rhs = std::make_tuple(index::_a); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 0 ); + BOOST_CHECK_EQUAL( num, 1ul ); } - { - constexpr auto lhs = std::make_tuple(i::_b); - constexpr auto rhs = std::make_tuple(i::_a); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_a, _b) : [RHS]tuple(_a)"){ + constexpr auto lhs = std::make_tuple(index::_a,index::_b); + constexpr auto rhs = std::make_tuple(index::_a); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 0 ); + BOOST_CHECK_EQUAL( num, 1ul ); } - - - { - constexpr auto lhs = std::make_tuple(i::_a); - constexpr auto rhs = std::make_tuple(i::_a); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_a) : [RHS]tuple(_a, _b)"){ + constexpr auto lhs = std::make_tuple(index::_b); + constexpr auto rhs = std::make_tuple(index::_a,index::_b); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 1 ); + BOOST_CHECK_EQUAL( num, 1ul ); } - { - constexpr auto lhs = std::make_tuple(i::_a,i::_b); - constexpr auto rhs = std::make_tuple(i::_a); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_a, _b) : [RHS]tuple(_a, _b)"){ + constexpr auto lhs = std::make_tuple(index::_a,index::_b); + constexpr auto rhs = std::make_tuple(index::_a,index::_b); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 1 ); + BOOST_CHECK_EQUAL( num, 2ul ); } - { - constexpr auto lhs = std::make_tuple(i::_b); - constexpr auto rhs = std::make_tuple(i::_a,i::_b); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_b, _a) : [RHS]tuple(_a, _b)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a); + constexpr auto rhs = std::make_tuple(index::_a,index::_b); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 1 ); + BOOST_CHECK_EQUAL( num, 2ul ); } - { - constexpr auto lhs = std::make_tuple(i::_a); - constexpr auto rhs = std::make_tuple(i::_a); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_b, _a, _c) : [RHS]tuple(_a, _b)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_c); + constexpr auto rhs = std::make_tuple(index::_a,index::_b); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 1 ); + BOOST_CHECK_EQUAL( num, 2ul ); } - - - { - constexpr auto lhs = std::make_tuple(i::_a,i::_b); - constexpr auto rhs = std::make_tuple(i::_a,i::_b); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_b, _a, _c) : [RHS]tuple(_a, _b, _d)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_c); + constexpr auto rhs = std::make_tuple(index::_a,index::_b,index::_d); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 2 ); + BOOST_CHECK_EQUAL( num, 2ul ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a); - constexpr auto rhs = std::make_tuple(i::_a,i::_b); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_b, _a, _d) : [RHS]tuple(_a, _b, _d)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_d); + constexpr auto rhs = std::make_tuple(index::_a,index::_b,index::_d); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 2 ); + BOOST_CHECK_EQUAL( num, 3ul ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_c); - constexpr auto rhs = std::make_tuple(i::_a,i::_b); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_b, _a, _d) : [RHS]tuple(_a, _b, _d, _)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_d); + constexpr auto rhs = std::make_tuple(index::_a,index::_b,index::_d,index::_); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 2 ); + BOOST_CHECK_EQUAL( num, 3ul ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_c); - constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_b, _a, _d, _) : [RHS]tuple(_a, _b, _d, _)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_d,index::_); + constexpr auto rhs = std::make_tuple(index::_a,index::_b,index::_d,index::_); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 2 ); + BOOST_CHECK_EQUAL( num, 3ul ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d); - constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_b, _a, _d, _) : [RHS]tuple(_, _b, _d, _)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_d,index::_); + constexpr auto rhs = std::make_tuple(index::_,index::_b,index::_d,index::_); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 3 ); + BOOST_CHECK_EQUAL( num, 2ul ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d); - constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d,i::_); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_, _a, _d, _) : [RHS]tuple(_, _b, _d, _)"){ + constexpr auto lhs = std::make_tuple(index::_,index::_a,index::_d,index::_); + constexpr auto rhs = std::make_tuple(index::_,index::_b,index::_d,index::_); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 3 ); + BOOST_CHECK_EQUAL( num, 1ul ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d,i::_); - constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d,i::_); + BOOST_TEST_CONTEXT("[Intersection of Indices] testing [LHS]tuple(_, _a, _d, _) : [RHS]tuple(_, _b, _d, _, _)"){ + constexpr auto lhs = std::make_tuple(index::_,index::_a,index::_d,index::_); + constexpr auto rhs = std::make_tuple(index::_,index::_b,index::_d,index::_,index::_); constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 3 ); + BOOST_CHECK_EQUAL( num, 1ul ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d,i::_); - constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_); - constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 2 ); - } - - { - constexpr auto lhs = std::make_tuple(i::_,i::_a,i::_d,i::_); - constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_); - constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 1 ); - } - - { - constexpr auto lhs = std::make_tuple(i::_,i::_a,i::_d,i::_); - constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_,i::_); - constexpr auto num = ublas::number_equal_indexes::value; - BOOST_CHECK_EQUAL( num, 1 ); - } } - - - - - - -BOOST_AUTO_TEST_CASE ( test_multi_index_index_position ) +BOOST_AUTO_TEST_CASE(test_multi_index_index_position, + *boost::unit_test::label("get_index_pos") + *boost::unit_test::description("Testing index position")) { namespace ublas = boost::numeric::ublas; - namespace i = ublas::index; - - { + namespace index = ublas::index; + + BOOST_TEST_CONTEXT("[Get Index Position] testing empty tuple"){ constexpr auto tuple = std::tuple<>{}; - constexpr auto ind = ublas::index_position::value; - BOOST_CHECK_EQUAL(ind,0); + constexpr auto ind = ublas::index_position::value; + BOOST_CHECK_EQUAL(ind,0ul); } - - { - constexpr auto tuple = std::make_tuple(i::_); - constexpr auto ind = ublas::index_position::value; - BOOST_CHECK_EQUAL(ind,0); + + BOOST_TEST_CONTEXT("[Get Index Position] testing get position of (_) in tuple(_)"){ + constexpr auto tuple = std::make_tuple(index::_); + constexpr auto ind = ublas::index_position::value; + BOOST_CHECK_EQUAL(ind,0ul); } - - { - constexpr auto tuple = std::make_tuple(i::_); - constexpr auto ind = ublas::index_position::value; - BOOST_CHECK_EQUAL(ind,1); + + BOOST_TEST_CONTEXT("[Get Index Position] testing get position of (_a) in tuple(_)"){ + constexpr auto tuple = std::make_tuple(index::_); + constexpr auto ind = ublas::index_position::value; + BOOST_CHECK_EQUAL(ind,1ul); } - - { - constexpr auto tuple = std::make_tuple(i::_,i::_a); - constexpr auto ind = ublas::index_position::value; - BOOST_CHECK_EQUAL(ind,0); + + BOOST_TEST_CONTEXT("[Get Index Position] testing get position of (_) in tuple(_, _a)"){ + constexpr auto tuple = std::make_tuple(index::_,index::_a); + constexpr auto ind = ublas::index_position::value; + BOOST_CHECK_EQUAL(ind,0ul); } - - { - constexpr auto tuple = std::make_tuple(i::_,i::_a); - constexpr auto ind = ublas::index_position::value; - BOOST_CHECK_EQUAL(ind,1); + + BOOST_TEST_CONTEXT("[Get Index Position] testing get position of (_a) in tuple(_, _a)"){ + constexpr auto tuple = std::make_tuple(index::_,index::_a); + constexpr auto ind = ublas::index_position::value; + BOOST_CHECK_EQUAL(ind,1ul); } - { - constexpr auto tuple = std::make_tuple(i::_,i::_a); - constexpr auto ind = ublas::index_position::value; - BOOST_CHECK_EQUAL(ind,2); + BOOST_TEST_CONTEXT("[Get Index Position] testing get position of (_b) in tuple(_, _a)"){ + constexpr auto tuple = std::make_tuple(index::_,index::_a); + constexpr auto ind = ublas::index_position::value; + BOOST_CHECK_EQUAL(ind,2ul); } - - - - { - constexpr auto tuple = std::make_tuple(i::_c,i::_,i::_a); - constexpr auto ind = ublas::index_position::value; - BOOST_CHECK_EQUAL(ind,0); + BOOST_TEST_CONTEXT("[Get Index Position] testing get position of (_c) in tuple(_c, _, _a)"){ + constexpr auto tuple = std::make_tuple(index::_c,index::_,index::_a); + constexpr auto ind = ublas::index_position::value; + BOOST_CHECK_EQUAL(ind,0ul); } - { - constexpr auto tuple = std::make_tuple(i::_c,i::_,i::_a,i::_); - constexpr auto ind = ublas::index_position::value; + BOOST_TEST_CONTEXT("[Get Index Position] testing get position of (_) in tuple(_c, _, _a, _)"){ + constexpr auto tuple = std::make_tuple(index::_c,index::_,index::_a,index::_); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,1); } - { - constexpr auto tuple = std::make_tuple(i::_c,i::_,i::_a); - constexpr auto ind = ublas::index_position::value; + BOOST_TEST_CONTEXT("[Get Index Position] testing get position of (_a) in tuple(_c, _, _a)"){ + constexpr auto tuple = std::make_tuple(index::_c,index::_,index::_a); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,2); } - { - constexpr auto tuple = std::make_tuple(i::_c,i::_,i::_a); - constexpr auto ind = ublas::index_position::value; + BOOST_TEST_CONTEXT("[Get Index Position] testing get position of (_d) in tuple(_c, _, _a)"){ + constexpr auto tuple = std::make_tuple(index::_c,index::_,index::_a); + constexpr auto ind = ublas::index_position::value; BOOST_CHECK_EQUAL(ind,3); } } - - - - - - - -BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) +BOOST_AUTO_TEST_CASE(test_multi_index_index_position_pairs, + *boost::unit_test::label("pos_pairs") + *boost::unit_test::description("Testing pair positions")) { namespace ublas = boost::numeric::ublas; - namespace i = ublas::index; - - { + namespace index = ublas::index; + + BOOST_TEST_CONTEXT("[Get Pair Position] testing empty tuple"){ constexpr auto lhs = std::tuple<>{}; constexpr auto rhs = std::tuple<>{}; auto array = ublas::index_position_pairs(lhs, rhs); BOOST_CHECK_EQUAL(array.size(), 0ul ); } - { - constexpr auto lhs = std::make_tuple(i::_a); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_a) : [RHS]tuple()"){ + constexpr auto lhs = std::make_tuple(index::_a); constexpr auto rhs = std::tuple<>{}; auto array = ublas::index_position_pairs(lhs, rhs); BOOST_CHECK_EQUAL(array.size(), 0ul ); } - { + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple() : [RHS]tuple(_a)"){ constexpr auto lhs = std::tuple<>{}; - constexpr auto rhs = std::make_tuple(i::_a); + constexpr auto rhs = std::make_tuple(index::_a); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_CHECK_EQUAL(array.size(), 0ul ); } - { - constexpr auto lhs = std::make_tuple(i::_b); - constexpr auto rhs = std::make_tuple(i::_a); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b) : [RHS]tuple(_a)"){ + constexpr auto lhs = std::make_tuple(index::_b); + constexpr auto rhs = std::make_tuple(index::_a); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_CHECK_EQUAL(array.size(), 0ul ); } - { - constexpr auto lhs = std::make_tuple(i::_a); - constexpr auto rhs = std::make_tuple(i::_a); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_a) : [RHS]tuple(_a)"){ + constexpr auto lhs = std::make_tuple(index::_a); + constexpr auto rhs = std::make_tuple(index::_a); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 1ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); BOOST_CHECK_EQUAL(array[0].second, 0 ); } - { - constexpr auto lhs = std::make_tuple(i::_a,i::_b); - constexpr auto rhs = std::make_tuple(i::_a); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_a, _b) : [RHS]tuple(_a)"){ + constexpr auto lhs = std::make_tuple(index::_a,index::_b); + constexpr auto rhs = std::make_tuple(index::_a); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 1ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); BOOST_CHECK_EQUAL(array[0].second, 0 ); } - { - constexpr auto lhs = std::make_tuple(i::_b); - constexpr auto rhs = std::make_tuple(i::_a,i::_b); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b) : [RHS]tuple(_a, _b)"){ + constexpr auto lhs = std::make_tuple(index::_b); + constexpr auto rhs = std::make_tuple(index::_a,index::_b); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 1ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); BOOST_CHECK_EQUAL(array[0].second, 1 ); } - { - constexpr auto lhs = std::make_tuple(i::_a); - constexpr auto rhs = std::make_tuple(i::_a); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_a) : [RHS]tuple(_a)"){ + constexpr auto lhs = std::make_tuple(index::_a); + constexpr auto rhs = std::make_tuple(index::_a); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 1ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); @@ -409,9 +377,9 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) - { - constexpr auto lhs = std::make_tuple(i::_a,i::_b); - constexpr auto rhs = std::make_tuple(i::_a,i::_b); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_a, _b) : [RHS]tuple(_a, _b)"){ + constexpr auto lhs = std::make_tuple(index::_a,index::_b); + constexpr auto rhs = std::make_tuple(index::_a,index::_b); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 2ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); @@ -420,9 +388,9 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) BOOST_CHECK_EQUAL(array[1].second, 1 ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a); - constexpr auto rhs = std::make_tuple(i::_a,i::_b); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b, _a) : [RHS]tuple(_a, _b)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a); + constexpr auto rhs = std::make_tuple(index::_a,index::_b); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 2ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); @@ -431,9 +399,9 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) BOOST_CHECK_EQUAL(array[1].second, 0 ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_c); - constexpr auto rhs = std::make_tuple(i::_a,i::_b); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b, _a, _c) : [RHS]tuple(_a, _b)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_c); + constexpr auto rhs = std::make_tuple(index::_a,index::_b); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 2ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); @@ -442,9 +410,9 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) BOOST_CHECK_EQUAL(array[1].second, 0 ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_c); - constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b, _a, _c) : [RHS]tuple(_a, _b, _d)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_c); + constexpr auto rhs = std::make_tuple(index::_a,index::_b,index::_d); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 2ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); @@ -453,9 +421,9 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) BOOST_CHECK_EQUAL(array[1].second, 0 ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d); - constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b, _a, _d) : [RHS]tuple(_a, _b, _d)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_d); + constexpr auto rhs = std::make_tuple(index::_a,index::_b,index::_d); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 3ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); @@ -466,9 +434,9 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) BOOST_CHECK_EQUAL(array[2].second, 2 ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d); - constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d,i::_); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b, _a, _d) : [RHS]tuple(_a, _b, _d, _)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_d); + constexpr auto rhs = std::make_tuple(index::_a,index::_b,index::_d,index::_); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 3ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); @@ -479,9 +447,9 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) BOOST_CHECK_EQUAL(array[2].second, 2 ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d,i::_); - constexpr auto rhs = std::make_tuple(i::_a,i::_b,i::_d,i::_); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b, _a, _d, _) : [RHS]tuple(_a, _b, _d, _)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_d,index::_); + constexpr auto rhs = std::make_tuple(index::_a,index::_b,index::_d,index::_); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 3ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); @@ -492,9 +460,9 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) BOOST_CHECK_EQUAL(array[2].second, 2 ); } - { - constexpr auto lhs = std::make_tuple(i::_b,i::_a,i::_d,i::_); - constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b, _a, _d, _) : [RHS]tuple(_a, _b, _d, _)"){ + constexpr auto lhs = std::make_tuple(index::_b,index::_a,index::_d,index::_); + constexpr auto rhs = std::make_tuple(index::_,index::_b,index::_d,index::_); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 2ul ); BOOST_CHECK_EQUAL(array[0].first , 0 ); @@ -503,61 +471,24 @@ BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) BOOST_CHECK_EQUAL(array[1].second, 2 ); } - { - constexpr auto lhs = std::make_tuple(i::_,i::_a,i::_d,i::_); - constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b, _a, _d, _) : [RHS]tuple(_a, _b, _d, _)"){ + constexpr auto lhs = std::make_tuple(index::_,index::_a,index::_d,index::_); + constexpr auto rhs = std::make_tuple(index::_,index::_b,index::_d,index::_); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_ASSERT(array.size() == 1ul ); BOOST_CHECK_EQUAL(array[0].first , 2 ); BOOST_CHECK_EQUAL(array[0].second, 2 ); } - { - constexpr auto lhs = std::make_tuple(i::_,i::_a,i::_d,i::_); - constexpr auto rhs = std::make_tuple(i::_,i::_b,i::_d,i::_,i::_); + BOOST_TEST_CONTEXT("[Get Pair Position] testing [LHS]tuple(_b, _a, _d, _) : [RHS]tuple(_a, _b, _d, _, _)"){ + constexpr auto lhs = std::make_tuple(index::_,index::_a,index::_d,index::_); + constexpr auto rhs = std::make_tuple(index::_,index::_b,index::_d,index::_,index::_); auto array = ublas::index_position_pairs(lhs, rhs); BOOST_STATIC_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 ) -//{ -// namespace ublas = boost::numeric::ublas; -// namespace i = ublas::index; - -// auto check = [](auto const& lhs, auto const& rhs) -// { -// auto array = ublas::index_position_pairs(lhs, rhs); - -// auto vector_pair = ublas::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(i::_a) , std::tuple<>{}); -// check(std::tuple<>{} , std::make_tuple(i::_a)); -// check(std::make_tuple(i::_a) , std::make_tuple(i::_b)); -// check(std::make_tuple(i::_a) , std::make_tuple(i::_a)); -// check(std::make_tuple(i::_a,i::_b), std::make_tuple(i::_a)); -// check(std::make_tuple(i::_a) , std::make_tuple(i::_a,i::_b)); -// check(std::make_tuple(i::_a,i::_b), std::make_tuple(i::_a,i::_b)); -// check(std::make_tuple(i::_b,i::_a), std::make_tuple(i::_a,i::_b)); -// check(std::make_tuple(i::_b,i::_a,i::_c), std::make_tuple(i::_a,i::_b,i::_d)); -//} - +} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_multiplication.cpp b/test/tensor/test_multiplication.cpp deleted file mode 100644 index c5ed51e5f..000000000 --- a/test/tensor/test_multiplication.cpp +++ /dev/null @@ -1,486 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#include -#include -#include - -#include -#include -#include "utility.hpp" - -#include - - -BOOST_AUTO_TEST_SUITE (test_tensor_contraction) - - -using test_types = zip>::with_t; - -//using test_types = zip::with_t; - - -struct fixture -{ - using extents_t = boost::numeric::ublas::extents<>; - const std::vector extents = - { - extents_t{1,1}, // 1 - extents_t{1,2}, // 2 - extents_t{2,1}, // 3 - extents_t{2,3}, // 4 - extents_t{5,4}, // 5 - extents_t{2,3,1}, // 6 - extents_t{4,1,3}, // 7 - extents_t{1,2,3}, // 8 - extents_t{4,2,3}, // 9 - extents_t{4,2,3,5} // 10 - }; -}; - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_mtv, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using vector_t = std::vector; - using extents_t = ublas::extents<>; - using extents_base_t = typename extents_t::base_type; - - - for(auto const& na : extents) { - - if(ublas::size(na) > 2) - continue; - - auto a = vector_t(ublas::product(na), value_t{2}); - auto wa = ublas::to_strides(na,layout_t{}); - for(auto m = std::size_t{0}; m < ublas::size(na); ++m){ - auto nb = extents_t {na[m],std::size_t{1}}; - auto wb = ublas::to_strides(nb,layout_t{}); - auto b = vector_t (ublas::product(nb), value_t{1} ); - - auto nc_base = extents_base_t(std::max(std::size_t{ublas::size(na)-1u}, std::size_t{2}), 1); - - for(auto i = 0ul, j = 0ul; i < ublas::size(na); ++i) - if(i != m) - nc_base[j++] = na[i]; - - auto nc = extents_t (nc_base); - auto wc = ublas::to_strides(nc,layout_t{}); - auto c = vector_t (ublas::product(nc), value_t{0}); - - ublas::detail::recursive::mtv( - m, - c.data(), nc.data(), wc.data(), - a.data(), na.data(), wa.data(), - b.data()); - - auto v = value_t(na[m]); - BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); - -// for(auto i = 0u; i < c.size(); ++i) -// BOOST_CHECK_EQUAL( c[i] , value_t( static_cast< inner_type_t >(na[m]) ) * a[i] ); - - } - } -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_mtm, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using vector_t = std::vector; - using extents_t = ublas::extents<>; - - for(auto const& na : extents) { - - if(ublas::size(na) != 2) - continue; - - auto a = vector_t (ublas::product(na), value_t{2}); - auto wa = ublas::to_strides(na,layout_t{}); - - auto nb = extents_t {na[1],na[0]}; - auto wb = ublas::to_strides(nb,layout_t{}); - auto b = vector_t (ublas::product(nb), value_t{1} ); - - auto nc = extents_t {na[0],nb[1]}; - auto wc = ublas::to_strides(nc,layout_t{}); - auto c = vector_t (ublas::product(nc)); - - - ublas::detail::recursive::mtm( - c.data(), nc.data(), wc.data(), - a.data(), na.data(), wa.data(), - b.data(), nb.data(), wb.data()); - - auto v = value_t(na[1])*a[0]; - BOOST_CHECK(std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v;})); - -// for(auto i = 0u; i < c.size(); ++i) -// BOOST_CHECK_EQUAL( c[i] , value_t( static_cast< inner_type_t >(na[1]) ) * a[0] ); - - - } -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttv, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using vector_t = std::vector; - using extents_t = ublas::extents<>; - using extents_base_t = typename extents_t::base_type; - - for(auto const& na : extents) { - - auto a = vector_t(ublas::product(na), value_t{2}); - auto wa = ublas::to_strides(na,layout_t{}); - for(auto m = std::size_t{0}; m < ublas::size(na); ++m){ - auto b = vector_t (na[m], value_t{1} ); - auto nb = extents_t {na[m],1}; - auto wb = ublas::to_strides(nb,layout_t{}); - - auto nc_base = extents_base_t(std::max(std::size_t{ublas::size(na)-1u}, std::size_t{2}),1); - - for(auto i = 0ul, j = 0ul; i < ublas::size(na); ++i) - if(i != m) - nc_base[j++] = na[i]; - - auto nc = extents_t (nc_base); - auto wc = ublas::to_strides(nc,layout_t{}); - auto c = vector_t (ublas::product(nc), value_t{0}); - - ublas::ttv(m+1, ublas::size(na), - c.data(), nc.data(), wc.data(), - a.data(), na.data(), wa.data(), - b.data(), nb.data(), wb.data()); - - auto v = value_t(na[m]); - BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); - -// for(auto i = 0u; i < c.size(); ++i) -// BOOST_CHECK_EQUAL( c[i] , value_t(na[m]) * a[i] ); - - } - } -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttm, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using vector_t = std::vector; - using extents_t = ublas::extents<>; - - - for(auto const& na : extents) { - - auto a = vector_t(ublas::product(na), value_t{2}); - auto wa = ublas::to_strides(na,layout_t{}); - for(auto m = std::size_t{0}; m < ublas::size(na); ++m){ - const auto nb = extents_t {na[m], na[m] }; - const auto b = vector_t (ublas::product(nb), value_t{1} ); - const auto wb = ublas::to_strides(nb,layout_t{}); - - - const auto& nc = na; - const auto wc = ublas::to_strides(nc,layout_t{}); - auto c = vector_t (ublas::product(nc), value_t{0}); - - ublas::ttm(m+1, ublas::size(na), - c.data(), nc.data(), wc.data(), - a.data(), na.data(), wa.data(), - b.data(), nb.data(), wb.data()); - - - auto v = value_t(na[m]); - BOOST_CHECK(std::equal(c.begin(),c.end(),a.begin(), [v](auto cc, auto aa){return cc == v*aa;})); - - -// for(auto i = 0u; i < c.size(); ++i) -// BOOST_CHECK_EQUAL( c[i] , value_t( static_cast< inner_type_t >(na[m]) ) * a[i] ); - - } - } -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt_permutation, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using vector_t = std::vector; - using extents_t = ublas::extents<>; - using extents_base_t = typename extents_t::base_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_base = na.base(); - assert(pi.size() == ublas::size(na)); - for(auto j = 0u; j < pi.size(); ++j) - nb_base[j] = na[pi[j]-1]; - return extents_t(nb_base); - }; - - - // 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 = ublas::to_strides(na,layout_t{}); - auto a = vector_t(ublas::product(na), value_t{2}); - auto pa = ublas::size(na); - auto pia = std::vector(pa); - std::iota( pia.begin(), pia.end(), std::size_t{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 = ublas::to_strides(nb,layout_t{}); - auto b = vector_t(ublas::product(nb), value_t{3}); - auto pb = ublas::size(nb); - - // the number of contractions is changed. - for(auto q = std::size_t{0}; q <= pa; ++q) { - - auto r = pa - q; - auto s = pb - q; - - auto pc = r+s > 0 ? std::max(std::size_t{r+s},std::size_t{2}) : std::size_t{2}; - - auto nc_base = extents_base_t(pc,std::size_t{1}); - - for(auto j = 0u; j < r; ++j) - nc_base[j] = na[pia[j]-1]; - - for(auto j = 0u; j < s; ++j) - nc_base[r+j] = nb[ pib_inv[j]-1 ]; - - auto nc = extents_t ( nc_base ); - auto wc = ublas::to_strides(nc,layout_t{}); - auto c = vector_t ( ublas::product(nc), value_t(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 = std::size_t{1}; - for(auto j = r; j < pa; ++j) - acc *= na[pia[j]-1]; - - auto v = value_t(acc)*a[0]*b[0]; - - BOOST_CHECK( std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v; } ) ); - - } - - 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 ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using vector_t = std::vector; - using extents_t = ublas::extents<>; - using extents_base_t = typename extents_t::base_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 = ublas::to_strides(na,layout_t{}); - auto a = vector_t(ublas::product(na), value_t{2}); - auto pa = ublas::size(na); - - auto const& nb = na; - auto wb = ublas::to_strides(nb,layout_t{}); - auto b = vector_t(ublas::product(nb), value_t{3}); - auto pb = ublas::size(nb); - - // std::cout << "na = "; - // std::copy(na.begin(), na.end(), std::ostream_iterator(std::cout, " ")); - // std::cout << std::endl; - - // std::cout << "nb = "; - // std::copy(nb.begin(), nb.end(), std::ostream_iterator(std::cout, " ")); - // std::cout << std::endl; - - - // the number of contractions is changed. - for( auto q = std::size_t{0}; q <= pa; ++q) { // pa - - auto r = pa - q; - auto s = pb - q; - - auto pc = r+s > 0 ? std::max(std::size_t{r+s},std::size_t{2}) : std::size_t{2}; - - auto nc_base = extents_base_t(pc,std::size_t{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_t ( nc_base ); - auto wc = ublas::to_strides(nc,layout_t{}); - auto c = vector_t ( ublas::product(nc), value_t{0} ); - - // std::cout << "nc = "; - // std::copy(nc.begin(), nc.end(), std::ostream_iterator(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 = std::size_t{1}; - for(auto i = r; i < pa; ++i) - acc *= na[i]; - - auto v = value_t(acc)*a[0]*b[0]; - - BOOST_CHECK( std::all_of(c.begin(),c.end(), [v](auto cc){return cc == v; } ) ); - } - - } -} - - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_inner, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using vector_t = std::vector; - - for(auto const& n : extents) { - - auto a = vector_t(ublas::product(n), value_t{2}); - auto b = vector_t(ublas::product(n), value_t{3}); - auto w = ublas::to_strides(n,layout_t{}); - - auto c = ublas::inner(ublas::size(n), n.data(), a.data(), w.data(), b.data(), w.data(), value_t(0)); - auto cref = std::inner_product(a.begin(), a.end(), b.begin(), value_t(0)); - - - BOOST_CHECK_EQUAL( c , cref ); - - } - -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_outer, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_t = typename value::first_type; - using layout_t = typename value::second_type; - using extents_t = ublas::extents<>; - using vector_t = std::vector; - - - for(auto const& na : extents) { - - auto a = vector_t(ublas::product(na), value_t{2}); - auto wa = ublas::to_strides(na,layout_t{}); - - for(auto const& nb : extents) { - - auto b = vector_t(ublas::product(nb), value_t{3}); - auto wb = ublas::to_strides(nb,layout_t{}); - - auto c = vector_t(ublas::product(nb)*ublas::product(na)); - auto nc_base = typename extents_t::base_type(ublas::size(na)+ublas::size(nb)); - - for(auto i = 0u; i < ublas::size(na); ++i) - nc_base[i] = na[i]; - for(auto i = 0u; i < ublas::size(nb); ++i) - nc_base[i+ublas::size(na)] = nb[i]; - - auto nc = extents_t(nc_base); - auto wc = ublas::to_strides(nc,layout_t{}); - - ublas::outer(c.data(), ublas::size(nc), nc.data(), wc.data(), - a.data(), ublas::size(na), na.data(), wa.data(), - b.data(), ublas::size(nb), nb.data(), wb.data()); - - for(auto const& cc : c) - BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); - } - - } - -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_operators_arithmetic.cpp b/test/tensor/test_operators_arithmetic.cpp deleted file mode 100644 index 98484ccf7..000000000 --- a/test/tensor/test_operators_arithmetic.cpp +++ /dev/null @@ -1,262 +0,0 @@ -// 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 - -#include -#include -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE(test_tensor_arithmetic_operations/*, * boost::unit_test::depends_on("test_tensor")*/) - -using double_extended = boost::multiprecision::cpp_bin_float_double_extended; - -using test_types = zip::with_t; - -struct fixture -{ - using extents_type = boost::numeric::ublas::extents<>; - - std::vector 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 - }; -}; - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - - 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 = 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) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - - 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) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - - 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; - (void)r; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 2*t(i) + 4 ); - - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 2*t(i) + 4 ); - - r = (t-2); - r += t; - r -= 2; - - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 2*t(i) - 4 ); - - r = (t*2); - r *= 3; - r *= t; - - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), 2*3*t(i)*t(i) ); - - r = (t2*2); - r /= 2; - r /= t2; - r *= t2; - - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), (t2(i)*2) / (2*t2(i)) * t2(i) ); - - r = (t2/2+1); - r /= (2/t2+1); - r /= t2; - - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( r(i), (t2(i)/2+1) / (2/t2(i)+1) / t2(i) ); - - tensor_type q = -r; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( q(i), -r(i) ); - - tensor_type p = +r; - for(auto i = 0ul; i < t.size(); ++i) - BOOST_CHECK_EQUAL ( p(i), r(i) ); - - }; - - for(auto const& e : extents) - check(e); - - auto r = tensor_type (extents.at(0)); - - BOOST_CHECK_NO_THROW ( r += tensor_type(extents.at(0)) + 2 + tensor_type(extents.at(0)) ); - BOOST_CHECK_THROW ( r += tensor_type(extents.at(0)) + 2 + tensor_type(extents.at(2)), std::runtime_error ); - BOOST_CHECK_THROW ( r += tensor_type(extents.at(1)) + 2 + tensor_type(extents.at(2)), std::runtime_error ); - BOOST_CHECK_THROW ( r += tensor_type(extents.at(2)) + 2 + tensor_type(extents.at(2)) + tensor_type(extents.at(1)), std::runtime_error ); - BOOST_CHECK_THROW ( r += tensor_type(extents.at(2)) + 2 + tensor_type(extents.at(2)) + 2 + tensor_type(extents.at(1)), std::runtime_error ); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_operators_comparison.cpp b/test/tensor/test_operators_comparison.cpp deleted file mode 100644 index b6aeb191a..000000000 --- a/test/tensor/test_operators_comparison.cpp +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) 2018 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 -#include -#include -#include -#include -#include "utility.hpp" - - -BOOST_AUTO_TEST_SUITE(test_tensor_comparison/*, * boost::unit_test::depends_on("test_tensor")*/) - -using double_extended = boost::multiprecision::cpp_bin_float_double_extended; - -using test_types = zip::with_t; - -struct fixture { - using extents_type = boost::numeric::ublas::extents<>; - 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; -}; - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - - 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) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - - 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) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using tensor_type = ublas::tensor_dynamic; - - - 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(ublas::empty(e)) - return; - - BOOST_CHECK( !(tensor_type(e,2) < 2) ); - BOOST_CHECK( !(tensor_type(e,2) > 2) ); - BOOST_CHECK( (tensor_type(e,2) >= 2) ); - BOOST_CHECK( (tensor_type(e,2) <= 2) ); - BOOST_CHECK( (tensor_type(e,2) == 2) ); - BOOST_CHECK( (tensor_type(e,2) != 3) ); - - BOOST_CHECK( !(2 > tensor_type(e,2)) ); - BOOST_CHECK( !(2 < tensor_type(e,2)) ); - BOOST_CHECK( (2 <= tensor_type(e,2)) ); - BOOST_CHECK( (2 >= tensor_type(e,2)) ); - BOOST_CHECK( (2 == tensor_type(e,2)) ); - BOOST_CHECK( (3 != tensor_type(e,2)) ); - - BOOST_CHECK( !( tensor_type(e,2)+3 < 5) ); - BOOST_CHECK( !( tensor_type(e,2)+3 > 5) ); - BOOST_CHECK( ( tensor_type(e,2)+3 >= 5) ); - BOOST_CHECK( ( tensor_type(e,2)+3 <= 5) ); - BOOST_CHECK( ( tensor_type(e,2)+3 == 5) ); - BOOST_CHECK( ( tensor_type(e,2)+3 != 6) ); - - - BOOST_CHECK( !( 5 > tensor_type(e,2)+3) ); - BOOST_CHECK( !( 5 < tensor_type(e,2)+3) ); - BOOST_CHECK( ( 5 >= tensor_type(e,2)+3) ); - BOOST_CHECK( ( 5 <= tensor_type(e,2)+3) ); - BOOST_CHECK( ( 5 == tensor_type(e,2)+3) ); - BOOST_CHECK( ( 6 != tensor_type(e,2)+3) ); - - - BOOST_CHECK( !( tensor_type(e,2)+tensor_type(e,3) < 5) ); - BOOST_CHECK( !( tensor_type(e,2)+tensor_type(e,3) > 5) ); - BOOST_CHECK( ( tensor_type(e,2)+tensor_type(e,3) >= 5) ); - BOOST_CHECK( ( tensor_type(e,2)+tensor_type(e,3) <= 5) ); - BOOST_CHECK( ( tensor_type(e,2)+tensor_type(e,3) == 5) ); - BOOST_CHECK( ( tensor_type(e,2)+tensor_type(e,3) != 6) ); - - - BOOST_CHECK( !( 5 > tensor_type(e,2)+tensor_type(e,3)) ); - BOOST_CHECK( !( 5 < tensor_type(e,2)+tensor_type(e,3)) ); - BOOST_CHECK( ( 5 >= tensor_type(e,2)+tensor_type(e,3)) ); - BOOST_CHECK( ( 5 <= tensor_type(e,2)+tensor_type(e,3)) ); - BOOST_CHECK( ( 5 == tensor_type(e,2)+tensor_type(e,3)) ); - BOOST_CHECK( ( 6 != tensor_type(e,2)+tensor_type(e,3)) ); - - }; - - for(auto const& e : extents) - check(e); - -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_expression_evaluation.cpp b/test/tensor/test_static_expression_evaluation.cpp deleted file mode 100644 index 7412eef01..000000000 --- a/test/tensor/test_static_expression_evaluation.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - - -#include -#include "utility.hpp" -#include - -#include - -BOOST_AUTO_TEST_SUITE(test_tensor_static_expression) - -using test_types = zip>::with_t; - - -struct fixture -{ - template - using extents_type = boost::numeric::ublas::extents; - - std::tuple< - extents_type<1,1>, // 1 - extents_type<2,3>, // 2 - extents_type<4,1,3>, // 3 - extents_type<4,2,3>, // 4 - extents_type<4,2,3,5> // 5 - > extents; -}; - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_static_expression_retrieve_extents, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto uplus1 = [](auto const& a){return a + value_type(1);}; - auto uplus2 = [](auto const& a){return value_type(2) + a;}; - auto bplus = std::plus {}; - auto bminus = std::minus{}; - - for_each_in_tuple(extents, [&](auto const& /*unused*/, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - - - auto t = tensor_type(); - 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( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); - - BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); - - }); - - for_each_in_tuple(extents, [&](auto I, auto& e1){ - - if ( I >= std::tuple_size_v - 1){ - return; - } - - using extents_type1 = std::decay_t; - using tensor_type1 = ublas::tensor_static; - - for_each_in_tuple(extents, [&](auto J, auto& e2){ - - if( J != I + 1 ){ - return; - } - - using extents_type2 = std::decay_t; - using tensor_type2 = ublas::tensor_static; - - auto v = value_type{}; - - tensor_type1 t1; - for(auto& tt: t1){ tt = v; v+=value_type{1}; } - - tensor_type2 t2; - 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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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 ) ); - - }); - }); -} - - - - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_static_expression_all_extents_equal, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto uplus1 = [](auto const& a){return a + value_type(1);}; - auto uplus2 = [](auto const& a){return value_type(2) + a;}; - auto bplus = std::plus {}; - auto bminus = std::minus{}; - - for_each_in_tuple(extents, [&](auto const& /*unused*/, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - - - auto t = tensor_type{}; - 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( t, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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( 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( bexpr_uexpr, t, bminus ); - - BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); - - }); - - - for_each_in_tuple(extents, [&](auto I, auto& e1){ - - if ( I >= std::tuple_size_v - 1){ - return; - } - - using extents_type1 = std::decay_t; - using tensor_type1 = ublas::tensor_static; - - for_each_in_tuple(extents, [&](auto J, auto& e2){ - - if( J != I + 1 ){ - return; - } - - using extents_type2 = std::decay_t; - using tensor_type2 = ublas::tensor_static; - - auto v = value_type{}; - - tensor_type1 t1; - for(auto& tt: t1){ tt = v; v+=value_type{1}; } - - tensor_type2 t2; - 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( t1, uplus1 ); - auto uexpr2 = ublas::detail::make_unary_tensor_expression( 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) ) ); - - }); - }); - -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_extents.cpp b/test/tensor/test_static_extents.cpp deleted file mode 100644 index c92794886..000000000 --- a/test/tensor/test_static_extents.cpp +++ /dev/null @@ -1,366 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#include -#include -#include -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE(test_static_extents) - - -struct fixture -{ - template - using extents = boost::numeric::ublas::extents; - - extents<> e0 {}; - extents<1> e1 {}; - extents<1, 1> e11 {}; - extents<2, 1> e21 {}; - extents<1, 2> e12 {}; - extents<2, 3> e23 {}; - extents<2, 1, 1> e211 {}; - extents<2, 3, 1> e231 {}; - extents<1, 2, 3> e123 {}; - extents<4, 2, 3> e423 {}; - extents<1, 2, 3, 4> e1234 {}; - extents<4, 2, 1, 3> e4213 {}; - extents<1, 2, 3, 4, 1> e12341 {}; - extents<4, 2, 1, 3, 1> e42131 {}; - extents<1, 4, 2, 1, 3, 1> e142131 {}; -}; - -BOOST_FIXTURE_TEST_CASE(test_extents_static_ctor, fixture, - *boost::unit_test::label("extents_static") *boost::unit_test::label("ctor")) -{ - - namespace ublas = boost::numeric::ublas; - - BOOST_CHECK( ublas::empty( e0)); - BOOST_CHECK(! ublas::empty( e1)); - BOOST_CHECK(! ublas::empty( e11)); - BOOST_CHECK(! ublas::empty( e12)); - BOOST_CHECK(! ublas::empty( e21)); - BOOST_CHECK(! ublas::empty( e23)); - BOOST_CHECK(! ublas::empty( e211)); - BOOST_CHECK(! ublas::empty( e123)); - BOOST_CHECK(! ublas::empty( e423)); - BOOST_CHECK(! ublas::empty( e1234)); - BOOST_CHECK(! ublas::empty( e4213)); - BOOST_CHECK(! ublas::empty(e142131)); - - BOOST_CHECK_EQUAL( ublas::size( e0),0); - BOOST_CHECK_EQUAL( ublas::size( e1),1); - BOOST_CHECK_EQUAL( ublas::size( e11),2); - BOOST_CHECK_EQUAL( ublas::size( e12),2); - BOOST_CHECK_EQUAL( ublas::size( e21),2); - BOOST_CHECK_EQUAL( ublas::size( e23),2); - BOOST_CHECK_EQUAL( ublas::size( e211),3); - BOOST_CHECK_EQUAL( ublas::size( e123),3); - BOOST_CHECK_EQUAL( ublas::size( e423),3); - BOOST_CHECK_EQUAL( ublas::size( e1234),4); - BOOST_CHECK_EQUAL( ublas::size( e4213),4); - BOOST_CHECK_EQUAL( ublas::size(e142131),6); - - - BOOST_CHECK_EQUAL( ublas::size_v,0); - BOOST_CHECK_EQUAL( ublas::size_v,1); - BOOST_CHECK_EQUAL( ublas::size_v,2); - BOOST_CHECK_EQUAL( ublas::size_v,2); - BOOST_CHECK_EQUAL( ublas::size_v,2); - BOOST_CHECK_EQUAL( ublas::size_v,2); - BOOST_CHECK_EQUAL( ublas::size_v,3); - BOOST_CHECK_EQUAL( ublas::size_v,3); - BOOST_CHECK_EQUAL( ublas::size_v,3); - BOOST_CHECK_EQUAL( ublas::size_v,4); - BOOST_CHECK_EQUAL( ublas::size_v,4); - BOOST_CHECK_EQUAL( ublas::size_v,6); - -} - -BOOST_FIXTURE_TEST_CASE(test_extents_static_product, fixture, - *boost::unit_test::label("extents_static") *boost::unit_test::label("product")) -{ - - namespace ublas = boost::numeric::ublas; - - BOOST_CHECK_EQUAL(ublas::product( e0), 0); - //FIXME: BOOST_CHECK_EQUAL(ublas::product( e1), 1); - BOOST_CHECK_EQUAL(ublas::product( e11), 1); - BOOST_CHECK_EQUAL(ublas::product( e12), 2); - BOOST_CHECK_EQUAL(ublas::product( e21), 2); - BOOST_CHECK_EQUAL(ublas::product( e23), 6); - BOOST_CHECK_EQUAL(ublas::product( e211), 2); - BOOST_CHECK_EQUAL(ublas::product( e123), 6); - BOOST_CHECK_EQUAL(ublas::product( e423), 24); - BOOST_CHECK_EQUAL(ublas::product( e1234), 24); - BOOST_CHECK_EQUAL(ublas::product( e4213), 24); - BOOST_CHECK_EQUAL(ublas::product(e142131), 24); - - - BOOST_CHECK_EQUAL(ublas::product_v, 0); - BOOST_CHECK_EQUAL(ublas::product_v, 1); - BOOST_CHECK_EQUAL(ublas::product_v, 1); - BOOST_CHECK_EQUAL(ublas::product_v, 2); - BOOST_CHECK_EQUAL(ublas::product_v, 2); - BOOST_CHECK_EQUAL(ublas::product_v, 6); - BOOST_CHECK_EQUAL(ublas::product_v, 2); - BOOST_CHECK_EQUAL(ublas::product_v, 6); - BOOST_CHECK_EQUAL(ublas::product_v, 24); - BOOST_CHECK_EQUAL(ublas::product_v, 24); - BOOST_CHECK_EQUAL(ublas::product_v, 24); - BOOST_CHECK_EQUAL(ublas::product_v, 24); -} - -BOOST_FIXTURE_TEST_CASE(test_static_extents_access, fixture, - *boost::unit_test::label("extents_static") *boost::unit_test::label("access")) -{ - namespace ublas = boost::numeric::ublas; - - BOOST_REQUIRE_EQUAL( ublas::size_v,0); - BOOST_REQUIRE_EQUAL( ublas::size_v,1); - BOOST_REQUIRE_EQUAL( ublas::size_v,2); - BOOST_REQUIRE_EQUAL( ublas::size_v,2); - BOOST_REQUIRE_EQUAL( ublas::size_v,2); - BOOST_REQUIRE_EQUAL( ublas::size_v,2); - BOOST_REQUIRE_EQUAL( ublas::size_v,3); - BOOST_REQUIRE_EQUAL( ublas::size_v,3); - BOOST_REQUIRE_EQUAL( ublas::size_v,3); - BOOST_REQUIRE_EQUAL( ublas::size_v,4); - BOOST_REQUIRE_EQUAL( ublas::size_v,4); - BOOST_REQUIRE_EQUAL( ublas::size_v,6); - - - BOOST_CHECK_EQUAL((ublas::get_v), 1); - - BOOST_CHECK_EQUAL((ublas::get_v), 1); - BOOST_CHECK_EQUAL((ublas::get_v), 1); - - BOOST_CHECK_EQUAL((ublas::get_v), 1); - BOOST_CHECK_EQUAL((ublas::get_v), 2); - - BOOST_CHECK_EQUAL((ublas::get_v), 2); - BOOST_CHECK_EQUAL((ublas::get_v), 1); - - BOOST_CHECK_EQUAL((ublas::get_v), 2); - BOOST_CHECK_EQUAL((ublas::get_v), 3); - - BOOST_CHECK_EQUAL((ublas::get_v), 2); - BOOST_CHECK_EQUAL((ublas::get_v), 1); - BOOST_CHECK_EQUAL((ublas::get_v), 1); - - BOOST_CHECK_EQUAL((ublas::get_v), 1); - BOOST_CHECK_EQUAL((ublas::get_v), 2); - BOOST_CHECK_EQUAL((ublas::get_v), 3); - - BOOST_CHECK_EQUAL((ublas::get_v), 4); - BOOST_CHECK_EQUAL((ublas::get_v), 2); - BOOST_CHECK_EQUAL((ublas::get_v), 3); - - BOOST_CHECK_EQUAL((ublas::get_v), 1); - BOOST_CHECK_EQUAL((ublas::get_v), 2); - BOOST_CHECK_EQUAL((ublas::get_v), 3); - BOOST_CHECK_EQUAL((ublas::get_v), 4); - - BOOST_CHECK_EQUAL((ublas::get_v), 4); - BOOST_CHECK_EQUAL((ublas::get_v), 2); - BOOST_CHECK_EQUAL((ublas::get_v), 1); - BOOST_CHECK_EQUAL((ublas::get_v), 3); - - //FIXME: BOOST_CHECK_EQUAL(e1 [0], 1); - - BOOST_CHECK_EQUAL(e11[0], 1); - BOOST_CHECK_EQUAL(e11[1], 1); - - BOOST_CHECK_EQUAL(e12[0], 1); - BOOST_CHECK_EQUAL(e12[1], 2); - - BOOST_CHECK_EQUAL(e21[0], 2); - BOOST_CHECK_EQUAL(e21[1], 1); - - BOOST_CHECK_EQUAL(e23[0], 2); - BOOST_CHECK_EQUAL(e23[1], 3); - - BOOST_CHECK_EQUAL(e211[0], 2); - BOOST_CHECK_EQUAL(e211[1], 1); - BOOST_CHECK_EQUAL(e211[2], 1); - - BOOST_CHECK_EQUAL(e123[0], 1); - BOOST_CHECK_EQUAL(e123[1], 2); - BOOST_CHECK_EQUAL(e123[2], 3); - - BOOST_CHECK_EQUAL(e423[0], 4); - BOOST_CHECK_EQUAL(e423[1], 2); - BOOST_CHECK_EQUAL(e423[2], 3); - - BOOST_CHECK_EQUAL(e1234[0], 1); - BOOST_CHECK_EQUAL(e1234[1], 2); - BOOST_CHECK_EQUAL(e1234[2], 3); - BOOST_CHECK_EQUAL(e1234[3], 4); - - BOOST_CHECK_EQUAL(e4213[0], 4); - BOOST_CHECK_EQUAL(e4213[1], 2); - BOOST_CHECK_EQUAL(e4213[2], 1); - BOOST_CHECK_EQUAL(e4213[3], 3); -} - -struct fixture_second -{ - template - using extents = boost::numeric::ublas::extents; - - std::tuple< - extents<> - > empty; - - std::tuple< - //FIXME: extents<1>, - extents<1,1>, - extents<1,1,1>, - extents<1,1,1,1> - > scalars; - - std::tuple< - extents<1,2>, - extents<2,1>, - extents<1,2,1>, - extents<2,1,1>, - extents<1,4,1,1>, - extents<5,1,1,1,1> - > vectors; - - std::tuple< - extents<2,3>, - extents<3,2,1>, - extents<4,4,1,1>, - extents<6,6,1,1,1,1> - > matrices; - - std::tuple< - extents<1,2,3>, - extents<1,2,3>, - extents<1,2,3,1>, - extents<4,2,3>, - extents<4,2,3,1>, - extents<4,2,3,1,1>, - extents<6,6,6,1,1,1>, - extents<6,6,1,1,1,6> - > tensors; -}; - - -BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture_second, - *boost::unit_test::label("extents_static") *boost::unit_test::label("is_scalar_vector_matrix_tensor")) { - - namespace ublas = boost::numeric::ublas; - - for_each_in_tuple(scalars,[](auto const& /*unused*/, auto const& e){ - BOOST_CHECK( ublas::is_scalar(e) ); - BOOST_CHECK( ublas::is_vector(e) ); - BOOST_CHECK( ublas::is_matrix(e) ); - BOOST_CHECK( !ublas::is_tensor(e) ); - - BOOST_CHECK( ublas::is_scalar_v); - BOOST_CHECK( ublas::is_vector_v); - BOOST_CHECK( ublas::is_matrix_v); - BOOST_CHECK( !ublas::is_tensor_v); - - }); - - for_each_in_tuple(vectors,[](auto const& /*unused*/, auto& e){ - BOOST_CHECK( !ublas::is_scalar(e) ); - BOOST_CHECK( ublas::is_vector(e) ); - BOOST_CHECK( ublas::is_matrix(e) ); - BOOST_CHECK( !ublas::is_tensor(e) ); - - BOOST_CHECK( !ublas::is_scalar_v); - BOOST_CHECK( ublas::is_vector_v); - BOOST_CHECK( ublas::is_matrix_v); - BOOST_CHECK( !ublas::is_tensor_v); - }); - - for_each_in_tuple(matrices,[](auto const& /*unused*/, auto& e){ - BOOST_CHECK( !ublas::is_scalar(e) ); - BOOST_CHECK( !ublas::is_vector(e) ); - BOOST_CHECK( ublas::is_matrix(e) ); - BOOST_CHECK( !ublas::is_tensor(e) ); - - BOOST_CHECK( !ublas::is_scalar_v); - BOOST_CHECK( !ublas::is_vector_v); - BOOST_CHECK( ublas::is_matrix_v); - BOOST_CHECK( !ublas::is_tensor_v); - }); - - for_each_in_tuple(tensors,[](auto const& /*unused*/, auto& e){ - BOOST_CHECK( !ublas::is_scalar(e) ); - BOOST_CHECK( !ublas::is_vector(e) ); - BOOST_CHECK( !ublas::is_matrix(e) ); - BOOST_CHECK( ublas::is_tensor(e) ); - - BOOST_CHECK( !ublas::is_scalar_v); - BOOST_CHECK( !ublas::is_vector_v); - BOOST_CHECK( !ublas::is_matrix_v); - BOOST_CHECK( ublas::is_tensor_v); - }); - -} - -BOOST_FIXTURE_TEST_CASE(test_static_extents_valid, fixture_second, - *boost::unit_test::label("extents_extents") *boost::unit_test::label("valid")) -{ - namespace ublas = boost::numeric::ublas; - -//FIXME: BOOST_CHECK(!ublas::is_valid (extents<0>{}) ); -//FIXME: BOOST_CHECK( ublas::is_valid (extents<2>{}) ); -//FIXME: BOOST_CHECK( ublas::is_valid (extents<3>{}) ); - - BOOST_CHECK(!ublas::is_valid_v> ); - BOOST_CHECK( ublas::is_valid_v> ); - BOOST_CHECK( ublas::is_valid_v> ); - - - for_each_in_tuple(scalars ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid (e) ); }); - for_each_in_tuple(vectors ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid (e) ); }); - for_each_in_tuple(matrices ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid (e) ); }); - for_each_in_tuple(tensors ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid (e) ); }); - - - for_each_in_tuple(scalars ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid_v ); }); - for_each_in_tuple(vectors ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid_v ); }); - for_each_in_tuple(matrices ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid_v ); }); - for_each_in_tuple(tensors ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK( ublas::is_valid_v ); }); -} - - -BOOST_FIXTURE_TEST_CASE(test_static_extents_comparsion_operator, fixture, - *boost::unit_test::label("extents_static") *boost::unit_test::label("equals")) -{ - namespace ublas = boost::numeric::ublas; - - BOOST_CHECK( e0 == e0 ); - BOOST_CHECK( e1 == e1 ); - BOOST_CHECK( e11 == e11 ); - BOOST_CHECK( e21 == e21 ); - BOOST_CHECK( e12 == e12 ); - BOOST_CHECK( e23 == e23 ); - BOOST_CHECK( e231 == e231 ); - BOOST_CHECK( e211 == e211 ); - BOOST_CHECK( e123 == e123 ); - BOOST_CHECK( e423 == e423 ); - BOOST_CHECK( e1234 == e1234 ); - BOOST_CHECK( e4213 == e4213 ); - BOOST_CHECK( e142131 == e142131 ); - -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_operators_arithmetic.cpp b/test/tensor/test_static_operators_arithmetic.cpp deleted file mode 100644 index 71e1447ad..000000000 --- a/test/tensor/test_static_operators_arithmetic.cpp +++ /dev/null @@ -1,242 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - - -#include - -#include -#include -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE(test_tensor_static_arithmetic_operations) - -using double_extended = boost::multiprecision::cpp_bin_float_double_extended; - -using test_types = zip::with_t; - -struct fixture -{ - template - using extents_type = boost::numeric::ublas::extents; - - fixture() = default; - - std::tuple< - extents_type<1,1>, // 1 - extents_type<2,3>, // 2 - extents_type<4,1,3>, // 3 - extents_type<4,2,3>, // 4 - extents_type<4,2,3,5> // 5 - > extents; - -}; - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - auto t = tensor_type (); - auto t2 = tensor_type (); - auto r = tensor_type (); - 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 (1) + tensor_type (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_each_in_tuple(extents,check); -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - auto t = tensor_type (); - auto t2 = tensor_type (); - 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_each_in_tuple(extents,check); -} - - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_assign_arithmetic_operations, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - auto t = tensor_type (); - auto t2 = tensor_type (); - auto r = tensor_type (); - 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_each_in_tuple(extents,check); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_operators_comparison.cpp b/test/tensor/test_static_operators_comparison.cpp deleted file mode 100644 index 9010482d0..000000000 --- a/test/tensor/test_static_operators_comparison.cpp +++ /dev/null @@ -1,198 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - - -#include -#include -#include -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE(test_tensor_static_comparison) - -using double_extended = boost::multiprecision::cpp_bin_float_double_extended; - -using test_types = zip::with_t; - -struct fixture { - - template - using extents_type = boost::numeric::ublas::extents; - - fixture()= default; - - std::tuple< - extents_type<1,1>, // 1 - extents_type<2,3>, // 2 - extents_type<4,1,3>, // 3 - extents_type<4,2,3>, // 4 - extents_type<4,2,3,5> // 5 - > extents; -}; - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto check = [](auto const& /*unused*/, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - auto t = tensor_type (); - auto t2 = tensor_type (); - 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_each_in_tuple(extents,check); - -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - - auto check = [](auto const& /*unused*/, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - - auto t = tensor_type (); - auto t2 = tensor_type (); - 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_each_in_tuple(extents,check); - -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_scalar, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - - for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - - BOOST_CHECK( tensor_type(value_type{2}) == tensor_type(value_type{2}) ); - BOOST_CHECK( tensor_type(value_type{2}) != tensor_type(value_type{1}) ); - - if(ublas::empty(e)) - return; - - BOOST_CHECK( !(tensor_type(2) < 2) ); - BOOST_CHECK( !(tensor_type(2) > 2) ); - BOOST_CHECK( (tensor_type(2) >= 2) ); - BOOST_CHECK( (tensor_type(2) <= 2) ); - BOOST_CHECK( (tensor_type(2) == 2) ); - BOOST_CHECK( (tensor_type(2) != 3) ); - - BOOST_CHECK( !(2 > tensor_type(2)) ); - BOOST_CHECK( !(2 < tensor_type(2)) ); - BOOST_CHECK( (2 <= tensor_type(2)) ); - BOOST_CHECK( (2 >= tensor_type(2)) ); - BOOST_CHECK( (2 == tensor_type(2)) ); - BOOST_CHECK( (3 != tensor_type(2)) ); - - BOOST_CHECK( !( tensor_type(2)+3 < 5) ); - BOOST_CHECK( !( tensor_type(2)+3 > 5) ); - BOOST_CHECK( ( tensor_type(2)+3 >= 5) ); - BOOST_CHECK( ( tensor_type(2)+3 <= 5) ); - BOOST_CHECK( ( tensor_type(2)+3 == 5) ); - BOOST_CHECK( ( tensor_type(2)+3 != 6) ); - - - BOOST_CHECK( !( 5 > tensor_type(2)+3) ); - BOOST_CHECK( !( 5 < tensor_type(2)+3) ); - BOOST_CHECK( ( 5 >= tensor_type(2)+3) ); - BOOST_CHECK( ( 5 <= tensor_type(2)+3) ); - BOOST_CHECK( ( 5 == tensor_type(2)+3) ); - BOOST_CHECK( ( 6 != tensor_type(2)+3) ); - - - BOOST_CHECK( !( tensor_type(2)+tensor_type(3) < 5) ); - BOOST_CHECK( !( tensor_type(2)+tensor_type(3) > 5) ); - BOOST_CHECK( ( tensor_type(2)+tensor_type(3) >= 5) ); - BOOST_CHECK( ( tensor_type(2)+tensor_type(3) <= 5) ); - BOOST_CHECK( ( tensor_type(2)+tensor_type(3) == 5) ); - BOOST_CHECK( ( tensor_type(2)+tensor_type(3) != 6) ); - - - BOOST_CHECK( !( 5 > tensor_type(2)+tensor_type(3)) ); - BOOST_CHECK( !( 5 < tensor_type(2)+tensor_type(3)) ); - BOOST_CHECK( ( 5 >= tensor_type(2)+tensor_type(3)) ); - BOOST_CHECK( ( 5 <= tensor_type(2)+tensor_type(3)) ); - BOOST_CHECK( ( 5 == tensor_type(2)+tensor_type(3)) ); - BOOST_CHECK( ( 6 != tensor_type(2)+tensor_type(3)) ); - - }); - -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_strides.cpp b/test/tensor/test_static_strides.cpp deleted file mode 100644 index 5f5a203e9..000000000 --- a/test/tensor/test_static_strides.cpp +++ /dev/null @@ -1,156 +0,0 @@ -// -// Copyright (c) 2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - -#include -#include - -BOOST_AUTO_TEST_SUITE(test_static_strides) - -using test_types = std::tuple; - -template -using extents = boost::numeric::ublas::extents; - -using first_order = boost::numeric::ublas::layout::first_order; -using last_order = boost::numeric::ublas::layout::last_order; - -BOOST_AUTO_TEST_CASE_TEMPLATE(test_static_strides_ctor, value, test_types) -{ - namespace ublas = boost::numeric::ublas; - - constexpr auto s11 = ublas::to_strides_v,first_order>; - constexpr auto s12 = ublas::to_strides_v,first_order>; - constexpr auto s21 = ublas::to_strides_v,first_order>; - constexpr auto s23 = ublas::to_strides_v,first_order>; - constexpr auto s231 = ublas::to_strides_v,first_order>; - constexpr auto s123 = ublas::to_strides_v,first_order>; - constexpr auto s423 = ublas::to_strides_v,first_order>; - - BOOST_CHECK_EQUAL(s11.empty(), false); - BOOST_CHECK_EQUAL(s12.empty(), false); - BOOST_CHECK_EQUAL(s21.empty(), false); - BOOST_CHECK_EQUAL(s23.empty(), false); - BOOST_CHECK_EQUAL(s231.empty(), false); - BOOST_CHECK_EQUAL(s123.empty(), false); - BOOST_CHECK_EQUAL(s423.empty(), false); - - BOOST_CHECK_EQUAL(s11.size(), 2); - BOOST_CHECK_EQUAL(s12.size(), 2); - BOOST_CHECK_EQUAL(s21.size(), 2); - BOOST_CHECK_EQUAL(s23.size(), 2); - BOOST_CHECK_EQUAL(s231.size(), 3); - BOOST_CHECK_EQUAL(s123.size(), 3); - BOOST_CHECK_EQUAL(s423.size(), 3); -} - -BOOST_AUTO_TEST_CASE(test_static_strides_ctor_access_first_order) -{ - namespace ublas = boost::numeric::ublas; - - constexpr auto s11 = ublas::to_strides_v,first_order>; - constexpr auto s12 = ublas::to_strides_v,first_order>; - constexpr auto s21 = ublas::to_strides_v,first_order>; - constexpr auto s23 = ublas::to_strides_v,first_order>; - constexpr auto s231 = ublas::to_strides_v,first_order>; - constexpr auto s213 = ublas::to_strides_v,first_order>; - constexpr auto s123 = ublas::to_strides_v,first_order>; - constexpr auto s423 = ublas::to_strides_v,first_order>; - - BOOST_REQUIRE_EQUAL(s11.size(), 2); - BOOST_REQUIRE_EQUAL(s12.size(), 2); - BOOST_REQUIRE_EQUAL(s21.size(), 2); - BOOST_REQUIRE_EQUAL(s23.size(), 2); - BOOST_REQUIRE_EQUAL(s231.size(), 3); - BOOST_REQUIRE_EQUAL(s213.size(), 3); - BOOST_REQUIRE_EQUAL(s123.size(), 3); - BOOST_REQUIRE_EQUAL(s423.size(), 3); - - - BOOST_CHECK_EQUAL(s11[0], 1); - BOOST_CHECK_EQUAL(s11[1], 1); - - BOOST_CHECK_EQUAL(s12[0], 1); - BOOST_CHECK_EQUAL(s12[1], 1); - - BOOST_CHECK_EQUAL(s21[0], 1); - BOOST_CHECK_EQUAL(s21[1], 2); // NOTE: is this the way we want to have it? - - BOOST_CHECK_EQUAL(s23[0], 1); - BOOST_CHECK_EQUAL(s23[1], 2); - - BOOST_CHECK_EQUAL(s231[0], 1); - BOOST_CHECK_EQUAL(s231[1], 2); - BOOST_CHECK_EQUAL(s231[2], 6); - - BOOST_CHECK_EQUAL(s123[0], 1); - BOOST_CHECK_EQUAL(s123[1], 1); - BOOST_CHECK_EQUAL(s123[2], 2); - - BOOST_CHECK_EQUAL(s213[0], 1); - BOOST_CHECK_EQUAL(s213[1], 2); - BOOST_CHECK_EQUAL(s213[2], 2); - - BOOST_CHECK_EQUAL(s423[0], 1); - BOOST_CHECK_EQUAL(s423[1], 4); - BOOST_CHECK_EQUAL(s423[2], 8); -} - -BOOST_AUTO_TEST_CASE(test_static_strides_ctor_access_last_order) -{ - namespace ublas = boost::numeric::ublas; - - constexpr auto s11 = ublas::to_strides_v,last_order>; - constexpr auto s12 = ublas::to_strides_v,last_order>; - constexpr auto s21 = ublas::to_strides_v,last_order>; - constexpr auto s23 = ublas::to_strides_v,last_order>; - constexpr auto s231 = ublas::to_strides_v,last_order>; - constexpr auto s213 = ublas::to_strides_v,last_order>; - constexpr auto s123 = ublas::to_strides_v,last_order>; - constexpr auto s423 = ublas::to_strides_v,last_order>; - - BOOST_REQUIRE_EQUAL(s11.size(), 2); - BOOST_REQUIRE_EQUAL(s12.size(), 2); - BOOST_REQUIRE_EQUAL(s21.size(), 2); - BOOST_REQUIRE_EQUAL(s23.size(), 2); - BOOST_REQUIRE_EQUAL(s231.size(), 3); - BOOST_REQUIRE_EQUAL(s213.size(), 3); - BOOST_REQUIRE_EQUAL(s123.size(), 3); - BOOST_REQUIRE_EQUAL(s423.size(), 3); - - - BOOST_CHECK_EQUAL(s11[0], 1); - BOOST_CHECK_EQUAL(s11[1], 1); - - BOOST_CHECK_EQUAL(s12[0], 2); //NOTE: is this the way we want the stride to be computed? - BOOST_CHECK_EQUAL(s12[1], 1); - - BOOST_CHECK_EQUAL(s21[0], 1); - BOOST_CHECK_EQUAL(s21[1], 1); - - BOOST_CHECK_EQUAL(s23[0], 3); - BOOST_CHECK_EQUAL(s23[1], 1); - - BOOST_CHECK_EQUAL(s231[0], 3); - BOOST_CHECK_EQUAL(s231[1], 1); - BOOST_CHECK_EQUAL(s231[2], 1); - - BOOST_CHECK_EQUAL(s123[0], 6); - BOOST_CHECK_EQUAL(s123[1], 3); - BOOST_CHECK_EQUAL(s123[2], 1); - - BOOST_CHECK_EQUAL(s213[0], 3); - BOOST_CHECK_EQUAL(s213[1], 3); - BOOST_CHECK_EQUAL(s213[2], 1); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_tensor.cpp b/test/tensor/test_static_tensor.cpp deleted file mode 100644 index 653a2726b..000000000 --- a/test/tensor/test_static_tensor.cpp +++ /dev/null @@ -1,398 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - - -#include -#include - -#include -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE ( test_tensor_static ) - -using test_types = zip>::with_t; - - -BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - -// auto a1 = ublas::tensor_static,layout_type>{}; -// BOOST_CHECK_EQUAL( a1.size() , 0ul ); -// BOOST_CHECK( a1.empty() ); - - auto a2 = ublas::tensor_static,layout_type>{}; - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - - auto a3 = ublas::tensor_static,layout_type>{}; - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - - auto a4 = ublas::tensor_static,layout_type>{}; - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - - auto a5 = ublas::tensor_static,layout_type>{}; - BOOST_CHECK_EQUAL( a5.size() , 2 ); - BOOST_CHECK( !a5.empty() ); - - auto a6 = ublas::tensor_static,layout_type>{}; - BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); - BOOST_CHECK( !a6.empty() ); - - auto a7 = ublas::tensor_static,layout_type>{}; - BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); - BOOST_CHECK( !a7.empty() ); - -} - - -struct fixture -{ - template - using extents_type = boost::numeric::ublas::extents; - - fixture()=default; - - std::tuple< - extents_type<1,1>, // 1 - extents_type<2,3>, // 2 - extents_type<4,1,3>, // 3 - extents_type<4,2,3>, // 4 - extents_type<4,2,3,5> // 5 - > extents; -}; - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ - using extents_type = std::decay_t; - auto t = ublas::tensor_static{}; - - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - if(ublas::empty(e)) { - BOOST_CHECK ( t.empty() ); - } - else{ - BOOST_CHECK ( !t.empty() ); - } - }); - -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ - using extents_type = std::decay_t; - auto r = ublas::tensor_static{0}; - - 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(ublas::empty(e)) { - BOOST_CHECK ( t.empty() ); - } - else{ - BOOST_CHECK ( !t.empty() ); - } - - for(auto i = 0ul; i < t.size(); ++i) - BOOST_TEST( t[i] == r[i]); - - }); -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - using other_layout_type = std::conditional_t::value, ublas::layout::last_order, ublas::layout::first_order>; - - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - auto r = tensor_type{0}; - ublas::tensor_static 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_TEST( q[i] == r[i]); - - }); -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_move_ctor, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto check = [](auto const& /*unused*/, auto& e) - { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - auto r = tensor_type{}; - auto t = std::move(r); - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - - if(ublas::empty(e)) { - BOOST_CHECK ( t.empty() ); - } - else{ - BOOST_CHECK ( !t.empty() ); - } - - }; - - for_each_in_tuple(extents,check); -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - std::random_device device{}; - std::minstd_rand0 generator(device()); - - using distribution_type = std::conditional_t, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; - auto distribution = distribution_type(1,6); - - for_each_in_tuple(extents, [&](auto const& /*unused*/, auto const& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - - auto r = value_type( static_cast< inner_type_t >(distribution(generator)) ); - auto t = tensor_type{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) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - using container_type = typename tensor_type::container_type; - - auto a = container_type(); - auto v = value_type {}; - - for(auto& aa : a){ - aa = v; - v += value_type{1}; - } - auto t = tensor_type(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) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - for_each_in_tuple(extents, [](auto const& /*unused*/, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - - auto t = tensor_type{}; - 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) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - auto check1 = [](const auto& 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 auto& t) - { - std::array k = {0,0}; - auto r = std::is_same::value ? 1 : 0; - auto q = std::is_same::value ? 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 auto& t) - { - std::array k= {0,0,0}; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 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 auto& t) - { - std::array k= {0,0,0,0}; - using op_type = std::conditional_t, std::minus<>, std::plus<>>; - auto r = std::is_same_v ? 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& /*unused*/, auto const& e) { - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - auto t = tensor_type{}; - auto v = value_type {}; - for(auto i = 0ul; i < t.size(); ++i){ - t[i] = v; - v+=value_type{1}; - } - - if constexpr ( std::tuple_size_v == 1) check1(t); - else if constexpr ( std::tuple_size_v == 2) check2(t); - else if constexpr ( std::tuple_size_v == 3) check3(t); - else if constexpr ( std::tuple_size_v == 4) check4(t); - - }; - - for_each_in_tuple(extents,check); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_types, fixture) -{ - namespace ublas = boost::numeric::ublas; - using value_type = typename value::first_type; - using layout_type = typename value::second_type; - - for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e){ - using extents_type = std::decay_t; - using tensor_type = ublas::tensor_static; - - auto v = value_type {} + value_type{1}; - auto t = tensor_type{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.empty()) { - BOOST_CHECK( t.data() == std::addressof( *t.begin () ) ) ; - BOOST_CHECK( t.data() == std::addressof( *t.cbegin() ) ) ; - } - }); - -} - -//BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_throw, value, test_types, fixture) -//{ -// namespace ublas = boost::numeric::ublas; -// using value_type = typename value::first_type; -// using layout_type = typename value::second_type; -// using tensor_type = ublas::tensor_static, layout_type>; - -// auto t = tensor_type{}; -// auto i = ublas::index::index_type<4>{}; -// BOOST_CHECK_THROW((void)t.operator()(i,i,i), std::runtime_error); - -//} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_static_tensor_matrix_vector.cpp b/test/tensor/test_static_tensor_matrix_vector.cpp deleted file mode 100644 index 22c2ba434..000000000 --- a/test/tensor/test_static_tensor_matrix_vector.cpp +++ /dev/null @@ -1,454 +0,0 @@ -// -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#include -#include -#include -#include -#include - -#include "utility.hpp" - - - -BOOST_AUTO_TEST_SUITE ( test_tensor_static_matrix_interoperability ) - -using test_types = zip::with_t; - - -BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, pair, test_types) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - - ublas::tensor_static,layout> a2 = matrix(1,1); - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - - ublas::tensor_static,layout> a3 = matrix(2,1); - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - - ublas::tensor_static,layout> a4 = matrix(1,2); - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - - ublas::tensor_static,layout> a5 = matrix(2,3); - BOOST_CHECK_EQUAL( a5.size() , 6 ); - BOOST_CHECK( !a5.empty() ); -} - - -BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, pair, test_types) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using vector = typename tensor::vector_type; - - ublas::tensor_static,layout> a2 = vector(1); - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - - ublas::tensor_static,layout> a3 = vector(2); - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - - ublas::tensor_static,layout> a4 = vector(2); - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - - ublas::tensor_static,layout> a5 = vector(3); - BOOST_CHECK_EQUAL( a5.size() , 3 ); - BOOST_CHECK( !a5.empty() ); -} - - -struct fixture -{ - template - using shape = boost::numeric::ublas::extents; - - fixture()=default; - - std::tuple< - shape<1,1>, // 0 - shape<2,3>, // 1 - shape<5,8>, // 2 - shape<9,7> // 3 - > extents; -}; - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - - auto check = [](auto const& /*unused*/, auto& e) { - using shape = std::decay_t; - using etensor = ublas::tensor_static; - - assert(ublas::size(e)==2); - etensor t = matrix{e[0],e[1]}; - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - BOOST_CHECK ( !t.empty() ); - }; - - for_each_in_tuple(extents,check); -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using vector = typename tensor::vector_type; - - auto check = [](auto const& /*unused*/, auto& e) { - using shape = std::decay_t; - using etensor = ublas::tensor_static; - - if constexpr( ublas::get_v == 1 ){ - assert(ublas::size(e)==2); - if(ublas::empty(e)) - return; - - etensor t = vector(ublas::product(e)); - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - BOOST_CHECK ( !t.empty() ); - } - - }; - - for_each_in_tuple(extents,check); -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - - auto check = [](auto const& /*unused*/, auto& e) { - using shape = std::decay_t; - using etensor = ublas::tensor_static; - - assert(ublas::size(e) == 2); - auto t = etensor{}; - auto r = matrix(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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - BOOST_CHECK ( !t.empty() ); - - 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_each_in_tuple(extents,check); -} - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using vector = typename tensor::vector_type; - - auto check = [](auto const& /*unused*/, auto& e) { - using shape = std::decay_t; - using etensor = ublas::tensor_static; - - assert(ublas::size(e) == 2); - - if constexpr( ublas::get_v == 1 ){ - auto t = etensor{}; - auto r = vector(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() , ublas::product (e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - BOOST_CHECK ( !t.empty() ); - - for(auto i = 0ul; i < t.size(); ++i){ - BOOST_CHECK_EQUAL( t[i], r(i) ); - } - } - }; - - for_each_in_tuple(extents,check); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - - auto check = [](auto const& /*unused*/, auto& e) { - using shape = std::decay_t; - using etensor = ublas::tensor_static; - - assert(ublas::size(e) == 2); - auto t = etensor{}; - auto r = matrix(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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - BOOST_CHECK ( !t.empty() ); - - 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_each_in_tuple(extents,check); -} - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using vector = typename tensor::vector_type; - - auto check = [](auto const& /*unused*/, auto& e) { - using shape = std::decay_t; - using etensor = ublas::tensor_static; - - assert(ublas::size(e) == 2); - if constexpr( ublas::get_v == 1 ){ - auto t = etensor{}; - auto r = vector(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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - BOOST_CHECK ( !t.empty() ); - - for(auto i = 0ul; i < t.size(); ++i){ - BOOST_CHECK_EQUAL( t[i], q(i) ); - } - } - }; - - for_each_in_tuple(extents,check); -} - - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - - for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e) { - using shape = std::decay_t; - using etensor = ublas::tensor_static; - - assert(ublas::size(e) == 2); - auto t = etensor{}; - auto r = matrix(e[0],e[1]); - std::iota(r.data().begin(),r.data().end(), 1); - t = r + 3*r; - etensor s = r + 3*r; - etensor 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - BOOST_CHECK ( !t.empty() ); - - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , ublas::size (e) ); - BOOST_CHECK ( !s.empty() ); - - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , ublas::size (e) ); - BOOST_CHECK ( !q.empty() ); - - - 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) ); - } - } - }); -} - - - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using vector = typename tensor::vector_type; - - for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e) { - using shape = std::decay_t; - using etensor = ublas::tensor_static; - - assert(ublas::size(e) == 2); - if constexpr( ublas::get_v == 1 ){ - auto t = etensor{}; - auto r = vector(e[0]*e[1]); - std::iota(r.data().begin(),r.data().end(), value{1}); - t = r + 3*r; - etensor s = r + 3*r; - etensor 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - BOOST_CHECK ( !t.empty() ); - - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , ublas::size (e) ); - BOOST_CHECK ( !s.empty() ); - - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , ublas::size (e) ); - BOOST_CHECK ( !q.empty() ); - - - - 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) ); - } - } - }); -} - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - using vector = typename tensor::vector_type; - - for_each_in_tuple(extents,[](auto const& /*unused*/, auto& e) { - using shape = std::decay_t; - - if constexpr(ublas::product_v <= 2) - return; - - assert(ublas::size_v == 2); - - auto Q = ublas::tensor_static,1>,layout>{} ; - auto A = matrix(e[0],e[1]); - auto b = vector(e[1]); - auto c = vector(e[0]); - std::iota(b.data().begin(),b.data().end(), value{1}); - std::fill(A.data().begin(),A.data().end(), value{1}); - std::fill(c.data().begin(),c.data().end(), value{2}); - std::fill(Q.begin(),Q.end(), 2); - - decltype(Q) 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() ); - - auto n = e[1]; - auto ab = value(std::div(n*(n+1),2).quot); - const auto ref = ab+4*Q(0)+2*c(0); - - BOOST_CHECK( std::all_of(T.begin(),T.end(), [ref](auto cc){ return ref == cc; }) ); - -// BOOST_CHECK_EQUAL( T(i), ab+4*Q(0)+2*c(0) ); - - }); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_strides.cpp b/test/tensor/test_strides.cpp index 71ef94256..2c45b6e12 100644 --- a/test/tensor/test_strides.cpp +++ b/test/tensor/test_strides.cpp @@ -1,5 +1,6 @@ -// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com +// +// Copyright (c) 2021 Cem Bassoy, cem.bassoy@gmail.com +// Copyright (c) 2021, Amit Singh, amitsingh19975@gmail.com // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -9,152 +10,422 @@ // Google and Fraunhofer IOSB, Ettlingen, Germany // - - #include -#include - -BOOST_AUTO_TEST_SUITE(test_strides) - -using test_types = std::tuple; - -using extents = boost::numeric::ublas::extents<>; -using first_order = boost::numeric::ublas::layout::first_order; -using last_order = boost::numeric::ublas::layout::last_order; - - -BOOST_AUTO_TEST_CASE_TEMPLATE( test_strides_ctor, value, test_types) +#include "fixture_utility.hpp" + +BOOST_AUTO_TEST_SUITE(test_strides, + *boost::unit_test::description("Validate Strides") +) + + +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::to_strides(extents<> const&, layout_type)") + *boost::unit_test::description("Testing dynamic strides construction") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_strides_dynamic_ctr, + LayoutType, + boost::numeric::ublas::layout_test_types, + boost::numeric::ublas::fixture_extents_dynamic +) { - namespace ublas = boost::numeric::ublas; - constexpr auto layout = value{}; - - auto s1 = ublas::to_strides(extents {1},layout); - auto s5 = ublas::to_strides(extents {5},layout); - auto s11 = ublas::to_strides(extents {1,1},layout); - auto s12 = ublas::to_strides(extents {1,2},layout); - auto s21 = ublas::to_strides(extents {2,1},layout); - auto s23 = ublas::to_strides(extents {2,3},layout); - auto s231 = ublas::to_strides(extents{2,3,1},layout); - auto s123 = ublas::to_strides(extents{1,2,3},layout); - auto s423 = ublas::to_strides(extents{4,2,3},layout); - - BOOST_CHECK (! s1.empty()); - BOOST_CHECK (! s5.empty()); - BOOST_CHECK (! s11.empty()); - BOOST_CHECK (! s12.empty()); - BOOST_CHECK (! s21.empty()); - BOOST_CHECK (! s23.empty()); - BOOST_CHECK (!s231.empty()); - BOOST_CHECK (!s123.empty()); - BOOST_CHECK (!s423.empty()); - - BOOST_CHECK_EQUAL ( s1.size(), 1); - BOOST_CHECK_EQUAL ( s5.size(), 1); - BOOST_CHECK_EQUAL ( s11.size(), 2); - BOOST_CHECK_EQUAL ( s12.size(), 2); - BOOST_CHECK_EQUAL ( s21.size(), 2); - BOOST_CHECK_EQUAL ( s23.size(), 2); - BOOST_CHECK_EQUAL ( s231.size(), 3); - BOOST_CHECK_EQUAL ( s123.size(), 3); - BOOST_CHECK_EQUAL ( s423.size(), 3); + namespace ublas = boost::numeric::ublas; + + constexpr auto check = [](auto const& e, std::size_t sz){ + auto const s = ublas::to_strides(e, LayoutType{}); + BOOST_CHECK (!s.empty()); + BOOST_CHECK_EQUAL( s.size(), sz); + }; + + BOOST_TEST_CONTEXT("[Dynamic Strides Construction] rank(1) dynamic strides"){ + check(n1, 1ul); + check(n2, 1ul); + } + + BOOST_TEST_CONTEXT("[Dynamic Strides Construction] rank(2) dynamic strides"){ + check(n11, 2ul); + check(n12, 2ul); + check(n21, 2ul); + check(n22, 2ul); + check(n32, 2ul); + } + + BOOST_TEST_CONTEXT("[Dynamic Strides Construction] rank(3) dynamic strides"){ + check(n111, 3ul); + check(n112, 3ul); + check(n121, 3ul); + check(n123, 3ul); + check(n211, 3ul); + check(n213, 3ul); + check(n321, 3ul); + check(n432, 3ul); + } + + BOOST_TEST_CONTEXT("[Dynamic Strides Construction] rank(4) dynamic strides"){ + check(n1111, 4ul); + check(n4231, 4ul); + } } -BOOST_AUTO_TEST_CASE( test_strides_ctor_access_first_order) +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::to_strides(extents const&, layout_type)") + *boost::unit_test::description("Testing static rank strides construction") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_strides_static_rank_ctr, + LayoutType, + boost::numeric::ublas::layout_test_types, + boost::numeric::ublas::fixture_extents_static_rank +) { - namespace ublas = boost::numeric::ublas; - constexpr auto layout = first_order{}; - - auto s1 = ublas::to_strides(extents {1},layout); - auto s5 = ublas::to_strides(extents {5},layout); - auto s11 = ublas::to_strides(extents {1,1},layout); - auto s12 = ublas::to_strides(extents {1,2},layout); - auto s21 = ublas::to_strides(extents {2,1},layout); - auto s23 = ublas::to_strides(extents {2,3},layout); - auto s231 = ublas::to_strides(extents{2,3,1},layout); - auto s123 = ublas::to_strides(extents{1,2,3},layout); - auto s423 = ublas::to_strides(extents{4,2,3},layout); - - BOOST_REQUIRE_EQUAL ( s11 .size(),2); - BOOST_REQUIRE_EQUAL ( s12 .size(),2); - BOOST_REQUIRE_EQUAL ( s21 .size(),2); - BOOST_REQUIRE_EQUAL ( s23 .size(),2); - BOOST_REQUIRE_EQUAL ( s231.size(),3); - BOOST_REQUIRE_EQUAL ( s123.size(),3); - BOOST_REQUIRE_EQUAL ( s423.size(),3); - - - BOOST_CHECK_EQUAL ( s11[0], 1); - BOOST_CHECK_EQUAL ( s11[1], 1); - - BOOST_CHECK_EQUAL ( s12[0], 1); - BOOST_CHECK_EQUAL ( s12[1], 1); + namespace ublas = boost::numeric::ublas; + + constexpr auto check = [](auto const& e, std::size_t sz){ + auto const s = ublas::to_strides(e, LayoutType{}); + BOOST_CHECK (!s.empty()); + BOOST_CHECK_EQUAL( s.size(), sz); + }; + + BOOST_TEST_CONTEXT("[Static Rank Strides Construction] static rank(1) strides"){ + check(n1, 1ul); + check(n2, 1ul); + } + + BOOST_TEST_CONTEXT("[Static Rank Strides Construction] static rank(2) strides"){ + check(n11, 2ul); + check(n12, 2ul); + check(n21, 2ul); + check(n22, 2ul); + check(n32, 2ul); + } + + BOOST_TEST_CONTEXT("[Static Rank Strides Construction] static rank(3) strides"){ + check(n111, 3ul); + check(n112, 3ul); + check(n121, 3ul); + check(n123, 3ul); + check(n211, 3ul); + check(n213, 3ul); + check(n321, 3ul); + check(n432, 3ul); + } + + BOOST_TEST_CONTEXT("[Static Rank Strides Construction] static rank(4) strides"){ + check(n1111, 4ul); + check(n4231, 4ul); + } +} - BOOST_CHECK_EQUAL ( s21[0], 1); - BOOST_CHECK_EQUAL ( s21[1], 1); +BOOST_TEST_DECORATOR( + *boost::unit_test::label("boost::numeric::ublas::to_strides(extents<...> const&, layout_type)") + *boost::unit_test::description("Testing static strides construction") +) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_strides_static_ctr, + LayoutType, + boost::numeric::ublas::layout_test_types, + boost::numeric::ublas::fixture_extents_static +) +{ + namespace ublas = boost::numeric::ublas; + + constexpr auto check = [](E const& /*e*/, std::size_t sz){ + constexpr auto s = ublas::to_strides_v; + BOOST_CHECK (!s.empty()); + BOOST_CHECK_EQUAL( s.size(), sz); + }; + + BOOST_TEST_CONTEXT("[Static Strides Construction] rank(1) static strides"){ + check(n1, 1ul); + check(n2, 1ul); + } + + BOOST_TEST_CONTEXT("[Static Strides Construction] rank(2) static strides"){ + check(n11, 2ul); + check(n12, 2ul); + check(n21, 2ul); + check(n22, 2ul); + check(n32, 2ul); + } + + BOOST_TEST_CONTEXT("[Static Strides Construction] rank(3) static strides"){ + check(n111, 3ul); + check(n112, 3ul); + check(n121, 3ul); + check(n123, 3ul); + check(n211, 3ul); + check(n213, 3ul); + check(n321, 3ul); + check(n432, 3ul); + } + + BOOST_TEST_CONTEXT("[Static Strides Construction] rank(4) static strides"){ + check(n1111, 4ul); + check(n4231, 4ul); + } +} +BOOST_FIXTURE_TEST_CASE(test_first_order_dynamic_strides, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("boost::numeric::ublas::to_strides(extents<> const&, first_order)") + *boost::unit_test::description("Testing the first order dynamic strides")) +{ + + namespace ublas = boost::numeric::ublas; + constexpr auto check = [](auto const& e, std::initializer_list l){ + auto const s = ublas::to_strides(e, ublas::layout::first_order{}); + BOOST_REQUIRE (!s.empty()); + BOOST_REQUIRE_EQUAL( s.size(), l.size()); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(s), std::end(s), std::begin(l), std::end(l)); + }; + + BOOST_TEST_CONTEXT("[Dynamic Strides(First Order)] rank(1) dynamic strides"){ + check(n1, {1ul}); + check(n2, {1ul}); + } + + BOOST_TEST_CONTEXT("[Dynamic Strides(First Order)] rank(2) dynamic strides"){ + check(n11, {1ul, 1ul}); + check(n12, {1ul, 1ul}); + check(n21, {1ul, 1ul}); + check(n22, {1ul, 2ul}); + check(n32, {1ul, 3ul}); + } + + BOOST_TEST_CONTEXT("[Dynamic Strides(First Order)] rank(3) dynamic strides"){ + check(n111, {1ul, 1ul, 1ul}); + check(n112, {1ul, 1ul, 1ul}); + check(n121, {1ul, 1ul, 1ul}); + check(n123, {1ul, 1ul, 2ul}); + check(n211, {1ul, 1ul, 1ul}); + check(n213, {1ul, 2ul, 2ul}); + check(n321, {1ul, 3ul, 6ul}); + check(n432, {1ul, 4ul, 12ul}); + } + + BOOST_TEST_CONTEXT("[Dynamic Strides(First Order)] rank(4) dynamic strides"){ + check(n1111, {1ul, 1ul, 1ul, 1ul}); + check(n4231, {1ul, 4ul, 8ul, 24ul}); + } +} - BOOST_CHECK_EQUAL ( s23[0], 1); - BOOST_CHECK_EQUAL ( s23[1], 2); +BOOST_FIXTURE_TEST_CASE(test_first_order_static_rank_strides, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("boost::numeric::ublas::to_strides(extents const&, first_order)") + *boost::unit_test::description("Testing the first order static rank strides")) +{ + + namespace ublas = boost::numeric::ublas; + constexpr auto check = [](auto const& e, std::initializer_list l){ + auto const s = ublas::to_strides(e, ublas::layout::first_order{}); + BOOST_REQUIRE (!s.empty()); + BOOST_REQUIRE_EQUAL( s.size(), l.size()); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(s), std::end(s), std::begin(l), std::end(l)); + }; + + BOOST_TEST_CONTEXT("[Static Rank Strides(First Order)] static rank(1) dynamic strides"){ + check(n1, {1ul}); + check(n2, {1ul}); + } + + BOOST_TEST_CONTEXT("[Static Rank Strides(First Order)] static rank(2) dynamic strides"){ + check(n11, {1ul, 1ul}); + check(n12, {1ul, 1ul}); + check(n21, {1ul, 1ul}); + check(n22, {1ul, 2ul}); + check(n32, {1ul, 3ul}); + } + + BOOST_TEST_CONTEXT("[Static Rank Strides(First Order)] static rank(3) dynamic strides"){ + check(n111, {1ul, 1ul, 1ul}); + check(n112, {1ul, 1ul, 1ul}); + check(n121, {1ul, 1ul, 1ul}); + check(n123, {1ul, 1ul, 2ul}); + check(n211, {1ul, 1ul, 1ul}); + check(n213, {1ul, 2ul, 2ul}); + check(n321, {1ul, 3ul, 6ul}); + check(n432, {1ul, 4ul, 12ul}); + } + + BOOST_TEST_CONTEXT("[Static Rank Strides(First Order)] static rank(4) dynamic strides"){ + check(n1111, {1ul, 1ul, 1ul, 1ul}); + check(n4231, {1ul, 4ul, 8ul, 24ul}); + } +} - BOOST_CHECK_EQUAL ( s231[0], 1); - BOOST_CHECK_EQUAL ( s231[1], 2); - BOOST_CHECK_EQUAL ( s231[2], 6); +BOOST_FIXTURE_TEST_CASE(test_first_order_static_strides, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("boost::numeric::ublas::to_strides(extents<...> const&, first_order)") + *boost::unit_test::description("Testing the first order static strides")) +{ + + namespace ublas = boost::numeric::ublas; + constexpr auto check = [](E const& /*e*/, std::initializer_list l){ + constexpr auto s = ublas::to_strides_v; + BOOST_REQUIRE (!s.empty()); + BOOST_REQUIRE_EQUAL( s.size(), l.size()); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(s), std::end(s), std::begin(l), std::end(l)); + }; + + BOOST_TEST_CONTEXT("[Static Strides(First Order)] rank(1) static dynamic strides"){ + check(n1, {1ul}); + check(n2, {1ul}); + } + + // TODO: Enable after fixing the issue #119 + // BOOST_TEST_CONTEXT("[Static Strides(First Order)] rank(2) static dynamic strides"){ + // check(n11, {1ul, 1ul}); + // check(n12, {1ul, 1ul}); + // check(n21, {1ul, 1ul}); + // check(n22, {1ul, 2ul}); + // check(n32, {1ul, 3ul}); + // } + + // BOOST_TEST_CONTEXT("[Static Strides(First Order)] rank(3) static dynamic strides"){ + // check(n111, {1ul, 1ul, 1ul}); + // check(n112, {1ul, 1ul, 1ul}); + // check(n121, {1ul, 1ul, 1ul}); + // check(n123, {1ul, 1ul, 2ul}); + // check(n211, {1ul, 1ul, 1ul}); + // check(n213, {1ul, 2ul, 2ul}); + // check(n321, {1ul, 3ul, 6ul}); + // check(n432, {1ul, 4ul, 12ul}); + // } + + // BOOST_TEST_CONTEXT("[Static Strides(First Order)] rank(4) static dynamic strides"){ + // check(n1111, {1ul, 1ul, 1ul, 1ul}); + // check(n4231, {1ul, 4ul, 8ul, 24ul}); + // } +} - BOOST_CHECK_EQUAL ( s123[0], 1); - BOOST_CHECK_EQUAL ( s123[1], 1); - BOOST_CHECK_EQUAL ( s123[2], 2); +BOOST_FIXTURE_TEST_CASE(test_last_order_dynamic_strides, + boost::numeric::ublas::fixture_extents_dynamic, + *boost::unit_test::label("boost::numeric::ublas::to_strides(extents<> const&, last_order)") + *boost::unit_test::description("Testing the last order dynamic strides")) +{ + + namespace ublas = boost::numeric::ublas; + constexpr auto check = [](auto const& e, std::initializer_list l){ + auto const s = ublas::to_strides(e, ublas::layout::last_order{}); + BOOST_REQUIRE (!s.empty()); + BOOST_REQUIRE_EQUAL( s.size(), l.size()); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(s), std::end(s), std::begin(l), std::end(l)); + }; + + BOOST_TEST_CONTEXT("[Dynamic Strides(Last Order)] rank(1) dynamic strides"){ + check(n1, {1ul}); + check(n2, {1ul}); + } + + BOOST_TEST_CONTEXT("[Dynamic Strides(Last Order)] rank(2) dynamic strides"){ + check(n11, {1ul, 1ul}); + check(n12, {1ul, 1ul}); + check(n21, {1ul, 1ul}); + check(n22, {2ul, 1ul}); + check(n32, {2ul, 1ul}); + } + + BOOST_TEST_CONTEXT("[Dynamic Strides(Last Order)] rank(3) dynamic strides"){ + check(n111, {1ul, 1ul, 1ul}); + check(n112, {2ul, 2ul, 1ul}); + check(n121, {1ul, 1ul, 1ul}); + check(n123, {6ul, 3ul, 1ul}); + check(n211, {1ul, 1ul, 1ul}); + check(n213, {3ul, 3ul, 1ul}); + check(n321, {2ul, 1ul, 1ul}); + check(n432, {6ul, 2ul, 1ul}); + } + + BOOST_TEST_CONTEXT("[Dynamic Strides(Last Order)] rank(4) dynamic strides"){ + check(n1111, {1ul, 1ul, 1ul, 1ul}); + check(n4231, {6ul, 3ul, 1ul, 1ul}); + } +} - BOOST_CHECK_EQUAL ( s423[0], 1); - BOOST_CHECK_EQUAL ( s423[1], 4); - BOOST_CHECK_EQUAL ( s423[2], 8); +BOOST_FIXTURE_TEST_CASE(test_last_order_static_rank_strides, + boost::numeric::ublas::fixture_extents_static_rank, + *boost::unit_test::label("boost::numeric::ublas::to_strides(extents const&, last_order)") + *boost::unit_test::description("Testing the last order static rank strides")) +{ + + namespace ublas = boost::numeric::ublas; + constexpr auto check = [](auto const& e, std::initializer_list l){ + auto const s = ublas::to_strides(e, ublas::layout::last_order{}); + BOOST_REQUIRE (!s.empty()); + BOOST_REQUIRE_EQUAL( s.size(), l.size()); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(s), std::end(s), std::begin(l), std::end(l)); + }; + + BOOST_TEST_CONTEXT("[Static Rank Strides(Last Order)] static rank(1) dynamic strides"){ + check(n1, {1ul}); + check(n2, {1ul}); + } + + BOOST_TEST_CONTEXT("[Static Rank Strides(Last Order)] static rank(2) dynamic strides"){ + check(n11, {1ul, 1ul}); + check(n12, {1ul, 1ul}); + check(n21, {1ul, 1ul}); + check(n22, {2ul, 1ul}); + check(n32, {2ul, 1ul}); + } + + BOOST_TEST_CONTEXT("[Static Rank Strides(Last Order)] static rank(3) dynamic strides"){ + check(n111, {1ul, 1ul, 1ul}); + check(n112, {2ul, 2ul, 1ul}); + check(n121, {1ul, 1ul, 1ul}); + check(n123, {6ul, 3ul, 1ul}); + check(n211, {1ul, 1ul, 1ul}); + check(n213, {3ul, 3ul, 1ul}); + check(n321, {2ul, 1ul, 1ul}); + check(n432, {6ul, 2ul, 1ul}); + } + + BOOST_TEST_CONTEXT("[Static Rank Strides(Last Order)] static rank(4) dynamic strides"){ + check(n1111, {1ul, 1ul, 1ul, 1ul}); + check(n4231, {6ul, 3ul, 1ul, 1ul}); + } } -BOOST_AUTO_TEST_CASE( test_strides_ctor_access_last_order) +BOOST_FIXTURE_TEST_CASE(test_last_order_static_strides, + boost::numeric::ublas::fixture_extents_static, + *boost::unit_test::label("boost::numeric::ublas::to_strides(extents<...> const&, last_order)") + *boost::unit_test::description("Testing the last order static strides")) { - namespace ublas = boost::numeric::ublas; - constexpr auto layout = last_order{}; - - auto s1 = ublas::to_strides(extents {1},layout); - auto s5 = ublas::to_strides(extents {5},layout); - auto s11 = ublas::to_strides(extents {1,1},layout); - auto s12 = ublas::to_strides(extents {1,2},layout); - auto s21 = ublas::to_strides(extents {2,1},layout); - auto s23 = ublas::to_strides(extents {2,3},layout); - auto s231 = ublas::to_strides(extents{2,3,1},layout); - auto s123 = ublas::to_strides(extents{1,2,3},layout); - auto s423 = ublas::to_strides(extents{4,2,3},layout); - - BOOST_REQUIRE_EQUAL ( s11 .size(),2); - BOOST_REQUIRE_EQUAL ( s12 .size(),2); - BOOST_REQUIRE_EQUAL ( s21 .size(),2); - BOOST_REQUIRE_EQUAL ( s23 .size(),2); - BOOST_REQUIRE_EQUAL ( s231.size(),3); - BOOST_REQUIRE_EQUAL ( s123.size(),3); - BOOST_REQUIRE_EQUAL ( s423.size(),3); - - BOOST_CHECK_EQUAL ( s11[0], 1); - BOOST_CHECK_EQUAL ( s11[1], 1); - - BOOST_CHECK_EQUAL ( s12[0], 1); - BOOST_CHECK_EQUAL ( s12[1], 1); - - BOOST_CHECK_EQUAL ( s21[0], 1); - BOOST_CHECK_EQUAL ( s21[1], 1); - - BOOST_CHECK_EQUAL ( s23[0], 3); - BOOST_CHECK_EQUAL ( s23[1], 1); - - BOOST_CHECK_EQUAL ( s231[0], 3); - BOOST_CHECK_EQUAL ( s231[1], 1); - BOOST_CHECK_EQUAL ( s231[2], 1); - - BOOST_CHECK_EQUAL ( s123[0], 6); - BOOST_CHECK_EQUAL ( s123[1], 3); - BOOST_CHECK_EQUAL ( s123[2], 1); - - BOOST_CHECK_EQUAL ( s423[0], 6); - BOOST_CHECK_EQUAL ( s423[1], 3); - BOOST_CHECK_EQUAL ( s423[2], 1); + + namespace ublas = boost::numeric::ublas; + constexpr auto check = [](E const& /*e*/, std::initializer_list l){ + constexpr auto s = ublas::to_strides_v; + BOOST_REQUIRE (!s.empty()); + BOOST_REQUIRE_EQUAL( s.size(), l.size()); + BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(s), std::end(s), std::begin(l), std::end(l)); + }; + + BOOST_TEST_CONTEXT("[Static Strides(Last Order)] rank(1) static dynamic strides"){ + check(n1, {1ul}); + check(n2, {1ul}); + } + + // TODO: Enable after fixing the issue #119 + // BOOST_TEST_CONTEXT("[Static Strides(Last Order)] rank(2) static dynamic strides"){ + // check(n11, {1ul, 1ul}); + // check(n12, {1ul, 1ul}); + // check(n21, {1ul, 1ul}); + // check(n22, {2ul, 1ul}); + // check(n32, {2ul, 1ul}); + // } + + // BOOST_TEST_CONTEXT("[Static Strides(Last Order)] rank(3) static dynamic strides"){ + // check(n111, {1ul, 1ul, 1ul}); + // check(n112, {2ul, 2ul, 1ul}); + // check(n121, {1ul, 1ul, 1ul}); + // check(n123, {6ul, 3ul, 1ul}); + // check(n211, {1ul, 1ul, 1ul}); + // check(n213, {3ul, 3ul, 1ul}); + // check(n321, {2ul, 1ul, 1ul}); + // check(n432, {6ul, 2ul, 1ul}); + // } + + // BOOST_TEST_CONTEXT("[Static Strides(Last Order)] rank(4) static dynamic strides"){ + // check(n1111, {1ul, 1ul, 1ul, 1ul}); + // check(n4231, {6ul, 3ul, 1ul, 1ul}); + // } } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/test_tensor_matrix_vector.cpp b/test/tensor/test_tensor_matrix_vector.cpp deleted file mode 100644 index bea8566a1..000000000 --- a/test/tensor/test_tensor_matrix_vector.cpp +++ /dev/null @@ -1,460 +0,0 @@ -// -// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com -// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com -// -// 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 -// Google and Fraunhofer IOSB, Ettlingen, Germany -// - - -#include -#include -#include -#include -#include - -#include "utility.hpp" - -BOOST_AUTO_TEST_SUITE ( test_tensor_matrix_interoperability ) - -using test_types = zip::with_t; - - -BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, pair, test_types) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - - tensor a2 = matrix(1,1); - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - BOOST_CHECK_NE( a2.data() , nullptr); - - tensor a3 = matrix(2,1); - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - BOOST_CHECK_NE( a3.data() , nullptr); - - tensor a4 = matrix(1,2); - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - BOOST_CHECK_NE( a4.data() , nullptr); - - tensor a5 = matrix(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, pair, test_types) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using vector = typename tensor::vector_type; - - tensor a2 = vector(1); - BOOST_CHECK_EQUAL( a2.size() , 1 ); - BOOST_CHECK( !a2.empty() ); - BOOST_CHECK_NE( a2.data() , nullptr); - - tensor a3 = vector(2); - BOOST_CHECK_EQUAL( a3.size() , 2 ); - BOOST_CHECK( !a3.empty() ); - BOOST_CHECK_NE( a3.data() , nullptr); - - tensor a4 = vector(2); - BOOST_CHECK_EQUAL( a4.size() , 2 ); - BOOST_CHECK( !a4.empty() ); - BOOST_CHECK_NE( a4.data() , nullptr); - - tensor a5 = vector(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::extents<>; - fixture() - : extents{ - extents_type{1,1}, // 1 - extents_type{2,3}, // 2 - extents_type{5,6}, // 3 - extents_type{9,7}} // 4 - { - } - - std::vector extents; -}; - - - - -BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - - auto check = [](auto const& e) { - assert(ublas::size(e)==2); - tensor t = matrix{e[0],e[1]}; - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using vector = typename tensor::vector_type; - - auto check = [](auto const& e) { - assert(ublas::size(e)==2); - if(ublas::empty(e)) - return; - - tensor t = vector(ublas::product(e)); - BOOST_CHECK_EQUAL ( t.size() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - - - auto check = [](auto const& e) - { - assert(ublas::size(e) == 2); - auto t = tensor(e); - auto r = matrix(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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using vector = typename tensor::vector_type; - - auto check = [](auto const& e) - { - assert(ublas::size(e) == 2); - auto t = tensor(e); - auto r = vector(e[0]*e[1]); - std::iota(r.data().begin(),r.data().end(), value{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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - - auto check = [](auto const& e) - { - assert(ublas::size(e) == 2); - auto t = tensor(e); - auto r = matrix(e[0],e[1]); - std::iota(r.data().begin(),r.data().end(), value{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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using vector = typename tensor::vector_type; - - auto check = [](auto const& e) - { - assert(ublas::size(e) == 2); - auto t = tensor(e); - auto r = vector(e[0]*e[1]); - std::iota(r.data().begin(),r.data().end(), value{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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - - auto check = [](auto const& e) - { - assert(ublas::size(e) == 2); - auto t = tensor(e); - auto r = matrix(e[0],e[1]); - std::iota(r.data().begin(),r.data().end(), value{1}); - t = r + 3*r; - tensor s = r + 3*r; - tensor 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size (e) ); - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , ublas::size (e) ); - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , ublas::size (e) ); - 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, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using vector = typename tensor::vector_type; - - auto check = [](auto const& e) - { - assert(ublas::size(e) == 2); - auto t = tensor(e); - auto r = vector(e[0]*e[1]); - std::iota(r.data().begin(),r.data().end(), value{1}); - t = r + 3*r; - tensor s = r + 3*r; - tensor 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( t.rank() , ublas::size(e) ); - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( s.rank() , ublas::size(e) ); - 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() , ublas::product(e) ); - BOOST_CHECK_EQUAL ( q.rank() , ublas::size(e) ); - 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, pair, test_types, fixture ) -{ - namespace ublas = boost::numeric::ublas; - using value = typename pair::first_type; - using layout = typename pair::second_type; - using tensor = ublas::tensor_dynamic; - using matrix = typename tensor::matrix_type; - using vector = typename tensor::vector_type; - - auto check = [](auto const& e) - { - if(product(e) <= 2) - return; - - assert(ublas::size(e) == 2); - auto Q = tensor{e[0],1}; - auto A = matrix(e[0],e[1]); - auto b = vector(e[1]); - auto c = vector(e[0]); - std::iota(b.data().begin(),b.data().end(), value{1}); - std::fill(A.data().begin(),A.data().end(), value{1}); - std::fill(c.data().begin(),c.data().end(), value{2}); - std::fill(Q.begin(),Q.end(), value{2}); - - tensor 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); - - const auto n = e[1]; - const auto ab = value(std::div(n*(n+1),2).quot); - const auto ref = ab+4*Q(0)+2*c(0); - BOOST_CHECK( std::all_of(T.begin(),T.end(), [ref](auto cc){ return ref == cc; }) ); - -// BOOST_CHECK_EQUAL( T(i), ab+4*Q(0)+2*c(0) ); - - }; - - - - for(auto const& e : extents) - check(e); -} - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tensor/utility.hpp b/test/tensor/utility.hpp index 93571be2a..0c4e20a29 100644 --- a/test/tensor/utility.hpp +++ b/test/tensor/utility.hpp @@ -16,6 +16,7 @@ #include #include #include +#include template struct zip_helper; @@ -50,22 +51,30 @@ struct zip_helper, type1, types1...> template using zip = zip_helper,types...>; +template +constexpr auto static_for_each(FnType&& fn) noexcept{ + auto helper = [fn = std::forward(fn)](std::index_sequence){ + (..., std::invoke(fn, std::integral_constant{})); + }; + helper(std::make_index_sequence{}); +} template -void for_each_in_tuple(std::tuple const& tuple, UnaryOp&& op) +constexpr void for_each_in_tuple(std::tuple const& tuple, UnaryOp&& op) { - auto invoke_op_for_tuple = [&](std::index_sequence) { - (..., std::invoke(op, Is, std::get(tuple))); + auto invoke_op_for_tuple = [&tuple, op = std::forward(op)](IType id) { + constexpr auto i = IType::value; + std::invoke(op, id, std::get(tuple)); }; - invoke_op_for_tuple(std::make_index_sequence>>{}); + static_for_each(std::move(invoke_op_for_tuple)); } namespace boost::numeric::ublas { template -void for_each_in_index(std::index_sequence, TA const& a, TB const& b, UnaryOp&& op) +constexpr void for_each_in_index(std::index_sequence, TA const& a, TB const& b, UnaryOp&& op) { (..., std::invoke(op,a,b,std::index_sequence{}) ); } @@ -99,6 +108,34 @@ struct inner_type< std::complex >{ template using inner_type_t = typename inner_type::type; +#include +namespace boost::numeric::ublas{ + using double_extended = boost::multiprecision::cpp_bin_float_double_extended; + + // using cpp_std_types = zip>::with_t; + using cpp_std_types = zip::with_t; + + using cpp_basic_std_types = zip::with_t; + using layout_test_types = std::tuple; + + // using test_types_with_no_layout = std::tuple>; + using test_types_with_no_layout = std::tuple; + + // using test_types = zip,double_extended>::with_t; + using test_types = zip::with_t; + + // NOTE: std::iota cannot fill the container with the complex number + // because the complex number does not support increment operator(++) + template + constexpr auto iota(auto& c, ValueType v) noexcept{ + auto inc = ValueType{1}; + for(auto& el : c){ + el = v; + v += inc; + } + } +} // namespace boost::numeric::ublas + // creates e.g. From c5850f6d093691696d88e0e924623fe3219fee5d Mon Sep 17 00:00:00 2001 From: Neel-Shah-29 <84740927+Neel-Shah-29@users.noreply.github.com> Date: Sun, 6 Feb 2022 23:50:35 +0530 Subject: [PATCH 32/36] refactor(tensor): Improve functions for enabling compiler optimizations in algorithms.cpp (#155) Compiler cannot perform small-object and other optimizations in algorithms.cpp . This is solved by providing the trailing return type and passing the lambda through one of its arguments. Fixes #150 Co-authored-by: Neel Shah --- .../boost/numeric/ublas/tensor/algorithms.hpp | 58 +++++++++---------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/include/boost/numeric/ublas/tensor/algorithms.hpp b/include/boost/numeric/ublas/tensor/algorithms.hpp index 66375e1c0..9cc057f0f 100644 --- a/include/boost/numeric/ublas/tensor/algorithms.hpp +++ b/include/boost/numeric/ublas/tensor/algorithms.hpp @@ -56,14 +56,12 @@ constexpr void copy(const SizeType p, SizeType const*const n, throw std::runtime_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); } - - std::function lambda; - - lambda = [&lambda, n, wc, wa](SizeType r, PointerOut c, PointerIn a) + auto lambda = [n, wc, wa](auto const& self, SizeType r, PointerOut c, PointerIn a) + -> void { if(r > 0){ for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d){ - lambda(r-1, c, a ); + self(self, r-1, c, a ); } } else{ @@ -73,7 +71,7 @@ constexpr void copy(const SizeType p, SizeType const*const n, } }; - lambda( p-1, c, a ); + return lambda(lambda, p-1, c, a ); } @@ -113,19 +111,19 @@ constexpr void transform(SizeType const p, throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - std::function lambda; - - lambda = [&lambda, n, wc, wa, op](SizeType r, PointerOut c, PointerIn a) + + auto lambda = [n, wc, wa, op](auto const& self, SizeType r, PointerOut c, PointerIn a) + -> void { if(r > 0) for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d) - lambda(r-1, c, a); + self(self, r-1, c, a); else for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d) *c = op(*a); }; - lambda( p-1, c, a ); + return lambda(lambda, p-1, c, a ); } @@ -162,22 +160,20 @@ constexpr ValueType accumulate(SizeType const p, SizeType const*const n, throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - std::function lambda; - - lambda = [&lambda, n, w](SizeType r, PointerIn a, ValueType k) + auto lambda = [n, w](auto const& self, SizeType r, PointerIn a, ValueType k) + -> ValueType { if(r > 0u) for(auto d = 0u; d < n[r]; a += w[r], ++d) - k = lambda(r-1, a, k); + k = self(self,r-1, a, k); else for(auto d = 0u; d < n[0]; a += w[0], ++d) k += *a; return k; }; - return lambda( p-1, a, k ); + return lambda(lambda, p-1, a, k ); } - /** @brief Performs a reduce operation with all elements of the tensor and an initial value * * Implements k = op ( k , A[i1,i2,...,ip] ), for all ir @@ -213,20 +209,20 @@ constexpr ValueType accumulate(SizeType const p, SizeType const*const n, throw std::runtime_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); - std::function lambda; - lambda = [&lambda, n, w, op](SizeType r, PointerIn a, ValueType k) - { + auto lambda = [n, w ,op](auto const& self, SizeType r, PointerIn a, ValueType k) + -> ValueType + { if(r > 0u) for(auto d = 0u; d < n[r]; a += w[r], ++d) - k = lambda(r-1, a, k); + k = self(self,r-1, a, k); else for(auto d = 0u; d < n[0]; a += w[0], ++d) k = op ( k, *a ); return k; }; - return lambda( p-1, a, k ); + return lambda(lambda, p-1, a, k ); } /** @brief Transposes a tensor @@ -272,19 +268,18 @@ constexpr void trans( SizeType const p, SizeType const*const na, SizeType const throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); - std::function lambda; - - lambda = [&lambda, na, wc, wa, pi](SizeType r, PointerOut c, PointerIn a) + auto lambda = [na, wc, wa, pi](auto const& self, SizeType r, PointerOut c, PointerIn a) + -> void { if(r > 0) for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) - lambda(r-1, c, a); + self(self,r-1, c, a); else for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) *c = *a; }; - lambda( p-1, c, a ); + return lambda( lambda ,p-1, c, a ); } @@ -327,19 +322,19 @@ constexpr void trans(SizeType const p, } - std::function* c, std::complex* a)> lambda; - lambda = [&lambda, na, wc, wa, pi](SizeType r, std::complex* c, std::complex* a) + auto lambda = [na, wc, wa, pi](auto const& self, SizeType r, std::complex* c, std::complex* a) + ->void { if(r > 0) for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) - lambda(r-1, c, a); + self(self,r-1, c, a); else for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) *c = std::conj(*a); }; - lambda( p-1, c, a ); + return lambda( lambda ,p-1, c, a ); } @@ -348,3 +343,4 @@ constexpr void trans(SizeType const p, #endif + From 3a4fe24ee16b4d6a084eb51c37cfeffba697ff71 Mon Sep 17 00:00:00 2001 From: Baoshuo Ren Date: Wed, 3 Aug 2022 03:32:49 +0800 Subject: [PATCH 33/36] chore: bump macos runner version (#177) GitHub Action is sunsetting the macOS 10.15 Actions runner. It will stop working intermittently until being completely removed by 2022-8-30: https://github.blog/changelog/2022-07-20-github-actions-the-macos-10-15-actions-runner-image-is-being-deprecated-and-will-be-removed-by-8-30-22 --- .github/workflows/apple.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index f0c8df792..9bd337780 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -16,8 +16,8 @@ on: - 'doc/**' jobs: build: - name: "MacOS 10.15 clang -std=c++${{matrix.cxxstd}}" - runs-on: macos-10.15 + name: "MacOS 11 clang -std=c++${{matrix.cxxstd}}" + runs-on: macos-11 strategy: fail-fast: true matrix: From 8934b49ebe5327964b42faefbb22334ba89f4574 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 22 Nov 2023 02:19:01 +0200 Subject: [PATCH 34/36] Add CMakeLists.txt. Closes #142. --- CMakeLists.txt | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..8e2358e4f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,38 @@ +# Generated by `boostdep --cmake numeric/ublas` +# Copyright 2020, 2021 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.8...3.20) + +project(boost_numeric_ublas VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) + +add_library(boost_numeric_ublas INTERFACE) +add_library(Boost::numeric_ublas ALIAS boost_numeric_ublas) + +target_include_directories(boost_numeric_ublas INTERFACE include) + +target_link_libraries(boost_numeric_ublas + INTERFACE + Boost::compute + Boost::concept_check + Boost::config + Boost::core + Boost::iterator + Boost::mpl + Boost::numeric_interval + Boost::range + Boost::serialization + Boost::smart_ptr + Boost::static_assert + Boost::type_traits + Boost::typeof +) + +target_compile_features(boost_numeric_ublas INTERFACE cxx_std_11) + +if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") + + add_subdirectory(test) + +endif() From 8708cbf0f48796dd187920e472ad393efea53162 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 6 May 2026 01:57:58 +0300 Subject: [PATCH 35/36] Remove dependencies on Boost.StaticAssert. (#198) Boost.StaticAssert has been merged into Boost.Config, so remove the dependency. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e2358e4f..341bfe598 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,6 @@ target_link_libraries(boost_numeric_ublas Boost::range Boost::serialization Boost::smart_ptr - Boost::static_assert Boost::type_traits Boost::typeof ) From 12034976d0d66030a0dfc8d61dab82d99a5e7ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Ferdinand=20Rivera=20Morell?= Date: Thu, 10 Sep 2026 09:55:44 -0500 Subject: [PATCH 36/36] Make the library modular usable. (#196) --- .github/workflows/apple.yml | 34 ++++---- .github/workflows/clangtidy.yml | 38 +++++---- .github/workflows/linux.yml | 80 ++++++++++++------- .github/workflows/sanitizer.yml | 79 +++++++++++------- .github/workflows/windows.yml | 45 ++++++----- benchmarks/Jamfile | 6 +- benchmarks/opencl/Jamfile | 2 +- build.jam | 33 ++++++++ examples/tensor/Jamfile | 11 ++- .../ublas/tensor/expression_evaluation.hpp | 1 + test/Jamfile | 75 ++++++++--------- test/opencl/Jamfile | 2 +- test/tensor/Jamfile | 11 +-- 13 files changed, 254 insertions(+), 163 deletions(-) create mode 100644 build.jam diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index 9bd337780..0b8950a5f 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -5,68 +5,68 @@ name: "Apple MacOS" -on: +on: push: - paths-ignore: + paths-ignore: - '**.md' - 'doc/**' pull_request: - paths-ignore: + paths-ignore: - '**.md' - 'doc/**' jobs: build: - name: "MacOS 11 clang -std=c++${{matrix.cxxstd}}" - runs-on: macos-11 + name: "MacOS clang -std=c++${{matrix.cxxstd}}" + runs-on: macos-latest strategy: - fail-fast: true + fail-fast: false matrix: - cxxstd: [2a] + cxxstd: [20,2b] steps: - uses: actions/checkout@v2 - + - name: Git Clone Boost.uBlas run: | cd ${GITHUB_WORKSPACE} cd .. - + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root cd boost-root echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} echo $BOOST_ROOT - + git submodule update --init --depth=1 --jobs 8 tools/build git submodule update --init --depth=1 --jobs 8 libs/config git submodule update --init --depth=1 --jobs 8 tools/boostdep - + mkdir -p libs/numeric/ cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - + - name: Bootstrap and Compile Boost.uBlas run: | cd $BOOST_ROOT ./bootstrap.sh ./b2 -j8 headers - echo "using clang : : $(brew --prefix llvm)/bin/clang++ ;" >> ~/user-config.jam; + echo "using clang ;" >> ~/user-config.jam; + - - name: Test Benchmarks run: | cd $BOOST_ROOT cd libs/numeric/ublas $BOOST_ROOT/b2 -j8 benchmarks cxxstd=${{matrix.cxxstd}} - + - name: Test Tensor Examples run: | cd $BOOST_ROOT cd libs/numeric/ublas $BOOST_ROOT/b2 -j8 examples/tensor cxxstd=${{matrix.cxxstd}} - + - name: Test Tensor run: | cd $BOOST_ROOT cd libs/numeric/ublas $BOOST_ROOT/b2 -j8 test/tensor cxxstd=${{matrix.cxxstd}} - + diff --git a/.github/workflows/clangtidy.yml b/.github/workflows/clangtidy.yml index 11b1aea41..1deae8115 100644 --- a/.github/workflows/clangtidy.yml +++ b/.github/workflows/clangtidy.yml @@ -5,48 +5,52 @@ name: "Static Analysis" -on: +on: push: - paths-ignore: + paths-ignore: - '**.md' - 'doc/**' pull_request: - paths-ignore: + paths-ignore: - '**.md' - 'doc/**' jobs: check: name: Linux Clang-Tidy - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - - name: Install Clang 11 - run: sudo apt-get update && sudo apt-get install -y clang-11 clang-tidy-11 - + - uses: actions/checkout@v4 + + - name: Install Clang + run: sudo apt-get update && sudo apt-get install -y clang clang-tidy + + - name: Setup + run: sudo apt-get update && sudo apt-get -y install sudo python3 git g++ curl xz-utils + - name: "Install Boost from Source" run: | cd .. git clone --depth 1 https://github.com/boostorg/boost.git --recursive --shallow-submodules cd boost - ./bootstrap.sh + ./bootstrap.sh ./b2 headers sudo cp -r -L boost /usr/include rm -rf boost - + - name: "Run Clang-Tidy" - run: clang-tidy-11 examples/tensor/*.cpp test/tensor/*.cpp -- -Iinclude -std=c++20 > reports.txt + run: clang-tidy examples/tensor/*.cpp test/tensor/*.cpp -- -Iinclude -std=c++20 > reports.txt - name: "Print Clang-Tidy Report" run: cat reports.txt - - - uses: actions/setup-python@v2 - + + - uses: actions/setup-python@v5 + with: { 'python-version': '3' } + - name: "Post review comments" if: github.event.pull_request.head.repo.full_name == github.repository run: | pip3 install 'unidiff~=0.6.0' --force-reinstall pip3 install 'PyGithub~=1.51' --force-reinstall pip3 install 'requests~=2.23' --force-reinstall - python ./.ci/post_review.py --repository ${{ github.repository }} --token ${{ github.token}} --pr ${{ github.event.pull_request.number }} --path reports.txt - + python ./.ci/post_review.py --repository ${{ github.repository }} --token ${{ github.token}} --pr ${{ github.event.pull_request.number }} --path reports.txt + diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 20b9c5311..9064222ad 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -5,64 +5,82 @@ name: "Linux" -on: +on: push: - paths-ignore: + paths-ignore: - '**.md' - 'doc/**' pull_request: - paths-ignore: + paths-ignore: - '**.md' - 'doc/**' jobs: build: - name: Ubuntu 20.04 "cxx=${{matrix.config.cxx}}, std=c++${{matrix.config.cxxstd}}, variant=c++${{matrix.config.variant}}" - runs-on: ubuntu-20.04 + name: Ubuntu "cxx=${{matrix.config.cxx}}, std=c++${{matrix.config.cxxstd}}, variant=c++${{matrix.config.variant}}" + runs-on: ubuntu-latest + container: + image: ${{matrix.config.container}} + volumes: + - /node20217:/node20217:rw,rshared + - ${{ startsWith(matrix.config.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }} strategy: - fail-fast: true + fail-fast: false # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early matrix: - config: - - { name: clang, cc: clang-10, cxx: clang++-10, cxxstd: 20, variant: debug, opt: off} - - { name: clang, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off} - - { name: clang, cc: clang-10, cxx: clang++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp, ldflags: -lgomp=libomp5} - - { name: clang, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp, ldflags: -lgomp=libomp5} - - { name: gcc, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: debug, opt: off} - - { name: gcc, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp, ldflags: -lgomp} - + config: + - { name: clang, cc: clang-10, cxx: clang++-10, cxxstd: 20, variant: debug, opt: off, container: 'ubuntu:20.04' } + - { name: clang, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off, container: 'ubuntu:20.04' } + - { name: clang, cc: clang-10, cxx: clang++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp, ldflags: -lgomp=libomp5, container: 'ubuntu:20.04' } + - { name: clang, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp, ldflags: -lgomp=libomp5, container: 'ubuntu:20.04' } + - { name: gcc, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: debug, opt: off, container: 'ubuntu:20.04' } + - { name: gcc, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp, ldflags: -lgomp, container: 'ubuntu:20.04' } + steps: - - uses: actions/checkout@v2 - + - name: Setup container environment + if: matrix.config.container + run: | + apt-get update + apt-get -y install sudo python3 git g++ curl xz-utils + + - name: Install nodejs20glibc2.17 + if: ${{ startsWith( matrix.config.container, 'ubuntu:1' ) }} + run: | + curl -LO https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz + tar -xf node-v20.9.0-linux-x64-glibc-217.tar.xz --strip-components 1 -C /node20217 + ldd /__e/node20/bin/node + - name: Install g++-10 if: matrix.config.cxx == 'g++-10' - run: sudo apt update && sudo apt-get install -y g++-10 libomp-dev - + run: sudo apt update && sudo apt-get install -y g++-10 libomp-dev + - name: Install Clang 10 if: matrix.config.cxx == 'clang++-10' - run: sudo apt-get update && sudo apt-get install -y clang-10 - + run: sudo apt-get update && sudo apt-get install -y clang-10 libstdc++-10-dev + - name: Install Clang 11 if: matrix.config.cxx == 'clang++-11' - run: sudo apt-get update && sudo apt-get install -y clang-11 - + run: sudo apt-get update && sudo apt-get install -y clang-11 libstdc++-10-dev + + - uses: actions/checkout@v4 + - name: Git Clone Boost.uBlas run: | cd ${GITHUB_WORKSPACE} cd .. - + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root cd boost-root echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} echo $BOOST_ROOT - + git submodule update --init --depth=1 --jobs 8 tools/build git submodule update --init --depth=1 --jobs 8 libs/config git submodule update --init --depth=1 --jobs 8 tools/boostdep - + mkdir -p libs/numeric/ cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas - python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + python3 tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - name: Bootstrap Boost and Compile Boost run: | @@ -70,13 +88,13 @@ jobs: ./bootstrap.sh ./b2 -j8 headers echo "using ${{ matrix.config.name }} : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; - + # - name: Test Benchmarks # run: | # cd $BOOST_ROOT # cd libs/numeric/ublas # $BOOST_ROOT/b2 -j 4 benchmarks toolset=clang cxxstd=${{matrix.config.cxxstd}} cxxflags="-O3" - + - name: Test Tensor Examples run: | cd $BOOST_ROOT/libs/numeric/ublas @@ -86,7 +104,7 @@ jobs: else $BOOST_ROOT/b2 -j8 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} cxxflags="${{matrix.config.cxxflags}}" linkflags="${{matrix.config.ldflags}}" fi - + - name: Test Tensor Unit-Tests run: | cd $BOOST_ROOT/libs/numeric/ublas @@ -95,5 +113,5 @@ jobs: $BOOST_ROOT/b2 -j8 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} else $BOOST_ROOT/b2 -j8 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} cxxflags="${{matrix.config.cxxflags}}" linkflags="${{matrix.config.ldflags}}" - fi - + fi + diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index a2edff34b..2582fde29 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -5,57 +5,82 @@ name: "Clang Sanitizer" -on: +on: push: - paths-ignore: + paths-ignore: - '**.md' - 'doc/**' pull_request: - paths-ignore: + paths-ignore: - '**.md' - 'doc/**' jobs: build: name: "${{matrix.config.name}} with ${{matrix.config.description}} sanitizer with std=${{matrix.config.cxx}} and variant=${{matrix.config.variant}}" - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest + container: + image: ${{matrix.config.container}} + volumes: + - /node20217:/node20217:rw,rshared + - ${{ startsWith(matrix.config.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }} strategy: fail-fast: false # If any compiler fails to compile, continue CI for next compiler in matrix instead of failing early matrix: config: - - { name: clang, description: address and leak, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off , cxxflags: -fsanitize=address -fno-omit-frame-pointer, ldflags: -fsanitize=address } - - { name: clang, description: undefined behavior, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off , cxxflags: -fsanitize=undefined, ldflags: -fsanitize=undefined } - - { name: clang, description: thread, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off , cxxflags: -fsanitize=thread, ldflags: -fsanitize=thread } - - { name: gcc, description: address and leak, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp -fsanitize=address -fno-omit-frame-pointer, ldflags: -fsanitize=address -fopenmp} -# - { name: gcc, description: undefined behavior, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp -fsanitize=undefined, ldflags: -fsanitize=undefined -fopenmp} -# - { name: gcc, description: thread, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, cxxflags: -fopenmp -fsanitize=thread, ldflags: -fsanitize=thread -fopenmp} - + - { name: clang, description: address and leak, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off , b2args: address-sanitizer=on, cxxflags: -fno-omit-frame-pointer, container: 'ubuntu:20.04' } + - { name: clang, description: undefined behavior, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off , b2args: undefined-sanitizer=on, ldflags: -shared-libsan, container: 'ubuntu:20.04' } + - { name: clang, description: thread, cc: clang-11, cxx: clang++-11, cxxstd: 20, variant: debug, opt: off , b2args: thread-sanitizer=on, container: 'ubuntu:20.04' } + - { name: gcc, description: address and leak, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, b2args: address-sanitizer=on, cxxflags: -fopenmp -fno-omit-frame-pointer, ldflags: -fopenmp, container: 'ubuntu:20.04' } +# - { name: gcc, description: undefined behavior, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, b2args: undefined-sanitizer=on, cxxflags: -fopenmp, ldflags: -fopenmp, container: 'ubuntu:20.04' } +# - { name: gcc, description: thread, cc: gcc-10, cxx: g++-10, cxxstd: 20, variant: release, opt: speed, b2args: thread-sanitizer=on, cxxflags: -fopenmp, ldflags: -fopenmp, container: 'ubuntu:20.04' } + steps: - - uses: actions/checkout@v2 - + - name: Setup container environment + if: matrix.config.container + run: | + apt-get update + apt-get -y install sudo python3 git g++ curl xz-utils + + - name: Install nodejs20glibc2.17 + if: ${{ startsWith( matrix.config.container, 'ubuntu:1' ) }} + run: | + curl -LO https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz + tar -xf node-v20.9.0-linux-x64-glibc-217.tar.xz --strip-components 1 -C /node20217 + ldd /__e/node20/bin/node + - name: Install Clang 11 run: sudo apt-get update && sudo apt-get install -y clang-11 clang-tools-11 - name: Install GCC 10 run: sudo apt-get update && sudo apt-get install -y g++-10 libomp-dev - + + - name: Locate UBSan runtime + if: matrix.config.description == 'undefined behavior' + run: | + UBSAN_DIR="$(dirname "$(${{matrix.config.cxx}} -print-file-name=libclang_rt.ubsan_standalone-x86_64.so)")" + echo "UBSAN_DIR=$UBSAN_DIR" + echo "LD_LIBRARY_PATH=$UBSAN_DIR:$LD_LIBRARY_PATH" >> $GITHUB_ENV + + - uses: actions/checkout@v4 + - name: Git Clone Boost.uBlas run: | cd ${GITHUB_WORKSPACE} cd .. - + git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root cd boost-root echo "BOOST_ROOT=${PWD}" >> ${GITHUB_ENV} echo $BOOST_ROOT - + git submodule update --init --depth=1 --jobs 8 tools/build git submodule update --init --depth=1 --jobs 8 libs/config git submodule update --init --depth=1 --jobs 8 tools/boostdep - + mkdir -p libs/numeric/ cp -rp ${GITHUB_WORKSPACE}/. libs/numeric/ublas - python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas + python3 tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - name: Bootstrap Boost and Compile Boost run: | @@ -65,19 +90,19 @@ jobs: echo "using ${{ matrix.config.name }} : : ${{ matrix.config.cxx }} ;" >> ~/user-config.jam; export ASAN_OPTIONS=symbolize=1 export ASAN_OPTIONS=detect_leaks=1 - + - name: Run Tensor Examples with "${{matrix.config.description}}" sanitizer - run: | - cd $BOOST_ROOT/libs/numeric/ublas + run: | + cd $BOOST_ROOT/libs/numeric/ublas ASAN_OPTIONS=detect_leaks=1 ASAN_OPTIONS=symbolize=1 - $BOOST_ROOT/b2 -j8 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} cxxflags="${{matrix.config.cxxflags}}" linkflags="${{matrix.config.ldflags}}" - - - name: Run Tensor Tests with "${{matrix.config.description}}" sanitizer + $BOOST_ROOT/b2 -j8 examples/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} cxxflags="${{matrix.config.cxxflags}}" linkflags="${{matrix.config.ldflags}}" ${{matrix.config.b2args}} + + - name: Run Tensor Tests with "${{matrix.config.description}}" sanitizer run: | cd $BOOST_ROOT/libs/numeric/ublas ASAN_OPTIONS=detect_leaks=1 ASAN_OPTIONS=symbolize=1 - $BOOST_ROOT/b2 -j8 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} cxxflags="${{matrix.config.cxxflags}}" linkflags="${{matrix.config.ldflags}}" - - + $BOOST_ROOT/b2 -j8 test/tensor toolset=${{matrix.config.name}} cxxstd=${{matrix.config.cxxstd}} variant=${{matrix.config.variant}} optimization=${{matrix.config.opt}} cxxflags="${{matrix.config.cxxflags}}" linkflags="${{matrix.config.ldflags}}" ${{matrix.config.b2args}} + + diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 3f761707e..72035b4f6 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -4,13 +4,13 @@ # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) name: "Windows" -on: +on: push: - paths-ignore: + paths-ignore: - '**.md' - 'doc/**' pull_request: - paths-ignore: + paths-ignore: - '**.md' - 'doc/**' jobs: @@ -20,21 +20,22 @@ jobs: strategy: fail-fast: true matrix: - config: -# - {os: windows-2016, toolset: msvc, version: 14.16, cxxstd: 11} + config: +# - {os: windows-2016, toolset: msvc, version: 14.16, cxxstd: 11} # - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: 11} # - {os: windows-2019, toolset: msvc, version: 14.28, cxxstd: 17} - - {os: windows-2019, toolset: msvc, version: 14.29, cxxstd: latest} +# - {os: windows-2019, toolset: msvc, version: 14.29, cxxstd: latest} # - {os: windows-2022, toolset: msvc, version: 14.30, cxxstd: latest} - + - {os: windows-2022, toolset: msvc, cxxstd: latest, toolsetver: 14.3 } + steps: - - uses: actions/checkout@v2 - + - uses: actions/checkout@v4 + - name: Enable Developer Command Prompt uses: ilammy/msvc-dev-cmd@v1 with: toolset: ${{matrix.config.version}} - + - name: Setup BOOST_ROOT shell: powershell run: | @@ -45,15 +46,15 @@ jobs: git submodule update --init --depth=1 tools/build git submodule update --init --depth=1 libs/config git submodule update --init --depth=1 tools/boostdep - + xcopy /s /e /q $env:GITHUB_WORKSPACE libs\numeric\ublas - + python tools/boostdep/depinst/depinst.py -g " --depth=1" -I benchmarks numeric/ublas - - + + echo "BOOST_ROOT=$pwd" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - echo "TOOLSET=${{matrix.config.toolset}}-${{matrix.config.version}}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - + echo "TOOLSET=${{matrix.config.toolset}}-${{matrix.config.toolsetver}}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + - name: Prepare BOOST_ROOT shell: powershell run: | @@ -63,33 +64,33 @@ jobs: import os regex toolset ; local toolset = [ regex.split [ os.environ TOOLSET ] "-" ] ; using $(toolset[1]) : $(toolset[2-]:J="-") : ; - '@ | sc "$env:USERPROFILE/user-config.jam" - + '@ | sc "$env:USERPROFILE/user-config.jam" + - name: Bootstrap BOOST_ROOT shell: cmd run: | cd %BOOST_ROOT% cmd /c bootstrap b2 -j8 headers - + # - name: Test Benchmarks # shell: cmd # run: | # cd %BOOST_ROOT% # cd libs\numeric\ublas # %BOOST_ROOT%\b2 -j 4 benchmarks toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 - + - name: Test Tensor Examples shell: cmd run: | cd %BOOST_ROOT% cd libs\numeric\ublas %BOOST_ROOT%\b2 -j8 examples/tensor toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 - + - name: Test Tensor shell: cmd run: | cd %BOOST_ROOT% cd libs\numeric\ublas %BOOST_ROOT%\b2 -j8 test/tensor toolset=%TOOLSET% cxxstd=${{matrix.config.cxxstd}} address-model=64 - + diff --git a/benchmarks/Jamfile b/benchmarks/Jamfile index ab2f77e82..0ff838f85 100644 --- a/benchmarks/Jamfile +++ b/benchmarks/Jamfile @@ -4,8 +4,10 @@ # 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/benchmarks - : requirements /boost/program_options//boost_program_options +project + : requirements + /boost/ublas//boost_ublas + /boost/program_options//boost_program_options ; exe add : add.cpp ; diff --git a/benchmarks/opencl/Jamfile b/benchmarks/opencl/Jamfile index 282d00711..045c9cefb 100644 --- a/benchmarks/opencl/Jamfile +++ b/benchmarks/opencl/Jamfile @@ -13,7 +13,7 @@ import ../../clblas ; using opencl ; using clblas ; -project boost/ublas/benchmarks/opencl +project : requirements /boost/program_options//boost_program_options gcc:-Wno-ignored-attributes diff --git a/build.jam b/build.jam new file mode 100644 index 000000000..299c0682c --- /dev/null +++ b/build.jam @@ -0,0 +1,33 @@ +# Copyright René Ferdinand Rivera Morell 2023-2024 +# 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) + +require-b2 5.2 ; + +constant boost_dependencies : + /boost/compute//boost_compute + /boost/concept_check//boost_concept_check + /boost/config//boost_config + /boost/core//boost_core + /boost/interval//boost_interval + /boost/iterator//boost_iterator + /boost/mpl//boost_mpl + /boost/range//boost_range + /boost/serialization//boost_serialization + /boost/smart_ptr//boost_smart_ptr + /boost/type_traits//boost_type_traits + /boost/typeof//boost_typeof ; + +project /boost/ublas + ; + +explicit + [ alias boost_ublas : : : + : include $(boost_dependencies) ] + [ alias all : boost_ublas benchmarks examples/tensor test ] + ; + +call-if : boost-library ublas + ; + diff --git a/examples/tensor/Jamfile b/examples/tensor/Jamfile index 101a8a4c9..0211d5416 100644 --- a/examples/tensor/Jamfile +++ b/examples/tensor/Jamfile @@ -6,20 +6,23 @@ # Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) -import ../../../../config/checks/config : requires ; - +import-search /boost/config/checks ; +import config : requires ; + # Project settings -project boost-ublas-tensor-example +project : requirements + /boost/ublas//boost_ublas BOOST_UBLAS_NO_EXCEPTIONS vacpp:"BOOST_UBLAS_NO_ELEMENT_PROXIES" gcc:"-Wall -pedantic -Wextra -Wno-unknown-pragmas" clang:"-Wall -pedantic -Wextra -Wno-unknown-pragmas" msvc:"/W4" # == all [ requires cxx17_if_constexpr ] + 20 ; -exe access_tensor : access_tensor.cpp ; +exe access_tensor : access_tensor.cpp /boost/multiprecision//boost_multiprecision ; exe simple_expressions : simple_expressions.cpp ; exe multiply_tensors_product_function : multiply_tensors_product_function.cpp ; exe multiply_tensors_einstein_notation : multiply_tensors_einstein_notation.cpp ; diff --git a/include/boost/numeric/ublas/tensor/expression_evaluation.hpp b/include/boost/numeric/ublas/tensor/expression_evaluation.hpp index d29b6eabe..5273d7be8 100644 --- a/include/boost/numeric/ublas/tensor/expression_evaluation.hpp +++ b/include/boost/numeric/ublas/tensor/expression_evaluation.hpp @@ -235,6 +235,7 @@ constexpr auto all_extents_equal(unary_tensor_expression const& expr, ex "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); using ::operator==; + using ::operator!=; if constexpr ( std::is_same::value ) if(e != expr.e.extents()) diff --git a/test/Jamfile b/test/Jamfile index f6716e2c6..78a6bc132 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -26,29 +26,30 @@ UBLAS_TESTSET ?= # Sparse matrices: USE_MAPPED_MATRIX USE_COMPRESSED_MATRIX USE_COORDINATE_MATRIX USE_MAPPED_VECTOR_OF_MAPPED_VECTOR USE_GENERALIZED_VECTOR_OF_VECTOR UBLAS_TESTSET_SPARSE = [ modules.peek : UBLAS_TESTSET_SPARSE ] ; -UBLAS_TESTSET_SPARSE ?= +UBLAS_TESTSET_SPARSE ?= USE_DOUBLE USE_STD_COMPLEX # USE_RANGE USE_SLICE # Too complex for regression testing USE_UNBOUNDED_ARRAY USE_MAP_ARRAY USE_STD_MAP - USE_MAPPED_VECTOR USE_COMPRESSED_VECTOR - USE_MAPPED_MATRIX USE_COMPRESSED_MATRIX + USE_MAPPED_VECTOR USE_COMPRESSED_VECTOR + USE_MAPPED_MATRIX USE_COMPRESSED_MATRIX ; # Generalize VofV still failing # USE_GENERALIZED_VECTOR_OF_VECTOR UBLAS_TESTSET_SPARSE_COO = [ modules.peek : UBLAS_TESTSET_SPARSE_COO ] ; -UBLAS_TESTSET_SPARSE_COO ?= +UBLAS_TESTSET_SPARSE_COO ?= USE_DOUBLE USE_STD_COMPLEX USE_UNBOUNDED_ARRAY USE_COORDINATE_VECTOR - USE_COORDINATE_MATRIX + USE_COORDINATE_MATRIX ; # Project settings -project boost-ublas-test +project : requirements + /boost/ublas//boost_ublas BOOST_UBLAS_NO_EXCEPTIONS vacpp:"BOOST_UBLAS_NO_ELEMENT_PROXIES" gcc:"-Wall -Wno-unknown-pragmas" @@ -111,16 +112,17 @@ test-suite numeric/uBLAS test33.cpp : : : USE_FLOAT - USE_DOUBLE - USE_STD_COMPLEX + USE_DOUBLE + USE_STD_COMPLEX USE_STD_MAP - USE_MAPPED_VECTOR_OF_MAPPED_VECTOR - : test3_mvov + USE_MAPPED_VECTOR_OF_MAPPED_VECTOR + : test3_mvov : ] [ run test4.cpp test42.cpp test43.cpp + /boost/math//boost_math_tr1 : : : $(UBLAS_TESTSET) ] @@ -165,92 +167,93 @@ test-suite numeric/uBLAS ] [ run triangular_layout.cpp ] - [ run comp_mat_erase.cpp + [ run comp_mat_erase.cpp /boost/test//included : : : msvc:on ] - [ run sparse_view_test.cpp + [ run sparse_view_test.cpp /boost/test//included : : : msvc:on ] - [ run begin_end.cpp + [ run begin_end.cpp /boost/math//boost_math_tr1 ] - [ run num_columns.cpp + [ run num_columns.cpp /boost/math//boost_math_tr1 ] - [ run num_rows.cpp + [ run num_rows.cpp /boost/math//boost_math_tr1 ] - [ run size.cpp + [ run size.cpp /boost/math//boost_math_tr1 ] - [ run test_coordinate_matrix_sort.cpp + [ run test_coordinate_matrix_sort.cpp /boost/math//boost_math_tr1 ] - [ run test_coordinate_matrix_sort.cpp + [ run test_coordinate_matrix_sort.cpp /boost/math//boost_math_tr1 : : : BOOST_UBLAS_COO_ALWAYS_DO_FULL_SORT : test_coordinate_matrix_always_do_full_sort : ] - [ run test_complex_norms.cpp + [ run test_complex_norms.cpp /boost/math//boost_math_tr1 ] - [ run test_scaled_norm.cpp + [ run test_scaled_norm.cpp /boost/math//boost_math_tr1 : : : BOOST_UBLAS_SCALED_NORM ] - [ run test_assignment.cpp + [ run test_assignment.cpp /boost/timer//boost_timer /boost/math//boost_math_tr1 : : : BOOST_UBLAS_COO_ALWAYS_DO_FULL_SORT + BOOST_TIMER_ENABLE_DEPRECATED ] [ run test_triangular.cpp : : : /boost/timer//boost_timer ] - [ run test_ticket7296.cpp + [ run test_ticket7296.cpp /boost/math//boost_math_tr1 : : : msvc:/wd4127 # The program checks that test facilities work fine. The warning appears many times. : : ] - [ run test_inplace_solve.cpp - : - : + [ run test_inplace_solve.cpp /boost/math//boost_math_tr1 + : + : : $(UBLAS_TESTSET) : test_inplace_solve_basic : ] - [ run test_inplace_solve.cpp - : - : + [ run test_inplace_solve.cpp /boost/math//boost_math_tr1 + : + : : $(UBLAS_TESTSET_SPARSE) $(UBLAS_TESTSET_SPARSE_COO) : test_inplace_solve_sparse : ] - [ run test_inplace_solve.cpp - : - : + [ run test_inplace_solve.cpp /boost/math//boost_math_tr1 + : + : : USE_MAPPED_VECTOR_OF_MAPPED_VECTOR : test_inplace_solve_mvov : ] - [ run test_coordinate_vector_inplace_merge.cpp + [ run test_coordinate_vector_inplace_merge.cpp /boost/math//boost_math_tr1 ] - [ run test_coordinate_matrix_inplace_merge.cpp + [ run test_coordinate_matrix_inplace_merge.cpp /boost/math//boost_math_tr1 ] - [ run test_banded_storage_layout.cpp + [ run test_banded_storage_layout.cpp /boost/math//boost_math_tr1 : : : : : ] - [ run test_fixed_containers.cpp + [ run test_fixed_containers.cpp /boost/math//boost_math_tr1 : : : ] - [ run test_matrix_vector.cpp + [ run test_matrix_vector.cpp /boost/math//boost_math_tr1 ] [ compile minimal_allocator_test.cpp ] ; diff --git a/test/opencl/Jamfile b/test/opencl/Jamfile index cc8679223..9da1870ed 100644 --- a/test/opencl/Jamfile +++ b/test/opencl/Jamfile @@ -13,7 +13,7 @@ import ../../clblas ; using opencl ; using clblas ; -project boost/ublas/test/opencl +project : requirements gcc:-Wno-ignored-attributes clang:-Wno-ignored-attributes diff --git a/test/tensor/Jamfile b/test/tensor/Jamfile index 908e359ea..92c393cff 100644 --- a/test/tensor/Jamfile +++ b/test/tensor/Jamfile @@ -11,18 +11,19 @@ # Google and Fraunhofer IOSB, Ettlingen, Germany # -import ../../../../config/checks/config : requires ; +import-search /boost/config/checks ; +import config : requires ; project boost/ublas/test/tensor : requirements - gcc:"-Wall -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-but-set-variable" - clang:"-Wall -Wno-unknown-pragmas -Wno-sign-compare" + gcc:"-Wall -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-but-set-variable -ffp-contract=off" + clang:"-Wall -Wno-unknown-pragmas -Wno-sign-compare -ffp-contract=off" [ requires cxx17_if_constexpr ] ; alias unit_test_framework : # sources - /boost//unit_test_framework + /boost/test//boost_unit_test_framework ; # make aliases explicit so the libraries will only be built when requested @@ -93,6 +94,6 @@ test-suite boost-ublas-tensor-test : : test_tensor : - # + # ] ;

        Banded Matrix