├── include ├── multi ├── boost │ └── multi │ │ ├── adaptors │ │ ├── blas │ │ │ ├── herk.su │ │ │ ├── cuda │ │ │ │ └── tests │ │ │ │ │ ├── gemm.su │ │ │ │ │ └── iamax.cpp │ │ │ ├── test │ │ │ │ ├── config.hpp.in │ │ │ │ ├── traits.cpp │ │ │ │ ├── operations.cpp │ │ │ │ ├── iamax.cpp │ │ │ │ ├── swap.cpp │ │ │ │ └── asum.cpp │ │ │ ├── side.hpp │ │ │ ├── filling.hpp │ │ │ ├── iamax.hpp │ │ │ ├── complex_traits.hpp │ │ │ ├── swap.hpp │ │ │ ├── examples │ │ │ │ └── gemv.cpp │ │ │ ├── traits.hpp │ │ │ ├── CMakeLists.txt │ │ │ ├── scal.hpp │ │ │ ├── numeric │ │ │ │ └── is_complex.hpp │ │ │ └── syrk.hpp │ │ ├── lapack.hpp │ │ ├── mpi │ │ │ ├── CMakeLists.txt │ │ │ └── test │ │ │ │ └── CMakeLists.txt │ │ ├── hipfft │ │ │ ├── test │ │ │ │ ├── hipfft.cpp │ │ │ │ └── CMakeLists.txt │ │ │ └── CMakeLists.txt │ │ ├── cuda │ │ │ ├── cublas.hpp │ │ │ ├── CMakeLists.txt │ │ │ ├── cublas │ │ │ │ ├── call.hpp │ │ │ │ ├── test │ │ │ │ │ ├── herk.cu │ │ │ │ │ ├── scal.cu │ │ │ │ │ ├── axpy.cu │ │ │ │ │ └── gemv.cu │ │ │ │ └── error.hpp │ │ │ ├── algorithms │ │ │ │ └── copy.hpp │ │ │ └── runtime │ │ │ │ └── error.hpp │ │ ├── complex │ │ │ └── CMakeLists.txt │ │ ├── thrust │ │ │ ├── test │ │ │ │ ├── device_vector.cu │ │ │ │ ├── vector.cu │ │ │ │ ├── by_key.cu │ │ │ │ └── universal.cu │ │ │ ├── CMakeLists.txt │ │ │ ├── fix_complex_traits_.hpp │ │ │ ├── fix_pointer_traits.hpp │ │ │ ├── reference.hpp │ │ │ ├── cuda │ │ │ │ └── test │ │ │ │ │ └── CMakeLists.txt │ │ │ ├── complex.hpp │ │ │ ├── omp │ │ │ │ └── test │ │ │ │ │ └── CMakeLists.txt │ │ │ └── allocator_traits.hpp │ │ ├── CMakeLists.txt │ │ ├── fftw │ │ │ ├── mpi_ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── environment.hpp │ │ │ │ └── test │ │ │ │ │ └── array_2d.cpp │ │ │ ├── test │ │ │ │ ├── thrust.cpp │ │ │ │ ├── so_shift.cpp │ │ │ │ ├── transpose.cpp │ │ │ │ └── direct_vs_transpose.cpp │ │ │ ├── memory.hpp │ │ │ └── CMakeLists.txt │ │ ├── cufft │ │ │ ├── CMakeLists.txt │ │ │ └── test │ │ │ │ └── CMakeLists.txt │ │ ├── lapack │ │ │ ├── filling.hpp │ │ │ ├── triangular.hpp │ │ │ ├── CMakeLists.txt │ │ │ ├── test │ │ │ │ └── CMakeLists.txt │ │ │ ├── getrf.hpp │ │ │ └── geqrf.hpp │ │ ├── totalview │ │ │ └── test │ │ │ │ ├── totalview.cpp │ │ │ │ └── CMakeLists.txt │ │ ├── blas.hpp │ │ ├── hipthrust │ │ │ └── test │ │ │ │ ├── vector.hip │ │ │ │ └── CMakeLists.txt │ │ └── hipfft.hpp │ │ ├── algorithms │ │ └── redux.hpp │ │ └── detail │ │ ├── is_trivial.hpp │ │ ├── config │ │ ├── VERSION.hpp │ │ ├── NO_UNIQUE_ADDRESS.hpp │ │ ├── ASSERT.hpp │ │ └── NODISCARD.hpp │ │ ├── types.hpp │ │ ├── what.hpp │ │ ├── implicit_cast.hpp │ │ └── pointer_traits.hpp └── multi.hpp ├── Testing └── Temporary │ ├── CTestCostData.txt │ └── LastTest.log ├── codecov.yml ├── cmake ├── multi-config.cmake.in └── multiConfig.cmake.in ├── benchmark ├── config.hpp ├── cuda │ └── CMakeLists.txt └── CMakeLists.txt ├── .deepsource.toml ├── .github ├── workflows │ ├── pull_request_template.md │ ├── gitlab-sync.yml │ └── pages.yml └── pull_request_template.md ├── meta └── libraries.json ├── test ├── main.cpp ├── drop.cpp ├── overload.cpp ├── coelements.cpp ├── flatted.cpp ├── elementwise_expr.cpp ├── element_moved.cpp ├── swap.cpp ├── Jamfile ├── sean.cpp ├── reversed.cpp └── array_legacy_c.cpp ├── .cmake-format.yaml ├── .gitlab └── merge_request_templates │ └── default.md ├── .gitignore ├── pre-commit ├── doc ├── Jamfile.v2 ├── index.html ├── multi.adoc └── multi │ ├── intro.adoc │ ├── primer.adoc │ └── install.adoc ├── CPPLINT.cfg ├── sonar-project.properties ├── .readthedocs.yaml ├── conanfile.py ├── .codecov.yml ├── LICENSE ├── examples ├── CMakeLists.txt ├── polymorphic_memory_resource.cpp ├── save.cpp ├── llnl_metall.cpp ├── cai_1d_heat.cpp └── lu_fact.cpp ├── .clang-format ├── mull.yml └── .gitlab-ci.yml /include/multi: -------------------------------------------------------------------------------- 1 | boost/multi -------------------------------------------------------------------------------- /Testing/Temporary/CTestCostData.txt: -------------------------------------------------------------------------------- 1 | --- 2 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/herk.su: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/cuda/tests/gemm.su: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | after_n_builds: 2 4 | -------------------------------------------------------------------------------- /cmake/multi-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/multi-targets.cmake") -------------------------------------------------------------------------------- /Testing/Temporary/LastTest.log: -------------------------------------------------------------------------------- 1 | Start testing: Nov 20 10:50 PST 2 | ---------------------------------------------------------- 3 | End testing: Nov 20 10:50 PST 4 | -------------------------------------------------------------------------------- /benchmark/config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MULTI_ADAPTORS_BLAS_TEST_CONFIG_HPP 2 | #define MULTI_ADAPTORS_BLAS_TEST_CONFIG_HPP 3 | 4 | #define CUDA_FOUND 1 5 | 6 | #endif 7 | 8 | -------------------------------------------------------------------------------- /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | test_patterns = ["test/**"] 4 | 5 | [[analyzers]] 6 | name = "test-coverage" 7 | 8 | [[analyzers]] 9 | name = "cxx" 10 | -------------------------------------------------------------------------------- /cmake/multiConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") 4 | check_required_components("@PROJECT_NAME@") 5 | 6 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/lapack.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | 3 | #pragma once 4 | 5 | #include "multi/adaptors/lapack/getrf.hpp" 6 | #include "multi/adaptors/lapack/potrf.hpp" 7 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/mpi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | # project(boost-multi-mpi VERSION 0.1) 3 | 4 | find_package(MPI REQUIRED) 5 | 6 | add_subdirectory(../mpi/test) 7 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/hipfft/test/hipfft.cpp: -------------------------------------------------------------------------------- 1 | namespace boost::multi::hipfft{} 2 | 3 | // namespace boost::multi{ 4 | // namespace cufft = hipfft; 5 | // } 6 | 7 | #include "../../cufft/test/cufft.cpp" 8 | -------------------------------------------------------------------------------- /.github/workflows/pull_request_template.md: -------------------------------------------------------------------------------- 1 | [![gitlab](https://gitlab.com/correaa/boost-multi/badges/constexpr-fill/pipeline.svg)](https://gitlab.com/correaa/boost-multi/-/pipelines) 2 | https://gitlab.com/correaa/boost-multi 3 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cuda/cublas.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #pragma once 6 | 7 | #include "boost/multi/adaptors/cuda/cublas/context.hpp" 8 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/complex/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # -*-indent-tabs-mode:nil;c-basic-offset:2;tab-width:4;autowrap:nil;-*- 2 | cmake_minimum_required(VERSION 3.13) # for reference Ubuntu 20.04 uses 3.16, 3.18 for BLAS::BLAS 3 | 4 | include_directories(${CMAKE_BINARY_DIR}) 5 | 6 | add_subdirectory(test) 7 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/test/config.hpp.in: -------------------------------------------------------------------------------- 1 | #ifndef MULTI_ADAPTORS_BLAS_TEST_CONFIG_HPP_IN // NOLINT(llvm-header-guard) name is sufficient 2 | #define MULTI_ADAPTORS_BLAS_TEST_CONFIG_HPP_IN 3 | 4 | #cmakedefine01 CUDA_FOUND // NOLINT(modernize-macro-to-enum) TODO(correaa) remove if possible 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/test/device_vector.cu: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(){ 4 | // thrust::device_vector D(5); 5 | // assert( D.size() == 5 ); 6 | sasa; 7 | // cudaDeviceSynchronize(); 8 | std::allocator alloc; 9 | int* p = alloc.allocate(10); 10 | p[0] = 2; 11 | return p[0] + 1; 12 | } 13 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Gitlab's [![gitlabci](https://gitlab.com/correaa/boost-multi/badges/master/pipeline.svg)](https://gitlab.com/correaa/boost-multi/-/pipelines?page=1&scope=all) 2 | 3 | This PR was open from a [Gitlab Merge request](https://gitlab.com/correaa/boost-multi/-/merge_requests/new), 4 | it will be probably be merged from Gitlab, and then in can be closed here. 5 | 6 | -------------------------------------------------------------------------------- /include/multi.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_HPP_ 6 | #define BOOST_MULTI_HPP_ 7 | 8 | #include "boost/multi/array.hpp" 9 | #include "boost/multi/array_ref.hpp" 10 | #include "boost/multi/broadcast.hpp" 11 | 12 | #endif // BOOST_MULTI_HPP_ 13 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | find_package(MPI) 3 | 4 | if(DISABLE_MPI) 5 | message(WARNING "MPI disabled, MPI adaptor will not be tested.") 6 | else() 7 | if(MPI_FOUND) 8 | add_subdirectory(./mpi) 9 | else() 10 | message(WARNING "MPI not found, MPI adaptor will not be tested.") 11 | endif() 12 | endif() 13 | 14 | # add_subdirectory(./cufft) 15 | 16 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/fftw/mpi_/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | 3 | set(CMAKE_VERBOSE_MAKEFILE ON) 4 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 5 | 6 | #project( 7 | # boost-multi-adaptors-fftw 8 | # VERSION 0.1 9 | # LANGUAGES CXX 10 | #) 11 | 12 | find_package(PkgConfig) 13 | pkg_search_module( 14 | FFTW 15 | fftw3 16 | IMPORTED_TARGET 17 | ) 18 | 19 | link_libraries(-lfftw3_mpi) 20 | 21 | add_subdirectory(test) 22 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | project( 3 | boost-multi-adaptor-cuda 4 | VERSION 0.1 5 | LANGUAGES CXX 6 | ) 7 | 8 | find_package(Boost CONFIG REQUIRED COMPONENTS headers) # REQUIRED COMPONENTS unit_test_framework) 9 | 10 | if(ENABLE_CUDA OR DEFINED CXXCUDA) 11 | enable_language(CUDA) 12 | 13 | enable_testing() 14 | 15 | add_subdirectory(test) 16 | add_subdirectory(cuda/test) 17 | endif() 18 | 19 | add_subdirectory(omp/test) 20 | -------------------------------------------------------------------------------- /meta/libraries.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "multi", 3 | "name": "Multi", 4 | "authors": [ 5 | "Alfredo Correa" 6 | ], 7 | "maintainers": [ 8 | "Alfredo Correa " 9 | ], 10 | "description": "Multi is a modern C++ library that provides access and manipulation of data in multidimensional arrays, for both CPU and GPU memory.", 11 | "category": [ 12 | "Containers", 13 | "Math" 14 | ], 15 | "cxxstd": "17" 16 | } 17 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | 7 | namespace multi = boost::multi; 8 | 9 | auto main() -> int { 10 | multi::array arr = { 11 | { 0, 1, 2, 3, 4}, 12 | { 5, 6, 7, 8, 9}, 13 | {10, 11, 12, 13, 14}, 14 | {15, 16, 17, 18, 19}, 15 | }; 16 | 17 | if(arr[2][3] != 13) { 18 | return 1; 19 | } 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /.cmake-format.yaml: -------------------------------------------------------------------------------- 1 | # run `cmake-format --in-place CMakeLists.txt` comply with the format in this file, for all files: `find . \( -name '*.cmake' -o -name 'CMakeLists.txt' \) -exec cmake-format -i {} \;` 2 | bullet_char: '*' 3 | dangle_parens: true 4 | line_ending: unix 5 | line_width: 240 6 | max_pargs_hwrap: 3 7 | separate_ctrl_name_with_space: false 8 | separate_fn_name_with_space: false 9 | tab_size: 4 10 | use_tabchars: true 11 | command_case: lower 12 | keyword_case: upper 13 | enable_sort: true 14 | autosort: true 15 | -------------------------------------------------------------------------------- /.gitlab/merge_request_templates/default.md: -------------------------------------------------------------------------------- 1 | [![cmakeworkflow](https://github.com/correaa/boost-multi/actions/workflows/cmake.yml/badge.svg?branch=%{source_branch})](https://github.com/correaa/boost-multi/actions?query=workflow%3ACMake+branch%3A%{source_branch}++) 2 | [![ciworkflow](https://github.com/correaa/boost-multi/actions/workflows/ci.yml/badge.svg?branch=%{source_branch})](https://github.com/correaa/boost-multi/actions?query=workflow%3ACI+branch%3A%{source_branch}++) 3 | [Create/view GitHub PR](https://github.com/correaa/boost-multi/compare/%{source_branch}) 4 | -------------------------------------------------------------------------------- /include/boost/multi/algorithms/redux.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #pragma once 6 | #ifndef BOOST_MULTI_ALGORITHM_REDUX_HPP 7 | #define BOOST_MULTI_ALGORITHM_REDUX_HPP 8 | 9 | // #include // for par // needs linking to TBB library 10 | // #include // for inner_product and transform_reduce 11 | 12 | namespace boost::multi { 13 | 14 | 15 | } // end namespace boost::multi 16 | 17 | #endif // BOOST_MULTI_ALGORITHM_GEMM_HPP 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build* 2 | .build* 3 | .vscode 4 | .devcontainer/* 5 | .cache/clangd/* 6 | 7 | # Prerequisites 8 | *.d 9 | 10 | # Compiled Object files 11 | *.slo 12 | *.lo 13 | *.o 14 | *.obj 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Compiled Dynamic libraries 21 | *.so 22 | *.dylib 23 | *.dll 24 | 25 | # Fortran module files 26 | *.mod 27 | *.smod 28 | 29 | # Compiled Static libraries 30 | *.lai 31 | *.la 32 | *.a 33 | *.lib 34 | 35 | # Executables 36 | *.exe 37 | *.out 38 | *.app 39 | 40 | # Cmake 41 | cmake-build-debug 42 | 43 | # Clion 44 | .idea 45 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cufft/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | 3 | set(CMAKE_VERBOSE_MAKEFILE ON) 4 | 5 | project( 6 | boost-multi-adaptors-blas 7 | VERSION 0.1 8 | LANGUAGES CXX 9 | ) 10 | 11 | if(ENABLE_CUDA OR DEFINED CXXCUDA) 12 | enable_language(CUDA) 13 | # set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr --extended-lambda") 14 | endif() 15 | 16 | # find_package(CUDA QUIET) 17 | include_directories(${CUDA_INCLUDE_DIRS}) 18 | link_libraries(${CUDA_CUFFT_LIBRARIES}) 19 | 20 | include_directories(${CMAKE_BINARY_DIR}) 21 | 22 | add_subdirectory(test) 23 | -------------------------------------------------------------------------------- /pre-commit: -------------------------------------------------------------------------------- 1 | (mkdir -p .build.g++cppcheck && cd .build.g++cppcheck && CXX=g++ cmake .. -G"Unix Makefiles" -DCMAKE_CXX_CPPCHECK="cppcheck;--enable=all;--inline-suppr;--suppress=*:*thrust/complex*;--suppress=missingInclude;--suppress=syntaxError;--suppress=unmatchedSuppression;--suppress=preprocessorErrorDirective;--language=c++;--std=c++14;--error-exitcode=66" && make -j 11 && ctest -j 12 --output-on-failure) || exit 2 | cpplint --quiet --filter=-whitespace/line_length,-whitespace/parens,-whitespace/tab,-readability/alt_tokens,-readability/nolint,-runtime/references,-build/include_order,-build/header_guar,-whitespace/operators *.hpp detail/*.hpp 3 | -------------------------------------------------------------------------------- /doc/Jamfile.v2: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Joaqu�n M L�pez Mu�oz. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # http://www.boost.org/LICENSE_1_0.txt) 5 | # 6 | # See http://www.boost.org/libs/multi for library home page. 7 | 8 | import asciidoctor ; 9 | 10 | html multi.html : multi.adoc ; 11 | 12 | install html_ : multi.html : html ; 13 | 14 | pdf multi.pdf : multi.adoc ; 15 | explicit multi.pdf ; 16 | 17 | install pdf_ : multi.pdf : multi ; 18 | explicit pdf_ ; 19 | 20 | alias boostdoc ; 21 | explicit boostdoc ; 22 | alias boostrelease : html_ ; 23 | explicit boostrelease ; 24 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/hipfft/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | 3 | project( 4 | boost-multi-adaptors-hipfft 5 | VERSION 0.1 6 | LANGUAGES CXX 7 | ) 8 | 9 | enable_language(HIP) 10 | find_package(hipFFT REQUIRED) 11 | # find_package(rocthrust REQUIRED) 12 | 13 | # if(ENABLE_CUDA OR DEFINED CXXCUDA) 14 | # enable_language(CUDA) 15 | # set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr --extended-lambda") 16 | # endif() 17 | 18 | # find_package(CUDA QUIET) 19 | #include_directories(${CUDA_INCLUDE_DIRS}) 20 | #link_libraries(${CUDA_CUFFT_LIBRARIES}) 21 | 22 | # include_directories(${CMAKE_BINARY_DIR}) 23 | 24 | add_subdirectory(test) 25 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | Boost.Multi Documentation 14 | 15 | 16 | 17 | Automatic redirection failed, please go to 18 | html/index.html 19 | 20 | 21 | -------------------------------------------------------------------------------- /CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | set noparent 2 | root=./include/ 3 | 4 | linelength=160 5 | 6 | filter=-build/include_order # this library uses this order of inclusion: local headers / third pary heders / boost headers / standard headers 7 | 8 | filter=-runtime/references # this library uses references 9 | 10 | filter=-readability/nolint # accept NOLINT from other linters 11 | filter=-readability/braces # bug in cpplint 2.0.2 for inline defined lambdas 12 | 13 | filter=-whitespace/braces # braces unfortunately makes local scopes need an extra space {} 14 | filter=-whitespace/parens # otherwise it will complain about whitespace in MACRO args 15 | filter=-whitespace/tab # this library uses tabs for indentation 16 | -------------------------------------------------------------------------------- /include/boost/multi/detail/is_trivial.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_DETAIL_IS_TRIVIAL_HPP 6 | #define BOOST_MULTI_DETAIL_IS_TRIVIAL_HPP 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace boost { // NOLINT(modernize-concat-nested-namespaces) 12 | namespace multi { 13 | 14 | // template struct is_trivially_default_constructible : std::is_trivially_default_constructible {}; 15 | // template struct is_trivial : std::is_trivial {}; 16 | 17 | 18 | } // end namespace multi 19 | } // end namespace boost 20 | 21 | #endif // BOOST_MULTI_DETAIL_IS_TRIVIAL_HPP 22 | -------------------------------------------------------------------------------- /test/drop.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2025 Alfredo A. Correa 2 | // Copyright 2024 Matt Borland 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // https://www.boost.org/LICENSE_1_0.txt 5 | 6 | #include // for implicit_cast, explicit_cast 7 | 8 | #include 9 | 10 | namespace multi = boost::multi; 11 | 12 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 13 | /* drop */ 14 | { 15 | multi::array AA({ 16 | {1, 5}, 17 | {1, 5} 18 | }, 19 | 0); 20 | AA[1][1] = 12; 21 | AA[2][1] = 13; 22 | 23 | BOOST_TEST( AA.dropped(1)[1][1] == 13 ); 24 | } 25 | 26 | return boost::report_errors(); 27 | } 28 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=correaa_boost-multi 2 | sonar.organization=correaa 3 | 4 | # This is the name and version displayed in the SonarCloud UI. 5 | #sonar.projectName=boost-multi 6 | #sonar.projectVersion=1.0 7 | 8 | 9 | # Path is relativep to the sonar-project.properties file. Replace "\" by "/" on Windows. 10 | #sonar.sources=. 11 | 12 | # Encoding of the source code. Default is default system encoding 13 | #sonar.sourceEncoding=UTF-8 14 | 15 | # sonar.issue.ignore.all=true 16 | 17 | # Cognitive Complexity of functions should not be too high cpp:S3776 18 | sonar.issue.ignore.specific.rule=cpp:S3776 19 | # "explicit" should be used on single-parameter constructors and conversion operators cpp:S1709 20 | sonar.issue.ignore.specific.rule=cpp:S1709 21 | -------------------------------------------------------------------------------- /include/boost/multi/detail/config/VERSION.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022-2023 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_CONFIG_VERSION_HPP_ 6 | #define BOOST_MULTI_CONFIG_VERSION_HPP_ 7 | 8 | // NOLINTBEGIN(cppcoreguidelines-macro-usage,modernize-macro-to-enum) indicate library version 9 | #define BOOST_MULTI_VERSION_MAJOR 0 10 | #define BOOST_MULTI_VERSION_MINOR 81 11 | #define BOOST_MULTI_VERSION_MICRO 0 12 | 13 | #define BOOST_MULTI_VERSION (BOOST_MULTI_VERSION_MAJOR * 10000 + BOOST_MULTI_VERSION_MINOR * 100 + BOOST_MULTI_VERSION_MICRO) 14 | 15 | // NOLINTEND(cppcoreguidelines-macro-usage,modernize-macro-to-enum) 16 | 17 | #endif // BOOST_MULTI_CONFIG_VERSION_HPP_ 18 | -------------------------------------------------------------------------------- /.github/workflows/gitlab-sync.yml: -------------------------------------------------------------------------------- 1 | name: GitlabSync # https://dev.to/brunorobert/github-and-gitlab-sync-44mn 2 | 3 | on: 4 | - push 5 | - delete 6 | 7 | jobs: 8 | sync: 9 | runs-on: ubuntu-latest 10 | name: Git Repo Sync 11 | steps: 12 | - uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | - uses: wangchucheng/git-repo-sync@v0.1.0 16 | with: 17 | # Such as https://github.com/wangchucheng/git-repo-sync.git 18 | target-url: ${{ secrets.TARGET_URL }} 19 | # Such as wangchucheng 20 | target-username: ${{ secrets.TARGET_USERNAME }} 21 | # You can store token in your project's 'Setting > Secrets' and reference the name here. Such as ${{ secrets.ACCESS\_TOKEN }} 22 | target-token: ${{ secrets.TARGET_TOKEN }} 23 | -------------------------------------------------------------------------------- /include/boost/multi/detail/types.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_DETAIL_TYPES_HPP 6 | #define BOOST_MULTI_DETAIL_TYPES_HPP 7 | #pragma once 8 | 9 | #include // for std::size_t 10 | #include // for make_signed_t 11 | 12 | namespace boost::multi { 13 | 14 | using size_t = std::make_signed_t; 15 | using size_type = std::make_signed_t; 16 | 17 | using index = std::make_signed_t; 18 | using difference_type = std::make_signed_t; 19 | 20 | using dimensionality_t = index; 21 | using dimensionality_type = dimensionality_t; 22 | 23 | } // end namespace boost::multi 24 | #endif // BOOST_MULTI_DETAIL_TYPES_HPP 25 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cuda/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | #project( 3 | # boost-multi-adaptor-cuda 4 | # VERSION 0.1 5 | # LANGUAGES CXX 6 | #) 7 | 8 | # set(CMAKE_CXX_STANDARD 17) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | set(CMAKE_CXX_EXTENSIONS OFF) 11 | 12 | find_package(Boost REQUIRED COMPONENTS) # unit_test_framework) 13 | 14 | if(ENABLE_HIP) 15 | enable_language(HIP) # may need `module load rocm` 16 | enable_testing() 17 | 18 | add_subdirectory(cublas/test) 19 | endif() 20 | 21 | if(ENABLE_CUDA OR DEFINED CXXCUDA) 22 | enable_language(CUDA) 23 | # set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -std=c++17 --extended-lambda --expt-relaxed-constexpr") 24 | 25 | enable_testing() 26 | list(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure") # needs cmake 3.1 27 | 28 | add_subdirectory(cublas/test) 29 | endif() 30 | -------------------------------------------------------------------------------- /include/boost/multi/detail/what.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_DETAIL_WHAT_HPP 6 | #define BOOST_MULTI_DETAIL_WHAT_HPP 7 | #pragma once 8 | 9 | namespace boost::multi::detail { 10 | template auto what(T&&) -> T&& = delete; // NOLINT(cppcoreguidelines-missing-std-forward) 11 | template auto what(Ts&&...) -> std::tuple = delete; // NOLINT(cppcoreguidelines-missing-std-forward) 12 | template auto what() -> std::tuple = delete; 13 | 14 | template auto what_value() -> std::integral_constant = delete; 15 | template struct what_value_t; 16 | } // namespace boost::multi::detail 17 | 18 | #endif // BOOST_MULTI_DETAIL_WHAT_HPP 19 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/lapack/filling.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_LAPACK_FILLING_HPP 6 | #define BOOST_MULTI_ADAPTORS_LAPACK_FILLING_HPP 7 | #pragma once 8 | 9 | // TODO(correaa) #include "multi/blas/filling.hpp" 10 | 11 | namespace boost::multi::lapack { 12 | 13 | enum class filling : char { 14 | lower = 'U', 15 | upper = 'L', 16 | }; 17 | 18 | inline auto flip(filling side) -> filling { 19 | switch(side) { 20 | case filling::lower: return filling::upper; 21 | case filling::upper: return filling::lower; 22 | } 23 | __builtin_unreachable(); // LCOV_EXCL_LINE 24 | } 25 | 26 | inline auto operator-(filling side) -> filling { return flip(side); } 27 | inline auto operator+(filling side) -> filling { return side; } 28 | 29 | } // namespace boost::multi::lapack 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/fix_complex_traits_.hpp: -------------------------------------------------------------------------------- 1 | // -*-indent-tabs-mode:t;c-basic-offset:4;tab-width:4;autowrap:nil;-*- 2 | // Copyright 2022-2023 Alfredo A. Correa 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace boost { 11 | namespace multi { 12 | 13 | #ifndef NDEBUG 14 | #pragma message "By including this header, the behavior of initialization of thrust::complex in multi::array's changes. ::thrust::complex elements will not be initialized." 15 | #endif 16 | 17 | template 18 | inline constexpr bool force_element_trivial_default_construction<::thrust::complex> = std::is_trivially_default_constructible_v; 19 | 20 | template struct is_trivially_default_constructible<::thrust::complex> : std::is_trivially_default_constructible {}; 21 | 22 | static_assert(is_trivially_default_constructible<::thrust::complex>::value); 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/side.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_BLAS_SIDE_HPP 6 | #define BOOST_MULTI_ADAPTORS_BLAS_SIDE_HPP 7 | 8 | namespace boost::multi::blas { 9 | 10 | enum class side : char { 11 | left = 'L', 12 | right = 'R' 13 | }; 14 | 15 | #ifdef __clang__ 16 | #pragma clang diagnostic push 17 | #pragma clang diagnostic ignored "-Wswitch-default" 18 | #endif 19 | 20 | inline auto swap(side sid) noexcept -> side { 21 | switch(sid) { // NOLINT(clang-diagnostic-switch-default) 22 | case side::left : return side::right; 23 | case side::right: return side::left ; 24 | } // __builtin_unreachable(); // LCOV_EXCL_LINE 25 | return {}; 26 | } 27 | 28 | #ifdef __clang__ 29 | #pragma clang diagnostic pop 30 | #endif 31 | 32 | 33 | } // end namespace boost::multi::blas 34 | #endif 35 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the OS, Python version and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.12" 13 | # You can also specify other tool versions: 14 | # nodejs: "19" 15 | # rust: "1.64" 16 | # golang: "1.19" 17 | 18 | # Build documentation in the "docs/" directory with Sphinx 19 | sphinx: 20 | configuration: docs/conf.py 21 | 22 | # Optionally build your docs in additional formats such as PDF and ePub 23 | # formats: 24 | # - pdf 25 | # - epub 26 | 27 | # Optional but recommended, declare the Python requirements required 28 | # to build your documentation 29 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 30 | python: 31 | install: 32 | - requirements: docs/requirements.txt 33 | -------------------------------------------------------------------------------- /doc/multi.adoc: -------------------------------------------------------------------------------- 1 | = https://gitlab.com/correaa/boost-multi[Boost.Multi] 2 | Alfredo A. Correa (last modified: {docdatetime}) 3 | :toc: left 4 | :toclevels: 2 5 | :idprefix: 6 | :docinfo: private-footer 7 | :source-highlighter: rouge 8 | :source-language: c++ 9 | :nofooter: 10 | :sectlinks: 11 | :leveloffset: +1 12 | :imagesdir: ../img 13 | :stem: latexmath 14 | :small: pass:[] 15 | :small-end: pass:[] 16 | 17 | ++++ 18 | 31 | ++++ 32 | 33 | include::multi/intro.adoc[] 34 | include::multi/install.adoc[] 35 | include::multi/primer.adoc[] 36 | include::multi/tutorial.adoc[] 37 | include::multi/interop.adoc[] 38 | include::multi/technical.adoc[] 39 | include::multi/reference.adoc[] 40 | include::multi/appendix.adoc[] 41 | 42 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/totalview/test/totalview.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE "C++ Unit Tests for Multi TotalView adaptor" 2 | #define BOOST_TEST_DYN_LINK 3 | 4 | // #include 5 | 6 | #include "multi/array.hpp" 7 | #include "multi/utility.hpp" 8 | 9 | #include "../../../adaptors/totalview.hpp" 10 | 11 | #include // transform 12 | #include 13 | #include 14 | #include // iota 15 | 16 | namespace multi = boost::multi; 17 | 18 | BOOST_AUTO_TEST_CASE(multi_1d) { 19 | 20 | std::vector V = {10, 20, 30}; 21 | 22 | multi::array const A = {1.0, 2.0, 3.0, 4.0, 5.0}; 23 | auto&& Apart = A({1, 3}); 24 | 25 | multi::array const B = { 26 | {1.0, 2.0, 3.0}, 27 | {4.0, 5.0, 6.0}, 28 | }; 29 | 30 | double sum = 0.0; 31 | for(auto i : A.extension()) { 32 | sum += A[i]; 33 | } 34 | 35 | BOOST_REQUIRE( sum == 15.0 ); 36 | BOOST_REQUIRE( B[1][0] == 4.0 ); 37 | } 38 | -------------------------------------------------------------------------------- /include/boost/multi/detail/config/NO_UNIQUE_ADDRESS.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2025 Alfredo A. Correa 2 | // Copyright 2024 Matt Borland 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // https://www.boost.org/LICENSE_1_0.txt 5 | 6 | #ifndef BOOST_MULTI_DETAIL_CONFIG_NO_UNIQUE_ADDRESS_HPP 7 | #define BOOST_MULTI_DETAIL_CONFIG_NO_UNIQUE_ADDRESS_HPP 8 | 9 | #ifdef __has_cpp_attribute 10 | #if __has_cpp_attribute(no_unique_address) >= 201803L && !defined(__NVCC__) && !defined(__PGI) && (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) 11 | // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) this macro will be needed until C++20 12 | #define BOOST_MULTI_NO_UNIQUE_ADDRESS [[no_unique_address]] 13 | #endif 14 | #endif 15 | 16 | #ifndef BOOST_MULTI_NO_UNIQUE_ADDRESS 17 | #ifdef _MSC_VER 18 | #define BOOST_MULTI_NO_UNIQUE_ADDRESS // [[msvc::no_unique_address]] 19 | #else 20 | #define BOOST_MULTI_NO_UNIQUE_ADDRESS 21 | #endif 22 | #endif 23 | 24 | #endif // BOOST_MULTI_DETAIL_CONFIG_NO_UNIQUE_ADDRESS_HPP 25 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/test/traits.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace multi = boost::multi; 13 | namespace blas = multi::blas; 14 | 15 | 16 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 17 | // BOOST_AUTO_TEST_CASE(multi_adaptors_blas_traits_simple_array) 18 | { 19 | multi::array const arr; 20 | BOOST_TEST( arr.empty() ); 21 | } 22 | 23 | // BOOST_AUTO_TEST_CASE(multi_adaptors_blas_traits) 24 | { 25 | static_assert(blas::is_d{}); 26 | static_assert(blas::is_s{}); 27 | 28 | static_assert(blas::is_c>{}); 29 | static_assert(blas::is_z>{}); 30 | } 31 | 32 | return boost::report_errors(); 33 | } 34 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/cuda/tests/iamax.cpp: -------------------------------------------------------------------------------- 1 | // © Alfredo A. Correa 2019-2024 2 | 3 | #define BOOST_TEST_MODULE "C++ Unit Tests for Multi cuBLAS iamax" 4 | #define BOOST_TEST_DYN_LINK 5 | 6 | // #include 7 | 8 | #include "../../../../adaptors/blas.hpp" 9 | #include "../../../../adaptors/cuda.hpp" 10 | #include "../../../../adaptors/blas/cuda.hpp" 11 | 12 | namespace multi = boost::multi; 13 | 14 | BOOST_AUTO_TEST_CASE(const multi_adaptors_blas_cuda_iamax){ 15 | using complex = std::complex; complex const I{0.0, 1.0}; 16 | { 17 | multi::array const A = {1.0 + 2.0*I, 2.0, 3.0 + 3.0*I, 4.0}; 18 | using multi::blas::iamax; 19 | BOOST_REQUIRE( iamax(A) == 2 ); 20 | } 21 | { 22 | multi::cuda::array const A = {1.0 + 2.0*I, 2.0, 3.0 + 3.0*I, 4.0}; 23 | using multi::blas::iamax; 24 | BOOST_REQUIRE( iamax(A) == 2 ); 25 | } 26 | { 27 | multi::cuda::managed::array const A = {1.0 + 2.0*I, 2.0, 3.0 + 3.0*I, 4.0}; 28 | using multi::blas::iamax; 29 | BOOST_REQUIRE( iamax(A) == 2 ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | from conan import ConanFile 2 | from conan.tools.files import copy 3 | 4 | 5 | class MultiConan(ConanFile): 6 | name = "b-multi" 7 | version = "0.80.1" 8 | homepage = "https://gitlab.com/correaa/boost-multi" 9 | description = "Multidimensional array access to contiguous or regularly contiguous memory. (Not an official Boost library)" 10 | topics = ( 11 | "array", 12 | "multidimensional", 13 | "library", 14 | ) 15 | license = "Boost" 16 | url = "https://gitlab.com/correaa/boost-multi" 17 | # No settings/options are necessary, this is header only 18 | exports_sources = "include/*" 19 | no_copy_source = True 20 | 21 | def package(self): 22 | # This will also copy the "include" folder 23 | copy(self, "*.hpp", self.source_folder, self.package_folder) 24 | 25 | def package_info(self): 26 | # For header-only packages, libdirs and bindirs are not used 27 | # so it's recommended to set those as empty. 28 | self.cpp_info.bindirs = [] 29 | self.cpp_info.libdirs = [] 30 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_BLAS_HPP 6 | #define BOOST_MULTI_ADAPTORS_BLAS_HPP 7 | #pragma once 8 | 9 | #include "boost/multi/adaptors/blas/traits.hpp" // IWYU pragma: export 10 | 11 | #include "boost/multi/adaptors/blas/asum.hpp" 12 | #include "boost/multi/adaptors/blas/axpy.hpp" 13 | #include "boost/multi/adaptors/blas/copy.hpp" 14 | #include "boost/multi/adaptors/blas/dot.hpp" 15 | #include "boost/multi/adaptors/blas/gemm.hpp" 16 | #include "boost/multi/adaptors/blas/gemv.hpp" // IWYU pragma: export 17 | #include "boost/multi/adaptors/blas/herk.hpp" 18 | #include "boost/multi/adaptors/blas/iamax.hpp" 19 | #include "boost/multi/adaptors/blas/nrm2.hpp" 20 | #include "boost/multi/adaptors/blas/scal.hpp" 21 | #include "boost/multi/adaptors/blas/swap.hpp" 22 | #include "boost/multi/adaptors/blas/syrk.hpp" 23 | #include "boost/multi/adaptors/blas/trsm.hpp" 24 | 25 | #endif // BOOST_MULTI_ADAPTORS_BLAS_HPP 26 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/hipfft/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | 3 | project( 4 | boost-multi-adaptors-hipfft-test 5 | VERSION 0.1 6 | LANGUAGES CXX 7 | ) 8 | 9 | enable_language(HIP) 10 | find_package(hipFFT REQUIRED) 11 | 12 | # FFTW has to go before blas to avoid unscrupulous (i.e. MKL) blas implementations that include FFTW and don't implement it properly 13 | find_package(PkgConfig REQUIRED) 14 | pkg_search_module( 15 | FFTW 16 | REQUIRED 17 | fftw3 18 | IMPORTED_TARGET 19 | ) 20 | include_directories(PkgConfig::FFTW) 21 | link_libraries(PkgConfig::FFTW) 22 | 23 | enable_testing() 24 | include(CTest) 25 | 26 | # include_directories(${CMAKE_BINARY_DIR}) 27 | 28 | find_package(Boost COMPONENTS unit_test_framework) 29 | 30 | add_executable(hipfft.cpp.x hipfft.cpp) 31 | set_source_files_properties(hipfft.cpp PROPERTIES LANGUAGE HIP) 32 | 33 | # target_link_libraries(${TEST_EXE} PRIVATE multi) 34 | target_link_libraries(hipfft.cpp.x PRIVATE hip::hipfft Boost::unit_test_framework multi) 35 | 36 | add_test(NAME hipfft.cpp.x COMMAND $) 37 | 38 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/fftw/test/thrust.cpp: -------------------------------------------------------------------------------- 1 | // © Alfredo A. Correa 2020-2024 2 | 3 | #define BOOST_TEST_MODULE "C++ Unit Tests for Multi FFTW adaptor (cpu) with thrust complex" 4 | #define BOOST_TEST_DYN_LINK 5 | 6 | // #include 7 | 8 | #include "../../fftw.hpp" 9 | 10 | #include 11 | #include 12 | 13 | namespace multi = boost::multi; 14 | 15 | BOOST_AUTO_TEST_CASE(const fftw_2D_identity){ 16 | using complex = thrust::complex; complex const I{0.0, 1.0}; 17 | 18 | multi::array const in = { 19 | { 1.0 + 2.0*I, 9.0 - 1.0*I, 2.0 + 4.0*I}, 20 | { 3.0 + 3.0*I, 7.0 - 4.0*I, 1.0 + 9.0*I}, 21 | { 4.0 + 1.0*I, 5.0 + 3.0*I, 2.0 + 4.0*I}, 22 | { 3.0 - 1.0*I, 8.0 + 7.0*I, 2.0 + 1.0*I}, 23 | { 31.0 - 1.0*I, 18.0 + 7.0*I, 2.0 + 10.0*I} 24 | }; 25 | auto fwd = multi::fftw::dft({true, true}, in, multi::fftw::forward); 26 | 27 | multi::array, 2> const in_t = in; 28 | 29 | auto fwd_t = multi::fftw::dft({true, true}, in_t, multi::fftw::forward); 30 | 31 | BOOST_REQUIRE( fwd == fwd_t ); 32 | } 33 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/mpi/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | if(ENABLE_CUDA) 4 | enable_language(CUDA) 5 | endif() 6 | 7 | enable_testing() 8 | include(CTest) 9 | 10 | find_package(Boost REQUIRED COMPONENTS NO_MODULE) 11 | 12 | add_executable(mpi.cpp.x mpi.cpp) 13 | 14 | if(ENABLE_CUDA) 15 | set_source_files_properties(${TEST_FILE} PROPERTIES LANGUAGE CUDA) 16 | endif() 17 | 18 | if(APPLE) 19 | # https://apple.stackexchange.com/a/121010 20 | # add_custom_command (TARGET mpi.cpp.x POST_BUILD COMMAND codesign --force --deep -s ACTMPI ${CMAKE_CURRENT_BINARY_DIR}/mpi.cpp.x) 21 | endif() 22 | 23 | target_link_libraries(mpi.cpp.x PRIVATE multi) 24 | target_link_libraries(mpi.cpp.x PRIVATE MPI::MPI_CXX Boost::boost) 25 | 26 | if(APPLE) 27 | add_test(NAME mpi.cpp.x COMMAND ${MPIEXEC_EXECUTABLE} --oversubscribe --mca btl ^tcp ${MPIEXEC_NUMPROC_FLAG} 4 ${MPIEXEC_PREFLAGS} $ ${MPIEXEC_POSTFLAGS}) 28 | else() 29 | add_test(NAME mpi.cpp.x COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 4 ${MPIEXEC_PREFLAGS} $ ${MPIEXEC_POSTFLAGS}) 30 | endif() -------------------------------------------------------------------------------- /include/boost/multi/adaptors/hipthrust/test/vector.hip: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE "C++ Unit Tests for Multi HIP thrust" 2 | // #include 3 | 4 | #include 5 | #include 6 | 7 | template void what(T&&) = delete; 8 | 9 | BOOST_AUTO_TEST_CASE(vector){ 10 | // H has storage for 4 integers 11 | thrust::host_vector H(4); 12 | 13 | // initialize individual elements 14 | H[0] = 14; 15 | H[1] = 20; 16 | H[2] = 38; 17 | H[3] = 46; 18 | 19 | // H.size() returns the size of vector H 20 | BOOST_TEST_REQUIRE( H.size() == 4 ); 21 | 22 | // print contents of H 23 | BOOST_TEST_REQUIRE( H[2] == 38 ); 24 | 25 | // resize H 26 | H.resize(2); 27 | 28 | BOOST_REQUIRE( H.size() == 2 ); 29 | 30 | // Copy host_vector H to device_vector D 31 | thrust::device_vector D = H; 32 | 33 | // f(D.data()); 34 | 35 | // elements of D can be modified 36 | D[0] = 99; 37 | D[1] = 88; 38 | 39 | thrust::device_ptr p = D.data(); // this works with rocm hip 5.6 40 | // thrust::pointer p = D.data(); // this works with rocm hip 5.6 41 | 42 | BOOST_REQUIRE( p[0] == 99 ); 43 | 44 | BOOST_TEST_REQUIRE( D[1] == 88 ); 45 | } 46 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cuda/cublas/call.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_CUDA_CUBLAS_CALL_HPP 6 | #define BOOST_MULTI_ADAPTORS_CUDA_CUBLAS_CALL_HPP 7 | #pragma once 8 | 9 | #include "boost/multi/adaptors/cuda/cublas/error.hpp" 10 | 11 | #if !defined(MULTI_USE_HIP) 12 | #include // cudaDeviceSynchronize 13 | #else 14 | #include // cudaDeviceSynchronize 15 | #endif 16 | 17 | #if !defined(MULTI_USE_HIP) 18 | #define hicup(name) cuda##name 19 | #define HICUP(name) CU##name 20 | #else 21 | #define hicup(name) hip##name 22 | #define HICUP(name) HIP##name 23 | #endif 24 | 25 | namespace boost::multi::cuda::cublas{ 26 | 27 | template // needs C++17 28 | void call(Args... args){ 29 | auto e = static_cast(Function(args...)); 30 | if(e != cublas::error::success) { throw std::system_error{e, "cannot call function "+ std::string{__PRETTY_FUNCTION__}}; } 31 | } 32 | 33 | #define CUBLAS_(F) call 34 | 35 | } 36 | 37 | #undef hicup 38 | #undef HICUP 39 | #endif // BOOST_MULTI_ADAPTORS_CUDA_CUBLAS_CALL_HPP 40 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/fftw/mpi_/environment.hpp: -------------------------------------------------------------------------------- 1 | #if COMPILATION_INSTRUCTIONS 2 | #mpicxx -I$HOME/prj/alf $0 -g -o $0x -lfftw3 -lfftw3_mpi &&mpirun -n 2 valgrind $0x;exit 3 | $CXXX $CXXFLAGS -O2 -g `mpicxx -showme:compile|sed 's/-pthread/ /g'` -I$HOME/prj/alf $0 -o $0x `mpicxx -showme:link|sed 's/-pthread/ /g'` -lfftw3 -lfftw3_mpi -lboost_timer&&mpirun -n 2 $0x;exit 4 | #endif 5 | 6 | #ifndef MULTI_FFTW_MPI_ENVIRONMENT_HPP 7 | #define MULTI_FFTW_MPI_ENVIRONMENT_HPP 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "../../../array_ref.hpp" 14 | 15 | #include 16 | 17 | namespace boost{ 18 | namespace multi{ 19 | namespace fftw{ 20 | namespace mpi{ 21 | 22 | namespace bmpi3 = boost::mpi3; 23 | 24 | struct environment{ 25 | explicit environment(bmpi3::environment&){fftw_mpi_init();} 26 | ~environment(){fftw_mpi_cleanup();} 27 | }; 28 | 29 | }}}} 30 | 31 | #if not __INCLUDE_LEVEL__ 32 | 33 | #include 34 | 35 | namespace bmpi3 = boost::mpi3; 36 | namespace multi = boost::multi; 37 | 38 | int bmpi3::main(int, char*[], mpi3::environment& env){ 39 | multi::fftw::mpi::environment fenv(env); 40 | return 0; 41 | } 42 | #endif 43 | #endif 44 | 45 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/fix_pointer_traits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2023 Alfredo A. Correa 2 | 3 | #ifndef BOOST_MULTI_ADAPTORS_THRUST_FIX_POINTER_TRAITS_HPP_ 4 | #define BOOST_MULTI_ADAPTORS_THRUST_FIX_POINTER_TRAITS_HPP_ 5 | #pragma once 6 | 7 | #include 8 | 9 | #include // for std::pointer_traits 10 | 11 | #include 12 | 13 | // #if(__CUDACC_VER_MAJOR__ * 10000 + __CUDACC_VER_MINOR__ * 100 + __CUDACC_VER_BUILD__ < 120500) 14 | // begin of nvcc thrust 11.5 workaround : https://github.com/NVIDIA/thrust/issues/1629 15 | namespace thrust { 16 | 17 | // template class pointer; 18 | // template struct pointer_traits; 19 | 20 | } // end namespace thrust 21 | 22 | template 23 | struct std::pointer_traits<::thrust::pointer> // NOLINT(cert-dcl58-cpp) normal way to specialize pointer_traits 24 | : ::thrust::detail::pointer_traits> { 25 | template 26 | using rebind = typename ::thrust::detail::pointer_traits<::thrust::pointer>::template rebind::other; 27 | }; 28 | // end of nvcc thrust 11.5 workaround 29 | // #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | after_n_builds: 2 4 | require_ci_to_pass: yes 5 | 6 | coverage: 7 | status: 8 | project: 9 | default: 10 | threshold: 0.5% 11 | patch: true 12 | changes: false 13 | precision: 2 14 | round: down 15 | range: "99..100" 16 | 17 | # Ignore testing directory itself 18 | ignore: 19 | - "test/" 20 | 21 | parsers: 22 | gcov: 23 | branch_detection: 24 | conditional: yes 25 | loop: yes 26 | method: no 27 | macro: no 28 | 29 | comment: 30 | layout: "header, diff" 31 | 32 | 33 | # Fixes report prefix paths from CI dynamic coverage action 34 | # from https://docs.codecov.io/docs/fixing-paths 35 | #fixes: 36 | # - "/builds/correaa::" 37 | 38 | #codecov: 39 | # disable_default_path_fixes: true 40 | # token: 999feb5b-a599-4d02-b9c5-46d977247f3a 41 | # notify: 42 | # require_ci_to_pass: yes 43 | # 44 | #coverage: 45 | # precision: 2 46 | # round: down 47 | # range: 99..100 48 | # 49 | # status: 50 | # project: yes 51 | # patch: yes 52 | # changes: no 53 | # 54 | #parsers: 55 | # gcov: 56 | # branch_detection: 57 | # conditional: yes 58 | # loop: yes 59 | # method: no 60 | # macro: no 61 | # 62 | #comment: 63 | # layout: "header, diff" 64 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/filling.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_BLAS_FILLING_HPP 6 | #define BOOST_MULTI_ADAPTORS_BLAS_FILLING_HPP 7 | 8 | #include "boost/multi/array_ref.hpp" 9 | 10 | #include "boost/multi/adaptors/blas/core.hpp" 11 | #include "boost/multi/adaptors/blas/operations.hpp" 12 | 13 | namespace boost::multi::blas { 14 | 15 | enum class filling : char { 16 | lower = 'U', 17 | upper = 'L' 18 | }; 19 | 20 | #ifdef __clang__ 21 | #pragma clang diagnostic push 22 | #pragma clang diagnostic ignored "-Wswitch-default" 23 | #endif 24 | 25 | inline auto flip(filling side) -> filling { 26 | switch(side) { // NOLINT(clang-diagnostic-switch-default) 27 | case filling::lower: return filling::upper; 28 | case filling::upper: return filling::lower; 29 | } // __builtin_unreachable(); // LCOV_EXCL_LINE 30 | return {}; 31 | } 32 | 33 | #ifdef __clang__ 34 | #pragma clang diagnostic pop 35 | #endif 36 | 37 | inline auto operator-(filling side) -> filling {return flip(side);} 38 | inline auto operator+(filling side) -> filling {return side;} 39 | 40 | } // end namespace boost::multi::blas 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/iamax.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_BLAS_IAMAX_HPP 6 | #define BOOST_MULTI_ADAPTORS_BLAS_IAMAX_HPP 7 | 8 | #include "boost/multi/adaptors/blas/core.hpp" 9 | 10 | namespace boost::multi::blas { 11 | 12 | template 13 | auto iamax_n(It first, Size n) { 14 | using core::iamax; 15 | return iamax(n, base(first), stride(first)); // if you get an error here make sure that you are including (and linking) the appropriate BLAS backend for your memory type 16 | } 17 | 18 | template 19 | auto iamax(It first, It last) 20 | -> decltype(iamax_n(first, std::distance(first, last))) { 21 | return iamax_n(first, std::distance(first, last)); 22 | } 23 | 24 | template 25 | auto iamax(X1D const& x) // NOLINT(readability-identifier-length) x conventional blas name 26 | -> decltype(iamax(begin(x), end(x))) { 27 | assert(! offset(x)); 28 | return iamax(begin(x), end(x)); 29 | } 30 | 31 | template 32 | auto amax(X1D const& x) { // NOLINT(readability-identifier-length) x conventional blas name 33 | return begin(x) + iamax(x); 34 | } 35 | 36 | } // end namespace boost::multi::blas 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/fftw/mpi_/test/array_2d.cpp: -------------------------------------------------------------------------------- 1 | // -*-indent-tabs-mode:t;c-basic-offset:4;tab-width:4;autowrap:nil;-*- 2 | // Copyright 2019-2022 Alfredo A. Correa 3 | 4 | //#include "../../../fftw/mpi.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | #include "../../../fftw.hpp" 10 | 11 | namespace mpi3 = boost::mpi3; 12 | namespace multi = boost::multi; 13 | 14 | int mpi3::main(int, char**, mpi3::communicator /*world*/){ 15 | // multi::fftw::mpi::environment fenv; 16 | 17 | // multi::fftw::mpi::array, 2> G({41, 321}, world); 18 | 19 | #if 0 20 | if(auto x = G.local_cutout().extensions()) 21 | for(auto i : std::get<0>(x)) 22 | for(auto j : std::get<1>(x)) 23 | G.local_cutout()[i][j] = std::complex(i + j, i + 2*j); 24 | 25 | multi::array, 2> L = G; // world replicas 26 | assert( L == G ); 27 | 28 | using multi::fftw::dft_forward; 29 | 30 | dft_forward(L, L); // dft in replicas 31 | dft_forward(G, G); 32 | 33 | if(auto x = G.local_cutout().extensions()) 34 | for(auto i : std::get<0>(x)) 35 | for(auto j : std::get<1>(x)) 36 | if(not(std::abs(G.local_cutout()[i][j] - L[i][j]) < 1e-8)) std::cout<< std::abs(G.local_cutout()[i][j] - L[i][j]) << std::endl; 37 | #endif 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /include/boost/multi/detail/config/ASSERT.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_DETAIL_CONFIG_ASSERT_HPP 6 | #define BOOST_MULTI_DETAIL_CONFIG_ASSERT_HPP 7 | 8 | #include 9 | 10 | #if defined(BOOST_MULTI_ASSERT_DISABLE) // to activate bounds check compile in debug mode (default) with -DBOOST_MULTI_ACCESS_DEBUG 11 | #define BOOST_MULTI_ASSERT(Expr) /*empty*/ // NOLINT(cppcoreguidelines-macro-usage 12 | #else 13 | #define BOOST_MULTI_ASSERT(Expr) assert(Expr) // NOLINT(cppcoreguidelines-macro-usage) 14 | #endif 15 | 16 | // #if defined(BOOST_MULTI_NDEBUG) || defined(__CUDACC__) 17 | // #define BOOST_MULTI_ASSERT(Expr) // NOLINT(cppcoreguidelines-macro-usage 18 | // #else 19 | // // #include 20 | // // // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) this is for very inefficient asserts 21 | // // #if defined(__cpp_lib_stacktrace) && (__cpp_lib_stacktrace >= 202011L) 22 | // // #define BOOST_MULTI_ASSERT(Expr) assert((std::cerr< 10 | #include 11 | 12 | namespace boost::multi::detail { // this library requires C++17 and above !!! 13 | 14 | template constexpr bool is_implicitly_convertible_v = std::is_convertible_v; // this library needs C++17 or higher (e.g. -std=c++17) 15 | template constexpr bool is_explicitly_convertible_v = std::is_constructible_v; 16 | 17 | template, int> =0> // NOLINT(modernize-use-constraints) TODO(correaa) 18 | constexpr auto implicit_cast(From&& ref) -> To {return static_cast(std::forward(ref));} 19 | 20 | template && ! std::is_convertible_v, int> =0> // NOLINT(modernize-use-constraints) TODO(correaa) 21 | constexpr auto explicit_cast(From&& ref) -> To {return static_cast(std::forward(ref));} 22 | 23 | } // end namespace boost::multi::detail 24 | #endif 25 | -------------------------------------------------------------------------------- /test/overload.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2025 Alfredo A. Correa 2 | // Copyright 2024 Matt Borland 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // https://www.boost.org/LICENSE_1_0.txt 5 | 6 | #include // for array 7 | 8 | #include 9 | 10 | #include // for complex 11 | #include // for operator==, string 12 | 13 | namespace multi = boost::multi; 14 | 15 | namespace { 16 | inline auto what_is(multi::array const& /*arr*/) { return std::string{"real"}; } // NOLINT(fuchsia-default-arguments-calls) 17 | inline auto what_is(multi::array, 2> const& /*arr*/) { return std::string{"complex"}; } // NOLINT(fuchsia-default-arguments-calls) 18 | } // end unnamed namespace 19 | 20 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 21 | // BOOST_AUTO_TEST_CASE(multi_array_overload) 22 | { 23 | multi::array const real_A({10, 20}); 24 | multi::array, 2> const cplx_A({10, 20}); 25 | 26 | std::string const real_str = what_is(real_A); 27 | std::string const complex_str = what_is(cplx_A); 28 | 29 | BOOST_TEST( real_str == "real" ); 30 | BOOST_TEST( complex_str == "complex" ); 31 | } 32 | return boost::report_errors(); 33 | } 34 | -------------------------------------------------------------------------------- /benchmark/cuda/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project( 4 | boost-multi-benchmark-cuda 5 | VERSION 0.1 6 | LANGUAGES CXX CUDA 7 | ) 8 | 9 | find_package(Boost REQUIRED COMPONENTS serialization unit_test_framework) 10 | find_package(benchmark REQUIRED) 11 | 12 | set(BLA_VENDOR Intel10_64lp) 13 | find_package(BLAS) 14 | if(BLAS_FOUND) # in some systems with MKL, regular BLAS headers need to be found for it to work 15 | message("Multi/BLAS: MKL environment detected") 16 | add_definitions(-DRETURN_BY_STACK) 17 | else() 18 | message("Multi/BLAS: MKL environment not detected, looking for other BLAS") 19 | unset(BLA_VENDOR) 20 | find_package(BLAS REQUIRED) 21 | endif() 22 | 23 | link_libraries(${BLAS_LIBRARIES}) 24 | 25 | set(CMAKE_CXX_STANDARD 17) 26 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 27 | set(CMAKE_CXX_EXTENSIONS OFF) 28 | 29 | set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -arch=sm_61 -std=c++17 --use_fast_math --expt-relaxed-constexpr --extended-lambda") # set(CMAKE_CUDA_STANDARD 17) 30 | 31 | enable_testing() 32 | include(CTest) 33 | 34 | # file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) 35 | 36 | include_directories(../../..) 37 | 38 | add_executable(axpy.cu.x axpy.cu) 39 | add_test(NAME axpy COMMAND axpy.cu.x) 40 | target_link_libraries(axpy.cu.x PRIVATE benchmark::benchmark) 41 | target_link_libraries(axpy.cu.x PRIVATE -lcublas) 42 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/test/vector.cu: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 11 | 12 | // BOOST_AUTO_TEST_CASE(vector) 13 | { 14 | // H has storage for 4 integers 15 | thrust::host_vector H(4); 16 | 17 | // initialize individual elements 18 | H[0] = 14; 19 | H[1] = 20; 20 | H[2] = 38; 21 | H[3] = 46; 22 | 23 | // H.size() returns the size of vector H 24 | BOOST_TEST( H.size() == 4 ); 25 | 26 | // print contents of H 27 | BOOST_TEST( H[2] == 38 ); 28 | 29 | // resize H 30 | H.resize(2); 31 | 32 | BOOST_TEST( H.size() == 2 ); 33 | 34 | // Copy host_vector H to device_vector D 35 | thrust::device_vector D = H; 36 | 37 | // f(D.data()); 38 | 39 | // elements of D can be modified 40 | D[0] = 99; 41 | D[1] = 88; 42 | 43 | // thurst::device_ptr p = D.data(); // doesn't work with CUDA 11.8 44 | thrust::cuda::pointer p = D.data(); // this works with thrust from CUDA 12.1 45 | BOOST_TEST( p[0] == 99 ); 46 | 47 | BOOST_TEST( D[1] == 88 ); 48 | } 49 | 50 | return boost::report_errors(); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /include/boost/multi/detail/pointer_traits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_DETAIL_POINTER_TRAITS_HPP 6 | #define BOOST_MULTI_DETAIL_POINTER_TRAITS_HPP 7 | #pragma once 8 | 9 | #include // for size_t 10 | #include // for iterator_traits 11 | #include // for allocator, pointer_traits 12 | #include // for conditional_t, declval, true_type 13 | 14 | namespace boost::multi { 15 | 16 | template struct priority_me : std::conditional_t>{}; 17 | 18 | template auto dat_aux(priority_me<0>, Pointer ) -> std::allocator::value_type>; 19 | template auto dat_aux(priority_me<1>, T* ) -> std::allocator::value_type>; 20 | template auto dat_aux(priority_me<2>, FancyPtr) -> typename FancyPtr::default_allocator_type; 21 | 22 | template 23 | struct pointer_traits/*, typename Pointer::default_allocator_type>*/ : std::pointer_traits{ 24 | using default_allocator_type = decltype(dat_aux(priority_me<2>{}, std::declval())); 25 | }; 26 | 27 | } // end namespace boost::multi 28 | #endif // BOOST_MULTI_DETAIL_POINTER_TRAITS_HPP 29 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/complex_traits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_BLAS_COMPLEX_TRAITS_HPP 6 | #define BOOST_MULTI_ADAPTORS_BLAS_COMPLEX_TRAITS_HPP 7 | 8 | #if defined(__NVCC__) || defined(__HIPCC__) // defined(__HIP_PLATFORM_AMD__) || defined(__HIP_PLATFORM_NVIDIA__) 9 | #include 10 | #endif 11 | 12 | #include // for std::complex 13 | 14 | namespace boost::multi::blas { 15 | 16 | template 17 | struct complex_traits { 18 | using real_type = typename Complex::real_type; 19 | constexpr static auto imaginary_unit() { return Complex{real_type{0}, real_type{1}}; } 20 | }; 21 | 22 | template 23 | struct complex_traits> { 24 | using real_type = typename ::std::complex::value_type; 25 | constexpr static auto imaginary_unit() { return ::std::complex{0, 1}; } 26 | }; 27 | 28 | #if defined(__NVCC__) || defined(__HIPCC__) // defined(__HIP_PLATFORM_AMD__) || defined(__HIP_PLATFORM_NVIDIA__) 29 | template 30 | struct complex_traits<::thrust::complex> { 31 | using real_type = typename ::thrust::complex::value_type; 32 | constexpr static auto imaginary_unit() { return std::complex{0, 1}; } 33 | }; 34 | #endif 35 | 36 | } // end namespace boost::multi::blas 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/totalview/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # -*-indent-tabs-mode:nil;c-basic-offset:2;tab-width:4;autowrap:nil;-*- 2 | #[=[Multi Test suite can be run like this: 3 | mkdir -p build 4 | cd build 5 | cmake .. [-DENABLE_CUDA=1] 6 | make -j 7 | ctest -j --output-on-error [-T memcheck] 8 | exit 9 | #]=] 10 | cmake_minimum_required(VERSION 3.11) 11 | 12 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") 13 | 14 | set(CMAKE_VERBOSE_MAKEFILE ON) 15 | 16 | project( 17 | boost-multi-adaptors-blis-test 18 | VERSION 0.1 19 | LANGUAGES CXX 20 | ) 21 | 22 | find_package(Boost REQUIRED COMPONENTS unit_test_framework) 23 | 24 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 25 | set(CMAKE_CXX_EXTENSIONS OFF) 26 | 27 | enable_testing() 28 | 29 | include(CTest) 30 | 31 | include_directories(${CMAKE_BINARY_DIR}) 32 | 33 | include_directories(../../../../../include) 34 | 35 | set(TEST_SRCS matrix.cpp) 36 | 37 | add_executable(totalview.x totalview.cpp) 38 | 39 | target_compile_features(totalview.x PUBLIC cxx_std_17) 40 | 41 | # target_compile_definitions(totalview.x PRIVATE "BOOST_PP_VARIADICS") 42 | target_compile_definitions(totalview.x PRIVATE ${Boost_DEFINITIONS}) 43 | target_include_directories(totalview.x SYSTEM PRIVATE ${Boost_INCLUDE_DIRS}) 44 | target_link_libraries(totalview.x PRIVATE ${Boost_LIBRARIES}) 45 | target_link_directories(totalview.x PRIVATE ${Boost_LIBRARY_DIRS}) 46 | 47 | add_test(NAME totalview.x COMMAND $) 48 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/reference.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022-2024 Alfredo A. Correa 2 | 3 | #pragma once 4 | 5 | #include // hipthrust needs this 6 | 7 | #if defined(__NVCC__) 8 | #define BOOST_MULTI_HD_ __host__ __device__ 9 | #else 10 | #define BOOST_MULTI_HD_ 11 | #endif 12 | 13 | namespace thrust { 14 | 15 | // TODO(correaa) consider restrict this for universal memory only 16 | template 17 | BOOST_MULTI_HD_ constexpr auto operator*( 18 | thrust::tagged_reference const& r1, 19 | thrust::tagged_reference const& r2 20 | ) 21 | ->decltype(thrust::raw_reference_cast(r1) * thrust::raw_reference_cast(r2)) { 22 | return thrust::raw_reference_cast(r1) * thrust::raw_reference_cast(r2); } 23 | 24 | template 25 | BOOST_MULTI_HD_ constexpr auto operator*( 26 | thrust::tagged_reference const& r1, 27 | T2 const& r2 28 | ) 29 | ->decltype(thrust::raw_reference_cast(r1) * r2) { 30 | return thrust::raw_reference_cast(r1) * r2; } 31 | 32 | template 33 | BOOST_MULTI_HD_ constexpr auto operator*( 34 | T1 const& r1, 35 | thrust::tagged_reference const& r2 36 | ) 37 | ->decltype(r2 * thrust::raw_reference_cast(r1)) { 38 | return r2 * thrust::raw_reference_cast(r1); } 39 | 40 | } 41 | 42 | #undef BOOST_MULTI_HD_ 43 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/cuda/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | if(ENABLE_CUDA OR DEFINED CXXCUDA) 4 | enable_language(CUDA) 5 | if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) 6 | set(CMAKE_CUDA_ARCHITECTURES native) 7 | endif() 8 | find_package(CUDAToolkit REQUIRED COMPONENTS Thrust) # requires cmake 3.17 9 | endif() 10 | 11 | find_package(Boost CONFIG REQUIRED) # tests require Boost.Core LightweightTest 12 | 13 | enable_testing() 14 | include(CTest) 15 | 16 | include_directories(${CMAKE_BINARY_DIR}) 17 | 18 | set(TEST_SRCS) 19 | # neighbor_list.cu) 20 | 21 | foreach(TEST_FILE ${TEST_SRCS}) 22 | if(ENABLE_CUDA OR DEFINED CXXCUDA) 23 | set(TEST_EXE "${TEST_FILE}.x") 24 | add_executable(${TEST_EXE} ${TEST_FILE}) 25 | 26 | target_compile_definitions(${TEST_EXE} PRIVATE ${Boost_DEFINITIONS}) 27 | 28 | # target_include_directories(${TEST_EXE} PRIVATE ${PROJECT_SOURCE_DIR}/include) 29 | target_include_directories(${TEST_EXE} PRIVATE ${CUDA_INCLUDE_DIRS}) 30 | 31 | #target_compile_options(${TEST_EXE} PRIVATE --expt-relaxed-constexpr) 32 | 33 | target_link_libraries(${TEST_EXE} PRIVATE ${CUDA_LIBRARIES}) 34 | target_link_libraries(${TEST_EXE} PRIVATE multi) 35 | 36 | set_source_files_properties(${TEST_FILE} PROPERTIES LANGUAGE CUDA) 37 | 38 | add_test(NAME ${TEST_EXE} COMMAND ./${TEST_EXE}) 39 | endif() 40 | endforeach() 41 | 42 | # target_compile_options(neighbor_list.cu.x PRIVATE $<$:--extended-lambda>) 43 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project( 4 | boost-multi-examples 5 | VERSION 0.1 6 | LANGUAGES CXX 7 | ) 8 | 9 | include_directories(../include) 10 | 11 | #find_package(multi) # see https://gitlab.com/correaa/boost-multi#using-the-library-installation-and-tests 12 | #... 13 | #target_link_library(my_target PUBLIC multi) 14 | 15 | find_package(Boost REQUIRED COMPONENTS iostreams serialization unit_test_framework timer) 16 | add_subdirectory("../" multi-bin) 17 | 18 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 19 | set(CMAKE_CXX_EXTENSIONS OFF) 20 | 21 | enable_testing() 22 | include(CTest) 23 | 24 | add_executable(serialization.cpp.x serialization.cpp) 25 | target_link_libraries(serialization.cpp.x PUBLIC multi) 26 | target_link_libraries(serialization.cpp.x PRIVATE ${Boost_LIBRARIES}) 27 | add_test(NAME serialization.cpp.x COMMAND serialization.cpp.x) 28 | 29 | add_executable(gj_solve.cpp.x gj_solve.cpp) 30 | target_link_libraries(gj_solve.cpp.x PUBLIC multi) 31 | target_link_libraries(gj_solve.cpp.x PRIVATE ${Boost_LIBRARIES}) 32 | add_test(NAME gj_solve.cpp.x COMMAND gj_solve.cpp.x) 33 | 34 | add_executable(redux.cpp.x redux.cpp) 35 | target_link_libraries(redux.cpp.x PUBLIC multi) 36 | target_link_libraries(redux.cpp.x PRIVATE ${Boost_LIBRARIES}) 37 | 38 | find_package(TBB) 39 | 40 | if(TBB_FOUND) 41 | target_link_libraries (redux.cpp.x PRIVATE TBB::tbb) 42 | target_compile_definitions(redux.cpp.x PUBLIC TBB_FOUND=1) 43 | endif() 44 | 45 | add_test(NAME redux.cpp.x COMMAND redux.cpp.x) 46 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/test/operations.cpp: -------------------------------------------------------------------------------- 1 | // © Alfredo A. Correa 2019-2024 2 | 3 | #define BOOST_TEST_MODULE "C++ Unit Tests for Multi BLAS operations and cuda" 4 | #define BOOST_TEST_DYN_LINK 5 | 6 | // #include 7 | 8 | #include "../../blas/dot.hpp" 9 | 10 | #include "../../../array.hpp" 11 | #include "../../blas/cuda.hpp" 12 | 13 | #include "../../../adaptors/cuda.hpp" 14 | #include "../../../complex.hpp" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | using std::cout; 21 | namespace multi = boost::multi; 22 | namespace blas = multi::blas; 23 | 24 | using complex = std::complex; constexpr complex I{0.0, 1.0}; 25 | 26 | BOOST_AUTO_TEST_CASE(const blas_conjugated_cpu) { 27 | multi::array const a = {5.0 + 2.0*I, 6.0 + 6.0*I, 7.0 + 2.0*I, 8.0 - 3.0*I}; 28 | BOOST_REQUIRE( blas::C(a)[1] == conj(a[1]) ); 29 | 30 | namespace cuda = multi::cuda; 31 | 32 | cuda::array const agpu = {5.0 + 2.0*I, 6.0 + 6.0*I, 7.0 + 2.0*I, 8.0 - 3.0*I}; 33 | BOOST_REQUIRE( blas::C(agpu)[1] == conj(agpu[1]) ); 34 | } 35 | 36 | BOOST_AUTO_TEST_CASE(blas_conjugated_gpu){ 37 | #if 0 38 | cuda::array const acu = {1.0 + I, 2.0 + 3.0*I, 3.0 + 2.0*I, 4.0 - 9.0*I}; 39 | cuda::array const bcu = {5.0 + 2.0*I, 6.0 + 6.0*I, 7.0 + 2.0*I, 8.0 - 3.0*I}; 40 | 41 | { 42 | cuda::array ccu; 43 | blas::dot(acu, bcu, ccu); 44 | BOOST_REQUIRE( ccu() == 19.0 - 27.0*I ); 45 | } 46 | BOOST_REQUIRE( blas::C(bcu)[1] == 2.0 - 3.0*I ); 47 | #endif 48 | } 49 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/fftw/test/so_shift.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | 7 | // #include // includes fftw3.hpp 8 | 9 | #include 10 | #include 11 | #include // for std::iota 12 | 13 | namespace multi = boost::multi; 14 | 15 | auto main() -> int { // NOLINT(bugprone-exception-escape) 16 | using complex = std::complex; 17 | 18 | // input array 19 | auto const x = std::invoke([] () noexcept { // NOLINT(readability-identifier-length) 20 | multi::dynamic_array const ret2(8); (void)ret2; 21 | 22 | multi::array ret(8); 23 | // fill the first array with some numbers 24 | std::iota(ret.begin(), ret.end(), 1.0); 25 | return ret; 26 | }); 27 | 28 | // output array 29 | // multi::array y(x.size()); // NOLINT(readability-identifier-length) 30 | // compute the FFT of x and store results in y 31 | // auto y = +multi::fftw::dft_forward(x); // NOLINT(readability-identifier-length) 32 | 33 | // display the results 34 | // std::cout << "FFT =" << std::endl; 35 | // std::copy(y.begin(), y.end(), std::ostream_iterator(std::cout, "\n")); 36 | 37 | // "shifted" results 38 | // std::rotate(y.begin(), y.begin() + y.size() / 2 + y.size() % 2, y.end()); 39 | 40 | // std::cout << "FFT shifted =" << std::endl; 41 | // std::copy(y.begin(), y.end(), std::ostream_iterator(std::cout, "\n")); 42 | } 43 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cuda/cublas/test/herk.cu: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #define BOOST_AUTO_TEST_CASE(CasenamE) /**/ 11 | 12 | namespace multi = boost::multi; 13 | namespace blas = multi::blas; 14 | 15 | using complex = thrust::complex; 16 | complex const I{0, 1}; 17 | 18 | int main() { 19 | BOOST_AUTO_TEST_CASE(multi_blas_herk){ 20 | multi::array, 2> const a = { 21 | {1.0 + 3.0 * I, 3.0 - 2.0 * I, 4.0 + 1.0 * I}, 22 | {9.0 + 1.0 * I, 7.0 - 8.0 * I, 1.0 - 3.0 * I} 23 | }; 24 | multi::thrust::cuda::array, 2> const a_gpu = a; 25 | 26 | { 27 | multi::array, 2> c({2, 2}, 9999.0); 28 | blas::herk(1.0, a, c); 29 | BOOST_TEST( c[1][0] == complex(50.0, -49.0) ); 30 | BOOST_TEST( c[0][1] == complex(50.0, +49.0) ); 31 | 32 | multi::array, 2> const c_copy = blas::herk(1.0, a); 33 | BOOST_TEST( c == c_copy ); 34 | } 35 | { 36 | multi::array, 2> c({3, 3}, 9999.0); 37 | blas::herk(1.0, blas::H(a), c); 38 | BOOST_TEST( c[2][1] == complex(41, +2) ); 39 | BOOST_TEST( c[1][2] == complex(41, -2) ); 40 | 41 | multi::array, 2> const c_copy = blas::herk(1., blas::H(a)); 42 | BOOST_TEST( c_copy == c ); 43 | } 44 | } 45 | 46 | return boost::report_errors(); 47 | } 48 | -------------------------------------------------------------------------------- /.github/workflows/pages.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy Docs 2 | 3 | on: 4 | push: 5 | branches: ["master"] # main Trigger on push to the main branch 6 | workflow_dispatch: # Allow manual runs 7 | 8 | permissions: 9 | contents: read 10 | pages: write 11 | id-token: write 12 | 13 | concurrency: 14 | group: "pages" 15 | cancel-in-progress: false 16 | 17 | jobs: 18 | build-docs: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v4 24 | 25 | - name: Set up Ruby (for Asciidoctor) 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: '3.2' 29 | 30 | - name: Install Asciidoctor 31 | run: | 32 | sudo apt-get -qq update 33 | sudo apt-get -qq install --no-install-recommends -y --quiet ca-certificates asciidoctor pandoc ruby-rouge 34 | 35 | - name: Install Boost Build (b2) 36 | run: | 37 | pandoc --version 38 | asciidoctor --version 39 | 40 | - name: Build Docs with b2 41 | run: | 42 | mkdir .public 43 | cd doc 44 | asciidoctor --failure-level=WARN -a source-highlighter=rouge -b xhtml5 multi.adoc 45 | cd .. 46 | cp -r doc/multi.html .public 47 | # cp -r doc/multi.html .public/index.html 48 | 49 | - name: Upload artifact for GitHub Pages 50 | uses: actions/upload-pages-artifact@v3 51 | with: 52 | path: .public # e.g. bin.v2/libs/foo/doc/html or similar 53 | 54 | deploy-docs: 55 | needs: build-docs 56 | runs-on: ubuntu-latest 57 | 58 | environment: 59 | name: github-pages 60 | url: ${{ steps.deployment.outputs.page_url }} 61 | 62 | steps: 63 | - name: Deploy to GitHub Pages 64 | id: deployment 65 | uses: actions/deploy-pages@v4 66 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/swap.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_BLAS_SWAP_HPP 6 | #define BOOST_MULTI_ADAPTORS_BLAS_SWAP_HPP 7 | #pragma once 8 | 9 | #include "boost/multi/adaptors/blas/core.hpp" 10 | 11 | namespace boost::multi::blas { 12 | 13 | using core::swap; 14 | 15 | template 16 | auto swap_n(It1 first, Size count, It2 first2) -> It2 { 17 | blas::default_context_of(base(first))->swap(count, base(first), stride(first), base(first2), stride(first2)); 18 | return first2 + count; 19 | } 20 | 21 | template 22 | auto swap(It1 first, It2 last, It2 first2) noexcept -> It2 { 23 | assert(stride(first) == stride(last)); 24 | return swap_n(first, last - first, first2); 25 | } 26 | 27 | template 28 | auto swap(X1D&& x, Y1D&& y) noexcept(false) -> Y1D&& { // NOLINT(readability-identifier-length) x, y conventional blas names, // NOSONAR(cpp:S5018) this swap can "fail" if sizes do not match 29 | assert( size(x) == size(y) ); 30 | swap( std::begin(x), std::end(std::forward(x)), std::begin(y) ); 31 | return std::forward(y); 32 | } 33 | 34 | template 35 | auto swap(X1D const&, Y1D const&) noexcept(false) = delete; // NOSONAR(cpp:S5018) this swap can "fail" if sizes do not match 36 | 37 | template 38 | auto operator^(X1D&& x, Y1D&& y) { // NOLINT(readability-identifier-length) BLAS naming 39 | blas::swap(x, y); 40 | return std::tie(std::forward(x), std::forward(y)); // or use std::forward_as_tuple ? 41 | } 42 | 43 | namespace operators { 44 | using blas::operator^; 45 | } // end namespace operators 46 | 47 | } // end namespace boost::multi::blas 48 | #endif 49 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/lapack/triangular.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | 3 | #ifndef MULTI_ADAPTORS_LAPACK_TRIANGULAR_HPP 4 | #define MULTI_ADAPTORS_LAPACK_TRIANGULAR_HPP 5 | 6 | #include "../../../multi/array.hpp" 7 | 8 | namespace boost::multi::lapack { 9 | enum class filling : char { 10 | lower = 'U', 11 | upper = 'L', 12 | } 13 | } 14 | 15 | namespace boost{ 16 | namespace multi{ 17 | namespace lapack{ 18 | 19 | template 20 | struct uhermitian : public multi::array{ 21 | // using multi::array::array; 22 | template< 23 | class MultiArray, 24 | typename = decltype(multi::array{std::forward(std::declval())}), 25 | std::enable_if_t, int> =0 26 | > 27 | explicit uhermitian(MultiArray&& ma) : multi::array{std::forward(ma)}{} 28 | template decltype(auto) operator[](Index i) const{ 29 | return multi::array::operator[](i); 30 | } 31 | decltype(auto) operator()(index i, index j) const{ 32 | return multi::array::operator[](std::min(i, j))[std::max(i, j)]; 33 | } 34 | }; 35 | 36 | }}} 37 | 38 | 39 | #ifdef _TEST_MULTI_ADAPTORS_LAPACK_TRIANGULAR 40 | 41 | #include 42 | #include 43 | 44 | using std::cout; 45 | namespace multi = boost::multi; 46 | using complex = std::complex; 47 | 48 | int main(){ 49 | auto const I = complex(0.,1.); 50 | 51 | multi::array A = 52 | {{167.413 , 126.804 - 0.00143505*I, 125.114 - 0.1485590*I}, 53 | {126.804 + 0.00143505*I, 167.381 , 126.746 + 0.0327519*I}, 54 | {125.114 + 0.14855900*I, 126.746 - 0.0327519*I , 167.231 }} 55 | ; 56 | multi::lapack::uhermitian H{std::move(A)}; 57 | assert( &H(1, 2) == &H(2, 1) ); 58 | 59 | } 60 | #endif 61 | #endif 62 | 63 | -------------------------------------------------------------------------------- /include/boost/multi/detail/config/NODISCARD.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | // Copyright 2024 Matt Borland 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // https://www.boost.org/LICENSE_1_0.txt 5 | 6 | #ifndef BOOST_MULTI_DETAIL_CONFIG_NODISCARD_HPP 7 | #define BOOST_MULTI_DETAIL_CONFIG_NODISCARD_HPP 8 | 9 | // clang-format off 10 | 11 | #ifdef __has_cpp_attribute 12 | 13 | // No discard first 14 | # ifdef __NVCC__ 15 | # define BOOST_MULTI_NODISCARD(MsG) 16 | # elif __has_cpp_attribute(nodiscard) 17 | # if (__has_cpp_attribute(nodiscard) >= 201907L) && (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) 18 | # define BOOST_MULTI_NODISCARD(MsG) [[nodiscard]] // [[nodiscard(MsG)]] in c++20 empty message is not allowed with paren 19 | # else 20 | # define BOOST_MULTI_NODISCARD(MsG) [[nodiscard]] // NOLINT(cppcoreguidelines-macro-usage) TODO(correaa) check if this is needed in C++17 21 | # endif 22 | # elif __has_cpp_attribute(gnu::warn_unused_result) 23 | # define BOOST_MULTI_NODISCARD(MsG) [[gnu::warn_unused_result]] 24 | # endif 25 | 26 | // No discard class 27 | # if(__has_cpp_attribute(nodiscard) && !defined(__NVCC__) && (!defined(__clang__) || (defined(__clang__) && (__cplusplus >= 202002L)))) 28 | # if (__has_cpp_attribute(nodiscard) >= 201907L) && (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) 29 | # define BOOST_MULTI_NODISCARD_CLASS(MsG) [[nodiscard_(MsG)]] 30 | # else 31 | # define BOOST_MULTI_NODISCARD_CLASS(MsG) [[nodiscard]] 32 | # endif 33 | # endif 34 | 35 | #endif 36 | 37 | #ifndef BOOST_MULTI_NODISCARD 38 | # define BOOST_MULTI_NODISCARD(MsG) 39 | #endif 40 | 41 | #ifndef BOOST_MULTI_NODISCARD_CLASS 42 | # define BOOST_MULTI_NODISCARD_CLASS(MsG) 43 | #endif 44 | 45 | // clang-format on 46 | 47 | #endif // BOOST_MULTI_DETAIL_CONFIG_NODISCARD_HPP 48 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/lapack/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) # 3.18 for LAPACK::LAPACK 2 | 3 | project( 4 | boost-multi-adaptor-lapack 5 | VERSION 0.1 6 | LANGUAGES CXX 7 | ) 8 | 9 | add_library(multi-lapack INTERFACE) 10 | 11 | if(NOT DEFINED ENABLE_CIRCLE) 12 | return() 13 | endif() 14 | 15 | find_package(LAPACK REQUIRED) 16 | 17 | foreach(lib ${LAPACK_LIBRARIES}) 18 | # https://cmake.org/cmake/help/latest/module/FindBLAS.html#blas-lapack-vendors 19 | if(${lib} MATCHES "mkl") 20 | message("Some LAPACK found matches MKL") 21 | target_compile_definitions(multi-lapack INTERFACE _MULTI_USING_LAPACK_MKL) 22 | # SET(CMAKE_SKIP_BUILD_RPATH FALSE) 23 | # SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) 24 | # SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib64") 25 | # SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 26 | # SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib64") 27 | endif() 28 | if(${lib} MATCHES "hpc_sdk") 29 | message("Some LAPACK found matches hpc_sdk (nvhpc)") # nvhpc may still use a different version of BLAS 30 | # add_definitions(-DBLAS_DOT_RETURNS_VOID) 31 | # target_compile_definitions(multi INTERFACE BLAS_DOT_RETURNS_VOID) 32 | endif() 33 | if(${lib} MATCHES "Accelerate") 34 | message("Some LAPACK found matches Accelerate (Apple) [beware of sdot and snrm2 bugs]") 35 | # message(WARNING "Apple Accelerate BLAS is known to have bugs in single precission function `sdot` and `smrm2`, be careful: https://stackoverflow.com/a/77017238/225186, https://fortran-lang.discourse.group/t/how-many-blas-libraries-have-this-error/4454/23, https://forums.developer.apple.com/forums/thread/717757") 36 | # add_definitions(-DBLAS_DOT_RETURNS_VOID) 37 | # target_compile_definitions(multi INTERFACE BLAS_DOT_RETURNS_VOID) 38 | endif() 39 | endforeach() 40 | 41 | 42 | target_link_libraries(multi-lapack INTERFACE multi LAPACK::LAPACK) 43 | 44 | add_subdirectory(./test) 45 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/fftw/memory.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_FFTW_MEMORY_HPP 6 | #define BOOST_MULTI_ADAPTORS_FFTW_MEMORY_HPP 7 | 8 | #include 9 | 10 | #include // for std:::size_t 11 | 12 | namespace boost::multi::fftw { 13 | 14 | template struct allocator; 15 | 16 | template<> struct allocator{}; 17 | 18 | template 19 | struct allocator { 20 | using value_type = T; 21 | using size_type = std::size_t; 22 | 23 | static auto allocate(size_type n) -> T* { 24 | if(n == 0) { 25 | return nullptr; 26 | } 27 | void* ptr = fftw_malloc(sizeof(T) * n); 28 | if(ptr == nullptr) { 29 | throw std::bad_alloc{}; 30 | } 31 | return static_cast(ptr); 32 | } 33 | static void deallocate(T* ptr, size_type n) { 34 | if(n != 0) { 35 | fftw_free(ptr); 36 | } 37 | } 38 | 39 | // constexpr auto operator==(allocator const& /*other*/) const -> bool { return true; } 40 | // constexpr auto operator!=(allocator const& /*other*/) const -> bool { return false; } 41 | constexpr friend auto operator==(allocator const& /*lhs*/, allocator const& /*rhs*/) { return true; } 42 | constexpr friend auto operator!=(allocator const& /*lhs*/, allocator const& /*rhs*/) { return false; } 43 | 44 | static constexpr auto max_size() noexcept { return std::numeric_limits::max() / sizeof(T); } 45 | }; 46 | 47 | template 48 | constexpr auto operator==(allocator const& /*a*/, allocator const& /*b*/) noexcept -> bool { return true; } 49 | 50 | template 51 | constexpr auto operator!=(allocator const& /*a*/, allocator const& /*b*/) noexcept -> bool { return false; } 52 | 53 | } // namespace boost::multi::fftw 54 | #endif // BOOST_MULTI_ADAPTORS_FFTW_MEMORY_HPP 55 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/fftw/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | 3 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 4 | 5 | add_library(multi_fftw3 INTERFACE) 6 | 7 | find_package(PkgConfig) 8 | if(PKG_CONFIG_FOUND) 9 | pkg_search_module( 10 | FFTW 11 | fftw3 12 | IMPORTED_TARGET 13 | ) 14 | if(FFTW_FOUND) 15 | # include_directories(PkgConfig::FFTW) this seems to be always incorrect 16 | link_libraries(PkgConfig::FFTW) 17 | target_link_libraries(multi_fftw3 INTERFACE PkgConfig::FFTW) 18 | 19 | include_directories(${CMAKE_BINARY_DIR}) 20 | 21 | add_subdirectory(test) 22 | # add_subdirectory(mpi) 23 | else() 24 | message(WARNING "Cannot find FFTW, FFTW-adaptor will not be tested. If you want this feature install FFTW, for example please run:" 25 | "\n sudo apt install pkg-config libfftw3-dev" 26 | "\n sudo dnf install fftw-devel # in Fedora" 27 | "\n brew install fftw pkgconf") 28 | endif() 29 | else() 30 | message(WARNING "Cannot find PkgConfig and/or FFTW, FFTW-adaptor will not be tested. If you want this feature install PkgConfig and FFTW, for example please run:" 31 | "\n sudo apt install pkg-config libfftw3-dev" 32 | "\n sudo dnf install fftw-devel # in Fedora") 33 | 34 | find_package(FFTW3 COMPONENTS fftw3) # or find_package(FFTW3 COMPONENTS fftw3f fftw3) for specific components 35 | 36 | if(FFTW3_FOUND) 37 | message(WARNING "Found FFTW3") 38 | target_link_libraries(multi_fftw3 INTERFACE FFTW3::fftw3) 39 | add_subdirectory(test) 40 | 41 | else() 42 | message(WARNING "Cannot find FFTW3, FFTW3-adaptor will not be tested. If you want this feature install PkgConfig and FFTW, for example please run:" 43 | "\n sudo apt install libfftw3-dev" 44 | "\n sudo dnf install fftw-devel # in Fedora" 45 | "\n vcpkg install fftw3 # on Windows") 46 | endif() 47 | endif() 48 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cuda/cublas/test/scal.cu: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #define BOOST_TEST_MODULE "C++ Unit Tests for Multi CUBLAS gemv" 6 | // #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | namespace multi = boost::multi; 20 | 21 | #include 22 | #define BOOST_AUTO_TEST_CASE(CasenamE) /**/ 23 | 24 | // #define BOOST_REQUIRE_CLOSE(X, Y, ToL) BOOST_TEST( std::abs( (X) - (Y) ) < (ToL) ) 25 | 26 | int main() { 27 | BOOST_AUTO_TEST_CASE(cublas_scal_complex_column) { 28 | namespace blas = multi::blas; 29 | 30 | using complex = thrust::complex; 31 | complex const I{0.0, 1.0}; 32 | multi::thrust::cuda::array arr = { 33 | {1.0 + I*0.0, 2.0 + I*0.0, 3.0 + I*0.0, 4.0 + I*0.0}, 34 | {5.0 + I*0.0, 6.0 + I*0.0, 7.0 + I*0.0, 8.0 + I*0.0}, 35 | {9.0 + I*0.0, 10.0 + I*0.0, 11.0 + I*0.0, 12.0 + I*0.0}, 36 | }; 37 | 38 | blas::scal(2.0, (~arr)[1]); 39 | 40 | multi::array arr_copy = arr; 41 | 42 | BOOST_TEST(( (~arr_copy)[1][2] == complex{20.0, 0.0} )); 43 | } 44 | 45 | BOOST_AUTO_TEST_CASE(cublas_scal_complex) { 46 | namespace blas = multi::blas; 47 | 48 | using complex = thrust::complex; 49 | complex const I{0.0, 1.0}; 50 | multi::array const x_copy = { {1.0 + I*1.0}, {2.0 + I*2.0}, {3.0 + I*3.0} }; 51 | auto x = x_copy; 52 | 53 | auto const alpha = complex{2.0, 3.0}; 54 | blas::scal(alpha, x); // x <- alpha*x 55 | 56 | BOOST_TEST(( x[1] == alpha*x_copy[1] )); 57 | } 58 | 59 | return boost::report_errors();} 60 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/hipfft.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2024 Alfredo A. Correa 2 | 3 | #ifndef BOOST_MULTI_ADAPTORS_HIPFFT_HPP 4 | #define BOOST_MULTI_ADAPTORS_HIPFFT_HPP 5 | 6 | #include 7 | #include 8 | 9 | using cudaError_t = hipError_t; 10 | 11 | constexpr static auto const& cudaDeviceReset = hipDeviceReset; 12 | constexpr static auto const& cudaDeviceSynchronize = hipDeviceSynchronize; 13 | constexpr static auto const& cudaSuccess = hipSuccess; 14 | 15 | #define cu2hip_fft(TypeleafnamE) using cufft ## TypeleafnamE = hipfft ## TypeleafnamE 16 | cu2hip_fft(Handle); 17 | cu2hip_fft(DoubleComplex); 18 | cu2hip_fft(Result); 19 | #undef cu2hip_fft 20 | 21 | #define cu2hip_fft(FunctionleafnamE) constexpr static auto const& cufft ## FunctionleafnamE = hipfft ## FunctionleafnamE 22 | cu2hip_fft(Create); 23 | cu2hip_fft(Destroy); 24 | cu2hip_fft(GetSize); 25 | cu2hip_fft(ExecZ2Z); 26 | cu2hip_fft(SetAutoAllocation); 27 | cu2hip_fft(SetWorkArea); 28 | cu2hip_fft(PlanMany); 29 | #undef cu2hip_fft 30 | 31 | #define CU2HIPFFT_(NamE) constexpr static auto const& CUFFT_ ## NamE = HIPFFT_ ## NamE 32 | 33 | CU2HIPFFT_(ALLOC_FAILED); 34 | CU2HIPFFT_(BACKWARD); 35 | 36 | constexpr static auto const& CUFFT_INVERSE = HIPFFT_BACKWARD; 37 | 38 | CU2HIPFFT_(EXEC_FAILED); 39 | CU2HIPFFT_(FORWARD); 40 | CU2HIPFFT_(INCOMPLETE_PARAMETER_LIST); 41 | CU2HIPFFT_(INTERNAL_ERROR); 42 | CU2HIPFFT_(INVALID_DEVICE); 43 | CU2HIPFFT_(INVALID_SIZE); 44 | CU2HIPFFT_(INVALID_TYPE); 45 | CU2HIPFFT_(INVALID_VALUE); 46 | CU2HIPFFT_(INVALID_PLAN); 47 | CU2HIPFFT_(NO_WORKSPACE); 48 | CU2HIPFFT_(NOT_IMPLEMENTED); 49 | CU2HIPFFT_(NOT_SUPPORTED); 50 | CU2HIPFFT_(UNALIGNED_DATA); 51 | CU2HIPFFT_(PARSE_ERROR); 52 | CU2HIPFFT_(SETUP_FAILED); 53 | CU2HIPFFT_(SUCCESS); 54 | CU2HIPFFT_(Z2Z); 55 | 56 | #undef CU2HIPFFT_ 57 | 58 | #include "cufft.hpp" 59 | 60 | // namespace boost::multi{ 61 | // namespace cufft = hipfft; 62 | // } 63 | 64 | #endif // BOOST_MULTI_ADAPTORS_HIPFFT_HPP 65 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/complex.hpp: -------------------------------------------------------------------------------- 1 | #ifdef COMPILATION// -*-indent-tabs-mode:t;c-basic-offset:4;tab-width:4;-*- 2 | $CXXX $CXXFLAGS $0 -o $0x&&$0x&&rm $0x;exit 3 | #endif 4 | // © Alfredo Correa 2020 5 | 6 | #ifndef MULTI_ADAPTORS_THRUST_COMPLEX_HPP 7 | #define MULTI_ADAPTORS_THRUST_COMPLEX_HPP 8 | 9 | #include 10 | #include 11 | 12 | namespace std{ 13 | template struct is_trivially_copy_constructible > : std::true_type{}; 14 | template struct is_trivially_constructible , thrust::complex> : std::true_type{}; 15 | 16 | template struct is_trivially_assignable&, thrust::complex> : std::true_type{}; 17 | template struct is_trivially_assignable&, thrust::complex const > : std::true_type{}; 18 | template struct is_trivially_assignable&, thrust::complex const&> : std::true_type{}; 19 | template struct is_trivially_assignable&, thrust::complex &> : std::true_type{}; 20 | 21 | // this one is controversional because it changes the behavior of initialization of values in multi (even in the cpu) 22 | template struct is_trivially_default_constructible> : is_trivially_default_constructible{}; 23 | } 24 | 25 | #if not __INCLUDE_LEVEL__ // _TEST_MULTI_COMPLEX 26 | 27 | #include "../../array.hpp" 28 | 29 | #include 30 | #include 31 | 32 | namespace multi = boost::multi; 33 | 34 | template void what(T&&)=delete; 35 | 36 | int main(){ 37 | using complex = thrust::complex; 38 | 39 | static_assert( std::is_trivially_default_constructible{}, "!"); 40 | static_assert( std::is_trivially_copy_constructible{} , "!"); 41 | static_assert( std::is_trivially_assignable{} , "!"); 42 | 43 | multi::array A = { 44 | { { 1., 2.}, { 3., 4.} }, 45 | { {22.,33.}, { 5., 9.} } 46 | }; 47 | } 48 | 49 | #endif 50 | #endif 51 | 52 | 53 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/lapack/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | if(ENABLE_CUDA) 4 | enable_language(CUDA) 5 | endif() 6 | 7 | # project( 8 | # boost-multi-adaptors-lapack-test 9 | # VERSION 0.1 10 | # LANGUAGES CXX 11 | # ) 12 | 13 | # set(CMAKE_CXX_STANDARD_REQUIRED ON) 14 | # set(CMAKE_CXX_EXTENSIONS OFF) 15 | 16 | find_package(Boost REQUIRED NO_MODULE) 17 | 18 | #find_package(LAPACK REQUIRED) 19 | 20 | # find_package(BLAS REQUIRED) 21 | 22 | # set(BLA_VENDOR OpenBLAS) 23 | # set(BLA_VENDOR Intel10_64lp) find_package(BLAS) if(BLAS_FOUND) # in some systems with MKL, regular BLAS headers need to be found for it to work message("Multi/BLAS: MKL environment detected") add_definitions(-DRETURN_BY_STACK) else() 24 | # message("Multi/BLAS: MKL environment not detected, looking for other BLAS") unset(BLA_VENDOR) 25 | # find_package(BLAS REQUIRED) 26 | # endif() 27 | 28 | # find_path( 29 | # BLAS_INCLUDE_DIRS 30 | # cblas.h 31 | # /usr/include 32 | # /usr/local/include 33 | # $ENV{BLAS_HOME}/include 34 | # ) 35 | 36 | # include_directories(../../../../../include) 37 | 38 | # link_libraries(${BLAS_LIBRARIES}) 39 | #link_libraries(-llapacke) 40 | 41 | # include_directories(${TEST_EXE} PRIVATE ${BLAS_INCLUDE_DIRS}) 42 | 43 | enable_testing() 44 | include(CTest) 45 | 46 | add_executable(getrf.cpp.x getrf.cpp) 47 | add_executable(geqrf.cpp.x geqrf.cpp) 48 | add_executable(potrf.cpp.x potrf.cpp) 49 | add_executable(svd.cpp.x svd.cpp) 50 | 51 | if(ENABLE_CUDA) 52 | set_source_files_properties(potrf.cpp PROPERTIES LANGUAGE CUDA) 53 | endif() 54 | 55 | target_link_libraries(getrf.cpp.x PUBLIC multi-lapack Boost::boost) 56 | target_link_libraries(geqrf.cpp.x PUBLIC multi-lapack Boost::boost) 57 | target_link_libraries(potrf.cpp.x PRIVATE multi-lapack Boost::boost) 58 | target_link_libraries(svd.cpp.x PUBLIC multi-lapack Boost::boost) 59 | 60 | add_test(NAME getrf.cpp.x COMMAND $) 61 | add_test(NAME geqrf.cpp.x COMMAND $) 62 | add_test(NAME potrf.cpp.x COMMAND $) 63 | add_test(NAME svd.cpp.x COMMAND $ ) 64 | -------------------------------------------------------------------------------- /test/coelements.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Alfredo A. Correa 2 | // Copyright 2024 Matt Borland 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // https://www.boost.org/LICENSE_1_0.txt 5 | 6 | #include 7 | 8 | #include 9 | 10 | #if defined(__cpp_lib_generator) && (__cpp_lib_generator >= 202207L) 11 | #include 12 | #endif 13 | 14 | namespace multi = boost::multi; 15 | 16 | // https://godbolt.org/z/7MqxhWvz3 17 | 18 | #if defined(__cpp_lib_generator) && (__cpp_lib_generator >= 202207L) 19 | #if defined(__GNUC__) 20 | #pragma GCC diagnostic ignored "-Wnull-dereference" 21 | #endif 22 | 23 | #include 24 | 25 | template 26 | std::generator 27 | co_extensions_elements(Arr2D const& arr2d) { 28 | auto const [is, js] = arr2d.extensions(); 29 | for(auto const i : is) { 30 | for(auto const j : js) { 31 | co_yield typename Arr2D::indexes{i, j}; 32 | } 33 | } 34 | } 35 | 36 | template 37 | std::generator 38 | co_celements(Arr2D const& arr2d) { 39 | auto const [is, js] = arr2d.extensions(); 40 | for(auto const i : is) { 41 | for(auto const j : js) { 42 | co_yield arr2d[i][j]; 43 | } 44 | } 45 | } 46 | 47 | #endif 48 | 49 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 50 | multi::array const arr = { 51 | {0, 1, 2}, 52 | {3, 4, 5} 53 | }; 54 | 55 | BOOST_TEST( arr.extension()[1] == 1 ); 56 | { 57 | auto const [i, j] = arr.extensions()[1][2]; 58 | BOOST_TEST( i == 1 ); 59 | BOOST_TEST( j == 2 ); 60 | } 61 | 62 | #if defined(__cpp_lib_generator) && (__cpp_lib_generator >= 202207L) 63 | for(auto const& [i, j] : co_extensions_elements(arr)) { 64 | std::cout << i << ' ' << j << '\n'; 65 | } 66 | { 67 | auto const [i, j] = *co_extensions_elements(arr).begin(); 68 | BOOST_TEST( i == 0 ); 69 | BOOST_TEST( j == 0 ); 70 | } 71 | { 72 | auto const [i, j] = *(++co_extensions_elements(arr).begin()); 73 | BOOST_TEST( i == 0 ); 74 | BOOST_TEST( j == 1 ); 75 | } 76 | { 77 | BOOST_TEST( *(++co_celements(arr).begin()) == 1 ); 78 | } 79 | #endif 80 | 81 | return boost::report_errors(); 82 | } 83 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/test/iamax.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | 3 | // #define BOOST_TEST_MODULE "C++ Unit Tests for Multi BLAS/cuBLAS iamax" 4 | 5 | // #include 6 | 7 | #include "../../blas/iamax.hpp" 8 | 9 | #include "../../../adaptors/blas/cuda.hpp" 10 | #include "../../../adaptors/cuda.hpp" 11 | #include "../../../array.hpp" 12 | 13 | #include 14 | 15 | using std::cout; 16 | namespace multi = boost::multi; 17 | namespace blas = multi::blas; 18 | 19 | using complex = std::complex; 20 | constexpr complex I{0.0, 1.0}; 21 | 22 | BOOST_AUTO_TEST_CASE(multi_adaptors_blas_iamax) { 23 | multi::array const A = { 24 | {1.0 + 2. * I, 2.0, 3.0, 4.0}, 25 | { 5.0, 6.0 + 3.0 * I, 7.0, 8.0}, 26 | { 9.0, 10.0, 11.0 + 4. * I, 12.0}, 27 | }; 28 | 29 | using blas::iamax; 30 | 31 | auto chess = [](auto const& a, auto const& b) { 32 | using std::abs; 33 | return abs(real(a)) + abs(imag(a)) < abs(real(b)) + abs(imag(b)); 34 | }; 35 | 36 | BOOST_REQUIRE(iamax(A[1])==std::max_element(begin(A[1]), end(A[1]), chess)-begin(A[1])); 37 | BOOST_REQUIRE(A[1][iamax(A[1])]==*std::max_element(begin(A[1]), end(A[1]), chess)); 38 | } 39 | 40 | BOOST_AUTO_TEST_CASE(multi_adaptors_blas_iamax_cuda) { 41 | multi::cuda::array const A = { 42 | {1.0 + 2.0 * I, 2.0, 3.0, 4.0}, 43 | { 5.0, 6.0 + 3.0 * I, 7.0, 8.0}, 44 | { 9.0, 10.0, 11.0 + 4.0 * I, 12.0}, 45 | }; 46 | using blas::iamax; 47 | BOOST_REQUIRE(iamax(A[1]) == 1); 48 | } 49 | 50 | BOOST_AUTO_TEST_CASE(multi_adaptors_blas_iamax_real) { 51 | multi::array const A = {1.0, 2.0, 3.0, 4.0}; 52 | 53 | auto i = blas::iamax(A); 54 | 55 | BOOST_REQUIRE( i == 3 ); 56 | BOOST_REQUIRE( A[blas::iamax(A)] == 4.0 ); 57 | 58 | BOOST_REQUIRE( *blas::amax(A) == 4.0 ); 59 | } 60 | 61 | using complex = std::complex; 62 | 63 | BOOST_AUTO_TEST_CASE(multi_adaptors_blas_iamax_complex) { 64 | multi::array const A = {1.0, 2.0, 3.0, 4.0}; 65 | 66 | auto i = blas::iamax(A); 67 | 68 | BOOST_REQUIRE( i == 3 ); 69 | BOOST_REQUIRE( A[blas::iamax(A)] == 4.0 ); 70 | BOOST_REQUIRE( *blas::amax(A) == 4.0 ); 71 | } 72 | -------------------------------------------------------------------------------- /test/flatted.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2025 Alfredo A. Correa 2 | // Copyright 2024 Matt Borland 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // https://www.boost.org/LICENSE_1_0.txt 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace multi = boost::multi; 11 | 12 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 13 | // BOOST_AUTO_TEST_CASE(array_flatted_2d) 14 | { 15 | multi::array arr = { 16 | {0, 1, 2}, 17 | {3, 4, 5}, 18 | }; 19 | 20 | BOOST_TEST( arr.flatted()[1] == 1 ); 21 | BOOST_TEST( arr.flatted()[4] == 4 ); 22 | 23 | arr.flatted()[4] = 44; 24 | 25 | BOOST_TEST( arr.flatted()[4] == 44 ); 26 | } 27 | 28 | // BOOST_AUTO_TEST_CASE(array_flatted_3d) 29 | { 30 | multi::array arr({13, 4, 5}); 31 | 32 | BOOST_TEST( arr.size() == 13 ); 33 | // BOOST_TEST( arr.rotated().is_flattable() ); 34 | 35 | { 36 | auto&& arrRFU = arr.rotated().flatted().unrotated(); // TODO(correaa) remove flatted? 37 | BOOST_TEST( &arrRFU[11][7] == &arr[11][1][2] ); 38 | } 39 | { 40 | auto&& arrRFU = (arr.rotated()).flatted().unrotated(); 41 | BOOST_TEST( &arrRFU[11][7] == &arr[11][7/5][7%5] ); 42 | } 43 | } 44 | 45 | // BOOST_AUTO_TEST_CASE(array_flatted_3d_bis) 46 | { 47 | multi::array const arr({13, 4, 5}); 48 | BOOST_TEST( arr.size() == 13 ); 49 | // BOOST_TEST( arr.is_flattable() ); 50 | BOOST_TEST( arr.flatted().size() == 13L*4L ); 51 | 52 | auto const& arr2 = arr.rotated(); 53 | BOOST_TEST( arr2.flatted().size() == 20 ); 54 | } 55 | 56 | // BOOST_AUTO_TEST_CASE(empty_array_3D_flatted) 57 | { 58 | multi::array const arr; 59 | // BOOST_TEST( arr.is_flattable() ); 60 | BOOST_TEST( arr.flatted().size() == 0 ); 61 | } 62 | 63 | // BOOST_AUTO_TEST_CASE(empty_array_2D_flatted) 64 | { 65 | multi::array const arr; 66 | // BOOST_TEST( arr.is_flattable() ); 67 | BOOST_TEST( arr.flatted().size() == 0 ); 68 | } 69 | 70 | // flatted strided 71 | { 72 | multi::array arr({4, 10}, 99); 73 | BOOST_TEST( &arr.strided(2).flatted()[5] != &arr[0][4] ); 74 | BOOST_TEST( &arr.strided(2).flatted()[5] == &arr[0][5] ); 75 | } 76 | 77 | return boost::report_errors(); 78 | } 79 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/omp/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | project( 3 | boost-multi-adaptor-thrust-omp-test 4 | VERSION 0.1 5 | LANGUAGES CXX 6 | ) 7 | 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | 11 | find_package(Boost CONFIG REQUIRED) # tests require Boost.Core LightweightTest 12 | 13 | find_package(OpenMP) 14 | 15 | if(${CMAKE_CXX_COMPILER_ID} MATCHES "NVHPC") 16 | if(${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS_EQUAL "22.11") 17 | message(WARNING "NVHPC 22.11 produces an internal error when compiling OMP code") 18 | return() 19 | endif() 20 | endif() 21 | 22 | if(DISABLE_THRUST_OMP) 23 | message(WARNING "OMP disabled, OMP-through-Thrust capabilities will not be tested") 24 | else() 25 | if(OpenMP_FOUND) 26 | find_package(Thrust CONFIG) 27 | 28 | if(NOT Thrust_FOUND) 29 | message(WARNING "Cannot find Thurst in the system, fetching from CCCL") 30 | 31 | find_package(Git QUIET) 32 | 33 | if(GIT_FOUND) 34 | message(STATUS "Git command found: ${GIT_EXECUTABLE}") 35 | else() 36 | message(WARNING "Git command not found, won't fetch content.") 37 | return() 38 | endif() 39 | 40 | include(FetchContent) 41 | FetchContent_Declare( 42 | cccl-cmake 43 | GIT_REPOSITORY https://github.com/NVIDIA/cccl.git 44 | GIT_TAG main # v3.1.0 45 | GIT_SHALLOW ON 46 | ) 47 | FetchContent_MakeAvailable(cccl-cmake) 48 | endif() 49 | 50 | include(CTest) 51 | enable_testing() 52 | 53 | thrust_create_target(ThrustOMP DEVICE OMP) 54 | 55 | add_executable(omp.cpp.x omp.cpp) 56 | 57 | target_include_directories(omp.cpp.x SYSTEM PUBLIC ${_THRUST_INCLUDE_DIR}) # needs this to include thrust as an -isystem header 58 | target_link_libraries(omp.cpp.x PRIVATE ThrustOMP) # SYSTEM has no effect here 59 | target_link_libraries(omp.cpp.x PRIVATE multi Boost::boost) 60 | 61 | add_test(NAME omp.cpp.x COMMAND $) 62 | else() 63 | message(WARNING "Cannot find OpenMP, will not be tested") 64 | endif() 65 | endif() 66 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/examples/gemv.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | int main() { 7 | // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, hicpp-avoid-c-arrays, modernize-avoid-c-arrays) test legacy types 8 | float matA[3][3] = { 9 | {1.1, 2.2, 3.3}, 10 | {4.4, 5.5, 6.6}, 11 | {7.7, 8.8, 9.9}, 12 | }; 13 | float vecB[3] = {1.0, 2.0, 3.0}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) test legacy types 14 | float vecC[3] = {0.0, 0.0, 0.0}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) test legacy types 15 | 16 | namespace multi = boost::multi; 17 | 18 | { // make references to c-arrays 19 | multi::array_ref A{matA}; 20 | multi::array_ref B{vecB}; 21 | multi::array_ref C{vecC}; 22 | 23 | multi::blas::gemv(1.0, A, B, 0.0, C); // C is output 24 | } 25 | { // make references to c-arrays 26 | auto const& A = multi::ref(matA); // deduce element type and dimensionality 27 | auto const& B = multi::ref(vecB); 28 | auto&& vecCref = multi::ref(vecC); 29 | 30 | multi::blas::gemv(1.0, A, B, 0.0, vecCref); // vecC holds the result 31 | } 32 | { // one liner 33 | multi::blas::gemv(1.0, multi::ref(matA), multi::ref(vecB), 0.0, multi::ref(vecC)); // vecC holds the result 34 | } 35 | { // one liner with output 36 | multi::ref(vecC) = multi::blas::gemv(1.0, multi::ref(matA), multi::ref(vecB)); 37 | } 38 | { // using the library, not references to c-arrays 39 | multi::array A = { 40 | {1.1, 2.2, 3.3}, 41 | {4.4, 5.5, 6.6}, 42 | {7.7, 8.8, 9.9}, 43 | }; 44 | multi::array B = {1.0, 2.0, 3.0}; 45 | 46 | multi::array C = multi::blas::gemv(1.0, A, B); 47 | } 48 | { 49 | multi::array A = { 50 | {1.1, 2.2, 3.3}, 51 | {4.4, 5.5, 6.6}, 52 | {7.7, 8.8, 9.9}, 53 | }; 54 | multi::array B = {1.0, 2.0, 3.0}; 55 | 56 | auto C =+ multi::blas::gemv(1.0, A, B); // create (allocate) the result in C 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /examples/polymorphic_memory_resource.cpp: -------------------------------------------------------------------------------- 1 | #ifdef COMPILATION// -*-indent-tabs-mode:t;c-basic-offset:4;tab-width:4;-*- 2 | ${CXX:-c++} -std=c++17 $CXXFLAGS $0 -o $0x&&$0x&&rm $0x;exit 3 | #endif 4 | // © Alfredo A. Correa 2020-2024 5 | 6 | #include "../../multi/array.hpp" 7 | 8 | #include 9 | #include // polymorphic memory resource, monotonic buffer 10 | 11 | namespace multi = boost::multi; 12 | 13 | int main() { 14 | static_assert( sizeof(multi::array) < sizeof(multi::pmr::array) , "!"); 15 | 16 | // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) make a small buffer TODO(correaa) replace with a std::array 17 | char buffer[13] = "____________"; // flawfinder: ignore , a small buffer on the stack or an allocation 18 | std::pmr::monotonic_buffer_resource pool{ 19 | std::data(buffer), std::size(buffer), 20 | std::pmr::null_memory_resource() 21 | }; 22 | 23 | multi::pmr::array A({2, 2}, 'a', &pool); 24 | multi::pmr::array B({3, 2}, 'b', &pool); 25 | 26 | assert( A.get_allocator() == B.get_allocator() ); 27 | assert( std::data(buffer) == std::string{"aaaabbbbbb__"} ); 28 | 29 | try { 30 | multi::pmr::array C({9, 9}, 'c', &pool); // there is no upstream resource so it throws 31 | } catch(std::bad_alloc&) { 32 | assert( std::data(buffer) == std::string{"aaaabbbbbb__"} ); 33 | } 34 | 35 | std::array buffer2; 36 | std::pmr::monotonic_buffer_resource pool2{ 37 | buffer.data(), buffer.size(), 38 | std::pmr::null_memory_resource() 39 | }; 40 | { 41 | multi::pmr::array D = A; 42 | D[0][0] = 'c'; 43 | assert(D.get_allocator() != A.get_allocator() ); 44 | assert(D.get_allocator().resource() == std::pmr::get_default_resource() ); 45 | } 46 | { 47 | multi::pmr::array D({2, 2}, &pool2); 48 | D = A; 49 | assert(D.get_allocator() != A.get_allocator() ); 50 | } 51 | { 52 | multi::pmr::array D(&pool2); 53 | D = std::move(A); 54 | assert(D.get_allocator() != A.get_allocator() ); 55 | assert(D[1][1] == 'a'); 56 | assert(A.is_empty()); 57 | } 58 | { 59 | multi::pmr::array D(&pool2); 60 | std::swap(D, B); 61 | assert(( D.get_allocator() == multi::pmr::array::allocator_type{&pool2} )); 62 | assert( B.is_empty() ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/traits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_BLAS_TRAITS_HPP 6 | #define BOOST_MULTI_ADAPTORS_BLAS_TRAITS_HPP 7 | 8 | #include 9 | #include // for enable_if_t, false_type, is_convertible, true... 10 | #include // for declval // IWYU pragma: keep 11 | 12 | namespace boost::multi::blas { // TODO(correaa) include in blas/detail? 13 | 14 | // TODO(correaa) : create a BinaryDouble concept? 15 | 16 | template()/std::declval()), float>{} > > 17 | auto is_s_aux(F&&) -> std::true_type ; 18 | auto is_s_aux(...) -> std::false_type; 19 | 20 | template struct is_s : decltype(is_s_aux(std::declval())) {using archetype = float;}; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) 21 | 22 | template()/std::declval()), double>{}> > 23 | auto is_d_aux(D&&) -> std::true_type ; 24 | auto is_d_aux(...) -> std::false_type; 25 | 26 | template struct is_d : decltype(is_d_aux(std::declval())) {using archetype = double;}; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) 27 | 28 | template) && is_s().real())>{} && is_s().imag())>{}>> 29 | auto is_c_aux(C&&) -> std::true_type; 30 | auto is_c_aux(...) -> std::false_type; 31 | 32 | template struct is_c : decltype(is_c_aux(std::declval())) {using archetype = std::complex;}; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) 33 | 34 | template) && is_d().real())>{} && is_d().imag())>{}>> 35 | auto is_z_aux(Z&&) -> std::true_type ; 36 | auto is_z_aux(...) -> std::false_type; 37 | 38 | template struct is_z : decltype(is_z_aux(std::declval())) {using archetype = std::complex;}; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) 39 | 40 | } // end namespace boost::multi::blas 41 | #endif 42 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # https://clang-format-configurator.site 2 | # Copyright 2020-2025 Alfredo A. Correa 3 | # this format specification requires clang-format version 15, it is optimized for clang-format version 19 4 | --- 5 | Language: Cpp 6 | AccessModifierOffset: -3 7 | AlignAfterOpenBracket: BlockIndent 8 | AlignArrayOfStructures: Right 9 | AlignConsecutiveAssignments: 10 | Enabled: true 11 | AcrossEmptyLines: false 12 | AcrossComments: false 13 | AlignConsecutiveDeclarations: 14 | Enabled: true 15 | AcrossEmptyLines: false 16 | AcrossComments: false 17 | AlignConsecutiveMacros: None 18 | AlignOperands: AlignAfterOperator 19 | AllowAllArgumentsOnNextLine: false 20 | AllowShortLambdasOnASingleLine: All 21 | AllowShortCaseLabelsOnASingleLine: true 22 | AlwaysBreakTemplateDeclarations: No 23 | # BreakConstructorInitializers: BeforeComma 24 | BreakInheritanceList: BeforeComma 25 | BraceWrapping: 26 | BeforeLambdaBody: false 27 | ColumnLimit: 0 28 | QualifierAlignment: Right 29 | ConstructorInitializerIndentWidth: 0 30 | ContinuationIndentWidth: 4 31 | Cpp11BracedListStyle: true 32 | FixNamespaceComments: true 33 | IncludeBlocks: Regroup 34 | IncludeCategories: 35 | - Regex: <(boost\/multi)\/ 36 | Priority: 1 37 | - Regex: <([A-Za-z0-9\Q/-_\E])+> 38 | Priority: 5 39 | - Regex: <(boost)\/ 40 | Priority: 4 41 | - Regex: <([A-Za-z0-9.\Q/-_\E])+> 42 | Priority: 3 43 | - Regex: '"([A-Za-z0-9.\Q/-_\E])+"' 44 | Priority: 2 45 | IndentPPDirectives: None 46 | IndentWidth: 4 47 | # LambdaBodyIndentation: Signature 48 | # OneLineFormatOffRegex: ^(\#ifdef|\#endif) # for clang-format version 21 49 | # PackConstructorInitializers: CurrentLine 50 | PenaltyBreakTemplateDeclaration: 10 51 | PointerAlignment: Left 52 | SpaceAfterTemplateKeyword: false 53 | SpaceBeforeAssignmentOperators: true 54 | SpaceBeforeParens: Custom 55 | SpaceBeforeParensOptions: 56 | AfterControlStatements: false 57 | AfterForeachMacros: false 58 | AfterFunctionDeclarationName: false 59 | AfterFunctionDefinitionName: false 60 | AfterIfMacros: false # AfterNot: false 61 | AfterOverloadedOperator: false # AfterPlacementOperator: false 62 | AfterRequiresInClause: false 63 | AfterRequiresInExpression: false 64 | BeforeNonEmptyParentheses: false 65 | SpacesBeforeTrailingComments: 2 66 | SpacesInLineCommentPrefix: 67 | Minimum: 1 68 | Standard: c++17 69 | TabWidth: 4 70 | UseTab: ForContinuationAndIndentation 71 | WhitespaceSensitiveMacros: 72 | - BOOST_TEST 73 | -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CXX=g++-9 cmake .. -D CMAKE_BUILD_TYPE=Release -D CMAKE_CUDA_HOST_COMPILER=g++-9 2 | cmake_minimum_required(VERSION 3.10) 3 | 4 | project( 5 | boost-multi-benchmark 6 | VERSION 0.1 7 | LANGUAGES CXX 8 | ) 9 | 10 | find_package(Boost REQUIRED COMPONENTS serialization unit_test_framework system iostreams) 11 | find_package(benchmark REQUIRED) 12 | 13 | set(BLA_VENDOR Intel10_64lp) # . /opt/intel/oneapi/mkl/latest/env/vars.sh 14 | find_package(BLAS) 15 | if(BLAS_FOUND) # in some systems with MKL, regular BLAS headers need to be found for it to work 16 | message("Multi/BLAS: MKL environment detected") 17 | add_definitions(-DRETURN_BY_STACK) 18 | else() 19 | message("Multi/BLAS: MKL environment not detected, looking for other BLAS") 20 | unset(BLA_VENDOR) 21 | find_package(BLAS REQUIRED) 22 | find_path( 23 | BLAS_INCLUDE_DIRS 24 | cblas.h 25 | /usr/include 26 | /usr/local/include 27 | $ENV{BLAS_HOME}/include 28 | ) 29 | endif() 30 | link_libraries(${BLAS_LIBRARIES}) 31 | 32 | #find_package(BLAS REQUIRED) 33 | #find_package(TBB REQUIRED HINTS "/usr") 34 | 35 | set(CMAKE_CXX_STANDARD 17) 36 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 37 | set(CMAKE_CXX_EXTENSIONS OFF) 38 | 39 | #set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -arch=sm_61 -std=c++17 --use_fast_math --expt-relaxed-constexpr --extended-lambda") # set(CMAKE_CUDA_STANDARD 17) 40 | 41 | enable_testing() 42 | include(CTest) 43 | 44 | # file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) 45 | 46 | #add_executable(thrust_assignment.cu.x thrust_assignment.cu) 47 | #add_test(NAME thrust_assignment.cu.x COMMAND thrust_assignment.cu.x) 48 | #target_link_libraries(thrust_assignment.cu.x PRIVATE benchmark::benchmark) 49 | 50 | add_executable(matrix_multiplication.cpp.x matrix_multiplication.cpp) 51 | target_link_libraries(matrix_multiplication.cpp.x benchmark::benchmark) 52 | target_link_libraries(matrix_multiplication.cpp.x -ltbb) 53 | add_test(NAME matrix_multiplication.cpp.x COMMAND matrix_multiplication.cpp.x) 54 | 55 | add_executable(algorithms_gemm.cpp.x algorithms_gemm.cpp) 56 | target_link_libraries(algorithms_gemm.cpp.x benchmark::benchmark Boost::unit_test_framework) 57 | target_link_libraries(algorithms_gemm.cpp.x -ltbb) 58 | add_test(NAME algorithms_gemm.cpp.x COMMAND algorithms_gemm.cpp.x) 59 | 60 | add_executable(serialization serialization.cpp) 61 | target_link_libraries(serialization benchmark::benchmark Boost::serialization Boost::iostreams) 62 | add_test(NAME serialization COMMAND serialization) 63 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/lapack/getrf.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2025 Alfredo A. Correa 2 | 3 | #ifndef BOOST_MULTI_ADAPTORS_LAPACK_GETRF_HPP 4 | #define BOOST_MULTI_ADAPTORS_LAPACK_GETRF_HPP 5 | 6 | #include "boost/multi/adaptors/blas/filling.hpp" 7 | #include "boost/multi/adaptors/lapack/core.hpp" 8 | 9 | #include "boost/multi/detail/config/NODISCARD.hpp" 10 | 11 | #include 12 | 13 | namespace boost::multi::lapack { 14 | 15 | using index = int; 16 | 17 | using blas::filling; 18 | 19 | template 20 | auto getrf(Context&& ctxt, A&& arr, IPIV&& ipiv){ 21 | assert( ipiv.size() == std::min(size(arr), size(~arr)) ); 22 | assert( stride(arr) == 1 ); 23 | // assert( stride(ipiv) == 1 ); 24 | multi::index const i = std::forward(ctxt).getrf(size(~arr), size(arr), arr.base(), stride(~arr), std::forward(ipiv).data() ); 25 | // if(i == 0) { return arr(); } 26 | // else { return arr({0, i - 1}, {0, i - 1}); } 27 | if(i == 0) { return std::forward(arr)(); } 28 | return std::forward(arr)({0, i - 1}, {0, i - 1}); 29 | } 30 | 31 | template 32 | void getrs(Context&& ctxt, LU const& lu, IPIV const& ipiv, B&& barr){ 33 | assert( size(lu) == size(~lu) ); 34 | assert( stride(lu) == 1 ); 35 | assert( size(ipiv) >= size(lu) ); 36 | // assert( stride(ipiv) == 1 ); 37 | assert( stride(barr) == 1 ); 38 | std::forward(ctxt).getrs('N', size(lu), size(~barr), lu.base(), stride(~lu), ipiv.data(), std::forward(barr).base(), stride(~barr)); 39 | } 40 | 41 | template 42 | void getrs_one(Context&& ctxt, LU const& lu, IPIV const& ipiv, V&& barr){ 43 | assert( size(lu) == size(~lu) ); 44 | assert( stride(lu) == 1 ); 45 | // assert( stride(ipiv) == 1 ); 46 | assert( stride(barr) == 1 ); 47 | std::forward(ctxt).getrs('N', size(lu), 1, lu.base(), stride(~lu), ipiv.data(), std::forward(barr).base(), size(lu)); 48 | } 49 | 50 | 51 | template 52 | auto getrf(A&& arr, IPIV&& ipiv){return getrf(::lapack::context{}, std::forward(arr), std::forward(ipiv));} 53 | 54 | template 55 | void getrs(LU const& lu, IPIV const& ipiv, B&& barr){return getrs(::lapack::context{}, lu, ipiv, std::forward(barr));} 56 | 57 | template 58 | void getrs_one(LU const& lu, IPIV const& ipiv, B&& barr){return getrs_one(::lapack::context{}, lu, ipiv, std::forward(barr));} 59 | 60 | 61 | } // namespace boost::multi::lapack 62 | 63 | #endif 64 | 65 | 66 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/fftw/test/transpose.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include // for generate 11 | #include // for operator-, duration, system... // NOLINT(build/c++11) 12 | #include // for operator==, complex 13 | #include // for invoke // IWYU pragma: keep 14 | #include // for operator<<, basic_os... 15 | #include // for linear_congruential_... 16 | #include // for operator<<, operator""s 17 | #include // for move 18 | 19 | namespace multi = boost::multi; 20 | 21 | class watch // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) 22 | : private std::chrono::high_resolution_clock { 23 | std::string label_; 24 | time_point start_ = now(); 25 | 26 | public: 27 | explicit watch(std::string label) : label_{std::move(label)} {} // NOLINT(fuchsia-default-arguments-calls) 28 | 29 | watch(watch const&) = delete; 30 | 31 | auto operator=(watch const&) -> watch& = delete; 32 | 33 | auto elapsed_sec() const { return std::chrono::duration(now() - start_).count(); } 34 | ~watch() { std::cerr << label_ << ": " << elapsed_sec() << " sec" << '\n'; } // NOLINT(cpp:S4963) 35 | }; 36 | 37 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 38 | multi::fftw::environment const env; 39 | 40 | using namespace std::string_literals; // NOLINT(build/namespaces) for ""s 41 | 42 | using complex = std::complex; 43 | 44 | auto const in = std::invoke([] () noexcept { 45 | multi::array ret({101, 99}); // ({1013, 997}); // ({10137, 9973}); 46 | std::generate( 47 | ret.elements().begin(), ret.elements().end(), 48 | [eng = std::default_random_engine{std::random_device{}()}, uniform_01 = std::uniform_real_distribution<>{}]() mutable { 49 | return complex{uniform_01(eng), uniform_01(eng)}; 50 | } 51 | ); 52 | return ret; 53 | }); 54 | 55 | multi::array out = in; 56 | 57 | watch const unnamed{"transposition with aux %ws wall, CPU (%p%)\n"s}; // NOLINT(misc-include-cleaner) bug in clang-tidy 18 58 | 59 | multi::array aux{~out}; 60 | 61 | out = std::move(aux); 62 | BOOST_TEST( out[35][79] == in[79][35] ); 63 | 64 | return boost::report_errors(); 65 | } 66 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | #project( 4 | # boost-multi-adaptors-blas 5 | # VERSION 0.1 6 | # LANGUAGES CXX 7 | #) 8 | 9 | find_package(BLAS) 10 | 11 | if(BLAS_FOUND) 12 | message("Some BLAS found: linker flags: ${BLAS_LINKER_FLAGS}, libs: ${BLAS_LIBRARIES}, libs95: ${BLAS95_LIBRARIES}") 13 | foreach(lib ${BLAS_LIBRARIES}) 14 | # https://cmake.org/cmake/help/latest/module/FindBLAS.html#blas-lapack-vendors 15 | if(${lib} MATCHES "mkl") 16 | message("Some BLAS found matches MKL") 17 | add_definitions(-DBLAS_DOT_RETURNS_VOID) 18 | target_compile_definitions(multi INTERFACE BLAS_DOT_RETURNS_VOID) 19 | # add_definitions(-D_MULTI_USING_BLAS_MKL) 20 | # in some systems with MKL, regular BLAS headers need to be found for it to work 21 | SET(CMAKE_SKIP_BUILD_RPATH FALSE) 22 | SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) 23 | SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib64") 24 | SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 25 | SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib64") 26 | endif() 27 | if(${lib} MATCHES "hpc_sdk") 28 | message("Some BLAS found matches hpc_sdk (nvhpc)") # nvhpc may still use a different version of BLAS 29 | add_definitions(-DBLAS_DOT_RETURNS_VOID) 30 | target_compile_definitions(multi INTERFACE BLAS_DOT_RETURNS_VOID) 31 | endif() 32 | if(${lib} MATCHES "Accelerate") 33 | message("Some BLAS found matches Accelerate (Apple) [beware of sdot and snrm2 bugs]") 34 | # message(WARNING "Apple Accelerate BLAS is known to have bugs in single precission function `sdot` and `smrm2`, be careful: https://stackoverflow.com/a/77017238/225186, https://fortran-lang.discourse.group/t/how-many-blas-libraries-have-this-error/4454/23, https://forums.developer.apple.com/forums/thread/717757") 35 | # add_definitions(-DBLAS_DOT_RETURNS_VOID) 36 | target_compile_definitions(multi INTERFACE BLAS_DOT_RETURNS_VOID) 37 | endif() 38 | endforeach() 39 | endif() 40 | 41 | if(BLAS_FOUND) 42 | find_package(Boost NO_MODULE) # COMPONENTS boost) # headers unit_test_framework) 43 | if(Boost_FOUND) 44 | add_subdirectory(test) 45 | else() 46 | message(WARNING "Boost Unit Test Framework not found, BLAS-adaptor tests will not be compiled and run. If you want this feature, install Boost") 47 | endif() 48 | else() 49 | message(WARNING 50 | "BLAS not found, BLAS-adaptor tests will not be compiled and run. If you want this feature install BLAS, for example please run:" 51 | "\n sudo apt install libblas-dev # in Ubuntu" 52 | "\n sudo dnf install blas-devel # in Fedora") 53 | message(WARNING "BLA_VENDOR was set to ${BLA_VENDOR}\n") 54 | endif() 55 | -------------------------------------------------------------------------------- /test/elementwise_expr.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include // IWYU pragma: keep 6 | 7 | #if __cplusplus >= 202302L 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace multi = boost::multi; 15 | 16 | int main() { 17 | auto const A = multi::array{ 18 | {0, 1, 2}, 19 | {3, 4, 5} 20 | }; 21 | auto const B = multi::array{ 22 | { 0, 10, 20}, 23 | {30, 40, 50} 24 | }; 25 | 26 | using multi::broadcast::apply; 27 | 28 | multi::array const C1 = apply(std::plus<>{}, A, B); 29 | 30 | BOOST_TEST( C1[1][1] == std::plus<>{}(A[1][1], B[1][1]) ); 31 | 32 | using multi::broadcast::operator+; 33 | multi::array const C2 = A + B; 34 | 35 | BOOST_TEST( C1 == C2 ); 36 | 37 | using multi::broadcast::operator-; 38 | multi::array const C3 = A - (-B); 39 | 40 | BOOST_TEST( C2 == C3 ); 41 | 42 | { 43 | multi::array aa = {1.0, 2.0, 3.0}; 44 | 45 | using multi::broadcast::exp; 46 | BOOST_TEST( std::abs( exp(aa)[2] - std::exp(aa[2]) ) < 1e-12 ); 47 | 48 | auto exp_aa_copy = +exp(aa); 49 | 50 | BOOST_TEST( std::abs( exp_aa_copy[2] - std::exp(aa[2]) ) < 1e-12 ); 51 | } 52 | // auto softmax = 53 | // std::views::transform([](auto row) { return row | stdv::transform([max = maxR1(row)](auto ele) { return exp(ele - max); }); }) 54 | // | std::views::transform([](auto nums) { return nums | stdv::transform([den = sumR1(nums)](auto num) { return num / den; }); }); 55 | 56 | // { 57 | // using multi::broadcast::apply; 58 | // 59 | // auto const matrix = 60 | // ([](auto ii) noexcept { return static_cast(ii); } ^ 61 | // multi::extensions_t(6)) 62 | // .partitioned(2); 63 | // 64 | // constexpr auto maxR1 = []>(R const& row, V low = std::numeric_limits::lowest()) { 65 | // return std::ranges::fold_left(row, low, std::ranges::max); 66 | // }; 67 | // 68 | // #define BOOST_MULTI_FWD(var) std::forward(var) 69 | // using multi::broadcast::apply_front; 70 | // auto matrix_minus_row_max = apply_front([&](auto row) { return apply_front([max = maxR1(row)](auto elem) { return elem/*- max*/; }, row); }, matrix); 71 | // 72 | // std::cout << std::abs( matrix_minus_row_max[0][2] ) << '\n'; 73 | // BOOST_TEST( std::abs( matrix_minus_row_max[0][2] ) < 1e-12F ); 74 | // } 75 | return boost::report_errors(); 76 | } 77 | #else 78 | auto main() -> int { 79 | return boost::report_errors(); 80 | } 81 | #endif 82 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/scal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_BLAS_SCAL_HPP 6 | #define BOOST_MULTI_ADAPTORS_BLAS_SCAL_HPP 7 | 8 | #include "boost/multi/adaptors/blas/core.hpp" 9 | // IWYU pragma: no_include "boost/multi/adaptors/blas/traits.hpp" // for blas, multi 10 | 11 | // IWYU pragma: no_include // for declval // needed by iwyu-clang-linux 12 | #include // for forward, declval 13 | 14 | namespace boost::multi::blas { 15 | 16 | using core::scal; 17 | 18 | template 19 | auto scal_n(typename It::element a, It first, Size count) { // NOLINT(readability-identifier-length) conventional BLAS naming 20 | auto ctxt = blas::default_context_of(first.base()); 21 | ctxt->scal(static_cast(count), &a, first.base(), static_cast(first.stride())); 22 | } 23 | 24 | template 25 | auto scal(Scalar const& a, It1D first, It1D last) // NOLINT(readability-identifier-length) conventional BLAS naming 26 | ->decltype(blas::scal_n(a, first, last - first)) { // NOLINT(fuchsia-default-arguments-calls) allow a possible double -> complex conversion (with default 0 imag part) 27 | return blas::scal_n(a, first, last - first); } // NOLINT(fuchsia-default-arguments-calls) same 28 | 29 | template // don't do this: ", typename Elem = typename X1D::element_type>" 30 | auto scal(Scalar const& a, X1D&& x) // NOLINT(readability-identifier-length) conventional BLAS naming 31 | ->decltype(blas::scal(a, x.begin(), x.end()), std::forward(x)) { 32 | return blas::scal(a, x.begin(), x.end()), std::forward(x); } 33 | 34 | template 35 | class scal_range { 36 | A alpha_; 37 | 38 | public: 39 | using scalar_type = A; 40 | explicit scal_range(A const& alpha) : alpha_{alpha} {} 41 | template 42 | friend auto operator*=(X1D&& x, scal_range const& self) // NOLINT(readability-identifier-length) conventional BLAS naming 43 | ->decltype(std::forward(scal(std::declval(), std::forward(x)))) { 44 | return std::forward(scal(self.alpha_, std::forward(x)));} 45 | }; 46 | 47 | template auto scal(A const& array) {return scal_range{array};} 48 | 49 | namespace operators { 50 | template 51 | auto operator*=(X&& x, Scalar const& alpha) -> X&& { // NOLINT(readability-identifier-length) conventional BLAS naming 52 | return blas::scal(alpha, std::forward(x)); 53 | } 54 | } // end namespace operators 55 | 56 | } // end namespace boost::multi::blas 57 | #endif 58 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cuda/cublas/test/axpy.cu: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | namespace multi = boost::multi; 15 | 16 | #include 17 | #define BOOST_AUTO_TEST_CASE(CasenamE) /**/ 18 | 19 | #define BOOST_REQUIRE_CLOSE(X, Y, ToL) BOOST_TEST( std::abs( (X) - (Y) ) < (ToL) ) 20 | 21 | int main() { 22 | BOOST_AUTO_TEST_CASE(blas_axpy_complex) { 23 | namespace blas = multi::blas; 24 | using complex = thrust::complex; 25 | 26 | { 27 | multi::thrust::cuda::array arr = { 28 | {{1.0, 0.0}, {2.0, 0.0}, {3.0, 0.0}, {4.0, 0.0}}, 29 | {{5.0, 0.0}, {6.0, 0.0}, {7.0, 0.0}, {8.0, 0.0}}, 30 | {{9.0, 0.0}, {10.0, 0.0}, {11.0, 0.0}, {12.0, 0.0}}, 31 | }; 32 | auto const const_arr = arr; 33 | 34 | multi::thrust::cuda::array const x = arr[2]; // NOLINT(readability-identifier-length) BLAS naming 35 | blas::axpy(complex{2.0, 0.0}, x, arr[1]); // arr can't be const 36 | 37 | multi::array arr_copy = arr; 38 | BOOST_TEST(( arr_copy[1][0] == complex{23.0, 0.0} )); 39 | } 40 | { 41 | multi::thrust::cuda::array arr = { 42 | {{1.0, 0.0}, {2.0, 0.0}, {3.0, 0.0}, {4.0, 0.0}}, 43 | {{5.0, 0.0}, {6.0, 0.0}, {7.0, 0.0}, {8.0, 0.0}}, 44 | {{9.0, 0.0}, {10.0, 0.0}, {11.0, 0.0}, {12.0, 0.0}}, 45 | }; 46 | auto const const_arr = arr; 47 | 48 | multi::thrust::cuda::array const x = arr[2]; // NOLINT(readability-identifier-length) BLAS naming 49 | arr[1] += blas::axpy(complex{2.0, 0.0}, x); 50 | 51 | multi::array arr_copy = arr; 52 | BOOST_TEST(( arr_copy[1][0] == complex{23.0, 0.0} )); 53 | } 54 | { 55 | multi::thrust::cuda::array arr = { 56 | {{1.0, 0.0}, {2.0, 0.0}, {3.0, 0.0}, {4.0, 0.0}}, 57 | {{5.0, 0.0}, {6.0, 0.0}, {7.0, 0.0}, {8.0, 0.0}}, 58 | {{9.0, 0.0}, {10.0, 0.0}, {11.0, 0.0}, {12.0, 0.0}}, 59 | }; 60 | auto const const_arr = arr; 61 | 62 | multi::thrust::cuda::array const x = arr[2]; // NOLINT(readability-identifier-length) BLAS naming 63 | arr[1] = blas::axpy(2.0, x); // blas::axpy(complex{2.0, 0.0}, x); 64 | 65 | multi::array arr_copy = arr; 66 | std::cout << arr_copy[1][0] << std::endl; 67 | BOOST_TEST(( arr_copy[1][0] == complex{23.0, 0.0} )); 68 | } 69 | } 70 | 71 | return boost::report_errors();} 72 | -------------------------------------------------------------------------------- /mull.yml: -------------------------------------------------------------------------------- 1 | mutators: 2 | - cxx_add_assign_to_sub_assign # Replaces += with -= 3 | - cxx_add_to_sub # Replaces + with - 4 | - cxx_and_assign_to_or_assign # Replaces &= with |= 5 | - cxx_and_to_or # Replaces & with | 6 | - cxx_assign_const # Replaces `a = b` with `a = 42` 7 | - cxx_bitwise_not_to_noop # Replaces ~x with x 8 | - cxx_div_assign_to_mul_assign # Replaces /= with *= 9 | - cxx_div_to_mul # Replaces / with * 10 | - cxx_eq_to_ne # Replaces == with != 11 | - cxx_ge_to_gt # Replaces >= with > 12 | - cxx_ge_to_lt # Replaces >= with < 13 | - cxx_gt_to_ge # Replaces > with >= 14 | - cxx_gt_to_le # Replaces > with <= 15 | - cxx_init_const # Replaces ‘T a = b’ with ‘T a = 42’ 16 | - cxx_le_to_gt # Replaces <= with > 17 | - cxx_le_to_lt # Replaces <= with < 18 | - cxx_logical_and_to_or # Replaces && with || 19 | - cxx_logical_or_to_and # Replaces || with && # The module was corrupted by 'cxx_logical_or_to_and' mutator. 20 | - cxx_lshift_assign_to_rshift_assign # Replaces <<= with >>= 21 | - cxx_lshift_to_rshift # Replaces << with >> 22 | - cxx_lt_to_ge # Replaces < with >= 23 | - cxx_lt_to_le # Replaces < with <= # TODO(correaa) investigate why this mutant survives with the range.contains function 24 | - cxx_minus_to_noop # Replaces -x with x 25 | - cxx_mul_assign_to_div_assign # Replaces *= with /= 26 | - cxx_mul_to_div # Replaces * with / 27 | - cxx_ne_to_eq # Replaces != with == 28 | - cxx_or_assign_to_and_assign # Replaces |= with &= 29 | - cxx_or_to_and # Replaces | with & 30 | - cxx_post_dec_to_post_inc # Replaces x– with x++ 31 | - cxx_post_inc_to_post_dec # Replaces x++ with x– 32 | - cxx_pre_dec_to_pre_inc # Replaces –x with ++x 33 | - cxx_pre_inc_to_pre_dec # Replaces ++x with –x 34 | - cxx_rem_assign_to_div_assign # Replaces %= with /= 35 | - cxx_rem_to_div # Replaces % with / 36 | - cxx_remove_negation # Replaces !a with a 37 | - cxx_remove_void_call # Removes calls to a function returning void 38 | - cxx_replace_scalar_call # Replaces call to a function with 42 39 | - cxx_rshift_assign_to_lshift_assign # Replaces >>= with <<= 40 | - cxx_rshift_to_lshift # Replaces << with >> 41 | - cxx_sub_assign_to_add_assign # Replaces -= with += 42 | - cxx_sub_to_add # Replaces - with + 43 | - cxx_xor_assign_to_or_assign # Replaces ^= with |= 44 | - cxx_xor_to_or # Replaces ^ with | 45 | - negate_mutator 46 | - scalar_value_mutator 47 | ignoreMutators: 48 | - cxx_logical_or_to_and # bug in mull 16 49 | - cxx_logical_and_to_or # bug in mull 16 50 | - scalar_value_mutator # bug in mull 17 51 | timeout: 20000 # in milliseconds 52 | # debug: 53 | # slowIRVerification: true 54 | quiet: true 55 | excludePaths: 56 | - .*test.* 57 | -------------------------------------------------------------------------------- /test/element_moved.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 10. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include // for array, apply, array_types<>::ele... 6 | 7 | #include 8 | 9 | // IWYU pragma: no_include // for remove_reference<>::type 10 | // IWYU pragma: no_include 11 | // IWYU pragma: no_include 12 | // IWYU pragma: no_include 13 | // IWYU pragma: no_include // for fill_n 14 | // IWYU pragma: no_include 15 | // IWYU pragma: no_include 16 | #include // for move, swap // IWYU pragma: keep 17 | #include // for vector, operator==, vector<>::va... 18 | 19 | namespace multi = boost::multi; 20 | 21 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 22 | // explicit_move_subarray_vector_2d_assign 23 | { 24 | multi::array, 2> arrA({10, 10}, std::vector(5, {}, {})); 25 | 26 | BOOST_TEST( arrA[2][2].size() == 5 ); 27 | { 28 | using std::move; 29 | multi::array, 2> arrB(arrA().element_moved()); // (arrA.extensions()); 30 | // arrB = arrA().element_moved(); 31 | 32 | BOOST_TEST( arrA.size() == 10 ); 33 | BOOST_TEST( arrB.size() == 10 ); 34 | BOOST_TEST( arrA[2][2].empty() ); 35 | BOOST_TEST( arrB[2][2].size() == 5 ); 36 | } 37 | } 38 | 39 | // explicit_move_subarray_vector_2d_ctor 40 | // { 41 | // multi::array, 2> arrA({10, 10}, std::vector(5)); 42 | 43 | // BOOST_TEST( arrA[2][2].size() == 5 ); 44 | // { 45 | // using std::move; 46 | // multi::array, 2> arrB{arrA().element_moved()}; 47 | 48 | // BOOST_TEST( arrA.size() == 10 ); 49 | // BOOST_TEST( arrB.size() == 10 ); 50 | // BOOST_TEST( arrA[2][2].size() == 0 ); 51 | // BOOST_TEST( arrB[2][2].size() == 5 ); 52 | // } 53 | // } 54 | 55 | // BOOST_AUTO_TEST_CASE(explicit_move_subarray_vector_1d) 56 | // { 57 | // multi::array, 1> arrA(10, std::vector(5)); 58 | 59 | // BOOST_TEST( arrA[2].size() == 5 ); 60 | // { 61 | // using std::move; 62 | // multi::array, 1> arrB(arrA.extensions()); 63 | // arrB() = arrA().element_moved(); 64 | // // std::copy(arrA().element_moved().begin(), arrA().element_moved().end(), arrB.begin()); 65 | 66 | // BOOST_TEST( arrA.size() == 10 ); 67 | // BOOST_TEST( arrB.size() == 10 ); 68 | // BOOST_TEST( arrA[2].size() == 0 ); 69 | // BOOST_TEST( arrB[2].size() == 5 ); 70 | // } 71 | // } 72 | 73 | return boost::report_errors(); 74 | } 75 | -------------------------------------------------------------------------------- /test/swap.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2024 Alfredo A. Correa 2 | // Copyright 2024 Matt Borland 3 | // Distributed under the Boost Software License, Version 10. 4 | // https://www.boost.org/LICENSE_1_0.txt 5 | 6 | #include // for array, apply, array_types<>::ele... 7 | 8 | #include 9 | 10 | #include // for swap // IWYU pragma: keep // for std::swap 11 | // IWYU pragma: no_include // for swap 12 | // IWYU pragma: no_include // for swap 13 | 14 | namespace multi = boost::multi; 15 | 16 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 17 | // swap_array_1D) 18 | { 19 | multi::array arr1 = {0, 1, 2, 3}; 20 | multi::array arr2 = {100, 101, 102}; 21 | 22 | using std::swap; 23 | swap(arr1, arr2); 24 | 25 | BOOST_TEST( arr1[1] == 101 ); 26 | BOOST_TEST( arr2[1] == 1 ); 27 | } 28 | 29 | // BOOST_AUTO_TEST_CASE(swap_array_2D) 30 | { 31 | multi::array arr1 = { 32 | {00, 01, 02, 03}, 33 | {10, 11, 12, 13}, 34 | {20, 21, 22, 23}, 35 | }; 36 | 37 | multi::array arr2 = { 38 | {100, 101, 102, 103}, 39 | {110, 111, 112, 113}, 40 | }; 41 | 42 | using std::swap; 43 | swap(arr1, arr2); 44 | 45 | BOOST_TEST( arr1[1][1] == 111 ); 46 | BOOST_TEST( arr2[1][1] == 11 ); 47 | } 48 | 49 | // BOOST_AUTO_TEST_CASE(swap_subarray_1D) 50 | { 51 | multi::array arr1 = {0, 1, 2, 3}; 52 | multi::array arr2 = {100, 101, 102, 103}; 53 | 54 | using std::swap; 55 | swap(arr1(), arr2()); 56 | 57 | BOOST_TEST( arr1[1] == 101 ); 58 | BOOST_TEST( arr2[1] == 1 ); 59 | } 60 | 61 | // BOOST_AUTO_TEST_CASE(swap_subarray_2D) 62 | { 63 | multi::array arr1 = { 64 | {00, 01, 02, 03}, 65 | {10, 11, 12, 13}, 66 | {20, 21, 22, 23}, 67 | }; 68 | 69 | multi::array arr2 = { 70 | {100, 101, 102, 103}, 71 | {110, 111, 112, 113}, 72 | {120, 121, 122, 123}, 73 | }; 74 | 75 | using std::swap; 76 | swap(arr1(), arr2()); 77 | 78 | BOOST_TEST( arr1[1][1] == 111 ); 79 | BOOST_TEST( arr2[1][1] == 11 ); 80 | } 81 | 82 | // BOOST_AUTO_TEST_CASE(swap_const_subarray_2D) 83 | { 84 | multi::array const arr1 = { 85 | {00, 01, 02, 03}, 86 | {10, 11, 12, 13}, 87 | {20, 21, 22, 23}, 88 | }; 89 | 90 | multi::array arr2 = { 91 | {100, 101, 102, 103}, 92 | {110, 111, 112, 113}, 93 | {120, 121, 122, 123}, 94 | }; 95 | 96 | // using std::swap; 97 | // swap(arr1(), arr2()); 98 | 99 | BOOST_TEST( arr1[1][1] == 11 ); 100 | BOOST_TEST( arr2[1][1] == 111 ); 101 | } 102 | 103 | return boost::report_errors(); 104 | } 105 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/hipthrust/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.24) 2 | 3 | project(boost-multi-adaptor-thrust-hip LANGUAGES CXX HIP) 4 | 5 | find_package(Boost REQUIRED COMPONENTS timer unit_test_framework) 6 | find_package(rocthrust REQUIRED) 7 | 8 | include(CMakePrintHelpers) 9 | 10 | cmake_print_properties(TARGETS roc::rocthrust PROPERTIES INTERFACE_LINK_LIBRARIES INTERFACE_INCLUDE_DIRECTORIES) 11 | 12 | enable_testing() 13 | 14 | include(CTest) 15 | 16 | # set(TEST_SRCS 17 | # # array.cu 18 | # # memory_resource.cu 19 | # # set_identity_kernel.cu 20 | # # speed.cu 21 | # # speed_algo.cu 22 | # # universal.cu 23 | # vector.cpp 24 | # ) 25 | 26 | # add_executable(vector.cu.nvidia.x vector.cu) 27 | # set_source_files_properties(vector.cu PROPERTIES LANGUAGE CUDA) 28 | 29 | # target_link_libraries(vector.cu.nvidia.x PRIVATE Boost::unit_test_framework) 30 | # add_test(NAME vector.cu.nvidia.x COMMAND vector.cu.nvidia.x) 31 | 32 | add_executable(vector.hip.amd.x vector.hip) 33 | set_source_files_properties(vector.hip PROPERTIES LANGUAGE HIP) 34 | target_link_libraries(vector.hip.amd.x PRIVATE Boost::unit_test_framework roc::rocthrust) 35 | target_compile_definitions(vector.hip.amd.x PRIVATE BOOST_TEST_DYN_LINK=1) 36 | 37 | add_test(NAME vector.hip.amd.x COMMAND $) 38 | 39 | add_executable(array.hip.amd.x array.hip) 40 | set_source_files_properties(array.hip PROPERTIES LANGUAGE HIP) 41 | target_link_libraries(array.hip.amd.x PRIVATE Boost::unit_test_framework Boost::timer multi roc::rocthrust) 42 | target_compile_definitions(array.hip.amd.x PRIVATE BOOST_TEST_DYN_LINK=1) 43 | 44 | add_test(NAME array.hip.amd.x COMMAND $) 45 | 46 | add_executable(speed.hip.amd.x speed.hip) 47 | set_source_files_properties(speed.hip PROPERTIES LANGUAGE HIP) 48 | target_link_libraries(speed.hip.amd.x PRIVATE Boost::unit_test_framework Boost::timer multi roc::rocthrust) 49 | target_compile_definitions(speed.hip.amd.x PRIVATE BOOST_TEST_DYN_LINK=1) 50 | target_compile_definitions(speed.hip.amd.x PRIVATE BOOST_TEST_MODULE="C++ Unit Tests for Multi CUDA thrust universal copy and assignment") 51 | 52 | add_test(NAME speed.hip.amd.x COMMAND $) 53 | 54 | # foreach(TEST_FILE ${TEST_SRCS}) 55 | # # set(TEST_EXE "${TEST_FILE}") 56 | # add_executable(vector ${TEST_FILE}) 57 | # # if(ENABLE_CUDA OR DEFINED CXXCUDA) 58 | # # set_source_files_properties(${TEST_FILE} PROPERTIES LANGUAGE HIP) 59 | # # endif() 60 | 61 | # # target_include_directories(${TEST_EXE} PRIVATE ../../../../../include) 62 | 63 | # # if(ENABLE_CUDA) 64 | # # add_test(NAME ${TEST_EXE} COMMAND ./${TEST_EXE}) 65 | # # endif() 66 | # endforeach() 67 | 68 | # set_tests_properties(speed.cu.x PROPERTIES RUN_SERIAL TRUE) 69 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/lapack/geqrf.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_LAPACK_GEQRF_HPP 6 | #define BOOST_MULTI_ADAPTORS_LAPACK_GEQRF_HPP 7 | 8 | #include "boost/multi/adaptors/blas/filling.hpp" 9 | #include "boost/multi/utility.hpp" // for size 10 | 11 | #include // for min 12 | #include 13 | #include // for runtime_error 14 | #include // for operator+, to_string, allocator 15 | #include // for forward 16 | 17 | extern "C" { 18 | using integer = int const&; 19 | 20 | void dgeqrf_( // NOLINT(readability-identifier-naming) externally linked 21 | integer, // M, 22 | integer, // N, 23 | double*, // A double precision, dimension( lda, * ) A, 24 | integer, // LDA, 25 | double*, // TAU, // double precision, dimension( * ) TAU, 26 | double*, // WORK, // double precision, dimension( * ) WORK, 27 | integer, // LWORK, 28 | integer // INFO 29 | ); 30 | } 31 | 32 | // namespace boost{namespace multi{namespace lapack{ 33 | namespace boost::multi::lapack { 34 | 35 | using blas::filling; 36 | 37 | template 38 | auto geqrf(Array2D&& aa, TAU& tau, Allocator alloc) -> Array2D&& { 39 | // assert( stride(~a) == 1); 40 | assert( size(tau) == std::min(size(~aa), size(aa)) ); 41 | 42 | double dwork; // NOLINT(cppcoreguidelines-init-variables) delayed initialization 43 | int info; // NOLINT(cppcoreguidelines-init-variables) delayed initialization 44 | dgeqrf_( 45 | size(~aa), size(aa), aa.base(), aa.stride(), 46 | tau.base(), 47 | &dwork, -1, 48 | info // cppcheck-suppress uninitvar ; 49 | ); 50 | if(info != 0) { // cppcheck-suppress identicalConditionAfterEarlyExit ; TODO(correaa) investigate 51 | throw std::runtime_error("Error in DGEQRF work estimation, info: " + std::to_string(info)); 52 | } 53 | 54 | auto const lwork = static_cast(dwork); 55 | auto* const work = alloc.allocate(lwork); 56 | 57 | dgeqrf_( 58 | size(~aa), size(aa), aa.base(), aa.stride(), 59 | tau.base(), 60 | work, lwork, 61 | info 62 | ); 63 | alloc.deallocate(work, lwork); 64 | 65 | if(info != 0) { // cppcheck-suppress identicalConditionAfterEarlyExit ; TODO(correaa) investigate 66 | throw std::runtime_error("Error in DGESVD computation, info: " + std::to_string(info)); 67 | } 68 | 69 | return std::forward(aa); 70 | } 71 | 72 | template> 73 | auto geqrf(Array2D&& aa, TAU&& tau) -> Array2D&& { 74 | return geqrf(std::forward(aa), std::forward(tau), Allocator{}); 75 | } 76 | 77 | } // end namespace boost::multi::lapack 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /examples/save.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2024 Alfredo A. Correa 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../../multi/array.hpp" 16 | #include 17 | 18 | enum format { xml, 19 | txt, 20 | bin }; 21 | 22 | namespace barch = boost::archive; 23 | namespace bs11n = boost::serialization; 24 | 25 | #define BOOST_MULTI_UNSWITCH __builtin_unreachable 26 | 27 | template 28 | void save(Array const& a, std::string const& name, format f) { 29 | std::ofstream ofs(name); 30 | *[&]() -> std::unique_ptr { 31 | switch(f) { 32 | case xml: return std::make_unique(ofs); 33 | case txt: return std::make_unique(ofs); 34 | case bin: return std::make_unique(ofs); 35 | } 36 | BOOST_MULTI_UNSWITCH(); 37 | }() << bs11n::make_nvp("root", a); 38 | assert(ofs); 39 | } 40 | 41 | template 42 | void save(Array const& a, std::experimental::filesystem::path p) { 43 | if(p.extension() == ".xml") 44 | return save(a, p.string(), xml); 45 | else if(p.extension() == ".txt") 46 | return save(a, p.string(), txt); 47 | else 48 | return save(a, p.string(), bin); 49 | } 50 | 51 | template 52 | void load(Array& a, std::string const& name, format f) { 53 | std::ifstream ifs(name); 54 | *[&]() -> std::unique_ptr {switch(f){ 55 | case xml: return std::make_unique(ifs); 56 | case txt: return std::make_unique(ifs); 57 | case bin: return std::make_unique(ifs); 58 | }BOOST_MULTI_UNSWITCH(); }() >> bs11n::make_nvp("root", a); 59 | assert(ifs); 60 | } 61 | 62 | template 63 | void save_xml(Array const& a, std::string const& name) { 64 | std::ofstream ofs(name); 65 | barch::xml_oarchive(ofs) << bs11n::make_nvp("root", a); 66 | } 67 | 68 | namespace multi = boost::multi; 69 | 70 | int main() { 71 | multi::array const arrD2d = { 72 | {1.0, 2.0, 3.0}, 73 | {4.0, 5.0, 6.0}, 74 | {7.0, 8.0, 9.0}, 75 | }; 76 | save(arrD2d, "arrD2d.xml"); 77 | 78 | multi::array arrD2d_copy; 79 | load(arrD2d_copy, "arrD2d.xml", format::xml); 80 | assert(arrD2d_copy == arrD2d); 81 | } 82 | 83 | #undef BOOST_MULTO_SWITCH 84 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/test/by_key.cu: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace multi = boost::multi; 15 | 16 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 17 | 18 | multi::thrust::universal_array M = { 19 | {15.0, 6.0, 18.0, 15.0}, 20 | {29.0, 26.0, 24.0, 10.0}, 21 | { 1.0, 4.0, 12.0, 8.0}, 22 | { 8.0, 15.0, 1.0, 14.0}, 23 | {26.0, 5.0, 12.0, 25.0}, 24 | {13.0, 14.0, 23.0, 25.0}, 25 | {20.0, 23.0, 19.0, 18.0}, 26 | {11.0, 14.0, 3.0, 12.0} 27 | }; 28 | 29 | BOOST_TEST( M.size() == 8 ); 30 | BOOST_TEST( (~M).size() == 4 ); 31 | 32 | 33 | using std::get; 34 | std::cout 35 | << get<0>(M.extensions()[1][1]) << ' ' 36 | << get<1>(M.extensions()[1][1]) << '\n' 37 | ; 38 | 39 | BOOST_TEST(true); 40 | // M.extensions().elements(); 41 | 42 | auto row_ids_begin_ref = 43 | thrust::make_transform_iterator( 44 | M.extensions().elements().begin(), 45 | [] __host__ __device__ (decltype(M)::indexes e) -> std::ptrdiff_t { using std::get; return get<0>(e); } 46 | ) 47 | ; 48 | 49 | auto row_ids_begin = 50 | thrust::make_transform_iterator( 51 | thrust::make_counting_iterator(std::ptrdiff_t{0}), 52 | [] __host__ __device__ (std::ptrdiff_t e) -> std::ptrdiff_t { return e / 4; } // std::get; return get<0>(e); } 53 | ) 54 | ; 55 | auto row_ids_end = row_ids_begin + M.num_elements(); 56 | 57 | auto row_ids_end_ref = row_ids_begin_ref + M.num_elements(); 58 | 59 | BOOST_TEST( thrust::equal(row_ids_begin, row_ids_end, row_ids_begin_ref) ); // , row_ids_end_ref) ); 60 | BOOST_TEST( thrust::equal(row_ids_begin+1, row_ids_end, row_ids_begin_ref+1) ); // row_ids_end_ref) ); 61 | 62 | BOOST_TEST( row_ids_end - row_ids_begin == M.num_elements() ); 63 | 64 | multi::thrust::universal_array sums(M.size()); 65 | 66 | thrust::reduce_by_key(thrust::cuda::par, 67 | row_ids_begin_ref, row_ids_end_ref, 68 | M.elements().begin(), 69 | thrust::make_discard_iterator(), 70 | sums.begin() 71 | ); 72 | 73 | // thrust::reduce_by_key( 74 | // thrust::make_counting_iterator(0), 75 | // thrust::make_counting_iterator(M.size()), 76 | // M.data(), 77 | // thrust::make_discard_iterator(), 78 | // sums.data() 79 | // ); 80 | 81 | BOOST_TEST( sums[0] == M[0][0] + M[0][1] + M[0][2] + M[0][3] ); 82 | BOOST_TEST( sums[1] == M[1][0] + M[1][1] + M[1][2] + M[1][3] ); 83 | 84 | return boost::report_errors(); 85 | } 86 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cuda/algorithms/copy.hpp: -------------------------------------------------------------------------------- 1 | #ifdef COMPILATION_INSTRUCTIONS//-*-indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4;-*- 2 | nvcc -D_TEST_MULTI_ADAPTORS_CUDA_ALGORITHMS_COPY -x cu $0 -o $0x -lboost_unit_test_framework -lboost_timer&&$0x&& 3 | clang++ -D_TEST_MULTI_ADAPTORS_CUDA_ALGORITHMS_COPY -x cuda --cuda-gpu-arch=sm_61 -std=c++14 $0 -o $0x -lcudart -lboost_unit_test_framework -lboost_timer&&$0x&& 4 | rm $0x; exit 5 | #endif 6 | 7 | #ifndef BOOST_MULTI_ADAPTORS_CUDA_ALGORITHMS_COPY_HPP 8 | #define BOOST_MULTI_ADAPTORS_CUDA_ALGORITHMS_COPY_HPP 9 | 10 | #include 11 | 12 | #include "../../../adaptors/cuda.hpp" 13 | //#include "../algorithms/for_each.hpp" 14 | 15 | #ifndef BOOST_MULTI_HD 16 | #if defined(__CUDACC__) 17 | #define BOOST_MULTI_HD __host__ __device__ 18 | #else 19 | #define BOOST_MULTI_HD 20 | #endif 21 | #endif 22 | 23 | namespace boost{ 24 | namespace multi{namespace cuda{ 25 | 26 | #if 0 27 | template{}> > 28 | array_iterator copy( 29 | array_iterator> f, 30 | array_iterator> l, 31 | array_iterator d 32 | ){ 33 | assert(0); 34 | assert(f.stride() == l.stride()); static_assert(sizeof(From) == sizeof(To), "!"); 35 | auto n = std::distance(f, l); 36 | if(f.stride()==1 and d.stride()==1){ 37 | auto s = cudaMemcpy(d.data(), raw_pointer_cast(f.data()), n*sizeof(To), cudaMemcpyDeviceToHost); assert( s == cudaSuccess ); 38 | }else{ 39 | auto s = cudaMemcpy2D(d.data(), d.stride()*sizeof(To), raw_pointer_cast(f.data()), f.stride()*sizeof(To), sizeof(To), n, cudaMemcpyDeviceToHost); 40 | assert( s == cudaSuccess ); 41 | } 42 | return d + n; 43 | } 44 | 45 | template{}> > 46 | array_iterator copy( 47 | array_iterator> f, 48 | array_iterator> l, 49 | array_iterator > d 50 | ){ 51 | assert(0); 52 | assert(f.stride() == l.stride()); static_assert(sizeof(From) == sizeof(To), "!"); 53 | auto n = std::distance(f, l); 54 | if(f.stride()==1 and d.stride()==1){ 55 | auto s = cudaMemcpy(raw_pointer_cast(d.data()), raw_pointer_cast(f.data()), n*sizeof(To), cudaMemcpyDeviceToHost); assert( s == cudaSuccess ); 56 | }else{ 57 | auto s = cudaMemcpy2D(raw_pointer_cast(d.data()), d.stride()*sizeof(To), raw_pointer_cast(f.data()), f.stride()*sizeof(To), sizeof(To), n, cudaMemcpyDeviceToDevice); 58 | assert( s == cudaSuccess ); 59 | } 60 | return d + n; 61 | } 62 | #endif 63 | 64 | }} 65 | } 66 | 67 | #endif // BOOST_MULTI_ADAPTORS_CUDA_ALGORITHMS_COPY_HPP 68 | -------------------------------------------------------------------------------- /examples/llnl_metall.cpp: -------------------------------------------------------------------------------- 1 | #ifdef COMPILATION // clang-format off 2 | ${CXX:-c++} -std=c++17 $CXXFLAGS -I../include -I$HOME/metall/include $0 -o$0.$X&&$0.$X&&rm $0.$X;exit 3 | #endif // clang-format on 4 | // Copyright 2019-2023 Alfredo A. Correa 5 | 6 | #include 7 | #include 8 | #include // for std::iota 9 | 10 | #include 11 | 12 | #include 13 | 14 | template 15 | using mallocator = metall::manager::allocator_type; 16 | 17 | namespace multi = boost::multi; 18 | 19 | template 20 | using marray = multi::array>; 21 | 22 | using std::tuple; 23 | 24 | int main() { 25 | std::filesystem::path const dir = "llnl_metall_mapped_file.bin/"; 26 | remove_all(dir); 27 | { 28 | metall::manager m{metall::create_only, dir.c_str(), 1 << 25}; 29 | 30 | auto&& arr1d = *m.construct>("arr1d")(std::tuple{10}, 5, m.get_allocator()); 31 | auto&& arr2d = *m.construct>("arr2d")(std::tuple{10, 10}, 1.0, m.get_allocator()); 32 | auto&& arr3d = *m.construct>("arr3d")(std::tuple{10, 10, 10}, 1u, m.get_allocator()); 33 | 34 | auto&& arr3d_copy = *m.construct>("arr3d_copy")(arr3d, m.get_allocator()); 35 | 36 | assert(arr1d[3] == 5); 37 | assert(arr2d[4][5] == 1.0); 38 | assert(arr3d[2][3][4] == 1U); 39 | 40 | arr1d[3] = 33; 41 | arr2d[4][5] = 45.001; 42 | std::iota(arr3d[6][7].begin(), arr3d[6][7].end(), 100); 43 | 44 | assert(arr3d_copy[6][7][8] == 1U); 45 | 46 | auto&& arr3d_assign = *m.construct>("arr3d_assign")(m.get_allocator()); 47 | arr3d_assign = arr3d; 48 | 49 | assert(arr3d_assign == arr3d); 50 | 51 | assert(arr3d_assign[6][7][8] == arr3d[6][7][8]); 52 | // m.flush(); 53 | } 54 | { 55 | metall::manager m{metall::open_only, dir.c_str()}; 56 | 57 | auto const& arr1d = *m.find>("arr1d").first; 58 | auto const& arr2d = *m.find>("arr2d").first; 59 | auto const& arr3d = *m.find>("arr3d").first; 60 | 61 | auto const& arr3d_copy = *m.find>("arr3d_copy").first; 62 | assert(std::addressof(arr3d)); 63 | 64 | auto const& arr3d_assign = *m.find>("arr3d_assign").first; 65 | assert(std::addressof(arr3d)); 66 | 67 | assert(arr1d[5] == 5); 68 | assert(arr1d[3] == 33); 69 | 70 | assert(arr2d[7][8] == 1.0); 71 | assert(arr2d[4][5] == 45.001); 72 | 73 | assert(arr3d[6][7][3] == 103); 74 | 75 | assert(arr3d_assign == arr3d); 76 | 77 | m.destroy>("arr1d"); 78 | m.destroy>("arr2d"); 79 | m.destroy>("arr3d"); 80 | m.destroy>("arr3d_copy"); 81 | m.destroy>("arr3d_assign"); 82 | } 83 | 84 | remove_all(dir); 85 | } -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/test/swap.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | 3 | #define BOOST_TEST_MODULE "C++ Unit Tests for Multi BLAS swap" 4 | // #include 5 | 6 | #include "../../blas.hpp" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace multi = boost::multi; 14 | 15 | BOOST_AUTO_TEST_CASE(lapack_potrf, *boost::unit_test::tolerance(0.00001)) { 16 | { 17 | multi::array A = { 18 | {1.0, 2.0, 3.0, 4.0}, 19 | {5.0, 6.0, 7.0, 8.0}, 20 | {9.0, 10.0, 11.0, 12.0}, 21 | }; 22 | BOOST_REQUIRE( A[0][2] == 3.0 ); 23 | BOOST_REQUIRE( A[2][2] == 11.0 ); 24 | 25 | multi::blas::swap(A[0], A[2]); // blas swap 26 | BOOST_REQUIRE( A[0][2] == 11.0 ); 27 | BOOST_REQUIRE( A[2][2] == 3.0 ); 28 | 29 | swap(A[0], A[2]); // built-in swap 30 | BOOST_REQUIRE( A[0][2] == 3.0 ); 31 | BOOST_REQUIRE( A[2][2] == 11.0 ); 32 | } 33 | { 34 | multi::array A = { 35 | {1.0, 2.0, 3.0, 4.0}, 36 | {5.0, 6.0, 7.0, 8.0}, 37 | {9.0, 10.0, 11.0, 12.0}, 38 | }; 39 | BOOST_REQUIRE( A[0][0] == 1.0 ); 40 | BOOST_REQUIRE( A[0][3] == 4.0 ); 41 | 42 | multi::blas::swap(rotated(A)[0], rotated(A)[3]); // blas swap (deep) 43 | BOOST_REQUIRE( A[0][0] == 4.0 ); 44 | BOOST_REQUIRE( A[0][3] == 1.0 ); 45 | 46 | swap(rotated(A)[0], rotated(A)[3]); // built-in swap (deep) 47 | BOOST_REQUIRE( A[0][0] == 1.0 ); 48 | BOOST_REQUIRE( A[0][3] == 4.0 ); 49 | } 50 | { 51 | using complex = std::complex; 52 | complex const I{0, 1}; 53 | multi::array A = { 54 | {1.0 + 2. * I, 2.0, 3.0, 4.0 + 3.0 * I}, 55 | { 5.0, 6.0, 7.0, 8.0}, 56 | { 9.0, 10.0, 11.0, 12.0}, 57 | }; 58 | BOOST_REQUIRE( A[0][0] == 1.0 + 2.0*I ); 59 | BOOST_REQUIRE( A[0][3] == 4.0 + 3.0*I ); 60 | 61 | multi::blas::swap(rotated(A)[0], rotated(A)[3]); // blas swap (deep) 62 | BOOST_REQUIRE( A[0][0] == 4.0 + 3.0*I ); 63 | BOOST_REQUIRE( A[0][3] == 1.0 + 2.0*I ); 64 | 65 | swap(rotated(A)[0], rotated(A)[3]); // built-in swap (deep) 66 | BOOST_REQUIRE( A[0][0] == 1.0 + 2.0*I ); 67 | BOOST_REQUIRE( A[0][3] == 4.0 + 3.0*I ); 68 | } 69 | { 70 | multi::array A = { 71 | {1.0, 2.0, 3.0, 4.0}, 72 | {5.0, 6.0, 7.0, 8.0}, 73 | {9.0, 10.0, 11.0, 12.0}, 74 | }; 75 | BOOST_REQUIRE( A[0][2] == 3.0 ); 76 | BOOST_REQUIRE( A[2][2] == 11.0 ); 77 | 78 | auto it = multi::blas::swap(begin(A[0]), end(A[0]) - 1, begin(A[2])); // blas swap 79 | BOOST_REQUIRE( it == end(A[2]) - 1 ); 80 | BOOST_REQUIRE( A[0][2] == 11.0 ); 81 | BOOST_REQUIRE( A[2][2] == 3.0 ); 82 | 83 | using std::swap_ranges; 84 | swap_ranges(begin(A[0]), end(A[0]), begin(A[2])); // built-in swap 85 | BOOST_REQUIRE( A[0][2] == 3.0 ); 86 | BOOST_REQUIRE( A[2][2] == 11.0 ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # # Copyright 2020-2025 Alfredo A. Correa 2 | 3 | image: debian:stable 4 | 5 | workflow: 6 | auto_cancel: 7 | on_new_commit: interruptible 8 | rules: 9 | - if: $CI_COMMIT_TAG 10 | - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 11 | - if: $CI_PIPELINE_SOURCE == 'merge_request_event' 12 | 13 | variables: 14 | GIT_SUBMODULE_STRATEGY: recursive 15 | CODECOV_TOKEN: "999feb5b-a599-4d02-b9c5-46d977247f3a" 16 | RT_VERSION: "0.1" 17 | NVIDIA_DISABLE_REQUIRE: 1 # disable nvidia driver check 18 | SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache 19 | GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task 20 | 21 | g++: # debian-stable: default is gcc 12.2.0 as of April 2024 22 | stage: build 23 | interruptible: false 24 | script: 25 | - apt-get -qq update && apt-get -qq install --no-install-recommends -y --quiet ca-certificates cmake g++ make libboost-timer-dev libboost-serialization-dev libblas-dev liblapack-dev libfftw3-dev pkg-config 26 | - g++ --version 27 | - mkdir build && cd build 28 | - cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-D_GLIBCXX_DEBUG=1" 29 | - cmake --build . --parallel 2 || cmake --build . --verbose 30 | - ctest -j 2 --output-on-failure 31 | 32 | clang++: 33 | stage: build 34 | # tags: 35 | # - non-shared 36 | interruptible: false 37 | script: 38 | - apt-get -qq update && apt-get -qq install --no-install-recommends -y --quiet clang cmake make libboost-timer-dev libboost-serialization-dev libblas-dev libfftw3-dev liblapack-dev pkg-config 39 | - mkdir build && cd build 40 | - clang++ --version 41 | - CXX=clang++ cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-D_GLIBCXX_DEBUG=1" 42 | - cmake --build . --parallel 2 || cmake --build . --parallel 1 --verbose 43 | - ctest -j 2 --output-on-failure 44 | except: 45 | - gitlab-org 46 | 47 | clang++-latest libc++: 48 | stage: build 49 | #image: debian:latest 50 | # tags: 51 | # - non-shared 52 | interruptible: true 53 | script: 54 | - apt-get -qq update && apt-get -qq install --no-install-recommends -y --quiet ca-certificates clang cmake make libboost-timer-dev libboost-serialization-dev libblas-dev libc++-dev libc++abi-dev libfftw3-dev liblapack-dev pkg-config tar wget 55 | - mkdir build && cd build 56 | - clang++ --version 57 | - CXX=clang++ cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-stdlib=libc++ -DBOOST_NO_CXX98_FUNCTION_BASE -D_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG" 58 | - cmake --build . --parallel 2 || cmake --build . --parallel 1 --verbose 59 | - ctest -j 2 --output-on-failure 60 | needs: ["clang++"] 61 | except: 62 | - gitlab-org 63 | 64 | -------------------------------------------------------------------------------- /examples/cai_1d_heat.cpp: -------------------------------------------------------------------------------- 1 | #if COMPILE_RUN_INSTRUCTIONS 2 | ${CXX:-c++} -std=c++2b $0 -I../include && ./a.out; exit 3 | #endif 4 | #include 5 | 6 | #include // for std::exp 7 | #include 8 | #include 9 | 10 | namespace multi = boost::multi; 11 | namespace stv = std::views; 12 | 13 | void plot(auto const& x, auto const& f, std::string const& title = "") { 14 | assert(x.size() == f.size()); 15 | std::cout << "set title '" << title << "'\n" 16 | << "plot '-' with linespoints\n"; 17 | for(auto i : x.extension()) { 18 | std::cout << x[i] << " " << f[i] << "\n"; 19 | } 20 | std::cout << 'e' << std::endl 21 | << "pause 0.1\n"; 22 | } 23 | 24 | template 25 | auto append(Range const& range, T const& value) { 26 | return stv::iota(typename Range::size_type{}, range.size() + 1) | stv::transform([&](auto i) -> decltype(auto) {return (i 30 | auto prepend(Range const& range, T const& value) { 31 | return stv::iota(typename Range::size_type{}, range.size() + 1) | stv::transform([&](auto i) -> decltype(auto) {return (i==0)?value:range[i-1];}); 32 | } 33 | 34 | auto main() -> int { 35 | 36 | using multi::operator+; 37 | 38 | // dx = 0.2; 39 | // x = [0:1:20]*dx; 40 | // f = x.*exp(-x.^2); 41 | // plot(x, f, 'ro'); 42 | 43 | auto dx = 0.2; 44 | auto x = +(stv::iota(0, 20) | stv::transform([dx](auto i) { return i * dx; })); 45 | auto f = +(x | stv::transform([](auto e) { return e * std::exp(-e * e); })); 46 | plot(x, f); 47 | 48 | // f_my_left = [NaN, f(1:end-1)]; 49 | // f_my_right = [f(2:end), NaN]; 50 | // d2f = (f_my_right - 2*f + f_my_left)/(dx^2); 51 | auto f_my_left = +prepend(f.taked(f.size() - 1), NAN); 52 | auto f_my_right = +append(f.dropped(1), NAN); 53 | auto d2f = +stv::zip_transform([dx2 = dx * dx](auto r, auto m, auto l) { return (r - 2 * m + l) / dx2; }, f_my_right, f, f_my_left); 54 | 55 | // dt = 0.01; D = 1; 56 | // for k=1:100, 57 | // f_my_left = [NaN, f(1:end-1)]; 58 | // f_my_right = [f(2:end), NaN]; 59 | // d2f = (f_my_right - 2*f + f_my_left)/(dx^2); 60 | // f(2:end-1) = f(2:end-1) + D*dt*d2f(2:end-1); 61 | // plot(x, f, 'ro-'); ylim([0 0.45]); drawnow 62 | // pause(0.1) 63 | // end 64 | 65 | auto dt = 0.01; 66 | auto D = 1.0; 67 | for(auto k = 0; k != 100; ++k) { 68 | f_my_left({1, f.size()}) = f({0, f.size() - 1}); 69 | f_my_right({0, f.size() - 1}) = f({1, f.size()}); 70 | 71 | d2f = stv::zip_transform([dx2 = dx * dx](auto r, auto m, auto l) { return (r - 2 * m + l) / dx2; }, f_my_right, f, f_my_left); 72 | f({1, f.size() - 1}) = stv::zip_transform([&](auto eff, auto d2) { return eff + D * dt * d2; }, f({1, f.size() - 1}), d2f({1, f.size() - 1})); 73 | plot(x, f, "k=" + std::to_string(k)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/numeric/is_complex.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_BLAS_NUMERIC_IS_COMPLEX_HPP 6 | #define BOOST_MULTI_ADAPTORS_BLAS_NUMERIC_IS_COMPLEX_HPP 7 | 8 | #include 9 | #include 10 | 11 | namespace boost::multi::blas::numeric { 12 | 13 | using std::true_type; 14 | using std::false_type; 15 | 16 | template auto has_real_fun_aux(T const& value) -> decltype(real(value), true_type{}); 17 | auto has_real_fun_aux(... ) -> decltype( false_type{}); 18 | template struct has_real_fun : decltype(has_real_fun_aux(std::declval())){}; 19 | template constexpr bool has_real_fun_v = has_real_fun::value; 20 | 21 | template auto has_real_aux(T const& value) -> decltype(value.real(), true_type{}); 22 | auto has_real_aux(... ) -> decltype( false_type{}); 23 | template struct has_real : decltype(has_real_aux(std::declval())){}; 24 | template constexpr bool has_real_v = has_real::value; 25 | 26 | template auto has_imag_fun_aux(T const& value) -> decltype(imag(value), true_type{}); 27 | auto has_imag_fun_aux(... ) -> decltype( false_type{}); 28 | template struct has_imag_fun : decltype(has_imag_fun_aux(std::declval())){}; 29 | template constexpr bool has_imag_fun_v = has_imag_fun::value; 30 | 31 | template auto has_imag_aux(T const& value) ->decltype(value.imag(), true_type{}); 32 | auto has_imag_aux(... ) ->decltype( false_type{}); 33 | template struct has_imag : decltype(has_imag_aux(std::declval())){}; 34 | template constexpr bool has_imag_v = has_imag::value; 35 | 36 | template struct is_complex : std::integral_constant || has_real_fun_v) && (has_imag_v || has_imag_fun_v) 38 | >{}; 39 | 40 | template auto real_is_aux(T const& value) -> typename std::is_same; 41 | template auto real_is_aux(... ) -> false_type; 42 | template struct real_is : decltype(real_is_aux(std::declval())){}; 43 | 44 | template auto imag_is_aux(T const& value) -> typename std::is_same; 45 | template auto imag_is_aux(... ) -> false_type; 46 | template struct imag_is : decltype(imag_is_aux(std::declval())){}; 47 | 48 | template struct is_complex_of : std::integral_constant::value && imag_is::value>{}; 49 | 50 | } // end namespace boost::multi::blas::numeric 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /test/Jamfile: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Matt Borland 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # https://www.boost.org/LICENSE_1_0.txt 4 | 5 | import testing ; 6 | import ../../config/checks/config : requires ; 7 | 8 | project : requirements 9 | 10 | # /boost/test//boost_unit_test_framework 11 | 12 | gcc:-Wall 13 | gcc:-Wextra 14 | 15 | clang:-Wall 16 | clang:-Wextra 17 | 18 | msvc:all 19 | 20 | # Additional flags by request 21 | gcc:-Wsign-conversion 22 | gcc:-Wconversion 23 | #gcc:-Wundef # Fix pending in Boost.Test 24 | gcc:-Wold-style-cast 25 | #gcc:-Wduplicated-branches 26 | gcc:-Wfloat-equal 27 | 28 | clang:-Wsign-conversion 29 | clang:-Wconversion 30 | clang:-Wundef 31 | clang:-Wold-style-cast 32 | clang:-Wfloat-equal 33 | 34 | # Clang-Cl likes to blow up builds with these compatibility checks 35 | clang:-Wno-c++98-compat 36 | clang:-Wno-c++98-compat-pedantic 37 | clang:-Wno-c++17-compat 38 | clang:-Wno-c++14-compat 39 | clang:"_CRT_SECURE_NO_WARNINGS" 40 | 41 | msvc:on 42 | #clang:on 43 | gcc:on 44 | 45 | [ requires cxx17_if_constexpr cxx17_structured_bindings cxx17_std_apply ] 46 | ; 47 | 48 | run allocator.cpp ; 49 | run array_cref.cpp ; 50 | run array_fancyref.cpp ; 51 | run array_legacy_c.cpp ; 52 | run array_ptr.cpp ; 53 | run array_ref.cpp ; 54 | run assignments.cpp ; 55 | #run boost_array_concept.cpp ; 56 | run comparisons.cpp ; 57 | run concepts.cpp ; 58 | run constructors.cpp ; 59 | run conversions.cpp ; 60 | run diagonal.cpp ; 61 | run element_access.cpp ; 62 | run element_transformed.cpp ; 63 | #run execution_policy.cpp ; 64 | run fill.cpp ; 65 | run fix_complex.cpp ; 66 | run flatted.cpp ; 67 | run index_range.cpp ; 68 | run initializer_list.cpp ; 69 | run iterator.cpp ; 70 | run layout.cpp ; 71 | run member_array_cast.cpp ; 72 | run minimalistic_ptr.cpp ; 73 | run move.cpp ; 74 | run nico_const_correctness.cpp ; 75 | run one_based.cpp ; 76 | run overload.cpp ; 77 | run partitioned.cpp ; 78 | run pmr.cpp ; 79 | run ranges.cpp ; 80 | run reextent.cpp ; 81 | run reinterpret_array_cast.cpp ; 82 | run reversed.cpp ; 83 | run rotated.cpp ; 84 | run scoped_allocator.cpp ; 85 | run select_column.cpp ; 86 | run sliced.cpp ; 87 | run sort.cpp ; 88 | run static_array_cast.cpp ; 89 | run std_vector_substitutability.cpp ; 90 | run subrange.cpp ; 91 | run transform.cpp ; 92 | run utility.cpp ; 93 | run zero_dimensionality.cpp ; 94 | -------------------------------------------------------------------------------- /doc/multi/intro.adoc: -------------------------------------------------------------------------------- 1 | [#intro] 2 | 3 | = Introduction 4 | 5 | :idprefix: intro_ 6 | 7 | _Multi_ is a modern C++ library that provides manipulation and access of data in multidimensional arrays for both CPU and GPU memory. 8 | 9 | Multidimensional array data structures are fundamental to several branches of computing, such as data analysis, image processing, and scientific simulations, and, in combination with GPUs, to Artificial Intelligence and Machine Learning. 10 | This library offers array containers and subarrays in arbitrary dimensions with well-behaved value semantics, 11 | featuring logical access recursively across dimensions and to elements through indices and iterators. 12 | 13 | The internal data structure layout is stride-based, which makes it compatible with low-level C libraries. 14 | 15 | The library interface is designed to be compatible with standard algorithms and ranges (STL) and special memory (including GPUs) and follows modern C++ design principles. 16 | 17 | Features of this library that aim to facilitate the manipulation of multidimensional arrays include: 18 | 19 | * Value semantics of multidimensional array containers and well-defined referential semantics to avoid unnecessary copies if possible. 20 | * Availability of different access patterns to the elements in the multidimensional structure, as nested sequences or as a single sequence of elements. 21 | A _D_-dimensional array can be interpreted either as an (STL-compatible) sequence of (_D_-1)-dimensional subarrays or as a flattened one-dimensional (also STL-compatible) sequence of elements. 22 | * Interoperability with both legacy C and modern C++ libraries (e.g., STL, ranges, Thrust --CUDA and AMD GPUs--, Boost). 23 | * Memory management and allocation to exploit modern memory spaces, including GPU memory, mapped memory, and fancy pointers. 24 | 25 | Do not confuse this library with 26 | https://www.boost.org/doc/libs/1_69_0/libs/multi_array/doc/index.html[Boost.MultiArray] 27 | or with the standard MDSpan proposal `std::mdspan`. 28 | This library shares some of their goals and is compatible with them, but it is designed at a different level of generality and with other priorities (such as the features listed above). 29 | The code is entirely independent and has fundamental implementation and semantics differences. 30 | 31 | The library's primary concern is with the storage and logic structure of data; 32 | it doesn't make algebraic or geometric assumptions about the arrays and their elements. 33 | (It is still a good building block for implementing mathematical algorithms, such as representing algebraic dense matrices in the 2D case.) 34 | 35 | The library does not throw exceptions and provides basic guarantees (such as no memory leaks) in their presence (e.g., thrown from allocations). 36 | Indexing and other logical errors result in undefined behavior, which this library attempts to reflect via assertions. 37 | 38 | _Multi_ is a header-only library and C++17 or later is required. 39 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/test/asum.cpp: -------------------------------------------------------------------------------- 1 | // -*-indent-tabs-mode:t;c-basic-offset:4;tab-width:4;autowrap:nil;-*- 2 | // Copyright 2019-2024 Alfredo A. Correa 3 | 4 | #define BOOST_TEST_MODULE "C++ Unit Tests for Multi BLAS asum" 5 | // #include 6 | 7 | #include "../../../adaptors/cuda.hpp" 8 | #include "../../../array.hpp" 9 | #include "../../blas/asum.hpp" 10 | #include "../../blas/cuda.hpp" 11 | 12 | #include "multi/adaptors/complex.hpp" 13 | 14 | #include 15 | #include 16 | 17 | namespace multi = boost::multi; 18 | 19 | BOOST_AUTO_TEST_CASE(const multi_blas_asum_double) { 20 | multi::array const A = { 21 | {1.0, 2.0, 3.0, 4.0}, 22 | {5.0, 6.0, 7.0, 8.0}, 23 | {9.0, 10.0, 11.0, 12.0}, 24 | }; 25 | using multi::blas::asum; 26 | BOOST_REQUIRE(asum(A[1]) == std::accumulate(begin(A[1]), end(A[1]), 0.0, [](auto&& a, auto&& b) { return a + std::abs(b); })); 27 | } 28 | 29 | BOOST_AUTO_TEST_CASE(const multi_blas_asum_complex) { 30 | using Z = multi::complex; // std::complex; 31 | 32 | auto const I = Z{0.0, 1.0}; 33 | 34 | multi::array const A = { 35 | {1.0 + 2.0 * I, 2.0, 3.0, 4.0}, 36 | { 5.0, 6.0 + 3.0 * I, 7.0, 8.0}, 37 | { 9.0, 10.0, 11.0 + 4.0 * I, 12.0}, 38 | }; 39 | 40 | using multi::blas::asum; 41 | BOOST_REQUIRE( 42 | asum(A[1]) == std::accumulate( 43 | begin(A[1]), end(A[1]), 0.0, 44 | [](auto&& a, auto&& b) { return a + std::abs(real(b)) + std::abs(imag(b)); } 45 | ) 46 | ); 47 | } 48 | 49 | BOOST_AUTO_TEST_CASE(const multi_blas_asum_double_cuda) { 50 | multi::cuda::array const A = { 51 | {1.0, 2.0, 3.0, 4.0}, 52 | {5.0, 6.0, 7.0, 8.0}, 53 | {9.0, 10.0, 11.0, 12.0}, 54 | }; 55 | using multi::blas::asum; 56 | BOOST_REQUIRE(asum(A[1]) == 26.0 ); 57 | } 58 | 59 | using complex = multi::complex; 60 | constexpr auto I = complex{0.0, 1.0}; 61 | 62 | BOOST_AUTO_TEST_CASE(const multi_blas_asum_complex_cuda) { 63 | namespace blas = multi::blas; 64 | 65 | multi::cuda::array const A = { 66 | {1.0 + 2.0 * I, 2.0 , 3.0 , 4.0}, 67 | {5.0 , 6.0 + 3.0 * I, 7.0 , 8.0}, 68 | {9.0 , 10.0 , 11.0 + 4.0 * I, 12.0}, 69 | }; 70 | 71 | BOOST_REQUIRE( blas::asum(A[1] ) == 29.0 ); 72 | BOOST_REQUIRE( blas::asum(A[1]({0, 4})) == 29.0 ); 73 | } 74 | 75 | BOOST_AUTO_TEST_CASE(const multi_blas_asum_complex_cuda_mutable) { 76 | using Z = multi::complex; 77 | 78 | auto const I = Z{0.0, 1.0}; 79 | 80 | multi::cuda::array const A = { 81 | {1.0 + 2.0 * I, 2.0 , 3.0 , 4.0}, 82 | {5.0 , 6.0 + 3.0 * I, 7.0 , 8.0}, 83 | {9.0 , 10.0 , 11.0 + 4.0 * I, 12.0}, 84 | }; 85 | 86 | using multi::blas::asum; 87 | BOOST_REQUIRE( asum(A[1] ) == Z{29.0} ); 88 | BOOST_REQUIRE( asum(A[1]({0, 4})) == Z{29.0} ); 89 | } 90 | -------------------------------------------------------------------------------- /doc/multi/primer.adoc: -------------------------------------------------------------------------------- 1 | [#primer] 2 | 3 | = Primer (basic usage) 4 | 5 | :idprefix: primer_ 6 | 7 | In this example, we initialize a 2-dimensional array of numbers, and then we inspect the properties of this array, copy the array, and manipulate the element values. 8 | The example can be followed link:https://godbolt.org/z/b8ao5Wz1T[online]. 9 | 10 | The individual elements are initialized from a nested rectangular list. 11 | ```cpp 12 | multi::array A = { 13 | {1.0, 2.0, 3.0}, 14 | {4.0, 5.0, 6.0}, 15 | }; 16 | 17 | auto const [n, m] = A.sizes(); 18 | 19 | assert( n == 2 ); // or std::get<0>(A.sizes()) == 2 20 | assert( m == 3 ); // or std::get<1>(A.sizes()) == 3 21 | 22 | assert( A.size() == 2 ); // size in first dimension, same as std::get<0>(A.sizes()) 23 | assert( A.num_elements() == 6 ); // total number of elements 24 | ``` 25 | 26 | Individual elements can be accessed by the multidimensional indices, using brackets. 27 | 28 | ```cpp 29 | assert( A[1][2] == 6.0 ); 30 | ``` 31 | 32 | The value of an array can be copied, (moved,) and compared; 33 | copies are equal but independent (disjoint). 34 | 35 | ```cpp 36 | std::array B = A; // we make a copy 37 | 38 | assert( B == A ); // copies are equal 39 | assert( B.extensions() == A.extensions() ); // extensions (sizes) are equal 40 | assert( B[0][1] == A[0][1] ); // all elements are equal 41 | assert( &B[0][1] != &A[0][1] ); // elements are independent (dfferent addresses) 42 | ``` 43 | 44 | An array can be initialized from its sizes alone, in which case the element values are defaulted: 45 | 46 | ```cpp 47 | multi::array C({3, 4, 5}); 48 | assert( C.num_elements() == 3*4*5 ); // 60 elements with unspecified values 49 | ``` 50 | 51 | Arrays can be passed by value or by reference. 52 | Most of the time, arguments should be passed through generic parameters to also allow functions to work with parts (subblocks, slices, etc.) of an array. 53 | The most useful functions work on the _concept_ of an array rather than on a concrete type, for example: 54 | 55 | ```cpp 56 | template // instead of the overspecific argument std::array 57 | auto element_1_1(ArrayDouble2D const& m) -> double const& { return m[1][1]; } 58 | ... 59 | assert( &element_1_1(A) == &A[1][1] ); 60 | ``` 61 | 62 | The function expects any array or subarray of dimension 2 (or greater) and returns an element with type `double`. 63 | 64 | The generic function template arguments that are not intended to be modified are passed by `const&`; otherwise, they are passed by forward-reference `&&`. 65 | In this way, the functions can be applied to subblocks of larger matrices. 66 | 67 | ```cpp 68 | assert( &element_1_1(C[0]) == &C[0][1][1] ); 69 | ``` 70 | 71 | (Although most of the examples use numeric elements for conciseness, the library is designed to hold general types (e.g. non-numeric, non-trivial types, like `std::string`, other containers or, in general, user-defined value-types.) 72 | -------------------------------------------------------------------------------- /examples/lu_fact.cpp: -------------------------------------------------------------------------------- 1 | #ifdef COMPILATION// -*-indent-tabs-mode:t;c-basic-offset:4;tab-width:4;-*- 2 | $CXX $0 -o $0x -lboost_timer `pkg-config --libs tbb` &&$0x&&rm $0x;exit 3 | #endif 4 | // Copyright 2018-2024 Alfredo A. Correa 5 | 6 | #include "../../multi/array.hpp" 7 | 8 | #include // transform 9 | #include 10 | #include 11 | #include // iota 12 | 13 | #include 14 | 15 | namespace multi = boost::multi; 16 | 17 | template 18 | Matrix&& lu_fact(Matrix&& A){ 19 | using multi::size; 20 | auto m = size(A);// n = size(A[0]);//std::get<1>(sizes(A)); 21 | using std::begin; using std::end; using multi::rotated; 22 | for(auto k = 0*m; k != std::min(m - 1, size(rotated(A))); ++k){ 23 | auto const& Ak = A[k]; 24 | auto const& Akk = Ak[k]; 25 | std::for_each(std::execution::par, 26 | begin(A) + k + 1, end(A), [&](auto&& Ai){ 27 | std::transform( 28 | begin(Ai)+k+1, end(Ai), begin(Ak)+k+1, begin(Ai)+k+1, 29 | [z=(Ai[k]/=Akk)](auto a, auto b){return a - z*b;} 30 | ); 31 | } 32 | ); 33 | } 34 | return std::forward(A); 35 | } 36 | 37 | template 38 | Matrix&& lu_fact2(Matrix&& A){ 39 | using multi::size; 40 | auto const [m, n] = A.sizes(); 41 | 42 | for(decltype(m) k = 0; k != m - 1; ++k){ 43 | for(auto i = k + 1; i != m; ++i){ 44 | auto const z = A[i][k]/A[k][k]; 45 | A[i][k] = z; 46 | std::transform(begin(A[i]) + k + 1, begin(A[i]) + std::max(n, k + 1), A[k].begin() + k + 1, begin(A[i]) + k + 1, [&](auto a, auto b){return a - z*b;}); 47 | } 48 | } 49 | return std::forward(A); 50 | } 51 | 52 | template 53 | Matrix&& lu_fact3(Matrix&& A){ 54 | using multi::size; 55 | auto const [m, n] = A.sizes(); 56 | for(auto k = 0*m; k != m - 1; ++k){ 57 | auto&& Ak = A[k]; 58 | std::for_each(std::execution::par, begin(A) + k + 1, end(A), [&](auto& Ai){ 59 | auto const z = Ai[k]/Ak[k]; 60 | Ai[k] = z; 61 | assert( k + 1 <= n ); 62 | for(auto j = k + 1; j < n; ++j) Ai[j] -= z*Ak[j]; 63 | }); 64 | } 65 | return std::forward(A); 66 | } 67 | 68 | using std::cout; 69 | int main(){ 70 | { 71 | multi::array A = { 72 | {-3.0, 2.0, -4.0}, 73 | { 0.0, 1.0, 2.0}, 74 | { 2.0, 4.0, 5.0}, 75 | }; 76 | multi::array y = {12.0, 5.0, 2.0}; 77 | double AA[3][3]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) test legacy types 78 | using std::copy; 79 | copy( begin(A), end(A), begin(*multi::array_ptr(&AA)) ); 80 | 81 | lu_fact(A); 82 | lu_fact(AA); 83 | assert( std::equal(begin(A), end(A), begin(*multi::array_ptr(&AA)), end(*multi::array_ptr(&AA))) ); 84 | } 85 | { 86 | multi::array A({6000, 7000}); std::iota(A.data(), A.data() + A.num_elements(), 0.1); 87 | std::transform(A.data(), A.data() + A.num_elements(), A.data(), [](auto x){return x/=2.0e6;}); 88 | { 89 | boost::timer::auto_cpu_timer t; 90 | lu_fact(A({3000, 6000}, {0, 4000})); 91 | cout << A[456][123] << std::endl; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cufft/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | 3 | set(CMAKE_VERBOSE_MAKEFILE ON) 4 | 5 | project( 6 | boost-multi-adaptors-blas-test 7 | VERSION 0.1 8 | LANGUAGES CXX 9 | ) 10 | 11 | # set(CMAKE_CXX_STANDARD 17) 12 | # set(CMAKE_CXX_STANDARD_REQUIRED ON) 13 | # set(CMAKE_CXX_EXTENSIONS OFF) 14 | 15 | if(NOT 16 | CMAKE_CXX_COMPILER_ID 17 | STREQUAL 18 | "PGI" 19 | ) 20 | find_package(Boost CONFIG) 21 | else() 22 | find_package(Boost CONFIG) 23 | # find_package(Boost REQUIRED) # cmake cannot detect this component with pgi compiler 24 | endif() 25 | 26 | if(ENABLE_CUDA OR DEFINED CXXCUDA) 27 | enable_language(CUDA) 28 | if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) 29 | set(CMAKE_CUDA_ARCHITECTURES native) 30 | endif() 31 | 32 | # set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr --extended-lambda") 33 | # find_package(CUDA QUIET) 34 | find_package(CUDAToolkit REQUIRED COMPONENTS cuFFT) 35 | # if(CUDA_FOUND) 36 | # message("CUDA found") 37 | # include_directories(${CUDA_INCLUDE_DIRS}) 38 | # # set(INQ_CUDA_LIBRARIES ${CUDA_CUFFT_LIBRARIES} ${CUDA_cusolver_LIBRARY} ${CUDA_CUBLAS_LIBRARIES}) 39 | # # link_libraries(${INQ_CUDA_LIBRARIES}) 40 | # else() 41 | # message("CUDA not found") 42 | # endif() 43 | endif() 44 | 45 | # FFTW has to go before blas to avoid unscrupulous (i.e. MKL) blas implementations that include FFTW and don't implement it properly 46 | find_package(PkgConfig) 47 | 48 | if(NOT PKG_CONFIG_FOUND) 49 | message(WARNING "pkgconfig not found (for FFTW). cuFFT tests needs FFTW.") 50 | return() 51 | endif() 52 | 53 | pkg_search_module( 54 | FFTW 55 | REQUIRED 56 | fftw3 57 | IMPORTED_TARGET 58 | ) 59 | include_directories(PkgConfig::FFTW) 60 | link_libraries(PkgConfig::FFTW) 61 | 62 | enable_testing() 63 | list(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure") # needs cmake 3.17 64 | include(CTest) 65 | 66 | include_directories(${CMAKE_BINARY_DIR}) 67 | 68 | # file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) 69 | set(TEST_SRCS cufft.cpp) 70 | 71 | foreach(TEST_FILE ${TEST_SRCS}) 72 | set(TEST_EXE "${TEST_FILE}.x") 73 | add_executable(${TEST_EXE} ${TEST_FILE}) 74 | if(ENABLE_CUDA OR DEFINED CXXCUDA) 75 | set_source_files_properties(${TEST_FILE} PROPERTIES LANGUAGE CUDA) 76 | # target_compile_options(${TEST_EXE} PRIVATE -std=c++17) 77 | endif() 78 | # target_compile_features (${TEST_EXE} PUBLIC cxx_std_17) 79 | 80 | target_compile_options( 81 | ${TEST_EXE} PRIVATE 82 | $<$>:-Wno-error=terminate> 83 | ) 84 | 85 | target_compile_definitions(${TEST_EXE} PRIVATE ${Boost_DEFINITIONS}) 86 | target_include_directories(${TEST_EXE} PRIVATE ${Boost_INCLUDE_DIRS}) 87 | 88 | target_link_libraries(${TEST_EXE} PRIVATE ${Boost_LIBRARIES}) 89 | target_link_directories(${TEST_EXE} PRIVATE ${Boost_LIBRARY_DIRS}) 90 | target_link_libraries(${TEST_EXE} PRIVATE multi) 91 | target_link_libraries(${TEST_EXE} PRIVATE CUDA::cufft) 92 | 93 | add_test(NAME ${TEST_EXE} COMMAND $) 94 | endforeach() 95 | -------------------------------------------------------------------------------- /test/sean.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | 7 | #include // IWYU pragma: keep 8 | 9 | #include // IWYU pragma: keep // for std::equal 10 | #include // IWYU pragma: keep 11 | #include // IWYU pragma: keep // for std::tuple // NOLINT(misc-include-cleaner) 12 | 13 | #if defined(__cplusplus) && (__cplusplus >= 202002L) && __has_include() 14 | #include // for constructible_from, defau... 15 | #include // IWYU pragma: keep 16 | #include // for is_constructible_v 17 | #endif 18 | 19 | namespace multi = boost::multi; 20 | 21 | auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-cognitive-complexity) 22 | { 23 | #ifdef __NVCC__ 24 | auto fun = [](auto ii, auto jj) noexcept { return static_cast((10 * ii) + jj); }; 25 | auto rst = fun ^ multi::extensions_t(5, 5); 26 | #else 27 | auto rst = [](auto ii, auto jj) noexcept { return static_cast((10 * ii) + jj); } ^ multi::extensions_t(5, 5); 28 | #endif 29 | multi::array const AA = rst; 30 | 31 | BOOST_TEST( AA.size() == rst.size() ); 32 | BOOST_TEST( AA.extensions() == rst.extensions() ); 33 | 34 | #if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) && !defined(_MSC_VER) 35 | multi::array const BB = rst | std::ranges::views::reverse; 36 | 37 | BOOST_TEST( AA[0] == BB[4] ); // as A[0][0] == B[4][0] && A[0][1] == B[4][1] ... 38 | BOOST_TEST( AA[1] == BB[3] ); // as A[1][0] == B[3][0] && A[1][1] == B[3][1] ... 39 | BOOST_TEST( AA[2] == BB[2] ); // ... 40 | BOOST_TEST( AA[3] == BB[1] ); 41 | BOOST_TEST( AA[4] == BB[0] ); 42 | #endif 43 | 44 | auto rstT = rst.transposed(); 45 | 46 | using std::get; 47 | BOOST_TEST( get<0>(rstT.extensions()) == get<1>(rst.extensions()) ); 48 | BOOST_TEST( get<1>(rstT.extensions()) == get<0>(rst.extensions()) ); 49 | 50 | BOOST_TEST( rstT[1][2] == rst[2][1] ); 51 | 52 | #if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) && !defined(_MSC_VER) 53 | static_assert(std::weakly_incrementable); 54 | static_assert(std::input_or_output_iterator); 55 | BOOST_TEST( rstT.begin() == std::ranges::begin(rstT) ); 56 | 57 | static_assert(std::constructible_from); 58 | static_assert(std::default_initializable); 59 | static_assert(std::is_constructible_v); 60 | static_assert(std::semiregular); 61 | BOOST_TEST( rstT.end() == std::ranges::end(rstT) ); 62 | 63 | static_assert(std::ranges::viewable_range); 64 | auto rstTR = rstT | std::ranges::views::reverse; 65 | 66 | BOOST_TEST( rstTR.back()[0] == rstT.front()[0] ); 67 | BOOST_TEST( rstTR.front()[0] == rstT.back()[0] ); 68 | 69 | auto rstTR2 = rstT.reversed(); 70 | 71 | BOOST_TEST( rstTR2[3][4] == rstTR[3][4] ); 72 | #endif 73 | } 74 | 75 | return boost::report_errors(); 76 | } 77 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/allocator_traits.hpp: -------------------------------------------------------------------------------- 1 | #ifdef COMPILATION_INSTRUCTIONS 2 | (echo "#include\""$0"\"" > $0.cpp) && nvcc -ccbin cuda-c++ --compiler-options "-std=c++14" -I$HOME/prj/alf -D_TEST_MULTI_ADAPTORS_THRUST_ALLOCATOR_TRAITS $0.cpp -o $0x && $0x && rm $0.cpp $0x; exit 3 | #endif 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_THRUST_HPP 6 | #define BOOST_MULTI_ADAPTORS_THRUST_HPP 7 | 8 | #include "../../detail/memory.hpp" 9 | 10 | #include 11 | 12 | #include 13 | 14 | namespace thrust { 15 | template device_ptr to_address(device_ptr p) {return p;} 16 | } // end namespace thrust 17 | 18 | namespace boost { 19 | namespace multi { 20 | namespace memory { 21 | 22 | template 23 | //template<> 24 | class allocator_traits> { 25 | using Alloc = thrust::device_allocator; 26 | 27 | public: 28 | using pointer = typename thrust::device_allocator::pointer; 29 | using value_type = T; 30 | using size_type = typename thrust::device_allocator::size_type; 31 | template using rebind_alloc = thrust::device_allocator; 32 | static pointer allocate(Alloc& a, size_type n){return a.allocate(n);} 33 | static void deallocate(Alloc& a, pointer p, size_type n){return a.deallocate(p, n);} 34 | 35 | private: 36 | static void construct(std::true_type, Alloc& a, pointer p){ 37 | cudaError_t s = cudaMemset(raw_pointer_cast(p), 0, sizeof(T)); assert( s == cudaSuccess ); 38 | } 39 | template 40 | static void construct(std::false_type, Alloc& a, pointer p, Args&&... args) { 41 | std::array buff; // char buff[sizeof(T)]; 42 | ::new(buff.data()) T(std::forward(args)...); // use ( ...) instead of { ...} for nvcc 43 | cudaError_t s = cudaMemcpy(raw_pointer_cast(p), buff.data(), buff.size(), cudaMemcpyHostToDevice); 44 | assert( s == cudaSuccess ); 45 | } 46 | 47 | public: 48 | template 49 | static void construct(Alloc& a, pointer p, Args&&... args) { 50 | construct(std::integral_constant{}>{}, a, p, std::forward(args)...); 51 | } 52 | 53 | private: 54 | static void destroy(std::true_type , Alloc& , pointer ) {} 55 | static void destroy(std::false_type, Alloc& a, pointer p) { 56 | std::array buff; // char buff[sizeof(T)]; 57 | cudaMemcpy(buff.data(), raw_pointer_cast(p), buff.size(), cudaMemcpyDeviceToHost); 58 | reinterpret_cast(buff).~T(); // ((T*)buff)->~T(); 59 | } 60 | 61 | public: 62 | static void destroy(Alloc& a, pointer p){destroy(std::is_trivially_destructible{}, a, p);} 63 | }; 64 | } // end namespace memory 65 | 66 | } // end namespace multi 67 | } // end namespace boost 68 | 69 | #ifdef _TEST_MULTI_ADAPTORS_THRUST_ALLOCATOR_TRAITS 70 | 71 | namespace multi = boost::multi; 72 | 73 | int main() { 74 | 75 | thrust::device_allocator aaa; 76 | thrust::device_ptr p = std::allocator_traits>::allocate(aaa, 10); 77 | 78 | multi::allocator_traits>::construct(aaa, p, 99.); 79 | } 80 | #endif 81 | #endif 82 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/thrust/test/universal.cu: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | // #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | auto universal_memory_supported() -> bool { 19 | std::cout << "testing for universal memory supported" << std::endl; 20 | int d; 21 | cudaGetDevice(&d); 22 | int is_cma = 0; 23 | cudaDeviceGetAttribute(&is_cma, cudaDevAttrConcurrentManagedAccess, d); 24 | if(is_cma) { 25 | std::cout << "universal memory is supported" << std::endl; 26 | } else { 27 | std::cout << "universal memory is NOT supported" << std::endl; 28 | } 29 | return (is_cma == 1)?true:false; 30 | } 31 | 32 | namespace multi = boost::multi; 33 | 34 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 35 | 36 | // BOOST_AUTO_TEST_CASE(thrust_universal_ptr) 37 | if(universal_memory_supported()) 38 | { 39 | multi::array Host({1024, 1024}); 40 | std::iota(Host.data_elements(), Host.data_elements() + Host.num_elements(), 12.0); 41 | 42 | multi::array> Univ({1024, 1024}); 43 | 44 | Univ({0, 10}, {0, 20}) = Host({0, 10}, {0, 20}); 45 | 46 | multi::array Hos2({1024, 1024}); 47 | Hos2({0, 10}, {0, 20}) = Univ({0, 10}, {0, 20}); 48 | 49 | BOOST_TEST( std::abs( Hos2[0][0] - 12.0 ) < 1e-10 ); 50 | } 51 | 52 | // BOOST_AUTO_TEST_CASE(thrust_universal_ptr_initializer_list) 53 | if(universal_memory_supported()) 54 | { 55 | multi::array Host = {1.0, 2.0, 3.0}; 56 | BOOST_TEST( Host.size() == 3 ); 57 | { 58 | multi::array> Univ(multi::extensions_t<1>{3}); 59 | Univ[0] = 3.0; 60 | Univ[1] = 2.0; 61 | Univ[2] = 1.0; 62 | 63 | Host() = Univ(); 64 | 65 | BOOST_TEST( Host[0] == 3.0 ); 66 | } 67 | { 68 | multi::array tmp = { 69 | 3.0, 70 | 2.0, 71 | 1.0, 72 | }; 73 | multi::array> Univ{multi::extensions_t<1>{3}}; 74 | Univ = tmp; 75 | 76 | Host() = Univ(); 77 | 78 | BOOST_TEST( Host[0] == 3.0 ); 79 | } 80 | { 81 | multi::array tmp = { 82 | 3.0, 83 | 2.0, 84 | 1.0, 85 | }; 86 | multi::array> Univ{tmp}; 87 | 88 | Host() = Univ(); 89 | 90 | BOOST_TEST( Host[0] == 3.0 ); 91 | } 92 | { 93 | multi::array> Univ = { 94 | 3.0, 95 | 2.0, 96 | 1.0, 97 | }; 98 | 99 | Host() = Univ(); 100 | 101 | std::cout << "host 0 " << Host[0] << '\n'; 102 | BOOST_TEST( Host[0] == 3.0 ); 103 | } 104 | } 105 | 106 | return boost::report_errors(); 107 | } 108 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/blas/syrk.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_BLAS_SYRK_HPP 6 | #define BOOST_MULTI_ADAPTORS_BLAS_SYRK_HPP 7 | 8 | #include "boost/multi/adaptors/blas/core.hpp" 9 | #include "boost/multi/adaptors/blas/filling.hpp" 10 | #include "boost/multi/adaptors/blas/numeric.hpp" 11 | 12 | namespace boost::multi::blas { 13 | 14 | using core::syrk; 15 | 16 | template 17 | auto syrk(filling c_side, typename A2D::element alpha, A2D const& a, typename A2D::element beta, C2D&& cc) { // NOLINT(readability-identifier-length) BLAS naming 18 | //->decltype(syrk('\0', '\0', size(c), size(a), alpha, base(a), stride(rotated(a)), beta, base(c), stride(c)), std::forward(c)){ 19 | using std::get; 20 | assert( cc.size() == get<1>(cc.sizes()) ); 21 | // cppcheck-suppress knownConditionTrueFalse ; bug in cppcheck 2.18? 22 | if(stride(a) == 1) { 23 | if(cc.stride() == 1) { 24 | syrk(flip(c_side) == filling::upper ? 'L' : 'U', 'N', cc.size(), size(a), &alpha, a.base(), a.rotated().stride(), &beta, cc.base(), cc.rotated().size()); 25 | } else { 26 | syrk(c_side == filling::upper ? 'L' : 'U', 'N', cc.size(), a.rotated().size(), &alpha, a.base(), a.rotated().stride(), &beta, cc.base(), cc.stride()); 27 | } 28 | } else { 29 | if(cc.stride() == 1) { 30 | syrk(flip(c_side) == filling::upper ? 'L' : 'U', 'T', cc.size(), a.rotated().size(), &alpha, a.base(), stride(a), &beta, cc.base(), cc.rotated().stride()); 31 | } else { 32 | syrk(c_side == filling::upper ? 'L' : 'U', 'T', cc.size(), a.rotated().size(), &alpha, a.base(), a.stride(), &beta, cc.base(), cc.stride()); 33 | } 34 | } 35 | return std::forward(cc); 36 | } 37 | 38 | template 39 | auto syrk(filling c_side, AA alpha, A2D const& a, C2D&& cc) // NOLINT(readability-identifier-length) BLAS naming 40 | -> decltype(syrk(c_side, alpha, a, 0.0, std::forward(cc))) { 41 | return syrk(c_side, alpha, a, 0.0, std::forward(cc)); 42 | } 43 | 44 | // template 45 | // auto syrk(AA alpha, A2D const& a, C2D&& c) // NOLINT(readability-identifier-length) BLAS naming 46 | // -> decltype(syrk(filling::upper, alpha, a, syrk(filling::lower, alpha, a, std::forward(c)))) { 47 | // return syrk(filling::upper, alpha, a, syrk(filling::lower, alpha, a, std::forward(c))); 48 | // } 49 | 50 | // template 51 | // [[nodiscard]] // ("because input argument is const") 52 | // // this decay in the return type is important 53 | // auto // NOLINTNEXTLINE(readability-identifier-length) BLAS naming 54 | // syrk(AA alpha, A2D const& a) -> std::decay_t { 55 | // return syrk(alpha, a, Ret({size(a), size(a)}, get_allocator(a))); 56 | // } 57 | 58 | // template 59 | // [[nodiscard]] auto syrk(A2D const& A) // NOLINT(readability-identifier-length) BLAS naming 60 | // -> decltype(syrk(1.0, A)) { 61 | // return syrk(1.0, A); 62 | // } 63 | 64 | } // end namespace boost::multi::blas 65 | #endif 66 | -------------------------------------------------------------------------------- /test/reversed.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2025 Alfredo A. Correa 2 | // Copyright 2024 Matt Borland 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // https://www.boost.org/LICENSE_1_0.txt 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include // for get // NOLINT(misc-include-cleaner) 11 | #include // for forward 12 | 13 | namespace multi = boost::multi; 14 | 15 | namespace { 16 | template 17 | auto flatted_last(Array&& arr) { 18 | return std::forward(arr).reversed().transposed().flatted().reversed(); 19 | } 20 | 21 | template 22 | auto partitioned_last(Array&& arr, multi::size_type n) { 23 | return std::forward(arr).reversed().partitioned(n).transposed().transposed().reversed(); 24 | } 25 | } // end unnamed namespace 26 | 27 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 28 | // BOOST_AUTO_TEST_CASE(multi_reversed_3d) 29 | { 30 | multi::array arr({30, 40, 50}); 31 | 32 | BOOST_TEST( arr.reversed().size() == 50 ); 33 | 34 | BOOST_TEST( & arr.reversed()[3][5][7] == &arr[7][5][3] ); 35 | } 36 | 37 | // BOOST_AUTO_TEST_CASE(multi_reversed_4d) 38 | { 39 | using std::get; // workaround no prior declaration in function call with explicit template arguments is a C++20 extension [-Wc++20-extensions] 40 | 41 | multi::array arr({13, 5, 7, 11}); 42 | 43 | BOOST_TEST( arr.reversed().size() == 11 ); 44 | 45 | BOOST_TEST( &arr.reversed()[1][2][3][4] == &arr[4][3][2][1] ); 46 | 47 | BOOST_TEST( get<0>( arr.reversed().transposed().flatted().reversed().sizes() ) == 13 ); 48 | BOOST_TEST( get<1>( arr.reversed().transposed().flatted().reversed().sizes() ) == 5 ); 49 | BOOST_TEST( get<2>( arr.reversed().transposed().flatted().reversed().sizes() ) == 77 ); 50 | 51 | BOOST_TEST(( sizes(arr.reversed().transposed().flatted().reversed()) == decltype(sizes(arr.reversed().transposed().flatted().reversed())){13, 5, 77} )); 52 | BOOST_TEST( &arr.reversed().transposed().flatted().reversed()[1][2][ 5] == & arr[1][2][0][ 5] ); 53 | BOOST_TEST( &arr.reversed().transposed().flatted().reversed()[1][2][10] == & arr[1][2][0][10] ); 54 | BOOST_TEST( &arr.reversed().transposed().flatted().reversed()[1][2][11] == & arr[1][2][1][ 0] ); 55 | BOOST_TEST( &arr.reversed().transposed().flatted().reversed()[1][2][12] == & arr[1][2][1][ 1] ); 56 | 57 | BOOST_TEST( & flatted_last(arr)[1][2][12] == & arr[1][2][1][1] ); 58 | } 59 | 60 | // BOOST_AUTO_TEST_CASE(multi_reversed_4d_partition_last) 61 | { 62 | multi::array arr({11, 5, 7, 12}); 63 | 64 | BOOST_TEST( arr.reversed().size() == 12 ); 65 | 66 | BOOST_TEST( & arr.reversed()[1][2][3][4] == &arr[4][3][2][1] ); 67 | 68 | BOOST_TEST( & arr.reversed().partitioned(3).transposed().reversed()[1][2][3][0][1] == & arr[1][2][3][1] ); 69 | BOOST_TEST( & arr.reversed().partitioned(3).transposed().reversed()[1][2][3][1][0] == & arr[1][2][3][4] ); 70 | BOOST_TEST( & arr.reversed().partitioned(3).transposed().reversed()[1][2][3][1][1] == & arr[1][2][3][5] ); 71 | 72 | BOOST_TEST( & partitioned_last(arr, 3)[1][2][3][1][1] == & arr[1][2][3][5] ); 73 | } 74 | 75 | return boost::report_errors(); 76 | } 77 | -------------------------------------------------------------------------------- /doc/multi/install.adoc: -------------------------------------------------------------------------------- 1 | [#install] 2 | 3 | = Installation 4 | 5 | :idprefix: install_ 6 | 7 | Before using the library, you can try it https://godbolt.org/z/dvacqK8jE[online]. 8 | 9 | _Multi_ has no external dependencies and can be used immediately after downloading. 10 | ```bash 11 | git clone https://gitlab.com/correaa/boost-multi.git 12 | ``` 13 | 14 | _Multi_ doesn't require installation since a single header is enough to use the entire core library; 15 | ```c++ 16 | #include 17 | 18 | int main() { ... } 19 | ``` 20 | 21 | The library can still be installed with CMake. 22 | The header (and CMake) files will be installed in the chosen prefix location (by default, `/usr/local/include/multi` and `/usr/local/share/multi`). 23 | ```bash 24 | cd boost-multi 25 | mkdir -p build && cd build 26 | cmake . -B ./build # --install-prefix=$HOME/.local 27 | cmake --install ./build # or sudo ... 28 | ``` 29 | 30 | _Testing_ the library requires Boost.Core (headers), installed for example, via 31 | `sudo apt install cmake git g{plus}{plus} libboost-test-dev make` 32 | or `sudo dnf install boost-devel cmake gcc-c{plus}{plus} git`. 33 | A CMake build system is provided to compile and run basic tests. 34 | ```bash 35 | ctest -C ./build 36 | ``` 37 | 38 | Once installed, other CMake projects (targets) can depend on Multi by adding a simple `add_subdirectory(my_multi_path)` or by `find_package`: 39 | ```cmake 40 | find_package(multi) # see https://gitlab.com/correaa/boost-multi 41 | ``` 42 | 43 | Alternatively to the library can be fetched on demand: 44 | ```cmake 45 | include(FetchContent) 46 | FetchContent_Declare(multi GIT_REPOSITORY https://gitlab.com/correaa/boost-multi.git) 47 | FetchContent_MakeAvailable(multi) 48 | ... 49 | target_link_libraries(my_target PUBLIC multi) 50 | ``` 51 | 52 | The code requires any modern https://godbolt.org/z/hxEYGYEWc[C\++ compiler] (or https://godbolt.org/z/zvYoMjeTh[CUDA compiler]) with standard C\++17 support; 53 | for reference, (at least) any of: 54 | LLVM's https://godbolt.org/z/51E1hjfnn[clang (5.0+)] (libc\++ and libstdc\++), 55 | GNU's https://godbolt.org/z/1nGEbKc5a[g\++ (7.1+)], 56 | Nvidia's https://godbolt.org/z/v9W889njx[nvcc (11.5+)] 57 | and 58 | https://godbolt.org/z/6z39PjT47[nvc\++ (22.7+)], 59 | Intel's icpx (2022.0.0+) and icc (2021.1.2+, deprecated), 60 | Baxter's https://www.circle-lang.org[circle] (https://godbolt.org/z/KeG417fMz[build 202+]), 61 | https://zig.news/kristoff/compile-a-c-c-project-with-zig-368j[Zig] in https://godbolt.org/z/cKGebsWMG[c++ mode (v0.9.0+)], 62 | Edison Design's https://edg.com/c[EDG] https://godbolt.org/z/693fxPedx[(6.5+)] 63 | and 64 | Microsoft's https://visualstudio.microsoft.com/vs/features/cplusplus[MSVC] (https://godbolt.org/z/Kqrva137M[+14.1]). 65 | 66 | (Multi code inside CUDA kernel can be compiled with `nvcc` and with https://godbolt.org/z/7dTKdPTxc[clang (in CUDA mode)]. 67 | Inside HIP code, it can be compiled with AMD's clang rocm (5.0+).) 68 | 69 | Optional _adaptor_ sublibraries (included in `multi/adaptors/`) have specific dependencies: fftw, , lapack, thurst, or CUDA 70 | (all of them can be installed with 71 | `sudo apt install libfftw3-dev lib64-dev liblapack64-dev libthrust-dev nvidia-cuda-dev` 72 | or `sudo dnf install fftw-devel ...`. 73 | ) 74 | -------------------------------------------------------------------------------- /test/array_legacy_c.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2025 Alfredo A. Correa 2 | // Copyright 2024 Matt Borland 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // https://www.boost.org/LICENSE_1_0.txt 5 | 6 | #include // for array, rotated, subarray, dimens... 7 | 8 | #include 9 | 10 | #include // for array 11 | #include // for complex 12 | #include // for apply // IWYU pragma: keep 13 | // IWYU pragma: no_include // for remove_reference<>::type 14 | #include // for move 15 | 16 | namespace multi = boost::multi; 17 | 18 | namespace fake { 19 | 20 | // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) testing a legacy interface 21 | using fftw_complex = double[2]; 22 | 23 | namespace { 24 | 25 | void fftw_plan_dft(int rank, int const* n, fftw_complex* in, fftw_complex* out, int sign, unsigned flags); 26 | 27 | void fftw_plan_dft(int rank, int const* n, fftw_complex* in, fftw_complex* out, int sign, unsigned flags) { 28 | (void)rank, (void)n, (void)in, (void)out, (void)sign, (void)flags; 29 | } 30 | 31 | } // end unnamed namespace 32 | 33 | } // end namespace fake 34 | 35 | namespace { 36 | constexpr auto f2(multi::array_ref&& array) -> double& { return std::move(array)[2]; } 37 | } // end unnamed namespace 38 | 39 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 40 | // BOOST_AUTO_TEST_CASE(array_legacy_c) 41 | { 42 | using complex = std::complex; 43 | 44 | multi::array const in = { 45 | {{150.0, 0.0}, {16.0, 0.0}, {17.0, 0.0}, {18.0, 0.0}, {19.0, 0.0}}, 46 | { {5.0, 0.0}, {5.0, 0.0}, {5.0, 0.0}, {5.0, 0.0}, {5.0, 0.0}}, 47 | {{100.0, 0.0}, {11.0, 0.0}, {12.0, 0.0}, {13.0, 0.0}, {14.0, 0.0}}, 48 | { {50.0, 0.0}, {6.0, 0.0}, {7.0, 0.0}, {8.0, 0.0}, {9.0, 0.0}}, 49 | }; 50 | 51 | multi::array, 2> out(extensions(in)); 52 | 53 | BOOST_TEST( dimensionality(out) == dimensionality(in) ); 54 | BOOST_TEST( sizes(out) == sizes(in) ); 55 | 56 | static_assert(sizeof(complex) == sizeof(fake::fftw_complex), "!"); 57 | fake::fftw_plan_dft( 58 | decltype(in)::dimensionality, 59 | std::apply([](auto... sizes) { return std::array{{static_cast(sizes)...}}; }, in.sizes()).data(), 60 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-type-const-cast) testing legacy code 61 | reinterpret_cast(const_cast(in.data_elements())), // NOSONAR 62 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): testing legacy code 63 | reinterpret_cast(out.data_elements()), 64 | 1, 0 65 | ); 66 | } 67 | 68 | #ifdef __clang__ 69 | #pragma clang diagnostic push 70 | #pragma clang diagnostic ignored "-Wunknown-warning-option" 71 | #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" 72 | #endif 73 | // BOOST_AUTO_TEST_CASE(array_legacy_c_2) 74 | { 75 | double arr[5] = {150.0, 16.0, 17.0, 18.0, 19.0}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 76 | BOOST_TEST( &f2(arr) == &arr[2] ); 77 | } 78 | #ifdef __clang__ 79 | #pragma clang diagnostic pop 80 | #endif 81 | 82 | return boost::report_errors(); 83 | } 84 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/fftw/test/direct_vs_transpose.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include // for is_const_v 18 | 19 | namespace multi = boost::multi; 20 | 21 | template<> 22 | inline constexpr bool multi::force_element_trivial_default_construction> = true; 23 | 24 | class watch : private std::chrono::high_resolution_clock { // NOSONAR(cpp:S4963) this class will report timing on destruction 25 | std::string label_; 26 | time_point start_ = now(); 27 | 28 | public: 29 | explicit watch(std::string_view label) : label_{label} {} 30 | 31 | watch(watch const&) = delete; 32 | watch(watch&&) = default; 33 | 34 | auto operator=(watch const&) = delete; 35 | auto operator=(watch&&) = delete; 36 | 37 | auto elapsed_sec() const { return std::chrono::duration(now() - start_).count(); } 38 | ~watch() { std::cerr << label_ << ": " << elapsed_sec() << " sec" << '\n'; } 39 | }; 40 | 41 | namespace { 42 | // clang-format off 43 | template 44 | inline 45 | #ifdef _MSC_VER 46 | __forceinline 47 | #else 48 | __attribute__((always_inline)) 49 | #endif 50 | void DoNotOptimize(Tp& value) { // NOLINT(readability-identifier-naming) 51 | #ifdef _MSC_VER 52 | _ReadWriteBarrier(); (void)value; 53 | #else 54 | #if defined(__clang__) || defined(__circle_build__) 55 | if constexpr(!std::is_const_v) { // NOLINT(bugprone-branch-clone) 56 | asm volatile("" : "+r,m"(value) : : "memory"); // NOLINT(hicpp-no-assembler) 57 | } else { // NOLINT(bugprone-branch-clone) 58 | asm volatile("" : "+m,r"(value) : : "memory"); // NOLINT(hicpp-no-assembler) 59 | } 60 | #else 61 | asm volatile("" : "+m,r"(value) : : "memory"); // NOLINT(hicpp-no-assembler) 62 | #endif 63 | #endif 64 | } 65 | // clang-format on 66 | } // end namespace 67 | 68 | auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) 69 | using complex = std::complex; 70 | 71 | auto in = [] { 72 | #ifndef NDEBUG 73 | auto ret = multi::array({100, 100, 100}); 74 | #else 75 | auto ret = multi::array({10, 10, 10}); 76 | #endif 77 | std::generate( 78 | ret.elements().begin(), ret.elements().end(), 79 | [eng = std::default_random_engine{std::random_device{}()}, 80 | dist = std::uniform_real_distribution<>{}]() mutable { 81 | return complex{dist(eng), dist(eng)}; 82 | } 83 | ); 84 | return ret; 85 | }(); 86 | 87 | auto const pn = multi::fftw::plan::forward({{false, false, false}}, in.base(), in.layout(), in.base(), in.layout()); 88 | 89 | DoNotOptimize(in); 90 | 91 | std::cout << pn.flops() << "FLOPS\n"; 92 | 93 | [&, unnamed = watch{"3D *100x100x100"}] { 94 | for(int i = 0; i != 100; ++i) { // NOLINT(altera-unroll-loops) 95 | pn.execute(in.base(), in.base()); 96 | } 97 | }(); 98 | 99 | DoNotOptimize(in); 100 | 101 | return boost::report_errors(); 102 | } 103 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cuda/cublas/test/gemv.cu: -------------------------------------------------------------------------------- 1 | // -*-indent-tabs-mode:t;c-basic-offset:4;tab-width:4;autowrap:nil;-*- 2 | // Copyright 2023-2024 Alfredo A. Correa 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | namespace multi = boost::multi; 16 | 17 | #define BOOST_AUTO_TEST_CASE(CasenamE) /**/ 18 | 19 | #define BOOST_REQUIRE_CLOSE(X, Y, ToL) BOOST_TEST( std::abs( (X) - (Y) ) < (ToL) ) 20 | 21 | int main() { 22 | BOOST_AUTO_TEST_CASE(multi_blas_gemv_complex) { 23 | namespace blas = multi::blas; 24 | using complex = thrust::complex; 25 | // NOLINTNEXTLINE(readability-identifier-length) BLAS naming 26 | multi::thrust::cuda::array const M_gpu = { 27 | { { 9.0, 0.0}, {24.0, 0.0}, {30.0, 0.0}, {9.0, 0.0} }, 28 | { { 4.0, 0.0}, {10.0, 0.0}, {12.0, 0.0}, {7.0, 0.0} }, 29 | { {14.0, 0.0}, {16.0, 0.0}, {36.0, 0.0}, {1.0, 0.0} }, 30 | }; 31 | 32 | multi::thrust::cuda::array const X_gpu = { {1.1, 0.0}, {2.1, 0.0}, {3.1, 0.0}, {4.1, 0.0} }; 33 | 34 | multi::thrust::cuda::array Y_gpu = { {4.0, 0.0}, {5.0, 0.0}, {6.0, 0.0} }; 35 | 36 | blas::gemv(/*alpha*/ 1.1, M_gpu, X_gpu, /*beta*/ 1.2, Y_gpu); // y = a*M*x + b*y 37 | 38 | multi::array const Y_copy = Y_gpu; 39 | 40 | using blas::operators::operator-; 41 | BOOST_REQUIRE_CLOSE( +blas::nrm2(Y_copy - multi::array{ {214.02, 0.0}, {106.43, 0.0}, {188.37, 0.0} }) , 0.0, 1e-13); 42 | } 43 | 44 | BOOST_AUTO_TEST_CASE(multi_blas_gemv_complex_value) { 45 | namespace blas = multi::blas; 46 | using complex = thrust::complex; 47 | // NOLINTNEXTLINE(readability-identifier-length) BLAS naming 48 | multi::thrust::cuda::array const M_gpu = { 49 | { { 9.0, 0.0}, {24.0, 0.0}, {30.0, 0.0}, {9.0, 0.0} }, 50 | { { 4.0, 0.0}, {10.0, 0.0}, {12.0, 0.0}, {7.0, 0.0} }, 51 | { {14.0, 0.0}, {16.0, 0.0}, {36.0, 0.0}, {1.0, 0.0} }, 52 | }; 53 | 54 | multi::thrust::cuda::array const X_gpu = { {1.1, 0.0}, {2.1, 0.0}, {3.1, 0.0}, {4.1, 0.0} }; 55 | 56 | auto const Y_gpu = +blas::gemv(/*alpha*/ 1.1, M_gpu, X_gpu); // y = a*M*x 57 | 58 | multi::array const Y_copy = Y_gpu; 59 | 60 | using blas::operators::operator-; 61 | BOOST_REQUIRE_CLOSE( +blas::nrm2(Y_copy - multi::array{ {209.22, 0.0}, {100.43, 0.0}, {181.17, 0.0} }) , 0.0, 1e-13); 62 | } 63 | 64 | BOOST_AUTO_TEST_CASE(cublas_gemv_real) { 65 | namespace blas = multi::blas; 66 | using T = double; 67 | // NOLINTNEXTLINE(readability-identifier-length) BLAS naming 68 | multi::thrust::cuda::array const M_gpu = { 69 | { 9.0, 24.0, 30.0, 9.0 }, 70 | { 4.0, 10.0, 12.0, 7.0 }, 71 | { 14.0, 16.0, 36.0, 1.0 }, 72 | }; 73 | 74 | multi::thrust::cuda::array const X_gpu = { 1.1, 2.1, 3.1, 4.1 }; 75 | 76 | multi::thrust::cuda::array Y_gpu = { 4.0, 5.0, 6.0 }; 77 | 78 | blas::gemv(/*alpha*/ 1.1, M_gpu, X_gpu, /*beta*/ 1.2, Y_gpu); // y = a*M*x + b*y 79 | 80 | multi::array const Y_copy = Y_gpu; 81 | 82 | using blas::operators::operator-; 83 | BOOST_REQUIRE_CLOSE( +blas::nrm2(Y_copy - multi::array{ 214.02, 106.43, 188.37 }) , 0.0, 1e-13); 84 | } 85 | 86 | return boost::report_errors();} 87 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cuda/cublas/error.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2024 Alfredo A. Correa 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // https://www.boost.org/LICENSE_1_0.txt 4 | 5 | #ifndef BOOST_MULTI_ADAPTORS_CUDA_CUBLAS_ERROR_HPP 6 | #define BOOST_MULTI_ADAPTORS_CUDA_CUBLAS_ERROR_HPP 7 | 8 | #if !defined(MULTI_USE_HIP) 9 | #include // cublasStatus_t 10 | #else 11 | #include // cublasStatus_t 12 | #endif 13 | 14 | #include 15 | #include // std::error_category 16 | #include // std::underlying_type 17 | 18 | #if !defined(MULTI_USE_HIP) 19 | #define hicup(name) cuda##name 20 | #define hicu(name) cu##name 21 | #define HICU(name) CU##name 22 | #define HICUP(name) CU##name 23 | #else 24 | #define hicup(name) hip##name 25 | #define hicu(name) hip##name 26 | #define HICU(name) HIP##name 27 | #define HICUP(name) HIP##name 28 | #endif 29 | 30 | namespace boost::multi::cuda::cublas{ 31 | 32 | enum class error : typename std::underlying_type::type{ 33 | success = HICUP(BLAS_STATUS_SUCCESS), 34 | not_initialized = HICUP(BLAS_STATUS_NOT_INITIALIZED), 35 | allocation_failed = HICUP(BLAS_STATUS_ALLOC_FAILED), 36 | invalid_value = HICUP(BLAS_STATUS_INVALID_VALUE), 37 | architecture_mismatch = HICUP(BLAS_STATUS_ARCH_MISMATCH), 38 | mapping_error = HICUP(BLAS_STATUS_MAPPING_ERROR), 39 | execution_failed = HICUP(BLAS_STATUS_EXECUTION_FAILED), 40 | internal_error = HICUP(BLAS_STATUS_INTERNAL_ERROR), 41 | not_supported = HICUP(BLAS_STATUS_NOT_SUPPORTED), 42 | // license_error = HICUP(BLAS_STATUS_LICENSE_ERROR), // not supported by hip 43 | }; 44 | 45 | std::string inline error_string(enum cublas::error err){ //https://stackoverflow.com/questions/13041399/equivalent-of-cudageterrorstring-for-cublas 46 | switch(err){ 47 | case cublas::error::success : return "CUBLAS_STATUS_SUCCESS" ; 48 | case cublas::error::not_initialized : return "CUBLAS_STATUS_NOT_INITIALIZED" ; 49 | case cublas::error::allocation_failed : return "CUBLAS_STATUS_ALLOC_FAILED" ; 50 | case cublas::error::invalid_value : return "CUBLAS_STATUS_INVALID_VALUE" ; 51 | case cublas::error::architecture_mismatch: return "CUBLAS_STATUS_ARCH_MISMATCH" ; 52 | case cublas::error::mapping_error : return "CUBLAS_STATUS_MAPPING_ERROR" ; 53 | case cublas::error::execution_failed : return "CUBLAS_STATUS_EXECUTION_FAILED"; 54 | case cublas::error::internal_error : return "CUBLAS_STATUS_INTERNAL_ERROR" ; 55 | case cublas::error::not_supported : return "CUBLAS_STATUS_NOT_SUPPORTED" ; 56 | // case cublas::error::license_error : return "CUBLAS_STATUS_LICENSE_ERROR" ; 57 | } 58 | return "cublas status "; 59 | } 60 | 61 | struct error_category : std::error_category{ 62 | char const* name() const noexcept override{return "cublas wrapper";} 63 | std::string message(int err) const override{return error_string(static_cast(err));} 64 | static error_category& instance(){static cublas::error_category instance; return instance;} 65 | }; 66 | 67 | inline std::error_code make_error_code(cublas::error err) noexcept{ 68 | return {int(err), cublas::error_category::instance()}; 69 | } 70 | 71 | } 72 | 73 | namespace std { 74 | template<> struct is_error_code_enum<::boost::multi::cuda::cublas::error> : true_type{}; 75 | } 76 | 77 | #undef hicu 78 | #undef hicup 79 | #undef HICU 80 | #undef HICUP 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/boost/multi/adaptors/cuda/runtime/error.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // cudaError_t 4 | #include // cudaGetErrorString 5 | 6 | #include 7 | #include // underlying_type 8 | 9 | namespace boost{ 10 | namespace multi{ 11 | namespace cuda{ 12 | namespace runtime{ 13 | 14 | enum /*class*/ error : std::underlying_type::type{ 15 | success = cudaSuccess, // = 0 The API call returned with no errors. In the case of query calls, this also means that the operation being queried is complete (see cudaEventQuery() and cudaStreamQuery()). 16 | missing_configuration = cudaErrorMissingConfiguration, 17 | // invalid_value /*invalid_argument*/ = cudaErrorInvalidValue, // = 1, This indicates that one or more of the parameters passed to the API call is not within an acceptable range of values. 18 | memory_allocation = cudaErrorMemoryAllocation, // = 2 // The API call failed because it was unable to allocate enough memory to perform the requested operation. 19 | initialization_error = cudaErrorInitializationError, 20 | lauch_failure = cudaErrorLaunchFailure, 21 | lauch_timeout = cudaErrorLaunchTimeout, 22 | lauch_out_of_resources = cudaErrorLaunchOutOfResources, 23 | invalid_device_function = cudaErrorInvalidDeviceFunction, 24 | invalid_configuration = cudaErrorInvalidConfiguration, 25 | invalid_device = cudaErrorInvalidDevice, 26 | invalid_value = cudaErrorInvalidValue, ///*invalid_argument*/ = cudaErrorInvalidValue, // = 1 This indicates that one or more of the parameters passed to the API call is not within an acceptable range of values. 27 | invalid_pitch_value = cudaErrorInvalidPitchValue, 28 | invalid_symbol = cudaErrorInvalidSymbol, 29 | unmap_buffer_object_failed = cudaErrorUnmapBufferObjectFailed, 30 | invalid_device_pointer = cudaErrorInvalidDevicePointer, 31 | invalid_texture = cudaErrorInvalidTexture, 32 | invalid_texture_binding = cudaErrorInvalidTextureBinding, 33 | invalid_channel_descriptor = cudaErrorInvalidChannelDescriptor, 34 | invalid_memcpy_direction = cudaErrorInvalidMemcpyDirection, 35 | invalud_filter_setting = cudaErrorInvalidFilterSetting, 36 | invalid_norm_setting = cudaErrorInvalidNormSetting, 37 | unknown = cudaErrorUnknown, 38 | invalid_resource_handle = cudaErrorInvalidResourceHandle, 39 | insuffient_driver = cudaErrorInsufficientDriver, 40 | no_device = cudaErrorNoDevice, 41 | set_on_active_process = cudaErrorSetOnActiveProcess, 42 | startup_failure = cudaErrorStartupFailure, 43 | invalid_ptx = cudaErrorInvalidPtx, 44 | no_kernel_image_for_device = cudaErrorNoKernelImageForDevice, 45 | jit_compiler_not_found = cudaErrorJitCompilerNotFound 46 | }; 47 | 48 | inline std::string string(enum error e){return cudaGetErrorString(static_cast(e));} 49 | 50 | struct error_category : std::error_category{ 51 | char const* name() const noexcept override{return "cuda wrapper";} 52 | std::string message(int e) const override{return string(static_cast(e));} 53 | static error_category& instance(){ 54 | static error_category instance; 55 | return instance; 56 | } 57 | }; 58 | 59 | inline std::error_code make_error_code(error err) noexcept{ 60 | return {static_cast(err), error_category::instance()}; 61 | } 62 | 63 | }}}} 64 | 65 | namespace std{template<> struct is_error_code_enum : true_type{};} 66 | 67 | --------------------------------------------------------------------------------