├── .appveyor.yml ├── .azure-pipelines ├── azure-pipelines-linux-clang.yml ├── azure-pipelines-linux-gcc.yml ├── azure-pipelines-osx.yml └── unix-build.yml ├── .github └── workflows │ ├── linux.yml │ ├── osx.yml │ └── windows.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── FindR.cmake ├── docs ├── Doxyfile ├── Makefile ├── environment.yml ├── make.bat └── source │ ├── _static │ └── main_stylesheet.css │ ├── api_reference.rst │ ├── array_tensor.rst │ ├── basic_usage.rst │ ├── cmake.svg │ ├── conda.svg │ ├── conf.py │ ├── cran.svg │ ├── debian.svg │ ├── index.rst │ ├── installation.rst │ ├── quantstack-white.svg │ ├── r_peculiarities.rst │ ├── rarray.rst │ ├── releasing.rst │ ├── roptional.rst │ ├── rtensor.rst │ ├── rvectorize.rst │ └── xtensor-r.svg ├── environment-dev-win.yml ├── environment-dev.yml ├── include └── xtensor-r │ ├── rarray.hpp │ ├── rcontainer.hpp │ ├── rcpp_extensions.hpp │ ├── roptional.hpp │ ├── rtensor.hpp │ ├── rvectorize.hpp │ └── xtensor_r_config.hpp ├── readthedocs.yml ├── test ├── CMakeLists.txt ├── copyGTest.cmake.in ├── downloadGTest.cmake.in ├── main.cpp ├── rcpp_tests.cpp ├── test_common.hpp ├── test_rarray.cpp ├── test_roptional.cpp ├── test_rreducer.cpp ├── test_rtensor.cpp ├── test_rvectorize.cpp ├── test_sfinae.cpp └── unittest.R └── xtensor-rConfig.cmake.in /.appveyor.yml: -------------------------------------------------------------------------------- 1 | build: false 2 | 3 | os: Visual Studio 2015 4 | 5 | platform: 6 | - x64 7 | 8 | environment: 9 | matrix: 10 | - MINICONDA: C:\xtensor-conda 11 | 12 | init: 13 | - "ECHO %MINICONDA%" 14 | - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat %PLATFORM% 15 | - ps: if($env:Platform -eq "x64"){Start-FileDownload 'http://repo.continuum.io/miniconda/Miniconda3-latest-Windows-x86_64.exe' C:\Miniconda.exe; echo "Done"} 16 | - ps: if($env:Platform -eq "x86"){Start-FileDownload 'http://repo.continuum.io/miniconda/Miniconda3-latest-Windows-x86.exe' C:\Miniconda.exe; echo "Done"} 17 | - cmd: C:\Miniconda.exe /S /D=C:\xtensor-conda 18 | - "set PATH=%MINICONDA%;%MINICONDA%\\Scripts;%MINICONDA%\\Library\\bin;%PATH%" 19 | # To enable RDP 20 | #- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) 21 | 22 | install: 23 | - conda config --set always_yes yes --set changeps1 no 24 | - conda update -q conda -c conda-forge 25 | # Host dependencies 26 | - conda install xtensor=0.24.4 r-rcpp r-rinside r-devtools -c conda-forge 27 | # Build dependencies 28 | - conda install m2w64-gcc m2w64-make m2w64-toolchain m2-libbz2 posix -c conda-forge 29 | # Full build on x64 with msys64 30 | - mkdir build 31 | - cd build 32 | - set PATH=%PATH:C:\Program Files\Git\usr\bin;=% 33 | - set R_HOME=%MINICONDA%\\Lib\\R 34 | - set MINGW_PATH=%MINICONDA%\\Library\\mingw-w64\\bin 35 | - "set PATH=%PATH%;%MINGW_PATH%;%MINICONDA%\\Lib\\R\\library\\RInside\\libs\\x64;%MINICONDA%\\Lib\\R\\bin\\x64" 36 | - cmake -D XTENSOR_INSTALL_R_PACKAGES=OFF -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH=%MINGW_PATH% -D CMAKE_INSTALL_PREFIX=%MINICONDA%\\Library -DDOWNLOAD_GTEST=ON .. 37 | - cmake --build . --target test_xtensor_r 38 | - cmake --build . --target install 39 | - cd test 40 | 41 | build_script: 42 | - .\test_xtensor_r 43 | -------------------------------------------------------------------------------- /.azure-pipelines/azure-pipelines-linux-clang.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: 'Linux_0' 3 | strategy: 4 | matrix: 5 | clang_6: 6 | llvm_version: '6.0' 7 | clang_7: 8 | llvm_version: '7' 9 | clang_8: 10 | llvm_version: '8' 11 | clang_9: 12 | llvm_version: '9' 13 | clang_10: 14 | llvm_version: '10' 15 | pool: 16 | vmImage: ubuntu-18.04 17 | variables: 18 | CC: clang-$(llvm_version) 19 | CXX: clang++-$(llvm_version) 20 | timeoutInMinutes: 360 21 | steps: 22 | 23 | - script: | 24 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test 25 | if [[ $(llvm_version) == '4.0' || $(llvm_version) == '5.0' ]]; then 26 | sudo apt-get update 27 | sudo apt-get --no-install-suggests --no-install-recommends install gcc-4.9 clang-$(llvm_version) 28 | else 29 | LLVM_VERSION=$(llvm_version) 30 | get -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - 31 | sudo add-apt-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-$LLVM_VERSION main" 32 | sudo apt-get update 33 | sudo apt-get --no-install-suggests --no-install-recommends install clang-$(llvm_version) 34 | fi 35 | displayName: Install build toolchain 36 | 37 | - bash: echo "##vso[task.prependpath]$CONDA/bin" 38 | displayName: Add conda to PATH 39 | 40 | - template: unix-build.yml 41 | -------------------------------------------------------------------------------- /.azure-pipelines/azure-pipelines-linux-gcc.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: 'Linux_1' 3 | strategy: 4 | matrix: 5 | gcc_6: 6 | gcc_version: '6' 7 | gcc_7: 8 | gcc_version: '7' 9 | gcc_8: 10 | gcc_version: '8' 11 | gcc_9: 12 | gcc_version: '9' 13 | pool: 14 | vmImage: ubuntu-18.04 15 | variables: 16 | CC: gcc-$(gcc_version) 17 | CXX: g++-$(gcc_version) 18 | timeoutInMinutes: 360 19 | steps: 20 | 21 | - script: | 22 | if [[ $(gcc_version) == '6' || $(gcc_version) == '7' || $(gcc_version) == '8' ]]; then 23 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test 24 | sudo apt-get update 25 | sudo apt-get --no-install-suggests --no-install-recommends install g++-$(gcc_version) 26 | fi 27 | displayName: Install build toolchain 28 | 29 | - bash: echo "##vso[task.prependpath]$CONDA/bin" 30 | displayName: Add conda to PATH 31 | 32 | - template: unix-build.yml 33 | -------------------------------------------------------------------------------- /.azure-pipelines/azure-pipelines-osx.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: 'OSX' 3 | strategy: 4 | matrix: 5 | macOS_12: 6 | image_name: 'macOS-12' 7 | osx_platform: 1 8 | pool: 9 | vmImage: $(image_name) 10 | variables: 11 | CC: clang 12 | CXX: clang++ 13 | timeoutInMinutes: 360 14 | steps: 15 | - script: | 16 | echo "Removing homebrew for Azure to avoid conflicts with conda" 17 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)" 18 | displayName: Remove homebrew 19 | 20 | - bash: | 21 | echo "##vso[task.prependpath]$CONDA/bin" 22 | sudo chown -R $USER $CONDA 23 | displayName: Add conda to PATH 24 | 25 | - template: unix-build.yml 26 | -------------------------------------------------------------------------------- /.azure-pipelines/unix-build.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - script: | 3 | conda config --set always_yes yes --set changeps1 no 4 | conda update -q conda 5 | conda env create --file environment-dev.yml 6 | displayName: Install dependencies 7 | 8 | - script: | 9 | source activate xtensor-r 10 | mkdir build 11 | cd build 12 | cmake -D DOWNLOAD_GTEST=ON -D CMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX $(Build.SourcesDirectory) 13 | displayName: Configure xtensor-r 14 | workingDirectory: $(Build.BinariesDirectory) 15 | 16 | - script: | 17 | source activate xtensor-r 18 | cmake --build . --target test_xtensor_r 19 | cmake --build . --target install 20 | displayName: Build xtensor-r 21 | workingDirectory: $(Build.BinariesDirectory)/build 22 | 23 | - script: | 24 | source activate xtensor-r 25 | echo "which tar" 26 | which tar 27 | if [[ $(osx_platform) == 1 ]]; then 28 | export TAR="/usr/bin/tar" 29 | else 30 | export TAR="/bin/tar" 31 | fi 32 | R -e "library(devtools); install_github('xtensor-stack/Xtensor.R', configure.args = '--novendor')" 33 | displayName: Install R package 34 | workingDirectory: $(Build.BinariesDirectory)/build 35 | 36 | - script: | 37 | if [[ $(osx_platform) != 1 ]]; then 38 | source activate xtensor-r 39 | ./test_xtensor_r 40 | fi 41 | displayName: Run C++ tests 42 | workingDirectory: $(Build.BinariesDirectory)/build/test 43 | 44 | - script: | 45 | source activate xtensor-r 46 | mkdir ~/.R 47 | touch ~/.R/Makevars 48 | echo "CXX14=$CXX" >> ~/.R/Makevars 49 | echo "CXX14FLAGS=-fPIC -O2" >> ~/.R/Makevars 50 | Rscript ./unittest.R 51 | displayName: Run R tests 52 | workingDirectory: $(Build.SourcesDirectory)/test 53 | -------------------------------------------------------------------------------- /.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | name: Linux 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | push: 6 | branches: [master] 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | defaults: 11 | run: 12 | shell: bash -e -l {0} 13 | jobs: 14 | build: 15 | runs-on: ubuntu-20.04 16 | name: ${{ matrix.sys.compiler }} ${{ matrix.sys.version }} 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | sys: 21 | - {compiler: gcc, version: '8'} 22 | - {compiler: gcc, version: '9'} 23 | - {compiler: gcc, version: '10'} 24 | - {compiler: gcc, version: '11'} 25 | - {compiler: clang, version: '15'} 26 | - {compiler: clang, version: '16'} 27 | 28 | steps: 29 | 30 | - name: Setup GCC 31 | if: ${{ matrix.sys.compiler == 'gcc' }} 32 | run: | 33 | GCC_VERSION=${{ matrix.sys.version }} 34 | sudo apt-get update 35 | sudo apt-get --no-install-suggests --no-install-recommends install g++-$GCC_VERSION 36 | CC=gcc-$GCC_VERSION 37 | echo "CC=$CC" >> $GITHUB_ENV 38 | CXX=g++-$GCC_VERSION 39 | echo "CXX=$CXX" >> $GITHUB_ENV 40 | 41 | - name: Setup clang 42 | if: ${{ matrix.sys.compiler == 'clang' }} 43 | run: | 44 | LLVM_VERSION=${{ matrix.sys.version }} 45 | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - || exit 1 46 | if [[ $LLVM_VERSION -ge 13 ]]; then 47 | sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-$LLVM_VERSION main" || exit 1 48 | else 49 | sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main" || exit 1 50 | fi || exit 1 51 | sudo apt-get update || exit 1 52 | sudo apt-get --no-install-suggests --no-install-recommends install clang-$LLVM_VERSION || exit 1 53 | sudo apt-get --no-install-suggests --no-install-recommends install g++-9 g++-9-multilib || exit 1 54 | sudo ln -s /usr/include/asm-generic /usr/include/asm 55 | CC=clang-$LLVM_VERSION 56 | echo "CC=$CC" >> $GITHUB_ENV 57 | CXX=clang++-$LLVM_VERSION 58 | echo "CXX=$CXX" >> $GITHUB_ENV 59 | 60 | - name: Checkout code 61 | uses: actions/checkout@v3 62 | 63 | - name: Set conda environment 64 | uses: mamba-org/setup-micromamba@v1 65 | with: 66 | environment-file: environment-dev.yml 67 | cache-environment: true 68 | 69 | - name: Configure using CMake 70 | run: cmake -Bbuild -DDOWNLOAD_GTEST=ON -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX $(Build.SourcesDirectory) 71 | 72 | - name: Install 73 | working-directory: build 74 | run: cmake --install . 75 | 76 | - name: Build 77 | working-directory: build 78 | run: cmake --build . --target test_xtensor_r --parallel 8 79 | 80 | - name: Install R package 81 | working-directory: build 82 | env: 83 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 84 | run: | 85 | echo "which tar" 86 | which tar 87 | export TAR="/usr/bin/tar" 88 | R -e "library(devtools); install_github('xtensor-stack/Xtensor.R', configure.args = '--novendor')" 89 | 90 | - name: Run tests (C++) 91 | working-directory: build/test 92 | run: ./test_xtensor_r 93 | 94 | - name: Run tests (R) 95 | working-directory: test 96 | run: | 97 | mkdir ~/.R 98 | touch ~/.R/Makevars 99 | echo "CXX14=$CXX" >> ~/.R/Makevars 100 | echo "CXX14FLAGS=-fPIC -O2" >> ~/.R/Makevars 101 | Rscript ./unittest.R 102 | 103 | -------------------------------------------------------------------------------- /.github/workflows/osx.yml: -------------------------------------------------------------------------------- 1 | name: OSX 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | push: 6 | branches: [master] 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | defaults: 11 | run: 12 | shell: bash -e -l {0} 13 | jobs: 14 | build: 15 | runs-on: macos-${{ matrix.os }} 16 | name: macos-${{ matrix.os }} 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | os: 21 | - 11 22 | - 12 23 | 24 | steps: 25 | 26 | - name: Checkout code 27 | uses: actions/checkout@v3 28 | 29 | - name: Set conda environment 30 | uses: mamba-org/setup-micromamba@v1 31 | with: 32 | environment-file: environment-dev.yml 33 | cache-environment: true 34 | 35 | - name: Configure using CMake 36 | run: cmake -Bbuild -DDOWNLOAD_GTEST=ON -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX $(Build.SourcesDirectory) 37 | 38 | - name: Install 39 | working-directory: build 40 | run: cmake --install . 41 | 42 | - name: Build 43 | working-directory: build 44 | run: cmake --build . --target test_xtensor_r --parallel 8 45 | 46 | - name: Install R package 47 | working-directory: build 48 | env: 49 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 50 | run: | 51 | echo "which tar" 52 | which tar 53 | export TAR="/usr/bin/tar" 54 | R -e "library(devtools); install_github('xtensor-stack/Xtensor.R', configure.args = '--novendor')" 55 | 56 | - name: Run tests (C++) 57 | working-directory: build/test 58 | run: ./test_xtensor_r 59 | 60 | - name: Run tests (R) 61 | working-directory: test 62 | run: | 63 | mkdir ~/.R 64 | touch ~/.R/Makevars 65 | echo "CXX14=$CXX" >> ~/.R/Makevars 66 | echo "CXX14FLAGS=-fPIC -O2" >> ~/.R/Makevars 67 | Rscript ./unittest.R 68 | 69 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | push: 6 | branches: [master] 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | defaults: 11 | run: 12 | #shell: msys2 {0} 13 | shell: bash -e -l {0} 14 | jobs: 15 | build: 16 | runs-on: [windows-latest] 17 | name: MINGW64 18 | 19 | steps: 20 | 21 | - name: Checkout code 22 | uses: actions/checkout@v3 23 | 24 | - name: Set conda environment 25 | uses: mamba-org/setup-micromamba@v1 26 | with: 27 | environment-file: environment-dev.yml 28 | cache-environment: true 29 | 30 | - name: Configure using CMake 31 | run: cmake -Bbuild -DXTENSOR_INSTALL_R_PACKAGES=OFF -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DDOWNLOAD_GTEST=ON $(Build.SourcesDirectory) 32 | 33 | - name: Install 34 | working-directory: build 35 | run: cmake --install . 36 | 37 | - name: Build 38 | working-directory: build 39 | run: cmake --build . --target test_xtensor_r --parallel 8 40 | 41 | # TODO: fix the test on Windows 42 | #- name: Run tests (C++) 43 | #working-directory: build/test 44 | #run: test_xtensor_r 45 | 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Session Data files 6 | .RData 7 | 8 | # Example code in package build process 9 | *-Ex.R 10 | 11 | # Output files from R CMD build 12 | /*.tar.gz 13 | 14 | # Output files from R CMD check 15 | /*.Rcheck/ 16 | 17 | # RStudio files 18 | .Rproj.user/ 19 | 20 | # produced vignettes 21 | vignettes/*.html 22 | vignettes/*.pdf 23 | 24 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 25 | .httr-oauth 26 | 27 | # knitr and R markdown default cache directories 28 | /*_cache/ 29 | /cache/ 30 | 31 | # Temporary files created by R markdown 32 | *.utf8.md 33 | *.knit.md 34 | 35 | # Build directory 36 | build/ 37 | 38 | # Test build artefacts 39 | test/test_xtensor 40 | test/CMakeCache.txt 41 | test/Makefile 42 | test/CMakeFiles/ 43 | test/cmake_install.cmake 44 | 45 | # Documentation build artefacts 46 | docs/CMakeCache.txt 47 | docs/xml/ 48 | docs/build/ 49 | 50 | # Other 51 | *.swp 52 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Copyright (c) Wolf Vollprecht, Johan Mabille and Sylvain Corlay # 3 | # Copyright (c) QuantStack # 4 | # # 5 | # Distributed under the terms of the BSD 3-Clause License. # 6 | # # 7 | # The full license is in the file LICENSE, distributed with this software. # 8 | ############################################################################ 9 | 10 | cmake_minimum_required(VERSION 3.1) 11 | project(xtensor-r) 12 | 13 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) 14 | set(XTENSOR_R_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) 15 | 16 | # Versionning 17 | # =========== 18 | 19 | set(XTENSOR_REQUIRED_VERSION 0.25.0) 20 | set(XTL_REQUIRED_VERSION 0.7.7) 21 | 22 | set(XTENSOR_R_CONFIG_FILE 23 | "${XTENSOR_R_INCLUDE_DIR}/xtensor-r/xtensor_r_config.hpp") 24 | file(STRINGS ${XTENSOR_R_CONFIG_FILE} xtensor_python_version_defines 25 | REGEX "#define XTENSOR_R_VERSION_(MAJOR|MINOR|PATCH)") 26 | foreach(ver ${xtensor_python_version_defines}) 27 | if(ver MATCHES "#define XTENSOR_R_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") 28 | set(XTENSOR_R_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") 29 | endif() 30 | endforeach() 31 | set(${PROJECT_NAME}_VERSION 32 | ${XTENSOR_R_VERSION_MAJOR}.${XTENSOR_R_VERSION_MINOR}.${XTENSOR_R_VERSION_PATCH}) 33 | message(STATUS "xtensor-r v${${PROJECT_NAME}_VERSION}") 34 | 35 | # Dependencies 36 | # ============ 37 | 38 | find_package(xtl ${XTL_REQUIRED_VERSION} REQUIRED) 39 | message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl") 40 | find_package(xtensor ${XTENSOR_REQUIRED_VERSION} REQUIRED) 41 | message(STATUS "Found xtensor: ${xtensor_INCLUDE_DIRS}/xtensor") 42 | 43 | # Build 44 | # ===== 45 | 46 | set(XTENSOR_R_HEADERS 47 | ${XTENSOR_R_INCLUDE_DIR}/xtensor-r/rarray.hpp 48 | ${XTENSOR_R_INCLUDE_DIR}/xtensor-r/rcontainer.hpp 49 | ${XTENSOR_R_INCLUDE_DIR}/xtensor-r/rcpp_extensions.hpp 50 | ${XTENSOR_R_INCLUDE_DIR}/xtensor-r/roptional.hpp 51 | ${XTENSOR_R_INCLUDE_DIR}/xtensor-r/rtensor.hpp 52 | ${XTENSOR_R_INCLUDE_DIR}/xtensor-r/rvectorize.hpp 53 | ${XTENSOR_R_INCLUDE_DIR}/xtensor-r/xtensor_r_config.hpp 54 | ) 55 | 56 | add_library(xtensor-r INTERFACE) 57 | target_include_directories(xtensor-r INTERFACE $ 58 | $) 59 | 60 | target_link_libraries(xtensor-r INTERFACE xtensor) 61 | get_target_property(inc_dir xtensor-r INTERFACE_INCLUDE_DIRECTORIES) 62 | message(STATUS "${inc_dir}") 63 | 64 | OPTION(BUILD_TESTS "xtensor-r test suite" OFF) 65 | OPTION(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF) 66 | 67 | if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) 68 | set(BUILD_TESTS ON) 69 | endif() 70 | 71 | find_package(R REQUIRED) 72 | 73 | if(BUILD_TESTS) 74 | # Locate Rcpp by invoking R 75 | execute_process( 76 | COMMAND ${R_COMMAND} -q -e "find.package('Rcpp')" 77 | OUTPUT_VARIABLE RCPP_FIND_RESULT_STRING 78 | RESULT_VARIABLE RCPP_FIND_RESULT) 79 | 80 | if(NOT RCPP_FIND_RESULT_STRING) 81 | message(SEND_ERROR "Rcpp not installed or not found!") 82 | else() 83 | string(REGEX MATCH "\".+\"" RCPP_LOCATION_LINE ${RCPP_FIND_RESULT_STRING}) 84 | string(REGEX REPLACE "\"" "" RCPP_LOCATION_LINE ${RCPP_LOCATION_LINE}) 85 | string(CONCAT Rcpp_INCLUDE_DIRS ${RCPP_LOCATION_LINE} "/include/") 86 | message("RCpp Include Directory: " ${Rcpp_INCLUDE_DIRS}) 87 | include_directories(SYSTEM ${Rcpp_INCLUDE_DIRS}) 88 | endif() 89 | 90 | 91 | # Locate RInside by invoking R 92 | execute_process( 93 | COMMAND ${R_COMMAND} -q -e "find.package('RInside')" 94 | OUTPUT_VARIABLE RINSIDE_FIND_RESULT_STRING 95 | RESULT_VARIABLE RINSIDE_FIND_RESULT) 96 | if(NOT RINSIDE_FIND_RESULT_STRING) 97 | message(SEND_ERROR "RInside not installed or not found!") 98 | else() 99 | string(REGEX MATCH "\".+\"" RINSIDE_LOCATION_LINE ${RINSIDE_FIND_RESULT_STRING}) 100 | string(REGEX REPLACE "\"" "" RINSIDE_LOCATION_LINE ${RINSIDE_LOCATION_LINE}) 101 | string(CONCAT RInside_INCLUDE_DIRS ${RINSIDE_LOCATION_LINE} "/include/") 102 | message("RInside Include Directory: " ${RInside_INCLUDE_DIRS}) 103 | 104 | set(OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) 105 | set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} ".dll") 106 | find_library(RINSIDE_LIBRARIES 107 | NAMES RInside 108 | HINTS ${RINSIDE_LOCATION_LINE}/lib ${RINSIDE_LOCATION_LINE}/libs/${R_LIB_ARCH} 109 | ) 110 | set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES}) 111 | include_directories(SYSTEM ${RInside_INCLUDE_DIRS}) 112 | endif() 113 | 114 | # Include the tests 115 | add_subdirectory(test) 116 | endif() 117 | 118 | # C++ Module Installation 119 | # ======================= 120 | 121 | include(GNUInstallDirs) 122 | include(CMakePackageConfigHelpers) 123 | 124 | install(TARGETS xtensor-r 125 | EXPORT ${PROJECT_NAME}-targets) 126 | 127 | # Makes the project importable from the build directory 128 | export(EXPORT ${PROJECT_NAME}-targets 129 | FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") 130 | 131 | install(FILES ${XTENSOR_R_HEADERS} 132 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xtensor-r) 133 | 134 | set(XTENSOR_R_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE 135 | STRING "install path for xtensor-rConfig.cmake") 136 | 137 | configure_package_config_file(${PROJECT_NAME}Config.cmake.in 138 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" 139 | INSTALL_DESTINATION ${XTENSOR_R_CMAKECONFIG_INSTALL_DIR}) 140 | 141 | # xtensor-r is header-only and does not depend on the architecture. 142 | # Remove CMAKE_SIZEOF_VOID_P from xtensor-rConfigVersion.cmake so that an xtensor-rConfig.cmake 143 | # generated for a 64 bit target can be used for 32 bit targets and vice versa. 144 | set(_XTENSOR_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) 145 | unset(CMAKE_SIZEOF_VOID_P) 146 | write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake 147 | VERSION ${${PROJECT_NAME}_VERSION} 148 | COMPATIBILITY AnyNewerVersion) 149 | set(CMAKE_SIZEOF_VOID_P ${_XTENSOR_CMAKE_SIZEOF_VOID_P}) 150 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake 151 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake 152 | DESTINATION ${XTENSOR_R_CMAKECONFIG_INSTALL_DIR}) 153 | install(EXPORT ${PROJECT_NAME}-targets 154 | FILE ${PROJECT_NAME}Targets.cmake 155 | DESTINATION ${XTENSOR_R_CMAKECONFIG_INSTALL_DIR}) 156 | 157 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, Johan Mabille, Sylvain Corlay and Wolf Vollprecht 2 | Copyright (c) 2017, QuantStack 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![xtensor-r](docs/source/xtensor-r.svg) 2 | 3 | [![Travis](https://travis-ci.org/xtensor-stack/xtensor-r.svg?branch=master)](https://travis-ci.org/xtensor-stack/xtensor-r) 4 | [![Appveyor](https://ci.appveyor.com/api/projects/status/xulke75tfifvnmj6?svg=true)](https://ci.appveyor.com/project/xtensor-stack/xtensor-r) 5 | [![Documentation](http://readthedocs.org/projects/xtensor-r/badge/?version=latest)](https://xtensor-r.readthedocs.io/en/latest/?badge=latest) 6 | [![Join the Gitter Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/QuantStack/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 7 | 8 | R bindings for the [xtensor](https://github.com/xtensor-stack/xtensor) C++ multi-dimensional array library. 9 | 10 | - `xtensor` is a C++ library for multi-dimensional arrays enabling numpy-style broadcasting and lazy computing. 11 | - `xtensor-r` enables inplace use of R arrays in C++ with all the benefits from `xtensor` 12 | 13 | - C++ universal functions and broadcasting 14 | - STL - compliant APIs. 15 | - A broad coverage of numpy APIs (see [the numpy to xtensor cheat sheet](http://xtensor.readthedocs.io/en/latest/numpy.html)). 16 | 17 | `xtensor-r` can be used either to author C++ extensions for R with [Rcpp](https://github.com/RcppCore/Rcpp), or applications that embed the R interpreter with [RInside](https://github.com/eddelbuettel/rinside). 18 | 19 | ## Example 20 | 21 | ```cpp 22 | #include // Standard library import for std::accumulate 23 | #define STRICT_R_HEADERS // Otherwise a PI macro is defined in R 24 | #include "xtensor/xmath.hpp" // xtensor import for the C++ universal functions 25 | #include "xtensor-r/rarray.hpp" // R bindings 26 | 27 | #include 28 | 29 | using namespace Rcpp; 30 | 31 | // [[Rcpp::plugins(cpp14)]] 32 | 33 | // [[Rcpp::export]] 34 | double sum_of_sines(xt::rarray& m) 35 | { 36 | auto sines = xt::sin(m); // sines does not actually hold values. 37 | return std::accumulate(sines.cbegin(), sines.cend(), 0.0); 38 | } 39 | ``` 40 | 41 | ```R 42 | v <- matrix(0:14, nrow=3, ncol=5) 43 | s <- sum_of_sines(v) 44 | s 45 | 46 | # prints 1.2853996391883833 47 | ``` 48 | 49 | ## Installation 50 | 51 | ### Installation of the standalone C++ library 52 | 53 | `xtensor-r` a header-only C++ library. It has been packaged for the mamba (or conda) package manager. 54 | 55 | ```bash 56 | mamba install xtensor-r -c conda-forge 57 | ``` 58 | 59 | `xtensor-r` can be installed from source with cmake in any installation prefix. For example, on unix systems 60 | 61 | ```bash 62 | cmake -D CMAKE_INSTALL_PREFIX=/prefix/path/ . 63 | make 64 | make install 65 | ``` 66 | 67 | ### Installation of the R package 68 | 69 | We provide a R package for Xtensor on both conda and CRAN (Comprehensive R Archive Network). 70 | The packaging boilerplate for the R package is available at https://github.com/xtensor-stack/Xtensor.R. 71 | 72 | To install the R package with conda: 73 | 74 | ```bash 75 | conda install r-xtensor -c conda-forge 76 | ``` 77 | 78 | To install the R package from CRAN: 79 | 80 | ```bash 81 | R CMD INSTALL xtensor 82 | ``` 83 | 84 | or from the GitHub repository using devtools 85 | 86 | ```R 87 | devtools::install_github("xtensor-stack/Xtensor.R") 88 | ``` 89 | 90 | The CRAN package vendors the headers for `xtensor-r`, xtensor`, `xtl` and `xsimd`. 91 | 92 | ## Documentation 93 | 94 | To get started with using `xtensor-r`, check out the full documentation 95 | 96 | http://xtensor-r.readthedocs.io/ 97 | 98 | ## Dependencies on `xtensor` and `Rcpp` 99 | 100 | `xtensor-r` depends on the `xtensor` and `Rcpp` libraries 101 | 102 | | `xtensor-r` | `xtensor` | `Rcpp` | 103 | |--------------|-----------|----------| 104 | | master | ^0.25.0 | ^1.0 | 105 | | 0.15.0 | ^0.25.0 | ^1.0 | 106 | | 0.14.2 | ^0.24.4 | ^1.0 | 107 | | 0.14.1 | ^0.24.0 | ^1.0 | 108 | | 0.14.0 | ^0.24.0 | ^1.0 | 109 | | 0.13.0 | ^0.23.0 | ^1.0 | 110 | | 0.12.1 | ^0.21.4 | ^1.0 | 111 | | 0.12.0 | ^0.21.2 | ^1.0 | 112 | 113 | - Core `xtensor` headers are vendored in the CRAN package. 114 | - When using the conda, or debian package managers, xtensor-r has a dependency on xtensor. 115 | 116 | ## License 117 | 118 | We use a shared copyright model that enables all contributors to maintain the copyright on their contributions. 119 | 120 | This software is licensed under the BSD-3-Clause license. See the [LICENSE](LICENSE) file for details. 121 | -------------------------------------------------------------------------------- /cmake/FindR.cmake: -------------------------------------------------------------------------------- 1 | # From https://github.com/Kitware/VTK/blob/master/CMake/FindR.cmake 2 | # 3 | # - This module locates an installed R distribution. 4 | # 5 | # Input: 6 | # R_LIB_ARCH - For windows (i386 or x64) 7 | # 8 | # Defines the following: 9 | # R_COMMAND - Path to R command 10 | # R_HOME - Path to 'R home', as reported by R 11 | # R_INCLUDE_DIR - Path to R include directory 12 | # R_LIBRARY_BASE - Path to R library 13 | # R_LIBRARY_BLAS - Path to Rblas / blas library 14 | # R_LIBRARY_LAPACK - Path to Rlapack / lapack library 15 | # R_LIBRARY_READLINE - Path to readline library 16 | # R_LIBRARIES - Array of: R_LIBRARY_BASE, R_LIBRARY_BLAS, R_LIBRARY_LAPACK, R_LIBRARY_BASE [, R_LIBRARY_READLINE] 17 | # 18 | # VTK_R_HOME - (deprecated, use R_HOME instead) Path to 'R home', as reported by R 19 | # 20 | # Variable search order: 21 | # 1. Attempt to locate and set R_COMMAND 22 | # - If unsuccessful, generate error and prompt user to manually set R_COMMAND 23 | # 2. Use R_COMMAND to set R_HOME 24 | # 3. Locate other libraries in the priority: 25 | # 1. Within a user-built instance of R at R_HOME 26 | # 2. Within an installed instance of R 27 | # 3. Within external system libraries 28 | # 29 | 30 | if(NOT R_LIB_ARCH) 31 | if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") 32 | set(R_LIB_ARCH x64) 33 | else() 34 | set(R_LIB_ARCH i386) 35 | endif() 36 | endif() 37 | 38 | set(TEMP_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE}) 39 | set(CMAKE_FIND_APPBUNDLE "NEVER") 40 | find_program(R_COMMAND R DOC "R executable.") 41 | set(CMAKE_FIND_APPBUNDLE ${TEMP_CMAKE_FIND_APPBUNDLE}) 42 | 43 | if(R_COMMAND) 44 | # temporarily append ".dll" to the cmake find_library suffixes 45 | set(OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) 46 | set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} ".dll") 47 | 48 | execute_process(WORKING_DIRECTORY . 49 | COMMAND ${R_COMMAND} RHOME 50 | OUTPUT_VARIABLE R_ROOT_DIR 51 | OUTPUT_STRIP_TRAILING_WHITESPACE) 52 | # deprecated 53 | if(VTK_R_HOME) 54 | set(R_HOME ${VTK_R_HOME} CACHE PATH "R home directory obtained from R RHOME") 55 | else() 56 | set(R_HOME ${R_ROOT_DIR} CACHE PATH "R home directory obtained from R RHOME") 57 | set(VTK_R_HOME ${R_HOME}) 58 | endif() 59 | # /deprecated 60 | # the following command does nothing currently, but will be used when deprecated code is removed 61 | set(R_HOME ${R_ROOT_DIR} CACHE PATH "R home directory obtained from R RHOME") 62 | 63 | find_path(R_INCLUDE_DIR R.h 64 | HINTS ${R_ROOT_DIR} ${R_ROOT_DIR}/bin/${R_LIB_ARCH} 65 | PATHS /usr/local/lib /usr/local/lib64 /usr/share 66 | PATH_SUFFIXES include R/include 67 | DOC "Path to file R.h") 68 | 69 | find_library(R_LIBRARY_BASE R 70 | HINTS ${R_ROOT_DIR}/lib ${R_ROOT_DIR}/bin/${R_LIB_ARCH} 71 | DOC "R library (example libR.a, libR.dylib, etc.).") 72 | 73 | find_library(R_LIBRARY_BLAS NAMES Rblas blas 74 | HINTS ${R_ROOT_DIR}/lib ${R_ROOT_DIR}/bin/${R_LIB_ARCH} 75 | DOC "Rblas library (example libRblas.a, libRblas.dylib, etc.).") 76 | 77 | find_library(R_LIBRARY_LAPACK NAMES Rlapack lapack 78 | HINTS ${R_ROOT_DIR}/lib ${R_ROOT_DIR}/bin/${R_LIB_ARCH} 79 | DOC "Rlapack library (example libRlapack.a, libRlapack.dylib, etc.).") 80 | 81 | find_library(R_LIBRARY_READLINE readline 82 | DOC "(Optional) system readline library. Only required if the R libraries were built with readline support.") 83 | 84 | # reset cmake find_library to initial value 85 | set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES}) 86 | else() 87 | message(SEND_ERROR "FindR.cmake requires the following variables to be set: R_COMMAND") 88 | endif() 89 | 90 | # Note: R_LIBRARY_BASE is added to R_LIBRARIES twice; this may be due to circular linking dependencies; needs further investigation 91 | set(R_LIBRARIES ${R_LIBRARY_BASE} ${R_LIBRARY_BLAS} ${R_LIBRARY_LAPACK} ${R_LIBRARY_BASE}) 92 | if(R_LIBRARY_READLINE) 93 | set(R_LIBRARIES ${R_LIBRARIES} ${R_LIBRARY_READLINE}) 94 | endif() 95 | -------------------------------------------------------------------------------- /docs/Doxyfile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = "xtensor-r" 2 | XML_OUTPUT = xml 3 | INPUT = ../include 4 | GENERATE_LATEX = NO 5 | GENERATE_MAN = NO 6 | GENERATE_RTF = NO 7 | CASE_SENSE_NAMES = NO 8 | GENERATE_HTML = NO 9 | GENERATE_XML = YES 10 | RECURSIVE = YES 11 | QUIET = YES 12 | JAVADOC_AUTOBRIEF = YES 13 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # You can set these variables from the command line. 2 | SPHINXOPTS = 3 | SPHINXBUILD = sphinx-build 4 | PAPER = 5 | BUILDDIR = build 6 | 7 | # User-friendly check for sphinx-build 8 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 9 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 10 | endif 11 | 12 | # Internal variables. 13 | PAPEROPT_a4 = -D latex_paper_size=a4 14 | PAPEROPT_letter = -D latex_paper_size=letter 15 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 16 | # the i18n builder cannot share the environment and doctrees with the others 17 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 18 | 19 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext api 20 | 21 | default: html 22 | 23 | help: 24 | @echo "Please use \`make ' where is one of" 25 | @echo " html to make standalone HTML files" 26 | @echo " dirhtml to make HTML files named index.html in directories" 27 | @echo " singlehtml to make a single large HTML file" 28 | @echo " pickle to make pickle files" 29 | @echo " json to make JSON files" 30 | @echo " htmlhelp to make HTML files and a HTML help project" 31 | @echo " qthelp to make HTML files and a qthelp project" 32 | @echo " applehelp to make an Apple Help Book" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | @echo " coverage to run coverage check of the documentation (if enabled)" 49 | 50 | clean: 51 | rm -rf $(BUILDDIR)/* 52 | rm -rf xml 53 | 54 | html: 55 | doxygen 56 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 57 | @echo 58 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 59 | 60 | dirhtml: 61 | doxygen 62 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 63 | @echo 64 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 65 | 66 | singlehtml: 67 | doxygen 68 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 69 | @echo 70 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 71 | 72 | pickle: 73 | doxygen 74 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 75 | @echo 76 | @echo "Build finished; now you can process the pickle files." 77 | 78 | json: 79 | doxygen 80 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 81 | @echo 82 | @echo "Build finished; now you can process the JSON files." 83 | 84 | htmlhelp: 85 | doxygen 86 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 87 | @echo 88 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 89 | ".hhp project file in $(BUILDDIR)/htmlhelp." 90 | 91 | epub: 92 | doxygen 93 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 94 | @echo 95 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 96 | 97 | latex: 98 | doxygen 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | doxygen 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo "Running LaTeX files through pdflatex..." 109 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 110 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 111 | 112 | latexpdfja: 113 | doxygen 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through platex and dvipdfmx..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | text: 120 | doxygen 121 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 122 | @echo 123 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 124 | 125 | man: 126 | doxygen 127 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 128 | @echo 129 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 130 | 131 | texinfo: 132 | doxygen 133 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 134 | @echo 135 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 136 | @echo "Run \`make' in that directory to run these through makeinfo" \ 137 | "(use \`make info' here to do that automatically)." 138 | 139 | info: 140 | doxygen 141 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 142 | @echo "Running Texinfo files through makeinfo..." 143 | make -C $(BUILDDIR)/texinfo info 144 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 145 | 146 | gettext: 147 | doxygen 148 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 149 | @echo 150 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 151 | 152 | changes: 153 | doxygen 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | doxygen 160 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 161 | @echo 162 | @echo "Link check complete; look for any errors in the above output " \ 163 | "or in $(BUILDDIR)/linkcheck/output.txt." 164 | 165 | doctest: 166 | doxygen 167 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 168 | @echo "Testing of doctests in the sources finished, look at the " \ 169 | "results in $(BUILDDIR)/doctest/output.txt." 170 | 171 | coverage: 172 | doxygen 173 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 174 | @echo "Testing of coverage in the sources finished, look at the " \ 175 | "results in $(BUILDDIR)/coverage/python.txt." 176 | 177 | xml: 178 | doxygen 179 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 180 | @echo 181 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 182 | 183 | pseudoxml: 184 | doxygen 185 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 186 | @echo 187 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 188 | -------------------------------------------------------------------------------- /docs/environment.yml: -------------------------------------------------------------------------------- 1 | name: xtensor-r-docs 2 | 3 | channels: 4 | - conda-forge 5 | 6 | dependencies: 7 | - breathe 8 | - sphinx_rtd_theme 9 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | set I18NSPHINXOPTS=%SPHINXOPTS% source 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | echo. coverage to run coverage check of the documentation if enabled 41 | goto end 42 | ) 43 | 44 | if "%1" == "clean" ( 45 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 46 | del /q /s %BUILDDIR%\* 47 | goto end 48 | ) 49 | 50 | 51 | REM Check if sphinx-build is available and fallback to Python version if any 52 | %SPHINXBUILD% 1>NUL 2>NUL 53 | if errorlevel 9009 goto sphinx_python 54 | goto sphinx_ok 55 | 56 | :sphinx_python 57 | 58 | set SPHINXBUILD=python -m sphinx.__init__ 59 | %SPHINXBUILD% 2> nul 60 | if errorlevel 9009 ( 61 | echo. 62 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 63 | echo.installed, then set the SPHINXBUILD environment variable to point 64 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 65 | echo.may add the Sphinx directory to PATH. 66 | echo. 67 | echo.If you don't have Sphinx installed, grab it from 68 | echo.http://sphinx-doc.org/ 69 | exit /b 1 70 | ) 71 | 72 | :sphinx_ok 73 | 74 | 75 | if "%1" == "html" ( 76 | doxygen 77 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 78 | if errorlevel 1 exit /b 1 79 | echo. 80 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 81 | goto end 82 | ) 83 | 84 | if "%1" == "dirhtml" ( 85 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 86 | if errorlevel 1 exit /b 1 87 | echo. 88 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 89 | goto end 90 | ) 91 | 92 | if "%1" == "singlehtml" ( 93 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 94 | if errorlevel 1 exit /b 1 95 | echo. 96 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 97 | goto end 98 | ) 99 | 100 | if "%1" == "pickle" ( 101 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 102 | if errorlevel 1 exit /b 1 103 | echo. 104 | echo.Build finished; now you can process the pickle files. 105 | goto end 106 | ) 107 | 108 | if "%1" == "json" ( 109 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 110 | if errorlevel 1 exit /b 1 111 | echo. 112 | echo.Build finished; now you can process the JSON files. 113 | goto end 114 | ) 115 | 116 | if "%1" == "htmlhelp" ( 117 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 118 | if errorlevel 1 exit /b 1 119 | echo. 120 | echo.Build finished; now you can run HTML Help Workshop with the ^ 121 | .hhp project file in %BUILDDIR%/htmlhelp. 122 | goto end 123 | ) 124 | 125 | if "%1" == "qthelp" ( 126 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 127 | if errorlevel 1 exit /b 1 128 | echo. 129 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 130 | .qhcp project file in %BUILDDIR%/qthelp, like this: 131 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\packagename.qhcp 132 | echo.To view the help file: 133 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\packagename.ghc 134 | goto end 135 | ) 136 | 137 | if "%1" == "devhelp" ( 138 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 139 | if errorlevel 1 exit /b 1 140 | echo. 141 | echo.Build finished. 142 | goto end 143 | ) 144 | 145 | if "%1" == "epub" ( 146 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 147 | if errorlevel 1 exit /b 1 148 | echo. 149 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 150 | goto end 151 | ) 152 | 153 | if "%1" == "latex" ( 154 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 155 | if errorlevel 1 exit /b 1 156 | echo. 157 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 158 | goto end 159 | ) 160 | 161 | if "%1" == "latexpdf" ( 162 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 163 | cd %BUILDDIR%/latex 164 | make all-pdf 165 | cd %~dp0 166 | echo. 167 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 168 | goto end 169 | ) 170 | 171 | if "%1" == "latexpdfja" ( 172 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 173 | cd %BUILDDIR%/latex 174 | make all-pdf-ja 175 | cd %~dp0 176 | echo. 177 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 178 | goto end 179 | ) 180 | 181 | if "%1" == "text" ( 182 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 183 | if errorlevel 1 exit /b 1 184 | echo. 185 | echo.Build finished. The text files are in %BUILDDIR%/text. 186 | goto end 187 | ) 188 | 189 | if "%1" == "man" ( 190 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 191 | if errorlevel 1 exit /b 1 192 | echo. 193 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 194 | goto end 195 | ) 196 | 197 | if "%1" == "texinfo" ( 198 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 199 | if errorlevel 1 exit /b 1 200 | echo. 201 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 202 | goto end 203 | ) 204 | 205 | if "%1" == "gettext" ( 206 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 207 | if errorlevel 1 exit /b 1 208 | echo. 209 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 210 | goto end 211 | ) 212 | 213 | if "%1" == "changes" ( 214 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 215 | if errorlevel 1 exit /b 1 216 | echo. 217 | echo.The overview file is in %BUILDDIR%/changes. 218 | goto end 219 | ) 220 | 221 | if "%1" == "linkcheck" ( 222 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 223 | if errorlevel 1 exit /b 1 224 | echo. 225 | echo.Link check complete; look for any errors in the above output ^ 226 | or in %BUILDDIR%/linkcheck/output.txt. 227 | goto end 228 | ) 229 | 230 | if "%1" == "doctest" ( 231 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 232 | if errorlevel 1 exit /b 1 233 | echo. 234 | echo.Testing of doctests in the sources finished, look at the ^ 235 | results in %BUILDDIR%/doctest/output.txt. 236 | goto end 237 | ) 238 | 239 | if "%1" == "coverage" ( 240 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 241 | if errorlevel 1 exit /b 1 242 | echo. 243 | echo.Testing of coverage in the sources finished, look at the ^ 244 | results in %BUILDDIR%/coverage/python.txt. 245 | goto end 246 | ) 247 | 248 | if "%1" == "xml" ( 249 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 250 | if errorlevel 1 exit /b 1 251 | echo. 252 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 253 | goto end 254 | ) 255 | 256 | if "%1" == "pseudoxml" ( 257 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 258 | if errorlevel 1 exit /b 1 259 | echo. 260 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 261 | goto end 262 | ) 263 | 264 | :end 265 | -------------------------------------------------------------------------------- /docs/source/_static/main_stylesheet.css: -------------------------------------------------------------------------------- 1 | .wy-nav-content{ 2 | max-width: 1000px; 3 | margin: auto; 4 | } 5 | -------------------------------------------------------------------------------- /docs/source/api_reference.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | API reference 8 | ============= 9 | 10 | Containers 11 | ---------- 12 | 13 | .. toctree:: 14 | :maxdepth: 2 15 | 16 | rarray 17 | rtensor 18 | roptional 19 | 20 | Numpy-style universal functions 21 | ------------------------------- 22 | 23 | .. toctree:: 24 | :maxdepth: 2 25 | 26 | rvectorize 27 | -------------------------------------------------------------------------------- /docs/source/array_tensor.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | Arrays and tensors 8 | ================== 9 | 10 | ``xtensor-r`` provides two container types wrapping R arrays: ``rarray`` and ``rtensor``. They are the counterparts 11 | to ``xarray`` and ``xtensor`` containers. 12 | 13 | rarray 14 | ------ 15 | 16 | Like ``xarray``, ``rarray`` has a dynamic shape. This means that you can reshape the R array on the C++ side and see this change reflected on the R side. ``rarray`` doesn't make a copy of the shape, but reads it each time it is needed. Therefore, if a reference on a ``rarray`` is kept in the C++ code and the corresponding R array is then reshaped in the R code, this modification will reflect in the ``rarray``. 17 | 18 | rtensor 19 | ------- 20 | 21 | Like ``xtensor``, ``rtensor`` has a static stack-allocated shape. This means that the shape of the R array is copied into the shape of the ``rtensor`` upon creation. As a consequence, reshapes are not reflected across languages. However, this drawback 22 | is offset by a more effective computation of shape and broadcast. 23 | 24 | -------------------------------------------------------------------------------- /docs/source/basic_usage.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | Basic Usage 8 | =========== 9 | 10 | Example : Use an algorithm of the C++ library on a R array inplace 11 | ------------------------------------------------------------------ 12 | 13 | **C++ code** 14 | 15 | .. code:: 16 | 17 | #include // Standard library import for std::accumulate 18 | #define STRICT_R_HEADERS // Otherwise a PI macro is defined in R 19 | #include "xtensor/xmath.hpp" // xtensor import for the C++ universal functions 20 | #include "xtensor-r/rarray.hpp" // R bindings 21 | #include 22 | 23 | using namespace Rcpp; 24 | 25 | // [[Rcpp::plugins(cpp14)]] 26 | 27 | // [[Rcpp::export]] 28 | double sum_of_sines(xt::rarray& m) 29 | { 30 | auto sines = xt::sin(m); // sines does not actually hold values. 31 | return std::accumulate(sines.cbegin(), sines.cend(), 0.0); 32 | } 33 | 34 | **R code:** 35 | 36 | .. code:: 37 | 38 | v <- matrix(0:14, nrow=3, ncol=5) 39 | s <- sum_of_sines(v) 40 | s 41 | 42 | **Outputs** 43 | 44 | .. code:: 45 | 46 | 1.2853996391883833 47 | 48 | Note that R places some restriction on what C++ types are usable. We've noted the 49 | differences in :ref:`r-pec`. -------------------------------------------------------------------------------- /docs/source/cmake.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 31 | 33 | 35 | 39 | 43 | 47 | 48 | 50 | 54 | 58 | 62 | 63 | 65 | 69 | 73 | 77 | 78 | 80 | 84 | 88 | 92 | 93 | 95 | 99 | 103 | 107 | 108 | 110 | 114 | 118 | 122 | 123 | 125 | 129 | 133 | 137 | 138 | 140 | 144 | 148 | 152 | 153 | 156 | 160 | 164 | 165 | 168 | 172 | 176 | 177 | 180 | 184 | 188 | 189 | 192 | 196 | 200 | 201 | 211 | 221 | 231 | 241 | 244 | 248 | 249 | 259 | 269 | 271 | 275 | 279 | 283 | 284 | 294 | 304 | 314 | 324 | 326 | 330 | 334 | 338 | 339 | 349 | 359 | 369 | 379 | 380 | 402 | 404 | 409 | 414 | 419 | 424 | 429 | 434 | 439 | 444 | 449 | 456 | 463 | 468 | 475 | 480 | 485 | 492 | 493 | 494 | -------------------------------------------------------------------------------- /docs/source/conda.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import subprocess 6 | 7 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True' 8 | 9 | if on_rtd: 10 | subprocess.call('cd ..; doxygen', shell=True) 11 | 12 | import sphinx_rtd_theme 13 | 14 | html_theme = "sphinx_rtd_theme" 15 | 16 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 17 | 18 | def setup(app): 19 | app.add_css_file("main_stylesheet.css") 20 | 21 | extensions = ['breathe', 'sphinx_rtd_theme'] 22 | breathe_projects = { 'xtensor-r': '../xml' } 23 | templates_path = ['_templates'] 24 | html_static_path = ['_static'] 25 | source_suffix = '.rst' 26 | master_doc = 'index' 27 | project = 'xtensor-r' 28 | copyright = '2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay' 29 | author = 'Wolf Vollprecht, Johan Mabille and Sylvain Corlay' 30 | 31 | html_logo = 'quantstack-white.svg' 32 | 33 | exclude_patterns = [] 34 | highlight_language = 'c++' 35 | pygments_style = 'sphinx' 36 | todo_include_todos = False 37 | htmlhelp_basename = 'xtensorrdoc' 38 | 39 | -------------------------------------------------------------------------------- /docs/source/cran.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/source/debian.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ]> 16 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 39 | 41 | 43 | 44 | 73 | 75 | 77 | 79 | 81 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | .. image:: xtensor-r.svg 8 | 9 | R bindings for the xtensor_ C++ multi-dimensional array library. 10 | 11 | Introduction 12 | ------------ 13 | 14 | What are ``xtensor`` and ``xtensor-r``? 15 | 16 | - ``xtensor`` is a C++ library for multi-dimensional arrays enabling numpy-style broadcasting and lazy computing. 17 | - ``xtensor-r`` enables inplace use of R arrays with all the benefits from ``xtensor`` 18 | 19 | - C++ universal functions and broadcasting 20 | - STL - compliant APIs. 21 | 22 | The `numpy to xtensor cheat sheet`_ from the ``xtensor`` documentation shows how numpy APIs translate to C++ with ``xtensor``. 23 | 24 | The Python bindings for ``xtensor`` are based on the Rcpp_ C++ library, which enables seemless interoperability between C++ and Python. 25 | 26 | Enabling R arrays in your C++ libraries 27 | --------------------------------------- 28 | 29 | Instead of exposing new types to R, ``xtensor-r`` enables the use of R data structures from C++ using R's C API. 30 | 31 | In addition to the basic accessors and iterators of ``xtensor`` containers, it also enables using R arrays with ``xtensor``'s expression system. 32 | 33 | Besides ``xtensor-r`` provides an API to create *Universal functions* from simple scalar functions from your C++ code. 34 | 35 | ``xtensor`` and ``xtensor-r`` require a modern C++ compiler supporting C++14. The following C++ compilers are supported: 36 | 37 | - On Windows platforms, Visual C++ 2015 Update 2, or more recent 38 | - On Unix platforms, gcc 4.9 or a recent version of Clang 39 | 40 | Licensing 41 | --------- 42 | 43 | We use a shared copyright model that enables all contributors to maintain the 44 | copyright on their contributions. 45 | 46 | This software is licensed under the BSD-3-Clause license. See the LICENSE file for details. 47 | 48 | .. toctree:: 49 | :caption: INSTALLATION 50 | :maxdepth: 2 51 | 52 | installation 53 | 54 | 55 | .. toctree:: 56 | :caption: USAGE 57 | :maxdepth: 2 58 | 59 | basic_usage 60 | array_tensor 61 | r_peculiarities 62 | 63 | .. toctree:: 64 | :caption: API REFERENCE 65 | :maxdepth: 2 66 | 67 | api_reference 68 | 69 | .. toctree:: 70 | :caption: DEVELOPER ZONE 71 | 72 | releasing 73 | 74 | .. _`numpy to xtensor cheat sheet`: http://xtensor.readthedocs.io/en/latest/numpy.html 75 | .. _xtensor: https://github.com/xtensor-stack/xtensor 76 | .. _Rcpp: http://www.rcpp.org/ 77 | -------------------------------------------------------------------------------- /docs/source/installation.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | 8 | .. raw:: html 9 | 10 | 20 | 21 | Installation of the xtensor-r C++ library 22 | ========================================= 23 | 24 | ``xtensor-r`` is a header-only C++ library. We maintain the conda package for xtensor-r and its dependencies. 25 | 26 | Besides the xtendor-r headers, all these methods place the `cmake` project configuration file in the right location so that third-party projects can use cmake's find_package to locate xtensor-r headers. 27 | 28 | .. image:: conda.svg 29 | 30 | Using the conda-forge package 31 | ----------------------------- 32 | 33 | A package for xtensor-r is available on the mamba (or conda) package manager. 34 | 35 | .. code:: 36 | 37 | mamba install -c conda-forge xtensor-r 38 | 39 | .. image:: cmake.svg 40 | 41 | From source with cmake 42 | ---------------------- 43 | 44 | You can also install ``xtensor-r`` from source with cmake. On Unix platforms, from the source directory: 45 | 46 | .. code:: 47 | 48 | mkdir build 49 | cd build 50 | cmake -DCMAKE_INSTALL_PREFIX=/path/to/prefix .. 51 | make install 52 | 53 | On Windows platforms, from the source directory: 54 | 55 | .. code:: 56 | 57 | mkdir build 58 | cd build 59 | cmake -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=/path/to/prefix .. 60 | nmake 61 | nmake install 62 | 63 | .. image:: cran.svg 64 | 65 | Installation of the R package 66 | ============================= 67 | 68 | We provide a R package for Xtensor on both conda and CRAN (Comprehensive R Archive Network). 69 | The packaging boilerplate for the R package is available at https://github.com/xtensor-stack/Xtensor.R. 70 | 71 | To install the R package with conda: 72 | 73 | .. code:: bash 74 | 75 | conda install r-xtensor -c conda-forge 76 | 77 | To install the R package from CRAN: 78 | 79 | .. code:: bash 80 | 81 | R CMD INSTALL xtensor 82 | 83 | or from the GitHub repository using devtools: 84 | 85 | .. code:: r 86 | 87 | devtools::install_github("xtensor-stack/Xtensor.R") 88 | 89 | .. note:: 90 | 91 | A key difference between the version of the R package available on CRAN and conda is that 92 | 93 | - the CRAN package *vendors* the headers of ``xtl``, ``xsimd``, ``xtensor``, and ``xtensor-r``. 94 | - the conda package *depends* on the conda packages for ``xtl``, ``xsimd``, ``xtensor`` and ``xtensor-r``. 95 | 96 | When installing the package from CRAN, it is still possible to drop the vendored dependencies by adding the 97 | ``--configure-args='--novendor'`` option to the ``R CMD INSTALL`` command, or by defining the ``NO_VENDOR_XTENSOR`` 98 | environment variable to ``YES``. 99 | 100 | -------------------------------------------------------------------------------- /docs/source/quantstack-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /docs/source/r_peculiarities.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | .. _r-pec: 8 | 9 | R Peculiarities 10 | =============== 11 | 12 | R supports only a subset of types available in C++. The types which are natively 13 | supported with xtensor-R are int (32 bit), double, complex, byte. 14 | Using other types (such as a C++ ``float``) in a ``rarray`` or ``rtensor`` will fail to compile. 15 | 16 | Below is a mapping from R to xtensor: 17 | 18 | +----------------+----------------------------------+ 19 | | R type | xtensor type | 20 | +================+==================================+ 21 | | Integer Vector | rarray or rarray | 22 | +----------------+----------------------------------+ 23 | | Real Vector | rarray | 24 | +----------------+----------------------------------+ 25 | | Complex Vector | rarray> | 26 | +----------------+----------------------------------+ 27 | | Raw Vector | rarray or rarray | 28 | +----------------+----------------------------------+ 29 | | Logical Vector | Not supported at the moment | 30 | +----------------+----------------------------------+ 31 | 32 | Note that, for illustration purposes, ``rarray`` was used above. The ``rtensor`` 33 | container works just as well. 34 | 35 | R's NA and NaN values 36 | --------------------- 37 | 38 | R encodes missing values (NAs) as special values of the underlying type. 39 | 40 | Xtensor-r supports R's missing values with the ``rarray_optional`` and 41 | ``rtensor_optional`` counterparts to ``rarray`` and ``rtensor`` which enable 42 | operations with missing values with the ``xoptional`` API. 43 | 44 | R defining PI as macro 45 | ---------------------- 46 | 47 | Ancient versions of ``S`` used to define a ``PI`` macro. This macro collides with 48 | xtensor, as xtensor is using ``PI`` as a variable name in the numeric constants. 49 | 50 | If you're encountering this issue, either reorder your headers so that the xmath 51 | header of xtensor is included before Rcpp / xtensor-r or use the following define 52 | before including xtensor-r and Rcpp: 53 | 54 | .. code:: 55 | 56 | #define STRICT_R_HEADERS 57 | 58 | This prevents the PI macro definition. 59 | -------------------------------------------------------------------------------- /docs/source/rarray.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | rarray 8 | ====== 9 | 10 | .. doxygenclass:: xt::rarray 11 | :project: xtensor-r 12 | :members: 13 | -------------------------------------------------------------------------------- /docs/source/releasing.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | Releasing xtensor-r 8 | =================== 9 | 10 | Releasing a new version 11 | ----------------------- 12 | 13 | From the master branch of xtensor-r 14 | 15 | - Make sure that you are in sync with the master branch of the upstream remote. 16 | - In file ``xtensor_r_config.hpp``, set the macros for ``XTENSOR_R_VERSION_MAJOR``, ``XTENSOR_R_VERSION_MINOR`` and ``XTENSOR_R_VERSION_PATCH`` to the desired values. 17 | - Update the readme file w.r.t. dependencies on xtensor and pybind11. 18 | - Stage the changes (``git add``), commit the changes (``git commit``) and add a tag of the form ``Major.minor.patch``. It is important to not add any other content to the tag name. 19 | - Push the new commit and tag to the main repository. (``git push``, and ``git push --tags``) 20 | 21 | Updating the conda-forge recipe 22 | ------------------------------- 23 | 24 | xtensor-r has been packaged for the conda package manager. Once the new tag has been pushed on GitHub, edit the conda-forge recipe for xtensor in the following fashion: 25 | 26 | - Update the version number to the new Major.minor.patch. 27 | - Set the build number to 0. 28 | - Update the hash of the source tarball. 29 | - Check for the versions of the dependencies. 30 | - Optionally, rerender the conda-forge feedstock. 31 | 32 | Releasing the R Package 33 | ======================= 34 | 35 | To build a package tarball for R, simply clone https://github.com/xtensor-stack/Xtensor.R and run 36 | 37 | .. code:: bash 38 | 39 | R CMD build . 40 | 41 | from the root of the source directory. 42 | 43 | To produce a package tarball *vendoring* the xtl, xsimd and xtensor dependencies (for e.g. CRAN), clone https://github.com/xtensor-stack/Xtensor.R and run 44 | 45 | .. code:: bash 46 | 47 | ./configure # Downloads xtl, xtensor, xsimd, and xtensor-r. 48 | R CMD build . 49 | 50 | from the root of the source directory. 51 | -------------------------------------------------------------------------------- /docs/source/roptional.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | roptional 8 | ========= 9 | 10 | .. doxygenclass:: xt::rcontainer_optional 11 | :project: xtensor-r 12 | :members: 13 | -------------------------------------------------------------------------------- /docs/source/rtensor.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | rtensor 8 | ======= 9 | 10 | .. doxygenclass:: xt::rtensor 11 | :project: xtensor-r 12 | :members: 13 | -------------------------------------------------------------------------------- /docs/source/rvectorize.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay 2 | 3 | Distributed under the terms of the BSD 3-Clause License. 4 | 5 | The full license is in the file LICENSE, distributed with this software. 6 | 7 | rvectorize 8 | ========== 9 | 10 | .. doxygenfunction:: xt::rvectorize 11 | :project: xtensor-r 12 | -------------------------------------------------------------------------------- /docs/source/xtensor-r.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 11 | 12 | 15 | 19 | 20 | 41 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /environment-dev-win.yml: -------------------------------------------------------------------------------- 1 | name: xtensor-r 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - cmake 6 | - xtensor=0.25.0 7 | - r-base 8 | - r-rcpp 9 | - m2w64-gcc 10 | - m2w64-make 11 | - m2w64-toolchain 12 | - m2-libbz2 13 | - posix 14 | # test dependencies 15 | - r-rinside 16 | - r-devtools 17 | - r-testthat 18 | -------------------------------------------------------------------------------- /environment-dev.yml: -------------------------------------------------------------------------------- 1 | name: xtensor-r 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - cmake 6 | - xtensor=0.25.0 7 | - r-base 8 | - r-rcpp 9 | # test dependencies 10 | - r-rinside 11 | - r-devtools 12 | - r-testthat 13 | -------------------------------------------------------------------------------- /include/xtensor-r/rarray.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #ifndef XTENSOR_R_ARRAY_HPP 11 | #define XTENSOR_R_ARRAY_HPP 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "xtensor/xbuffer_adaptor.hpp" 19 | #include "xtensor/xcontainer.hpp" 20 | #include "xtensor/xiterator.hpp" 21 | #include "xtensor/xsemantic.hpp" 22 | #include "xtensor/xutils.hpp" 23 | 24 | #include "xtensor-r/rcontainer.hpp" 25 | 26 | namespace xt 27 | { 28 | template 29 | class rarray; 30 | 31 | template 32 | struct xcontainer_inner_types> 33 | { 34 | using r_type = T; 35 | using underlying_type = r_detail::get_underlying_value_type_r; 36 | using storage_type = xbuffer_adaptor; 37 | using reference = typename storage_type::reference; 38 | using const_reference = typename storage_type::const_reference; 39 | using size_type = typename storage_type::size_type; 40 | constexpr static int SXP = Rcpp::traits::r_sexptype_traits::rtype; 41 | using shape_type = xt::dynamic_shape; 42 | using strides_type = xt::dynamic_shape; 43 | using backstrides_type = xt::dynamic_shape; 44 | 45 | using shape_value_type = typename Rcpp::traits::storage_type::type; 46 | using inner_shape_type = xbuffer_adaptor; 47 | using inner_strides_type = strides_type; 48 | using inner_backstrides_type = backstrides_type; 49 | using temporary_type = rarray; 50 | static constexpr layout_type layout = layout_type::column_major; 51 | }; 52 | 53 | template 54 | struct xiterable_inner_types> 55 | : xcontainer_iterable_types> 56 | { 57 | }; 58 | 59 | /** 60 | * @class rarray 61 | * @brief Multidimensional container providing the xtensor container semantics to an R array. 62 | * 63 | * rarray is similar to the xarray container in that it has a dynamic dimensionality. 64 | * Reshapes of a rarray container are reflected in the underlying R array. 65 | * 66 | * @tparam T The type of the element stored in the rarray. 67 | * 68 | * @sa rtensor 69 | */ 70 | template 71 | class rarray : public rcontainer>, 72 | public xcontainer_semantic> 73 | { 74 | public: 75 | 76 | using self_type = rarray; 77 | using base_type = rcontainer; 78 | using semantic_base = xcontainer_semantic>; 79 | 80 | using inner_types = xcontainer_inner_types; 81 | 82 | using underlying_type = typename inner_types::underlying_type; 83 | using storage_type = typename inner_types::storage_type; 84 | using value_type = typename storage_type::value_type; 85 | using reference = typename storage_type::reference; 86 | using const_reference = typename storage_type::const_reference; 87 | using pointer = typename storage_type::pointer; 88 | using const_pointer = typename storage_type::const_pointer; 89 | using size_type = typename storage_type::size_type; 90 | using difference_type = typename storage_type::difference_type; 91 | 92 | using shape_type = typename inner_types::shape_type; 93 | using strides_type = typename inner_types::strides_type; 94 | using backstrides_type = typename inner_types::backstrides_type; 95 | using inner_shape_type = typename inner_types::inner_shape_type; 96 | using inner_strides_type = typename inner_types::inner_strides_type; 97 | using inner_backstrides_type = typename inner_types::inner_backstrides_type; 98 | 99 | using iterable_base = xiterable; 100 | 101 | using iterator = typename iterable_base::iterator; 102 | using const_iterator = typename iterable_base::const_iterator; 103 | 104 | using stepper = typename iterable_base::stepper; 105 | using const_stepper = typename iterable_base::const_stepper; 106 | 107 | constexpr static int SXP = Rcpp::traits::r_sexptype_traits::rtype; 108 | 109 | constexpr static std::size_t rank = SIZE_MAX; 110 | 111 | rarray() = default; 112 | rarray(SEXP exp); 113 | 114 | rarray(const shape_type& shape); 115 | rarray(const shape_type& shape, const_reference value); 116 | 117 | rarray(const value_type& t); 118 | rarray(nested_initializer_list_t t); 119 | rarray(nested_initializer_list_t t); 120 | rarray(nested_initializer_list_t t); 121 | rarray(nested_initializer_list_t t); 122 | rarray(nested_initializer_list_t t); 123 | 124 | template 125 | static rarray from_shape(S&& shape); 126 | 127 | template 128 | rarray(const xexpression& e); 129 | 130 | rarray(const self_type& rhs); 131 | self_type& operator=(const self_type& rhs); 132 | 133 | rarray(self_type&&) = default; 134 | self_type& operator=(self_type&&) = default; 135 | 136 | template 137 | self_type& operator=(const xexpression& e); 138 | 139 | layout_type layout() const; 140 | 141 | // Internal method, called when the stored SEXP changes 142 | void update(SEXP new_sexp) noexcept; 143 | 144 | private: 145 | 146 | storage_type m_storage; 147 | inner_shape_type m_shape; 148 | strides_type m_strides; 149 | strides_type m_backstrides; 150 | 151 | template 152 | void init_from_shape(const S& shape); 153 | 154 | const inner_shape_type& shape_impl() const noexcept; 155 | const inner_strides_type& strides_impl() const noexcept; 156 | const inner_backstrides_type& backstrides_impl() const noexcept; 157 | storage_type& storage_impl() noexcept; 158 | const storage_type& storage_impl() const noexcept; 159 | 160 | void update_shape_and_strides() noexcept; 161 | 162 | friend class xcontainer>; 163 | friend class rcontainer, Rcpp::PreserveStorage>; 164 | }; 165 | 166 | /************************* 167 | * rarray implementation * 168 | *************************/ 169 | 170 | /** 171 | * @name Constructors 172 | */ 173 | //@{ 174 | template 175 | inline rarray::rarray(SEXP exp) 176 | { 177 | detail::check_coercion(exp); 178 | base_type::rstorage::set__(Rcpp::r_cast(exp)); 179 | } 180 | 181 | template 182 | template 183 | inline void rarray::init_from_shape(const S& shape) 184 | { 185 | if (shape.size() == 0) 186 | { 187 | base_type::rstorage::set__(Rf_allocVector(SXP, 1)); 188 | } 189 | else 190 | { 191 | Rcpp::IntegerVector tmp_shape(shape.begin(), shape.end()); 192 | base_type::rstorage::set__(Rf_allocArray(SXP, SEXP(tmp_shape))); 193 | } 194 | } 195 | 196 | /** 197 | * Allocates an uninitialized rarray with the specified shape. 198 | * @param shape the shape of the rarray 199 | */ 200 | template 201 | inline rarray::rarray(const shape_type& shape) 202 | { 203 | init_from_shape(shape); 204 | } 205 | 206 | /** 207 | * Allocates a rarray with the specified shape. Elements are 208 | * initialized to the specified value. 209 | * @param shape the shape of the rarray 210 | * @param value the value of the elements 211 | */ 212 | template 213 | inline rarray::rarray(const shape_type& shape, const_reference value) 214 | { 215 | init_from_shape(shape); 216 | std::fill(this->begin(), this->end(), value); 217 | } 218 | 219 | /** 220 | * Allocates a rarray with nested initializer lists. 221 | */ 222 | template 223 | inline rarray::rarray(const value_type& t) 224 | { 225 | init_from_shape(xt::shape(t)); 226 | nested_copy(m_storage.begin(), t); 227 | } 228 | 229 | template 230 | inline rarray::rarray(nested_initializer_list_t t) 231 | { 232 | init_from_shape(xt::shape(t)); 233 | nested_copy(this->begin(), t); 234 | } 235 | 236 | template 237 | inline rarray::rarray(nested_initializer_list_t t) 238 | { 239 | init_from_shape(xt::shape(t)); 240 | nested_copy(this->begin(), t); 241 | } 242 | 243 | template 244 | inline rarray::rarray(nested_initializer_list_t t) 245 | { 246 | init_from_shape(xt::shape(t)); 247 | nested_copy(this->begin(), t); 248 | } 249 | 250 | template 251 | inline rarray::rarray(nested_initializer_list_t t) 252 | { 253 | init_from_shape(xt::shape(t)); 254 | nested_copy(this->begin(), t); 255 | } 256 | 257 | template 258 | inline rarray::rarray(nested_initializer_list_t t) 259 | { 260 | init_from_shape(xt::shape(t)); 261 | nested_copy(this->begin(), t); 262 | } 263 | 264 | /** 265 | * Allocates and returns an rarray with the specified shape. 266 | * @param shape the shape of the rarray 267 | */ 268 | template 269 | template 270 | inline rarray rarray::from_shape(S&& shape) 271 | { 272 | return self_type(xtl::forward_sequence(shape)); 273 | } 274 | //@} 275 | 276 | /** 277 | * @name Copy semantic 278 | */ 279 | //@{ 280 | /** 281 | * The copy constructor. 282 | */ 283 | template 284 | inline rarray::rarray(const self_type& rhs) 285 | : base_type(rhs), semantic_base(rhs) 286 | { 287 | init_from_shape(rhs.shape()); 288 | std::copy(rhs.storage().cbegin(), rhs.storage().cend(), this->storage().begin()); 289 | } 290 | 291 | /** 292 | * The assignment operator. 293 | */ 294 | template 295 | inline auto rarray::operator=(const self_type& rhs) -> self_type& 296 | { 297 | self_type tmp(rhs); 298 | *this = std::move(tmp); 299 | return *this; 300 | } 301 | //@} 302 | 303 | /** 304 | * @name Extended copy semantic 305 | */ 306 | //@{ 307 | /** 308 | * The extended copy constructor. 309 | */ 310 | template 311 | template 312 | inline rarray::rarray(const xexpression& e) 313 | { 314 | semantic_base::assign(e); 315 | } 316 | 317 | /** 318 | * The extended assignment operator. 319 | */ 320 | template 321 | template 322 | inline auto rarray::operator=(const xexpression& e) -> self_type& 323 | { 324 | return semantic_base::operator=(e); 325 | } 326 | //@} 327 | 328 | template 329 | inline layout_type rarray::layout() const 330 | { 331 | return layout_type::column_major; 332 | } 333 | 334 | template 335 | inline auto rarray::shape_impl() const noexcept -> const inner_shape_type& 336 | { 337 | return m_shape; 338 | } 339 | 340 | template 341 | inline auto rarray::strides_impl() const noexcept -> const inner_strides_type& 342 | { 343 | return m_strides; 344 | } 345 | 346 | template 347 | inline auto rarray::backstrides_impl() const noexcept -> const inner_backstrides_type& 348 | { 349 | return m_backstrides; 350 | } 351 | 352 | template 353 | inline auto rarray::storage_impl() noexcept -> storage_type& 354 | { 355 | return m_storage; 356 | } 357 | 358 | template 359 | inline auto rarray::storage_impl() const noexcept -> const storage_type& 360 | { 361 | return m_storage; 362 | } 363 | 364 | template 365 | inline void rarray::update(SEXP new_sexp) noexcept 366 | { 367 | this->m_shape = detail::r_shape_to_buffer_adaptor(new_sexp); 368 | resize_container(m_strides, m_shape.size()); 369 | resize_container(m_backstrides, m_shape.size()); 370 | std::size_t sz = xt::compute_strides(m_shape, layout_type::column_major, m_strides, m_backstrides); 371 | this->m_storage = storage_type(reinterpret_cast(Rcpp::internal::r_vector_start(new_sexp)), sz); 372 | } 373 | 374 | template 375 | inline void rarray::update_shape_and_strides() noexcept 376 | { 377 | m_shape = detail::r_shape_to_buffer_adaptor(*this); 378 | xt::compute_strides(m_shape, layout_type::column_major, m_strides, m_backstrides); 379 | } 380 | } 381 | 382 | namespace Rcpp 383 | { 384 | template 385 | inline SEXP wrap(const xt::rarray& arr) 386 | { 387 | return SEXP(arr); 388 | } 389 | } 390 | 391 | #endif 392 | -------------------------------------------------------------------------------- /include/xtensor-r/rcontainer.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #ifndef XTENSOR_R_CONTAINER_HPP 11 | #define XTENSOR_R_CONTAINER_HPP 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "xtensor/xbuffer_adaptor.hpp" 18 | #include "xtensor/xcontainer.hpp" 19 | 20 | #include "xtl/xsequence.hpp" 21 | 22 | #include "xtensor_r_config.hpp" 23 | 24 | #include "rcpp_extensions.hpp" 25 | 26 | #include 27 | 28 | // Fake type for R logicals 29 | struct rlogical {}; 30 | 31 | // This handles the conversion of xtensor back to R type 32 | // When an xtensor with a T of rlogical is seen, the retrieved rtype 33 | // is LGLSXP (even though it is stored internally as an int in xtensor) 34 | namespace Rcpp 35 | { 36 | namespace traits 37 | { 38 | template<> 39 | struct r_sexptype_traits 40 | { 41 | static constexpr int rtype = LGLSXP; 42 | }; 43 | } 44 | } 45 | 46 | namespace xt 47 | { 48 | #if defined(__GNUC__) && !defined(__clang__) 49 | namespace workaround 50 | { 51 | inline void complex_allocator() 52 | { 53 | std::allocator> a; 54 | } 55 | } 56 | #endif 57 | 58 | // R stores logicals as int32. This ensures that when a logical is seen, 59 | // the internal xtensor storage type uses an int. 60 | namespace r_detail 61 | { 62 | template 63 | struct get_underlying_value_type_r 64 | { 65 | using type = T; 66 | }; 67 | 68 | template <> 69 | struct get_underlying_value_type_r 70 | { 71 | using type = int; 72 | }; 73 | } 74 | 75 | namespace detail 76 | { 77 | inline xbuffer_adaptor r_shape_to_buffer_adaptor(SEXP exp) 78 | { 79 | SEXP dim = Rf_getAttrib(exp, R_DimSymbol); 80 | SEXP shape_sexp = Rf_isNull(dim) ? SEXP(Rcpp::IntegerVector::create(Rf_length(exp))) : dim; 81 | 82 | std::size_t n = (std::size_t)Rf_xlength(shape_sexp); 83 | return xbuffer_adaptor(Rcpp::internal::r_vector_start(shape_sexp), n); 84 | } 85 | 86 | inline xbuffer_adaptor r_shape_to_buffer_adaptor(SEXP exp, std::size_t n) 87 | { 88 | SEXP dim = Rf_getAttrib(exp, R_DimSymbol); 89 | SEXP shape_sexp = Rf_isNull(dim) ? SEXP(Rcpp::IntegerVector::create(Rf_length(exp))) : dim; 90 | 91 | if (n != (std::size_t)Rf_xlength(shape_sexp)) 92 | { 93 | throw std::runtime_error("Could not convert shape for rtensor. Dimensions don't match."); 94 | } 95 | return xbuffer_adaptor(Rcpp::internal::r_vector_start(shape_sexp), n); 96 | } 97 | 98 | template 99 | inline void check_coercion(SEXP exp) 100 | { 101 | #if XTENSOR_WARN_ON_COERCE 102 | if (TYPEOF(exp) != SXP) 103 | { 104 | Rcpp::warning("Coerced object from '%s' to '%s'. Avoid for speed & in-place operations.", 105 | Rf_type2char(TYPEOF(exp)), 106 | Rf_type2char(SXP)); 107 | } 108 | #endif 109 | } 110 | } 111 | 112 | /** 113 | * @class rcontainer 114 | * @brief Base class for xtensor containers wrapping R arryays. 115 | * 116 | * The rcontainer class should not be instantiated directly. Instead, used should 117 | * use rtensor and rarray instances. 118 | * 119 | * @tparam D The derived type, i.e. the inheriting class for which rcontainer 120 | * provides the interface. 121 | * @tparam SP The Rcpp storage policy, defaults to Rcpp::PreserveStorage 122 | */ 123 | template class SP = Rcpp::PreserveStorage> 124 | class rcontainer : public xcontainer, public SP 125 | { 126 | public: 127 | 128 | using derived_type = D; 129 | 130 | using rstorage = SP; 131 | 132 | using base_type = xcontainer; 133 | using inner_types = xcontainer_inner_types; 134 | using r_type = typename inner_types::r_type; 135 | using storage_type = typename inner_types::storage_type; 136 | using value_type = typename storage_type::value_type; 137 | using reference = typename storage_type::reference; 138 | using const_reference = typename storage_type::const_reference; 139 | using pointer = typename storage_type::pointer; 140 | using const_pointer = typename storage_type::const_pointer; 141 | using size_type = typename storage_type::size_type; 142 | using difference_type = typename storage_type::difference_type; 143 | 144 | #ifndef XTENSOR_R_ALLOW_REINTERPRETATION 145 | static_assert(xtl::disjunction, 146 | std::is_same, 147 | std::is_same, 148 | std::is_same, 149 | std::is_same>>::value == true, 150 | "R containers can only be of type rlogical, int, double, std::complex."); 151 | #endif 152 | using shape_type = typename inner_types::shape_type; 153 | using strides_type = typename inner_types::strides_type; 154 | using backstrides_type = typename inner_types::backstrides_type; 155 | using inner_shape_type = typename inner_types::inner_shape_type; 156 | using inner_strides_type = typename inner_types::inner_strides_type; 157 | 158 | using iterable_base = xiterable; 159 | 160 | using iterator = typename iterable_base::iterator; 161 | using const_iterator = typename iterable_base::const_iterator; 162 | 163 | using stepper = typename iterable_base::stepper; 164 | using const_stepper = typename iterable_base::const_stepper; 165 | 166 | static constexpr layout_type static_layout = layout_type::column_major; 167 | static constexpr bool contiguous_layout = true; 168 | 169 | template 170 | void resize(S&& shape, bool force = false); 171 | 172 | template 173 | void reshape(S&& shape); 174 | 175 | layout_type layout() const; 176 | bool is_contiguous() const noexcept; 177 | 178 | // explicitly forward data against ambiguity with Rcpp::Storage::data; 179 | using base_type::data; 180 | 181 | protected: 182 | 183 | rcontainer() = default; 184 | ~rcontainer() = default; 185 | 186 | rcontainer(const rcontainer&) = default; 187 | rcontainer& operator=(const rcontainer&) = default; 188 | 189 | rcontainer(rcontainer&&) = default; 190 | rcontainer& operator=(rcontainer&&) = default; 191 | }; 192 | 193 | 194 | /** 195 | * Resizes the container. 196 | * @param shape the new shape 197 | */ 198 | template class SP> 199 | template 200 | inline void rcontainer::resize(S&& shape, bool force) 201 | { 202 | // if SEXP not initialized, it will be NULL (e.g. in constructor) 203 | if (Rf_isNull(*this) || shape.size() != this->dimension() || !std::equal(std::begin(shape), std::end(shape), this->shape().cbegin()) || force) 204 | { 205 | derived_type tmp(xtl::forward_sequence(shape)); 206 | this->derived_cast() = std::move(tmp); 207 | } 208 | } 209 | 210 | /** 211 | * Reshapes the container. 212 | * @param shape the new shape 213 | */ 214 | template class SP> 215 | template 216 | inline void rcontainer::reshape(S&& shape) 217 | { 218 | if (compute_size(shape) != this->size()) 219 | { 220 | throw std::runtime_error("Cannot reshape with incorrect number of elements."); 221 | } 222 | 223 | if (shape.size() != this->dimension() || !std::equal(std::begin(shape), std::end(shape), this->shape().cbegin())) 224 | { 225 | auto tmp_shape = Rcpp::IntegerVector(std::begin(shape), std::end(shape)); 226 | Rf_setAttrib(rstorage::get__(), R_DimSymbol, SEXP(tmp_shape)); 227 | this->derived_cast().update_shape_and_strides(); 228 | } 229 | } 230 | 231 | template class SP> 232 | inline layout_type rcontainer::layout() const 233 | { 234 | return layout_type::column_major; 235 | } 236 | 237 | template class SP> 238 | inline bool rcontainer::is_contiguous() const noexcept 239 | { 240 | return this->derived_cast().strides().front() == difference_type(1); 241 | } 242 | } 243 | 244 | #endif 245 | -------------------------------------------------------------------------------- /include/xtensor-r/rcpp_extensions.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #ifndef XTENSOR_R_RCPP_EXTENSIONS_HPP 11 | #define XTENSOR_R_RCPP_EXTENSIONS_HPP 12 | 13 | #include 14 | 15 | namespace xt 16 | { 17 | template 18 | class rarray; 19 | 20 | template 21 | class rtensor; 22 | 23 | template 24 | class rcontainer_optional; 25 | } 26 | 27 | namespace Rcpp 28 | { 29 | // Specializing Rcpp traits for xtensor types prevents copies 30 | // occuring in the generic `as` function from Rcpp, called 31 | // from the generic exporter. 32 | namespace traits 33 | { 34 | template 35 | class Exporter> 36 | { 37 | public: 38 | 39 | Exporter(SEXP x) 40 | : m_sexp(x) 41 | { 42 | } 43 | 44 | inline xt::rarray get() 45 | { 46 | return xt::rarray(m_sexp); 47 | } 48 | 49 | private: 50 | 51 | SEXP m_sexp; 52 | }; 53 | 54 | template 55 | class Exporter> 56 | { 57 | public: 58 | 59 | Exporter(SEXP x) 60 | : m_sexp(x) 61 | { 62 | } 63 | 64 | inline xt::rtensor get() 65 | { 66 | return xt::rtensor(m_sexp); 67 | } 68 | 69 | private: 70 | 71 | SEXP m_sexp; 72 | }; 73 | 74 | template 75 | class Exporter> 76 | { 77 | public: 78 | 79 | Exporter(SEXP x) 80 | : m_sexp(x) 81 | { 82 | } 83 | 84 | inline xt::rcontainer_optional get() 85 | { 86 | return xt::rcontainer_optional(m_sexp); 87 | } 88 | 89 | private: 90 | 91 | SEXP m_sexp; 92 | }; 93 | } 94 | } 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /include/xtensor-r/roptional.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #ifndef XTENSOR_R_OPTIONAL_HPP 11 | #define XTENSOR_R_OPTIONAL_HPP 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #include "rarray.hpp" 23 | #include "rtensor.hpp" 24 | 25 | namespace xt 26 | { 27 | /*********************************** 28 | * rcontainer_optional declaration * 29 | ***********************************/ 30 | 31 | template 32 | class rcontainer_optional; 33 | 34 | template 35 | using rarray_optional = rcontainer_optional>; 36 | 37 | template 38 | using rtensor_optional = rcontainer_optional>; 39 | 40 | /* 41 | * R uses special NaN values to represent missing floating values in arrays. 42 | * 43 | * rna_proxy is a proxy on the value with a boolean semantics, corresponding 44 | * to "has_value", i.e. `true` is the value is not NA, false otherwise. 45 | */ 46 | template 47 | struct rna_proxy 48 | { 49 | using cpp_type = std::decay_t; 50 | constexpr static int rtype = Rcpp::traits::r_sexptype_traits::rtype; 51 | 52 | rna_proxy(XT val) : m_val(val) 53 | { 54 | } 55 | 56 | inline operator bool() const 57 | { 58 | return !Rcpp::traits::is_na(m_val); 59 | } 60 | 61 | inline rna_proxy& operator=(bool val) 62 | { 63 | if (val == false) 64 | { 65 | m_val = Rcpp::traits::get_na(); 66 | } 67 | else if (m_val == Rcpp::traits::get_na()) 68 | { 69 | m_val = 0; 70 | } 71 | return *this; 72 | } 73 | 74 | XT m_val; 75 | }; 76 | 77 | template 78 | struct xproxy_inner_types> 79 | { 80 | using proxy = rna_proxy; 81 | using reference = rna_proxy; 82 | using pointer = rna_proxy; 83 | }; 84 | 85 | template 86 | struct rna_proxy_functor 87 | { 88 | using underlying_type = std::decay_t; 89 | 90 | template 91 | using simd_return_type = xt_simd::simd_return_type; 92 | 93 | using cpp_type = std::decay_t; 94 | constexpr static int rtype = Rcpp::traits::r_sexptype_traits::rtype; 95 | 96 | using value_type = bool; 97 | using reference = rna_proxy; 98 | using const_reference = rna_proxy; 99 | using pointer = rna_proxy; 100 | using const_pointer = rna_proxy; 101 | 102 | reference operator()(T& val) 103 | { 104 | return val; 105 | } 106 | 107 | const_reference operator()(const T& val) const 108 | { 109 | return val; 110 | } 111 | 112 | // TODO: boolean loading in xsimd 113 | // template 114 | // auto proxy_simd_load(const E& expr, std::size_t n) const 115 | // { 116 | // using simd_value_type = typename E::simd_value_type; 117 | // return expr.template load_simd(n) == simd_value_type(NA_INTEGER); 118 | // } 119 | 120 | // template 121 | // auto proxy_simd_store(E& expr, std::size_t n, const simd& batch) const 122 | // { 123 | // using simd_value_type = typename E::simd_value_type; 124 | // return expr.template store_simd(n, xt_simd::select(batch, simd_value_type(0), simd_value_type(NA_INTEGER))); 125 | // } 126 | }; 127 | 128 | template 129 | struct xcontainer_inner_types> 130 | { 131 | using raw_value_expression = RC; 132 | using value_type = typename raw_value_expression::value_type; 133 | using value_storage_type = typename raw_value_expression::storage_type&; 134 | using raw_flag_expression = xfunctor_adaptor, RC&>; 135 | using flag_storage_type = xfunctor_adaptor, RC&>; 136 | using storage_type = xoptional_assembly_storage; 137 | using temporary_type = rcontainer_optional; 138 | }; 139 | 140 | template 141 | struct xiterable_inner_types> 142 | { 143 | using assembly_type = rcontainer_optional; 144 | using inner_shape_type = typename RC::inner_shape_type; 145 | using stepper = xoptional_assembly_stepper; 146 | using const_stepper = xoptional_assembly_stepper; 147 | }; 148 | 149 | /** 150 | * @class rcontainer_optional 151 | * @brief Multidimensional container of optional values providing the xtensor 152 | * container semantics to an R array. 153 | * 154 | * ``rcontainer_optional`` is not meant to be used directly, but through the aliases 155 | * ``rarray_optional`` and ``rtensor_optional``. 156 | * 157 | * Depending on the value type, optional values are reference proxies on R's 158 | * ``NA_INTEGER``, ``NA_LOGICAL``, ``NA_REAL``, ``NA_STRING``, or ``R_NilValue``. 159 | * 160 | * Besides support for optionality, ``rarray_optional`` and ``rtensor_optional`` are similar 161 | * to the \ref rarray and \ref rtensor respectively, with respect to dynamic and static 162 | * dimensionality. 163 | * 164 | * @tparam T The type of the element stored in the rarray. 165 | */ 166 | template 167 | class rcontainer_optional : public xoptional_assembly_base>, 168 | public xcontainer_semantic> 169 | { 170 | public: 171 | 172 | using self_type = rcontainer_optional; 173 | using base_type = xoptional_assembly_base; 174 | using semantic_base = xcontainer_semantic; 175 | 176 | using storage_type = typename base_type::storage_type; 177 | using assembly_type = rcontainer_optional; 178 | 179 | explicit rcontainer_optional(SEXP exp); 180 | 181 | rcontainer_optional(const rcontainer_optional&); 182 | rcontainer_optional& operator=(const rcontainer_optional&); 183 | rcontainer_optional(rcontainer_optional&&); 184 | rcontainer_optional& operator=(rcontainer_optional&&); 185 | 186 | template 187 | rcontainer_optional(const xexpression& e); 188 | 189 | template 190 | rcontainer_optional& operator=(const xexpression& e); 191 | 192 | operator SEXP() const noexcept; 193 | 194 | private: 195 | 196 | auto& value_impl() noexcept; 197 | const auto& value_impl() const noexcept; 198 | auto& has_value_impl() noexcept; 199 | const auto& has_value_impl() const noexcept; 200 | auto& storage_impl() noexcept; 201 | const auto& storage_impl() const noexcept; 202 | 203 | RC m_value; 204 | xfunctor_adaptor, RC&> m_flag; 205 | storage_type m_storage_proxy; 206 | 207 | friend xoptional_assembly_base>; 208 | }; 209 | 210 | /************************************** 211 | * rcontainer_optional implementation * 212 | **************************************/ 213 | 214 | template 215 | inline rcontainer_optional::rcontainer_optional(SEXP exp) 216 | : m_value(exp), m_flag(m_value), m_storage_proxy(m_value.storage(), m_flag) 217 | { 218 | } 219 | 220 | template 221 | inline rcontainer_optional::rcontainer_optional(const rcontainer_optional& rhs) 222 | : m_value(rhs.m_value), m_flag(m_value), m_storage_proxy(m_value.storage(), m_flag) 223 | { 224 | } 225 | 226 | template 227 | inline auto rcontainer_optional::operator=(const self_type& rhs) -> self_type& 228 | { 229 | base_type::operator=(rhs); 230 | m_value = rhs.m_value; 231 | return *this; 232 | } 233 | 234 | template 235 | inline rcontainer_optional::rcontainer_optional(self_type&& rhs) 236 | : m_value(std::move(rhs.m_value)), m_flag(m_value), m_storage_proxy(m_value.storage(), m_flag) 237 | { 238 | } 239 | 240 | template 241 | inline auto rcontainer_optional::operator=(self_type&& rhs) -> self_type& 242 | { 243 | base_type::operator=(rhs); 244 | m_value = std::move(rhs.m_value); 245 | return *this; 246 | } 247 | 248 | template 249 | template 250 | inline rcontainer_optional::rcontainer_optional(const xexpression& e) 251 | : m_value(), m_flag(m_value), m_storage_proxy(m_value.storage(), m_flag) 252 | { 253 | semantic_base::assign(e); 254 | } 255 | 256 | template 257 | template 258 | inline auto rcontainer_optional::operator=(const xexpression& e) -> self_type& 259 | { 260 | return semantic_base::operator=(e); 261 | } 262 | 263 | template 264 | inline auto& rcontainer_optional::value_impl() noexcept 265 | { 266 | return m_value; 267 | } 268 | 269 | template 270 | inline const auto& rcontainer_optional::value_impl() const noexcept 271 | { 272 | return m_value; 273 | } 274 | 275 | template 276 | inline auto& rcontainer_optional::has_value_impl() noexcept 277 | { 278 | return m_flag; 279 | } 280 | 281 | template 282 | inline const auto& rcontainer_optional::has_value_impl() const noexcept 283 | { 284 | return m_flag; 285 | } 286 | 287 | template 288 | inline auto& rcontainer_optional::storage_impl() noexcept 289 | { 290 | return m_storage_proxy; 291 | } 292 | 293 | template 294 | inline const auto& rcontainer_optional::storage_impl() const noexcept 295 | { 296 | return m_storage_proxy; 297 | } 298 | 299 | template 300 | inline rcontainer_optional::operator SEXP() const noexcept 301 | { 302 | return SEXP(m_value); 303 | } 304 | } 305 | 306 | #endif 307 | 308 | -------------------------------------------------------------------------------- /include/xtensor-r/rtensor.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #ifndef XTENSOR_R_TENSOR_HPP 11 | #define XTENSOR_R_TENSOR_HPP 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "xtensor/xbuffer_adaptor.hpp" 18 | #include "xtensor/xiterator.hpp" 19 | #include "xtensor/xsemantic.hpp" 20 | #include "xtensor/xutils.hpp" 21 | 22 | #include "rcontainer.hpp" 23 | 24 | namespace xt 25 | { 26 | template 27 | class rtensor; 28 | 29 | template 30 | struct xiterable_inner_types> 31 | : xcontainer_iterable_types> 32 | { 33 | }; 34 | 35 | template 36 | struct xcontainer_inner_types> 37 | { 38 | using r_type = T; 39 | using underlying_type = r_detail::get_underlying_value_type_r; 40 | using storage_type = xbuffer_adaptor; 41 | using reference = typename storage_type::reference; 42 | using const_reference = typename storage_type::const_reference; 43 | using size_type = typename storage_type::size_type; 44 | using shape_type = std::array; 45 | using strides_type = shape_type; 46 | using backstrides_type = shape_type; 47 | using inner_shape_type = xbuffer_adaptor; 48 | using inner_strides_type = strides_type; 49 | using inner_backstrides_type = backstrides_type; 50 | using temporary_type = rtensor; 51 | static constexpr layout_type layout = layout_type::column_major; 52 | }; 53 | 54 | /** 55 | * @class rtensor 56 | * @brief Multidimensional container providing the xtensor container semantics wrapping an R array. 57 | * 58 | * rtensor is similar to the xtensor container in that it has a static dimensionality. 59 | * 60 | * Unlike the rarray container, rtensor cannot be reshaped with a different number of dimensions 61 | * and reshapes are not reflected on the R side. However, rtensor has benefits compared to rarray 62 | * in terms of performances. rtensor shapes are stack-allocated which makes iteration upon rtensor 63 | * faster than with pyarray. 64 | * 65 | * @tparam T The type of the element stored in the rarray. 66 | * @sa rarray 67 | */ 68 | template 69 | class rtensor : public rcontainer>, 70 | public xcontainer_semantic> 71 | { 72 | public: 73 | 74 | using self_type = rtensor; 75 | using semantic_base = xcontainer_semantic; 76 | using base_type = rcontainer; 77 | 78 | using inner_types = xcontainer_inner_types; 79 | using underlying_type = typename inner_types::underlying_type; 80 | 81 | using storage_type = typename base_type::storage_type; 82 | using value_type = typename base_type::value_type; 83 | using reference = typename base_type::reference; 84 | using const_reference = typename base_type::const_reference; 85 | using pointer = typename base_type::pointer; 86 | using size_type = typename base_type::size_type; 87 | using shape_type = typename base_type::shape_type; 88 | using strides_type = typename base_type::strides_type; 89 | using backstrides_type = typename base_type::backstrides_type; 90 | using inner_shape_type = typename base_type::inner_shape_type; 91 | using inner_strides_type = typename base_type::inner_strides_type; 92 | using inner_backstrides_type = typename base_type::inner_backstrides_type; 93 | 94 | constexpr static int SXP = Rcpp::traits::r_sexptype_traits::rtype; 95 | 96 | constexpr static std::size_t rank = N; 97 | 98 | rtensor(); 99 | rtensor(nested_initializer_list_t t); 100 | 101 | explicit rtensor(SEXP exp); 102 | explicit rtensor(const shape_type& shape); 103 | explicit rtensor(const shape_type& shape, const_reference value); 104 | 105 | template 106 | static rtensor from_shape(S&& shape); 107 | 108 | rtensor(const self_type& rhs); 109 | self_type& operator=(const self_type& rhs); 110 | 111 | rtensor(self_type&&) = default; 112 | self_type& operator=(self_type&& e) = default; 113 | 114 | template 115 | rtensor(const xexpression& e); 116 | 117 | template 118 | self_type& operator=(const xexpression& e); 119 | 120 | layout_type layout() const; 121 | 122 | // Internal method, called when the stored SEXP changes 123 | void update(SEXP new_sexp) noexcept; 124 | 125 | private: 126 | 127 | inner_shape_type m_shape; 128 | inner_strides_type m_strides; 129 | inner_backstrides_type m_backstrides; 130 | storage_type m_storage; 131 | 132 | template 133 | void init_from_shape(const S& shape); 134 | 135 | inner_shape_type& shape_impl() noexcept; 136 | const inner_shape_type& shape_impl() const noexcept; 137 | inner_strides_type& strides_impl() noexcept; 138 | const inner_strides_type& strides_impl() const noexcept; 139 | inner_backstrides_type& backstrides_impl() noexcept; 140 | const inner_backstrides_type& backstrides_impl() const noexcept; 141 | 142 | storage_type& storage_impl() noexcept; 143 | const storage_type& storage_impl() const noexcept; 144 | 145 | void update_shape_and_strides() noexcept; 146 | 147 | friend class xcontainer>; 148 | friend class rcontainer, Rcpp::PreserveStorage>; 149 | }; 150 | 151 | /*************************** 152 | * rtensor implementation * 153 | ***************************/ 154 | 155 | /** 156 | * @name Constructors 157 | */ 158 | //@{ 159 | /** 160 | * Allocates an uninitialized rtensor. 161 | */ 162 | template 163 | inline rtensor::rtensor() 164 | { 165 | auto tmp_shape = Rcpp::IntegerVector(N, 1); 166 | base_type::rstorage::set__(Rf_allocArray(SXP, SEXP(tmp_shape))); 167 | m_storage[0] = T(); 168 | } 169 | 170 | template 171 | inline rtensor::rtensor(SEXP exp) 172 | { 173 | detail::check_coercion(exp); 174 | base_type::rstorage::set__(Rcpp::r_cast(exp)); 175 | } 176 | 177 | template 178 | template 179 | inline void rtensor::init_from_shape(const S& shape) 180 | { 181 | if (N != shape.size()) 182 | { 183 | throw std::runtime_error("Wrong dimensions for rtensor."); 184 | } 185 | if (shape.size() == 0) 186 | { 187 | base_type::rstorage::set__(Rf_allocVector(SXP, 1)); 188 | } 189 | else 190 | { 191 | auto tmp_shape = Rcpp::IntegerVector(shape.begin(), shape.end()); 192 | base_type::rstorage::set__(Rf_allocArray(SXP, SEXP(tmp_shape))); 193 | } 194 | // everything else is handled by update() 195 | } 196 | 197 | template 198 | template 199 | inline rtensor rtensor::from_shape(S&& shape) 200 | { 201 | shape_type temp_shape = xtl::forward_sequence(shape); 202 | return self_type(temp_shape); 203 | } 204 | 205 | /** 206 | * Allocates a rtensor with a nested initializer list. 207 | */ 208 | template 209 | inline rtensor::rtensor(nested_initializer_list_t t) 210 | : self_type(xt::shape(t)) 211 | { 212 | nested_copy(this->begin(), t); 213 | } 214 | 215 | /** 216 | * Allocates an uninitialized rtensor with the specified shape and 217 | * layout. 218 | * @param shape the shape of the rtensor 219 | * @param l the layout_type of the rtensor 220 | */ 221 | template 222 | inline rtensor::rtensor(const shape_type& shape) 223 | { 224 | init_from_shape(shape); 225 | } 226 | 227 | /** 228 | * Allocates a rtensor with the specified shape and layout. Elements 229 | * are initialized to the specified value. 230 | * @param shape the shape of the rtensor 231 | * @param value the value of the elements 232 | * @param l the layout_type of the rtensor 233 | */ 234 | template 235 | inline rtensor::rtensor(const shape_type& shape, const_reference value) 236 | { 237 | init_from_shape(shape); 238 | std::fill(m_storage.begin(), m_storage.end(), value); 239 | } 240 | //@} 241 | 242 | /** 243 | * @name Copy semantic 244 | */ 245 | //@{ 246 | /** 247 | * The copy constructor. 248 | */ 249 | template 250 | inline rtensor::rtensor(const self_type& rhs) 251 | : base_type(), semantic_base(rhs) 252 | { 253 | init_from_shape(rhs.shape()); 254 | std::copy(rhs.storage().cbegin(), rhs.storage().cend(), this->storage().begin()); 255 | } 256 | 257 | /** 258 | * The assignment operator. 259 | */ 260 | template 261 | inline auto rtensor::operator=(const self_type& rhs) -> self_type& 262 | { 263 | self_type tmp(rhs); 264 | *this = std::move(tmp); 265 | return *this; 266 | } 267 | //@} 268 | 269 | /** 270 | * @name Extended copy semantic 271 | */ 272 | //@{ 273 | /** 274 | * The extended copy constructor. 275 | */ 276 | template 277 | template 278 | inline rtensor::rtensor(const xexpression& e) 279 | { 280 | init_from_shape(e.derived_cast().shape()); 281 | semantic_base::assign(e); 282 | } 283 | 284 | /** 285 | * The extended assignment operator. 286 | */ 287 | template 288 | template 289 | inline auto rtensor::operator=(const xexpression& e) -> self_type& 290 | { 291 | return semantic_base::operator=(e); 292 | } 293 | //@} 294 | 295 | template 296 | inline layout_type rtensor::layout() const 297 | { 298 | return layout_type::column_major; 299 | } 300 | 301 | template 302 | inline auto rtensor::shape_impl() noexcept -> inner_shape_type& 303 | { 304 | return m_shape; 305 | } 306 | 307 | template 308 | inline auto rtensor::shape_impl() const noexcept -> const inner_shape_type& 309 | { 310 | return m_shape; 311 | } 312 | 313 | template 314 | inline auto rtensor::strides_impl() noexcept -> inner_strides_type& 315 | { 316 | return m_strides; 317 | } 318 | 319 | template 320 | inline auto rtensor::strides_impl() const noexcept -> const inner_strides_type& 321 | { 322 | return m_strides; 323 | } 324 | 325 | template 326 | inline auto rtensor::backstrides_impl() noexcept -> inner_backstrides_type& 327 | { 328 | return m_backstrides; 329 | } 330 | 331 | template 332 | inline auto rtensor::backstrides_impl() const noexcept -> const inner_backstrides_type& 333 | { 334 | return m_backstrides; 335 | } 336 | 337 | template 338 | inline auto rtensor::storage_impl() noexcept -> storage_type& 339 | { 340 | return m_storage; 341 | } 342 | 343 | template 344 | inline auto rtensor::storage_impl() const noexcept -> const storage_type& 345 | { 346 | return m_storage; 347 | } 348 | 349 | template 350 | inline void rtensor::update(SEXP new_sexp) noexcept 351 | { 352 | m_shape = detail::r_shape_to_buffer_adaptor(*this, N); 353 | std::size_t sz = xt::compute_strides(m_shape, layout_type::column_major, m_strides, m_backstrides); 354 | m_storage = storage_type(reinterpret_cast(Rcpp::internal::r_vector_start(new_sexp)), sz); 355 | } 356 | 357 | template 358 | inline void rtensor::update_shape_and_strides() noexcept 359 | { 360 | m_shape = detail::r_shape_to_buffer_adaptor(*this, N); 361 | xt::compute_strides(m_shape, layout_type::column_major, m_strides, m_backstrides); 362 | } 363 | } 364 | 365 | namespace Rcpp 366 | { 367 | template 368 | inline SEXP wrap(const xt::rtensor& arr) 369 | { 370 | return SEXP(arr); 371 | } 372 | } 373 | 374 | #endif 375 | -------------------------------------------------------------------------------- /include/xtensor-r/rvectorize.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #ifndef XTENSOR_R_VECTORIZE_HPP 11 | #define XTENSOR_R_VECTORIZE_HPP 12 | 13 | #include 14 | 15 | #include "rarray.hpp" 16 | #include "xtensor/xvectorize.hpp" 17 | 18 | namespace xt 19 | { 20 | 21 | template 22 | struct rvectorizer 23 | { 24 | xvectorizer m_vectorizer; 25 | 26 | template , rvectorizer>::value>> 27 | rvectorizer(F&& func) 28 | : m_vectorizer(std::forward(func)) 29 | { 30 | } 31 | 32 | inline rarray operator()(const rarray&... args) const 33 | { 34 | rarray res = m_vectorizer(args...); 35 | return res; 36 | } 37 | }; 38 | 39 | /** 40 | * @brief Create numpy-style universal function from scalar function. 41 | */ 42 | template 43 | inline rvectorizer rvectorize(R (*f)(Args...)) 44 | { 45 | return rvectorizer(f); 46 | } 47 | 48 | /// @cond DOXYGEN_INCLUDE_OVERLOADS 49 | template 50 | inline rvectorizer rvectorize(F&& f, R (*)(Args...)) 51 | { 52 | return rvectorizer(std::forward(f)); 53 | } 54 | 55 | template 56 | inline auto rvectorize(F&& f) -> decltype(rvectorize(std::forward(f), (detail::get_function_type*)nullptr)) 57 | { 58 | return rvectorize(std::forward(f), (detail::get_function_type*)nullptr); 59 | } 60 | /// @endcond 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /include/xtensor-r/xtensor_r_config.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #ifndef XTENSOR_R_CONFIG_HPP 11 | #define XTENSOR_R_CONFIG_HPP 12 | 13 | #define XTENSOR_R_VERSION_MAJOR 0 14 | #define XTENSOR_R_VERSION_MINOR 15 15 | #define XTENSOR_R_VERSION_PATCH 0 16 | 17 | #ifndef XTENSOR_WARN_ON_COERCE 18 | #define XTENSOR_WARN_ON_COERCE 1 19 | #endif 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: "ubuntu-22.04" 5 | tools: 6 | python: "mambaforge-22.9" 7 | 8 | conda: 9 | environment: docs/environment.yml 10 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Copyright (c) Wolf Vollprecht, Johan Mabille and Sylvain Corlay # 3 | # Copyright (c) QuantStack # 4 | # # 5 | # Distributed under the terms of the BSD 3-Clause License. # 6 | # # 7 | # The full license is in the file LICENSE, distributed with this software. # 8 | ############################################################################ 9 | 10 | cmake_minimum_required(VERSION 3.1) 11 | 12 | set(CMAKE_MACOSX_RPATH 1) 13 | set(CMAKE_SKIP_BUILD_RPATH FALSE) 14 | set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) 15 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 16 | 17 | if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) 18 | project(xtensor-r-test) 19 | 20 | find_package(xtensor REQUIRED CONFIG) 21 | set(XTENSOR_INCLUDE_DIR ${xtensor_INCLUDE_DIRS}) 22 | 23 | find_package(xtensor-r REQUIRED CONFIG) 24 | set(XTENSOR_R_INCLUDE_DIR ${xtensor-r_INCLUDE_DIRS}) 25 | endif () 26 | 27 | message(STATUS "Forcing tests build type to Release") 28 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) 29 | 30 | include(CheckCXXCompilerFlag) 31 | 32 | string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) 33 | 34 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") 35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wunused-parameter -Wextra -Wreorder -Wconversion") 36 | CHECK_CXX_COMPILER_FLAG("-std=c++14" HAS_CPP14_FLAG) 37 | 38 | if (HAS_CPP14_FLAG) 39 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") 40 | else() 41 | message(FATAL_ERROR "Unsupported compiler -- xtensor requires C++14 support!") 42 | endif() 43 | endif() 44 | 45 | if(MSVC) 46 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /MP /bigobj") 47 | set(CMAKE_EXE_LINKER_FLAGS /MANIFEST:NO) 48 | endif() 49 | 50 | if (DOWNLOAD_GTEST OR GTEST_SRC_DIR) 51 | if(DOWNLOAD_GTEST) 52 | # Download and unpack googletest at configure time 53 | configure_file(downloadGTest.cmake.in googletest-download/CMakeLists.txt) 54 | else() 55 | # Copy local source of googletest at configure time 56 | configure_file(copyGTest.cmake.in googletest-download/CMakeLists.txt) 57 | endif() 58 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . 59 | RESULT_VARIABLE result 60 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) 61 | if(result) 62 | message(FATAL_ERROR "CMake step for googletest failed: ${result}") 63 | endif() 64 | execute_process(COMMAND ${CMAKE_COMMAND} --build . 65 | RESULT_VARIABLE result 66 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) 67 | if(result) 68 | message(FATAL_ERROR "Build step for googletest failed: ${result}") 69 | endif() 70 | 71 | # Add googletest directly to our build. This defines 72 | # the gtest and gtest_main targets. 73 | add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src 74 | ${CMAKE_CURRENT_BINARY_DIR}/googletest-build EXCLUDE_FROM_ALL) 75 | 76 | set(GTEST_INCLUDE_DIRS "${gtest_SOURCE_DIR}/include") 77 | set(GTEST_BOTH_LIBRARIES gtest_main gtest) 78 | else() 79 | find_package(GTest REQUIRED) 80 | endif() 81 | 82 | find_package(Threads) 83 | 84 | include_directories(${GTEST_INCLUDE_DIRS}) 85 | 86 | find_package(R REQUIRED) 87 | 88 | include_directories(${R_INCLUDE_DIR} SYSTEM) 89 | 90 | link_directories(${R_ROOT_DIR}/lib) 91 | link_directories(${R_ROOT_DIR}/bin/${R_LIB_ARCH}) 92 | link_directories(${RINSIDE_LOCATION_LINE}/libs/${R_LIB_ARCH}) 93 | link_directories(${RINSIDE_LOCATION_LINE}/lib) 94 | link_directories(${CMAKE_INSTALL_PREFIX}/lib) 95 | 96 | set(XTENSOR_R_TESTS 97 | main.cpp 98 | test_rarray.cpp 99 | test_rreducer.cpp 100 | test_roptional.cpp 101 | test_rtensor.cpp 102 | test_rvectorize.cpp 103 | test_sfinae.cpp 104 | ) 105 | 106 | add_executable(test_xtensor_r ${XTENSOR_R_TESTS} ${XTENSOR_R_HEADERS}) 107 | target_link_libraries(test_xtensor_r xtensor-r ${R_LIBRARIES} ${RINSIDE_LIBRARIES} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) 108 | 109 | if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) 110 | add_dependencies(test_xtensor_r gtest_main) 111 | endif() 112 | 113 | if(UNIX) 114 | add_custom_target(xtest COMMAND export R_HOME=${R_HOME} && ./test_xtensor_r DEPENDS test_xtensor_r) 115 | else() 116 | add_custom_target(xtest COMMAND set R_HOME=${R_HOME} && .\\test_xtensor_r DEPENDS test_xtensor_r) 117 | endif() 118 | -------------------------------------------------------------------------------- /test/copyGTest.cmake.in: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Copyright (c) Wolf Vollprecht, Johan Mabille and Sylvain Corlay # 3 | # Copyright (c) QuantStack # 4 | # # 5 | # Distributed under the terms of the BSD 3-Clause License. # 6 | # # 7 | # The full license is in the file LICENSE, distributed with this software. # 8 | ############################################################################ 9 | 10 | cmake_minimum_required(VERSION 2.8.2) 11 | 12 | project(googletest-download NONE) 13 | 14 | IF(WIN32) 15 | # Disabling pthreads on windows + mingw 16 | SET(GTEST_DISABLE_PTHREADS ON) 17 | ENDIF() 18 | 19 | include(ExternalProject) 20 | ExternalProject_Add(googletest 21 | URL "${GTEST_SRC_DIR}" 22 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" 23 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" 24 | CONFIGURE_COMMAND "" 25 | BUILD_COMMAND "" 26 | INSTALL_COMMAND "" 27 | TEST_COMMAND "" 28 | CMAKE_ARGS -DGTEST_DISABLE_PTHREADS=${GTEST_DISABLE_PTHREADS} 29 | ) 30 | 31 | -------------------------------------------------------------------------------- /test/downloadGTest.cmake.in: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Copyright (c) Wolf Vollprecht, Johan Mabille and Sylvain Corlay # 3 | # Copyright (c) QuantStack # 4 | # # 5 | # Distributed under the terms of the BSD 3-Clause License. # 6 | # # 7 | # The full license is in the file LICENSE, distributed with this software. # 8 | ############################################################################ 9 | 10 | cmake_minimum_required(VERSION 2.8.2) 11 | 12 | project(googletest-download NONE) 13 | 14 | IF(WIN32) 15 | # Disabling pthreads on windows + mingw 16 | SET(GTEST_DISABLE_PTHREADS ON) 17 | ENDIF() 18 | 19 | include(ExternalProject) 20 | 21 | ExternalProject_Add(googletest 22 | GIT_REPOSITORY https://github.com/google/googletest.git 23 | GIT_TAG release-1.10.0 24 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" 25 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" 26 | CONFIGURE_COMMAND "" 27 | BUILD_COMMAND "" 28 | INSTALL_COMMAND "" 29 | TEST_COMMAND "" 30 | CMAKE_ARGS -DGTEST_DISABLE_PTHREADS=${GTEST_DISABLE_PTHREADS} 31 | ) 32 | 33 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #include "gtest/gtest.h" 13 | #include "xtensor-r/rarray.hpp" 14 | 15 | #include "RInside.h" 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | 20 | RInside R(argc, argv); 21 | 22 | ::testing::InitGoogleTest(&argc, argv); 23 | 24 | // Run test suite 25 | int ret = RUN_ALL_TESTS(); 26 | 27 | exit(ret); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /test/rcpp_tests.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | // [[Rcpp::plugins(cpp14)]] 11 | // [[Rcpp::depends(xtensor)]] 12 | 13 | #include "xtensor-r/rcontainer.hpp" 14 | #include "xtensor-r/rarray.hpp" 15 | #include "xtensor/xmath.hpp" 16 | #include "xtensor/xio.hpp" 17 | 18 | // [[Rcpp::export]] 19 | int modify_cpp(xt::rarray& x) 20 | { 21 | // check that passing by reference works correctly 22 | x(0, 0) = -1000; 23 | x(9, 2) = 1000; 24 | return 1; 25 | } 26 | 27 | // [[Rcpp::export]] 28 | int reshape_cpp(xt::rarray& x) 29 | { 30 | // reshape in-place 31 | x.reshape({3, 10}); 32 | return 1; 33 | } 34 | 35 | // [[Rcpp::export]] 36 | xt::rarray cpp_add(xt::rarray& x, xt::rarray& y) 37 | { 38 | return x + y; 39 | } 40 | 41 | void xassert(bool cond) 42 | { 43 | if (!cond) throw std::runtime_error("CPP ASSERT TRIGGERED."); 44 | } 45 | 46 | // [[Rcpp::export]] 47 | int call_int(xt::rarray& x) 48 | { 49 | xassert(x(0, 0) == 1); 50 | xassert(x(0, 2) == 5); 51 | x(1, 1) = 35; 52 | return 1; 53 | } 54 | 55 | // [[Rcpp::export]] 56 | int call_lgl(xt::rarray& x) 57 | { 58 | xassert(x(0, 0) == 1); 59 | x(1, 1) = 0; 60 | return 1; 61 | } 62 | 63 | // [[Rcpp::export]] 64 | int call_stdcomplex(xt::rarray>& x) 65 | { 66 | using cplx = std::complex; 67 | xassert(x(0, 0) == cplx(0., 1.)); 68 | xassert(x(1, 2) == cplx(1., 5.)); 69 | x(0, 2) = cplx(-10., -100.); 70 | return 1; 71 | } 72 | 73 | // [[Rcpp::export]] 74 | xt::rarray reduce_1d() 75 | { 76 | xt::rarray a = {1, 2, 3, 4}; 77 | return xt::sum(a, 0); 78 | } 79 | -------------------------------------------------------------------------------- /test/test_common.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #ifndef TEST_COMMON_HPP 11 | #define TEST_COMMON_HPP 12 | 13 | #include "xtensor/xlayout.hpp" 14 | #include "xtensor/xmanipulation.hpp" 15 | 16 | #include "xtl/xsequence.hpp" 17 | 18 | namespace xt 19 | { 20 | template 21 | bool operator==(const uvector& lhs, const std::vector& rhs) 22 | { 23 | return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); 24 | } 25 | 26 | template 27 | bool operator==(const std::vector& lhs, const uvector& rhs) 28 | { 29 | return rhs == lhs; 30 | } 31 | 32 | template > 33 | struct layout_result 34 | { 35 | using vector_type = uvector; 36 | using value_type = typename C::value_type; 37 | using size_type = typename C::size_type; 38 | using shape_type = C; 39 | using strides_type = C; 40 | 41 | using assigner_type = std::vector>; 42 | 43 | inline layout_result() 44 | { 45 | m_shape = {3, 2, 4}; 46 | m_assigner.resize(m_shape[0]); 47 | for (value_type i = 0; i < m_shape[0]; ++i) 48 | { 49 | m_assigner[i].resize(m_shape[1]); 50 | } 51 | m_assigner[0][0] = {-1, 1, 2, 3}; 52 | m_assigner[0][1] = {4, 5, 6, 7}; 53 | m_assigner[1][0] = {8, 9, 10, 11}; 54 | m_assigner[1][1] = {12, 13, 14, 15}; 55 | m_assigner[2][0] = {16, 17, 18, 19}; 56 | m_assigner[2][1] = {20, 21, 22, 23}; 57 | } 58 | 59 | shape_type m_shape; 60 | strides_type m_strides; 61 | strides_type m_backstrides; 62 | vector_type m_data; 63 | assigner_type m_assigner; 64 | 65 | inline size_type size() const { return m_data.size(); } 66 | inline const shape_type& shape() const { return m_shape; } 67 | inline const strides_type& strides() const { return m_strides; } 68 | inline const strides_type& backstrides() const { return m_backstrides; } 69 | inline const vector_type& storage() const { return m_data; } 70 | }; 71 | 72 | template > 73 | struct column_major_result : layout_result 74 | { 75 | inline column_major_result() 76 | { 77 | this->m_strides = {1, 3, 6}; 78 | this->m_backstrides = {2, 3, 18}; 79 | this->m_data = {-1, 8, 16, 4, 12, 20, 80 | 1, 9, 17, 5, 13, 21, 81 | 2, 10, 18, 6, 14, 22, 82 | 3, 11, 19, 7, 15, 23}; 83 | } 84 | }; 85 | 86 | template > 87 | struct central_major_result : layout_result 88 | { 89 | inline central_major_result() 90 | { 91 | this->m_strides = { 8, 1, 2 }; 92 | this->m_backstrides = { 16, 1, 6}; 93 | this->m_data = {-1, 4, 1, 5, 2, 6, 3, 7, 94 | 8, 12, 9, 13, 10, 14, 11, 15, 95 | 16, 20, 17, 21, 18, 22, 19, 23}; 96 | } 97 | }; 98 | 99 | template > 100 | struct unit_shape_result 101 | { 102 | using vector_type = std::vector; 103 | using size_type = typename C::size_type; 104 | using shape_type = C; 105 | using strides_type = C; 106 | 107 | using assigner_type = std::vector>; 108 | 109 | inline unit_shape_result() 110 | { 111 | m_shape = {3, 1, 4}; 112 | m_strides = {4, 0, 1}; 113 | m_backstrides = {8, 0, 3}; 114 | m_data = {-1, 8, 16, 1, 9, 17, 2, 10, 18, 3, 11, 19}; 115 | m_assigner.resize(m_shape[0]); 116 | for (std::size_t i = 0; i < std::size_t(m_shape[0]); ++i) 117 | { 118 | m_assigner[i].resize(m_shape[1]); 119 | } 120 | m_assigner[0][0] = {-1, 1, 2, 3}; 121 | m_assigner[1][0] = {8, 9, 10, 11}; 122 | m_assigner[2][0] = {16, 17, 18, 19}; 123 | } 124 | 125 | shape_type m_shape; 126 | strides_type m_strides; 127 | strides_type m_backstrides; 128 | vector_type m_data; 129 | assigner_type m_assigner; 130 | 131 | inline size_type size() const { return m_data.size(); } 132 | inline const shape_type& shape() const { return m_shape; } 133 | inline const strides_type& strides() const { return m_strides; } 134 | inline const strides_type& backstrides() const { return m_backstrides; } 135 | inline const vector_type& storage() const { return m_data; } 136 | }; 137 | 138 | template 139 | void compare_shape(V& vec, const R& result) 140 | { 141 | EXPECT_TRUE(std::equal(vec.shape().cbegin(), vec.shape().cend(), result.shape().cbegin())); 142 | EXPECT_TRUE(std::equal(vec.strides().cbegin(), vec.strides().cend(), result.strides().cbegin())); 143 | EXPECT_EQ(vec.size(), result.size()); 144 | } 145 | 146 | template > 147 | void test_resize(V& vec) 148 | { 149 | column_major_result cm; 150 | vec.resize(cm.m_shape); 151 | compare_shape(vec, cm); 152 | } 153 | 154 | template > 155 | void test_transpose(V& vec) 156 | { 157 | using shape_type = typename V::shape_type; 158 | using strides_type = typename V::strides_type; 159 | { 160 | SCOPED_TRACE("transpose"); 161 | shape_type shape_new = xtl::make_sequence(vec.dimension(), 0); 162 | std::copy(vec.shape().cbegin(), vec.shape().cend(), shape_new.begin()); 163 | auto vt = transpose(vec); 164 | std::reverse(shape_new.begin(), shape_new.end()); 165 | EXPECT_EQ(vt.shape(), shape_new); 166 | } 167 | 168 | { 169 | SCOPED_TRACE("transpose with data"); 170 | column_major_result rm; 171 | vec.resize(rm.shape()); 172 | 173 | assign_array(vec, rm.m_assigner); 174 | EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin())); 175 | 176 | auto vec_copy = vec; 177 | 178 | shape_type shape_new(rm.shape()); 179 | auto vt = transpose(vec); 180 | std::reverse(shape_new.begin(), shape_new.end()); 181 | EXPECT_EQ(vt.shape(), shape_new); 182 | EXPECT_TRUE(std::equal(vt.storage().cbegin(), vt.storage().cend(), rm.m_data.cbegin())); 183 | 184 | strides_type new_strides = {rm.m_strides[2], 185 | rm.m_strides[1], 186 | rm.m_strides[0]}; 187 | EXPECT_EQ(vt.strides(), new_strides); 188 | 189 | strides_type new_backstrides = {rm.m_backstrides[2], 190 | rm.m_backstrides[1], 191 | rm.m_backstrides[0]}; 192 | EXPECT_EQ(vt.backstrides(), new_backstrides); 193 | 194 | EXPECT_EQ(vec_copy(0, 0, 0), vt(0, 0, 0)); 195 | EXPECT_EQ(vec_copy(0, 1, 0), vt(0, 1, 0)); 196 | EXPECT_EQ(vec_copy(1, 1, 0), vt(0, 1, 1)); 197 | EXPECT_EQ(vec_copy(1, 1, 2), vt(2, 1, 1)); 198 | } 199 | 200 | { 201 | SCOPED_TRACE("transpose with permutation"); 202 | column_major_result rm; 203 | vec.resize(rm.shape()); 204 | 205 | assign_array(vec, rm.m_assigner); 206 | EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin())); 207 | 208 | auto vec_copy = vec; 209 | 210 | shape_type a = xtl::make_sequence(vec.dimension(), 0); 211 | std::copy(vec.shape().cbegin(), vec.shape().cend(), a.begin()); 212 | auto vt = transpose(vec, {1, 0, 2}); 213 | shape_type shape_new = {a[1], a[0], a[2]}; 214 | EXPECT_TRUE(std::equal(vt.shape().cbegin(), vt.shape().cend(), shape_new.begin())); 215 | EXPECT_TRUE(std::equal(vt.storage().cbegin(), vt.storage().cend(), rm.m_data.cbegin())); 216 | 217 | strides_type new_strides = {rm.m_strides[1], 218 | rm.m_strides[0], 219 | rm.m_strides[2]}; 220 | EXPECT_EQ(vt.strides(), new_strides); 221 | 222 | strides_type new_backstrides = {rm.m_backstrides[1], 223 | rm.m_backstrides[0], 224 | rm.m_backstrides[2]}; 225 | EXPECT_EQ(vt.backstrides(), new_backstrides); 226 | 227 | EXPECT_EQ(vec_copy(0, 0, 0), vt(0, 0, 0)); 228 | EXPECT_EQ(vec_copy(0, 1, 0), vt(1, 0, 0)); 229 | EXPECT_EQ(vec_copy(1, 1, 0), vt(1, 1, 0)); 230 | EXPECT_EQ(vec_copy(1, 1, 2), vt(1, 1, 2)); 231 | 232 | // Compilation check only 233 | std::vector perm = {1, 0, 2}; 234 | transpose(vec, perm); 235 | } 236 | 237 | { 238 | SCOPED_TRACE("transpose permutation throws"); 239 | column_major_result rm; 240 | vec.resize(rm.shape()); 241 | 242 | EXPECT_THROW(transpose(vec, {1, 1, 0}, check_policy::full()), transpose_error); 243 | EXPECT_THROW(transpose(vec, {1, 0, 2, 3}, check_policy::full()), transpose_error); 244 | EXPECT_THROW(transpose(vec, {1, 2}, check_policy::full()), transpose_error); 245 | EXPECT_THROW(transpose(vec, {3, 0, 1}, check_policy::full()), transpose_error); 246 | } 247 | } 248 | 249 | template 250 | void assign_array(V1& dst, const V2& src) 251 | { 252 | for (std::size_t i = 0; i < std::size_t(dst.shape()[0]); ++i) 253 | { 254 | for (std::size_t j = 0; j < std::size_t(dst.shape()[1]); ++j) 255 | { 256 | for (std::size_t k = 0; k < std::size_t(dst.shape()[2]); ++k) 257 | { 258 | dst(i, j, k) = src[i][j][k]; 259 | } 260 | } 261 | } 262 | } 263 | 264 | template 265 | void test_bound_check(V& vec) 266 | { 267 | #ifdef XTENSOR_ENABLE_ASSERT 268 | EXPECT_ANY_THROW(vec(10, 10, 10)); 269 | #else 270 | (void)vec; 271 | #endif 272 | } 273 | 274 | template > 275 | void test_access(V& vec) 276 | { 277 | { 278 | SCOPED_TRACE("column_major access"); 279 | column_major_result cm; 280 | vec.resize(cm.m_shape); 281 | assign_array(vec, cm.m_assigner); 282 | EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cm.m_data.cbegin())); 283 | EXPECT_EQ(vec(0, 1, 1), vec(1, 1)); 284 | EXPECT_EQ(vec(2, 1, 3), vec(2, 2, 2, 1, 3)); 285 | test_bound_check(vec); 286 | } 287 | 288 | { 289 | SCOPED_TRACE("unit_shape access"); 290 | unit_shape_result usr; 291 | vec.resize(usr.m_shape); 292 | assign_array(vec, usr.m_assigner); 293 | EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), usr.m_data.cbegin())); 294 | EXPECT_EQ(vec(0, 1, 0), vec(1, 0)); 295 | EXPECT_EQ(vec(2, 0, 3), vec(2, 2, 2, 0, 3)); 296 | test_bound_check(vec); 297 | } 298 | } 299 | 300 | template 301 | void indexed_assign_array(V1& dst, const V2& src) 302 | { 303 | xindex index(dst.dimension()); 304 | for (std::size_t i = 0; i < std::size_t(dst.shape()[0]); ++i) 305 | { 306 | index[0] = i; 307 | for (std::size_t j = 0; j < std::size_t(dst.shape()[1]); ++j) 308 | { 309 | index[1] = j; 310 | for (std::size_t k = 0; k < std::size_t(dst.shape()[2]); ++k) 311 | { 312 | index[2] = k; 313 | dst[index] = src[i][j][k]; 314 | } 315 | } 316 | } 317 | } 318 | 319 | template > 320 | void test_indexed_access(V& vec) 321 | { 322 | xindex index1 = {1, 1}; 323 | xindex index2 = {2, 2, 2, 1, 3}; 324 | 325 | { 326 | SCOPED_TRACE("column_major access"); 327 | column_major_result cm; 328 | vec.resize(cm.m_shape); 329 | indexed_assign_array(vec, cm.m_assigner); 330 | EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cm.m_data.cbegin())); 331 | EXPECT_EQ(vec(0, 1, 1), vec[index1]); 332 | EXPECT_EQ(vec(2, 1, 3), vec[index2]); 333 | } 334 | 335 | { 336 | SCOPED_TRACE("unit_shape access"); 337 | unit_shape_result usr; 338 | vec.resize(usr.m_shape); 339 | indexed_assign_array(vec, usr.m_assigner); 340 | EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), usr.m_data.cbegin())); 341 | xindex id1 = {1, 0}; 342 | xindex id2 = {2, 2, 2, 0, 3}; 343 | EXPECT_EQ(vec(0, 1, 0), vec[id1]); 344 | EXPECT_EQ(vec(2, 0, 3), vec[id2]); 345 | } 346 | } 347 | 348 | template 349 | void test_broadcast(V& vec) 350 | { 351 | using shape_type = typename V::shape_type; 352 | 353 | shape_type s = {3, 1, 4, 2}; 354 | vec.resize(s); 355 | 356 | { 357 | SCOPED_TRACE("same shape"); 358 | shape_type s1 = s; 359 | bool res = vec.broadcast_shape(s1); 360 | EXPECT_EQ(s1, s); 361 | EXPECT_TRUE(res); 362 | } 363 | 364 | { 365 | SCOPED_TRACE("different shape"); 366 | shape_type s2 = {3, 5, 1, 2}; 367 | shape_type s2r = {3, 5, 4, 2}; 368 | bool res = vec.broadcast_shape(s2); 369 | EXPECT_EQ(s2, s2r); 370 | EXPECT_FALSE(res); 371 | } 372 | 373 | { 374 | SCOPED_TRACE("incompatible shapes"); 375 | shape_type s4 = {2, 1, 3, 2}; 376 | bool wit = false; 377 | try 378 | { 379 | vec.broadcast_shape(s4); 380 | } 381 | catch (broadcast_error&) 382 | { 383 | wit = true; 384 | } 385 | EXPECT_TRUE(wit); 386 | } 387 | } 388 | 389 | template 390 | void test_broadcast2(V& vec) 391 | { 392 | using shape_type = typename V::shape_type; 393 | 394 | shape_type s = {3, 1, 4, 2}; 395 | vec.resize(s); 396 | 397 | { 398 | SCOPED_TRACE("different dimensions"); 399 | shape_type s3 = {5, 3, 1, 4, 2}; 400 | shape_type s3r = s3; 401 | bool res = vec.broadcast_shape(s3); 402 | EXPECT_EQ(s3, s3r); 403 | EXPECT_FALSE(res); 404 | } 405 | } 406 | 407 | template > 408 | void test_iterator(V& vec) 409 | { 410 | { 411 | SCOPED_TRACE("column_major storage iterator"); 412 | column_major_result cm; 413 | vec.resize(cm.m_shape); 414 | std::copy(cm.storage().cbegin(), cm.storage().cend(), vec.template begin()); 415 | EXPECT_TRUE(std::equal(cm.storage().cbegin(), cm.storage().cend(), vec.storage().cbegin())); 416 | } 417 | } 418 | } 419 | 420 | #endif 421 | -------------------------------------------------------------------------------- /test/test_rarray.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include "gtest/gtest.h" 11 | 12 | #include "xtensor/xarray.hpp" 13 | 14 | #include "xtensor-r/rarray.hpp" 15 | 16 | #include "test_common.hpp" 17 | 18 | namespace xt 19 | { 20 | TEST(rarray, initializer_constructor) 21 | { 22 | rarray t 23 | {{{ 0, 1, 2}, 24 | { 3, 4, 5}, 25 | { 6, 7, 8}}, 26 | {{ 9, 10, 11}, 27 | {12, 13, 14}, 28 | {15, 16, 17}}}; 29 | 30 | EXPECT_EQ(t.dimension(), 3); 31 | EXPECT_EQ(t(0, 0, 1), 1); 32 | EXPECT_EQ(t.shape()[0], 2); 33 | } 34 | 35 | TEST(rarray, shaped_constructor) 36 | { 37 | { 38 | SCOPED_TRACE("column_major constructor"); 39 | column_major_result<> cm; 40 | rarray ca(cm.m_shape); 41 | compare_shape(ca, cm); 42 | EXPECT_EQ(layout_type::column_major, ca.layout()); 43 | } 44 | } 45 | 46 | TEST(rarray, valued_constructor) 47 | { 48 | { 49 | SCOPED_TRACE("column_major valued constructor"); 50 | column_major_result<> cm; 51 | int value = 2; 52 | rarray ca(cm.m_shape, value); 53 | compare_shape(ca, cm); 54 | std::vector vec(ca.size(), value); 55 | EXPECT_TRUE(std::equal(vec.cbegin(), vec.cend(), ca.storage().cbegin())); 56 | } 57 | } 58 | 59 | TEST(rarray, copy_semantic) 60 | { 61 | column_major_result<> res; 62 | int value = 2; 63 | rarray a(res.m_shape, value); 64 | 65 | { 66 | SCOPED_TRACE("copy constructor"); 67 | rarray b(a); 68 | compare_shape(a, b); 69 | EXPECT_EQ(a.storage(), b.storage()); 70 | a.storage()[0] += 1; 71 | EXPECT_NE(a.storage()[0], b.storage()[0]); 72 | } 73 | 74 | { 75 | SCOPED_TRACE("assignment operator"); 76 | column_major_result<> r; 77 | rarray c(r.m_shape, 0); 78 | EXPECT_NE(a.storage(), c.storage()); 79 | c = a; 80 | compare_shape(a, c); 81 | EXPECT_EQ(a.storage(), c.storage()); 82 | a.storage()[0] += 1; 83 | EXPECT_NE(a.storage()[0], c.storage()[0]); 84 | } 85 | } 86 | 87 | TEST(rarray, move_semantic) 88 | { 89 | column_major_result<> res; 90 | int value = 2; 91 | rarray a(res.m_shape, value); 92 | 93 | { 94 | SCOPED_TRACE("move constructor"); 95 | rarray tmp(a); 96 | rarray b(std::move(tmp)); 97 | compare_shape(a, b); 98 | EXPECT_EQ(a.storage(), b.storage()); 99 | } 100 | 101 | { 102 | SCOPED_TRACE("move assignment"); 103 | column_major_result<> r; 104 | rarray c(r.m_shape, 0); 105 | EXPECT_NE(a.storage(), c.storage()); 106 | rarray tmp(a); 107 | c = std::move(tmp); 108 | compare_shape(a, c); 109 | EXPECT_EQ(a.storage(), c.storage()); 110 | } 111 | } 112 | 113 | TEST(rarray, extended_constructor) 114 | { 115 | xt::xarray a1 = { { 1, 2 },{ 3, 4 } }; 116 | xt::xarray a2 = { { 1, 2 },{ 3, 4 } }; 117 | rarray c = a1 + a2; 118 | EXPECT_EQ(c(0, 0), a1(0, 0) + a2(0, 0)); 119 | EXPECT_EQ(c(0, 1), a1(0, 1) + a2(0, 1)); 120 | EXPECT_EQ(c(1, 0), a1(1, 0) + a2(1, 0)); 121 | EXPECT_EQ(c(1, 1), a1(1, 1) + a2(1, 1)); 122 | } 123 | 124 | TEST(rarray, resize) 125 | { 126 | rarray a; 127 | test_resize(a); 128 | } 129 | 130 | TEST(rarray, access) 131 | { 132 | rarray a; 133 | test_access(a); 134 | } 135 | 136 | TEST(rarray, indexed_access) 137 | { 138 | rarray a; 139 | test_indexed_access(a); 140 | } 141 | 142 | TEST(rarray, broadcast_shape) 143 | { 144 | rarray a; 145 | test_broadcast(a); 146 | test_broadcast2(a); 147 | } 148 | 149 | TEST(rarray, iterator) 150 | { 151 | rarray a; 152 | test_iterator(a); 153 | } 154 | 155 | TEST(rarray, initializer_list) 156 | { 157 | // rarray a0(1); 158 | rarray a1({1, 2}); 159 | rarray a2({{1, 2}, {2, 4}, {5, 6}}); 160 | // EXPECT_EQ(1, a0()); 161 | EXPECT_EQ(2, a1(1)); 162 | EXPECT_EQ(4, a2(1, 1)); 163 | } 164 | 165 | // TODO zerod 166 | // TEST(rarray, zerod) 167 | // { 168 | // rarray a; 169 | // EXPECT_EQ(0, a()); 170 | // } 171 | 172 | TEST(rarray, reshape) 173 | { 174 | rarray a = {{1,2,3}, {4,5,6}}; 175 | auto ptr = a.data(); 176 | a.reshape({1, 6}); 177 | std::vector sc1({1, 6}); 178 | EXPECT_TRUE(std::equal(sc1.cbegin(), sc1.cend(), a.shape().cbegin()) && a.shape().size() == 2); 179 | EXPECT_EQ(ptr, a.data()); 180 | a.reshape({6}); 181 | std::vector sc2 = {6}; 182 | EXPECT_TRUE(std::equal(sc2.cbegin(), sc2.cend(), a.shape().cbegin()) && a.shape().size() == 1); 183 | EXPECT_EQ(ptr, a.data()); 184 | } 185 | 186 | TEST(rarray, from_shape) 187 | { 188 | auto a = rarray::from_shape({4, 5}); 189 | EXPECT_EQ(a.shape()[0], 4); 190 | EXPECT_EQ(a.shape()[1], 5); 191 | EXPECT_EQ(a.size(), 20); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /test/test_roptional.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include "gtest/gtest.h" 11 | 12 | #include "xtensor-r/roptional.hpp" 13 | 14 | namespace xt 15 | { 16 | TEST(roptional, roptional_access) 17 | { 18 | using cpp_type = double; 19 | constexpr static int rtype = Rcpp::traits::r_sexptype_traits::rtype; 20 | auto mi = Rcpp::traits::get_na(); 21 | 22 | rarray t 23 | {{{ 0, 1, 2}, 24 | { 3, mi, 5}, 25 | { 6, mi, 8}}, 26 | {{ 9, 10, 11}, 27 | {mi, mi, mi}, 28 | {15, 16, 17}}}; 29 | SEXP exp = SEXP(t); 30 | rarray_optional o(exp); 31 | 32 | // Check has_value on elements 33 | EXPECT_TRUE(o(0, 0, 0).has_value()); 34 | EXPECT_TRUE(o(0, 0, 1).has_value()); 35 | EXPECT_TRUE(o(0, 0, 2).has_value()); 36 | 37 | EXPECT_TRUE(o(0, 1, 0).has_value()); 38 | EXPECT_FALSE(o(0, 1, 1).has_value()); 39 | EXPECT_TRUE(o(0, 1, 2).has_value()); 40 | 41 | EXPECT_TRUE(o(0, 2, 0).has_value()); 42 | EXPECT_FALSE(o(0, 2, 1).has_value()); 43 | EXPECT_TRUE(o(0, 2, 2).has_value()); 44 | 45 | EXPECT_TRUE(o(1, 0, 0).has_value()); 46 | EXPECT_TRUE(o(1, 0, 1).has_value()); 47 | EXPECT_TRUE(o(1, 0, 2).has_value()); 48 | 49 | EXPECT_FALSE(o(1, 1, 0).has_value()); 50 | EXPECT_FALSE(o(1, 1, 1).has_value()); 51 | EXPECT_FALSE(o(1, 1, 2).has_value()); 52 | 53 | EXPECT_TRUE(o(1, 2, 0).has_value()); 54 | EXPECT_TRUE(o(1, 2, 1).has_value()); 55 | EXPECT_TRUE(o(1, 2, 2).has_value()); 56 | 57 | // Check has_value() on expression 58 | auto hv = o.has_value(); 59 | EXPECT_TRUE(hv(0, 2, 0)); 60 | EXPECT_FALSE(hv(0, 2, 1)); 61 | EXPECT_TRUE(hv(0, 2, 2)); 62 | 63 | // Check value() on expression 64 | auto v = o.value(); 65 | EXPECT_EQ(v(0, 2, 0), 6.0); 66 | EXPECT_EQ(v(0, 2, 2), 8.0); 67 | } 68 | 69 | TEST(roptional, roptional_set) 70 | { 71 | using cpp_type = double; 72 | constexpr static int rtype = Rcpp::traits::r_sexptype_traits::rtype; 73 | auto mi = Rcpp::traits::get_na(); 74 | 75 | rarray t 76 | {{{ 0, 1, 2}, 77 | { 3, mi, 5}, 78 | { 6, mi, 8}}, 79 | {{ 9, 10, 11}, 80 | {mi, mi, mi}, 81 | {15, 16, 17}}}; 82 | SEXP exp = SEXP(t); 83 | rarray_optional o(exp); 84 | 85 | // Test setting element 86 | EXPECT_FALSE(o(0, 2, 1).has_value()); 87 | o(0, 2, 1) = 1.0; 88 | EXPECT_TRUE(o(0, 2, 1).has_value()); 89 | o(0, 2, 1).has_value() = false; 90 | EXPECT_FALSE(o(0, 2, 1).has_value()); 91 | 92 | // Test setting xtl::missing 93 | EXPECT_TRUE(o(0, 0, 0).has_value()); 94 | o(0, 0, 0) = xtl::missing(); 95 | EXPECT_FALSE(o(0, 0, 0).has_value()); 96 | } 97 | 98 | TEST(roptional, assign_optional) 99 | { 100 | using cpp_type = double; 101 | constexpr static int rtype = Rcpp::traits::r_sexptype_traits::rtype; 102 | auto mi = Rcpp::traits::get_na(); 103 | 104 | rarray t {0}; 105 | SEXP exp = SEXP(t); 106 | rarray_optional o(exp); 107 | 108 | // Assign expression 109 | xtensor_optional m 110 | {{ 1.0 , 2.0 }, 111 | { 3.0 , xtl::missing() }}; 112 | o = m; 113 | 114 | EXPECT_EQ(o.dimension(), 2); 115 | EXPECT_TRUE(o(0, 0).has_value()); 116 | EXPECT_TRUE(o(0, 1).has_value()); 117 | EXPECT_TRUE(o(1, 0).has_value()); 118 | EXPECT_FALSE(o(1, 1).has_value()); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /test/test_rreducer.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "xtensor-r/rarray.hpp" 17 | #include "xtensor-r/rtensor.hpp" 18 | 19 | namespace xt 20 | { 21 | TEST(rxreducer, sum) 22 | { 23 | xt::rarray x_array = {{1, 2, 3}, {4, 5, 6}}; 24 | auto x_sum = xt::sum(x_array, 1); 25 | 26 | EXPECT_EQ(x_sum(0), 6); 27 | EXPECT_EQ(x_sum(1), 15); 28 | } 29 | 30 | TEST(rxreducer, variance) 31 | { 32 | // For computing references 33 | xt::xtensor data = {{1, 2, 3}, {4, 5, 6}}; 34 | std::vector const axes = {1}; 35 | 36 | { // xt:rarray 37 | xt::rarray arr = data; 38 | EXPECT_EQ(xt::variance(arr)(0), xt::variance(data)(0)); 39 | auto var = xt::variance(arr, axes); 40 | EXPECT_EQ(xt::variance(arr, axes), xt::variance(data, axes)); 41 | } 42 | { // xt:rtensor 43 | xt::rtensor arr = data; 44 | EXPECT_EQ(xt::variance(arr)(0), xt::variance(data)(0)); 45 | auto var = xt::variance(arr, axes); 46 | EXPECT_EQ(xt::variance(arr, axes), xt::variance(data, axes)); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/test_rtensor.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include "gtest/gtest.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "xtensor/xtensor.hpp" 18 | 19 | #include "xtensor-r/rtensor.hpp" 20 | 21 | #include "test_common.hpp" 22 | 23 | namespace xt 24 | { 25 | using container_type = std::array; 26 | 27 | TEST(rtensor, initializer_constructor) 28 | { 29 | rtensor t 30 | {{{ 0, 1, 2}, 31 | { 3, 4, 5}, 32 | { 6, 7, 8}}, 33 | {{ 9, 10, 11}, 34 | {12, 13, 14}, 35 | {15, 16, 17}}}; 36 | EXPECT_EQ(t.dimension(), 3); 37 | EXPECT_EQ(t(0, 0, 1), 1); 38 | EXPECT_EQ(t.shape()[0], 2); 39 | } 40 | 41 | TEST(rtensor, shaped_constructor) 42 | { 43 | { 44 | SCOPED_TRACE("column_major constructor"); 45 | column_major_result cm; 46 | rtensor ca(cm.m_shape); 47 | compare_shape(ca, cm); 48 | EXPECT_EQ(layout_type::column_major, ca.layout()); 49 | } 50 | } 51 | 52 | TEST(rtensor, strided_constructor) 53 | { 54 | column_major_result cmr; 55 | rtensor cma(cmr.m_shape); 56 | compare_shape(cma, cmr); 57 | } 58 | 59 | TEST(rtensor, valued_constructor) 60 | { 61 | { 62 | SCOPED_TRACE("column_major valued constructor"); 63 | column_major_result cm; 64 | int value = 2; 65 | rtensor ca(cm.m_shape, value); 66 | compare_shape(ca, cm); 67 | std::vector vec(ca.size(), value); 68 | EXPECT_TRUE(std::equal(vec.begin(), vec.end(), ca.storage().begin())); 69 | } 70 | } 71 | 72 | TEST(rtensor, strided_valued_constructor) 73 | { 74 | column_major_result cmr; 75 | int value = 2; 76 | rtensor cma(cmr.m_shape, value); 77 | compare_shape(cma, cmr); 78 | std::vector vec(cma.size(), value); 79 | EXPECT_TRUE(std::equal(vec.begin(), vec.end(), cma.storage().begin())); 80 | } 81 | 82 | TEST(rtensor, copy_semantic) 83 | { 84 | column_major_result res; 85 | int value = 2; 86 | rtensor a(res.m_shape, value); 87 | 88 | { 89 | SCOPED_TRACE("copy constructor"); 90 | rtensor b(a); 91 | compare_shape(a, b); 92 | EXPECT_EQ(a.storage(), b.storage()); 93 | a.storage()[0] += 1; 94 | EXPECT_NE(a.storage()[0], b.storage()[0]); 95 | } 96 | 97 | { 98 | SCOPED_TRACE("assignment operator"); 99 | column_major_result r; 100 | rtensor c(r.m_shape, 0); 101 | EXPECT_NE(a.storage(), c.storage()); 102 | c = a; 103 | compare_shape(a, c); 104 | EXPECT_EQ(a.storage(), c.storage()); 105 | a.storage()[0] += 1; 106 | EXPECT_NE(a.storage()[0], c.storage()[0]); 107 | } 108 | } 109 | 110 | TEST(rtensor, move_semantic) 111 | { 112 | column_major_result res; 113 | int value = 2; 114 | rtensor a(res.m_shape, value); 115 | 116 | { 117 | SCOPED_TRACE("move constructor"); 118 | rtensor tmp(a); 119 | rtensor b(std::move(tmp)); 120 | compare_shape(a, b); 121 | EXPECT_EQ(a.storage(), b.storage()); 122 | } 123 | 124 | { 125 | SCOPED_TRACE("move assignment"); 126 | column_major_result r; 127 | rtensor c(r.m_shape, 0); 128 | EXPECT_NE(a.storage(), c.storage()); 129 | rtensor tmp(a); 130 | c = std::move(tmp); 131 | compare_shape(a, c); 132 | EXPECT_EQ(a.storage(), c.storage()); 133 | } 134 | } 135 | 136 | TEST(rtensor, extended_constructor) 137 | { 138 | xt::xtensor a1 = { {1, 2}, {3, 4} }; 139 | xt::xtensor a2 = { {1, 2}, {3, 4} }; 140 | rtensor c = a1 + a2; 141 | EXPECT_EQ(c(0, 0), a1(0, 0) + a2(0, 0)); 142 | EXPECT_EQ(c(0, 1), a1(0, 1) + a2(0, 1)); 143 | EXPECT_EQ(c(1, 0), a1(1, 0) + a2(1, 0)); 144 | EXPECT_EQ(c(1, 1), a1(1, 1) + a2(1, 1)); 145 | } 146 | 147 | TEST(rtensor, resize) 148 | { 149 | rtensor a; 150 | test_resize, container_type>(a); 151 | } 152 | 153 | /*TEST(rtensor, transpose) 154 | { 155 | rtensor a; 156 | test_transpose, container_type>(a); 157 | }*/ 158 | 159 | TEST(rtensor, access) 160 | { 161 | rtensor a; 162 | test_access, container_type>(a); 163 | } 164 | 165 | TEST(rtensor, indexed_access) 166 | { 167 | rtensor a; 168 | test_indexed_access, container_type>(a); 169 | } 170 | 171 | TEST(rtensor, broadcast_shape) 172 | { 173 | rtensor a; 174 | test_broadcast(a); 175 | } 176 | 177 | TEST(rtensor, iterator) 178 | { 179 | rtensor a; 180 | test_iterator, container_type>(a); 181 | } 182 | 183 | // TEST(rtensor, zerod) 184 | // { 185 | // rtensor a; 186 | // EXPECT_EQ(0, a()); 187 | // } 188 | 189 | TEST(rtensor, reshape) 190 | { 191 | rtensor a = {{1,2,3}, {4,5,6}}; 192 | auto ptr = a.data(); 193 | a.reshape({1, 6}); 194 | EXPECT_EQ(ptr, a.data()); 195 | EXPECT_THROW(a.reshape({6}), std::runtime_error); 196 | } 197 | 198 | TEST(rtensor, from_shape) 199 | { 200 | auto a = rtensor::from_shape({4, 5}); 201 | EXPECT_EQ(a.shape()[0], 4); 202 | EXPECT_EQ(a.shape()[1], 5); 203 | EXPECT_EQ(a.size(), 20); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /test/test_rvectorize.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille, and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include "gtest/gtest.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "test_common.hpp" 17 | 18 | #include "xtensor-r/rtensor.hpp" 19 | #include "xtensor-r/rvectorize.hpp" 20 | 21 | namespace xt 22 | { 23 | double f1(double a, double b) 24 | { 25 | return a + b; 26 | } 27 | 28 | using shape_type = std::vector; 29 | 30 | TEST(rvectorize, function) 31 | { 32 | auto vecf1 = rvectorize(f1); 33 | shape_type shape = { 3, 2 }; 34 | rarray a(shape, 1.5); 35 | rarray b(shape, 2.3); 36 | rarray c = vecf1(a, b); 37 | EXPECT_EQ(a(0, 0) + b(0, 0), c(0, 0)); 38 | } 39 | 40 | TEST(rvectorize, lambda) 41 | { 42 | auto vecf1 = rvectorize([](double a, double b) { return a + b; }); 43 | shape_type shape = { 3, 2 }; 44 | rarray a(shape, 1.5); 45 | rarray b(shape, 2.3); 46 | rarray c = vecf1(a, b); 47 | EXPECT_EQ(a(0, 0) + b(0, 0), c(0, 0)); 48 | } 49 | 50 | TEST(rvectorize, complex) 51 | { 52 | using complex_t = std::complex; 53 | shape_type shape = { 3, 2 }; 54 | rarray a(shape, complex_t(1.2, 2.5)); 55 | auto f = rvectorize([](complex_t x) { return std::abs(x); }); 56 | auto res = f(a); 57 | double exp = std::abs(a(1, 1)); 58 | EXPECT_EQ(exp, res(1, 1)); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/test_sfinae.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Wolf Vollprecht, Johan Mabille and Sylvain Corlay * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #include "gtest/gtest.h" 13 | #include "xtensor-r/rtensor.hpp" 14 | #include "xtensor-r/rarray.hpp" 15 | #include "xtensor/xarray.hpp" 16 | #include "xtensor/xtensor.hpp" 17 | 18 | namespace xt 19 | { 20 | template ::value, int> = 0> 21 | inline bool sfinae_has_fixed_rank(E&&) 22 | { 23 | return false; 24 | } 25 | 26 | template ::value, int> = 0> 27 | inline bool sfinae_has_fixed_rank(E&&) 28 | { 29 | return true; 30 | } 31 | 32 | TEST(sfinae, fixed_rank) 33 | { 34 | xt::rarray a = {{9, 9, 9}, {9, 9, 9}}; 35 | xt::rtensor b = {9, 9}; 36 | xt::rtensor c = {{9, 9}, {9, 9}}; 37 | 38 | EXPECT_TRUE(sfinae_has_fixed_rank(a) == false); 39 | EXPECT_TRUE(sfinae_has_fixed_rank(b) == true); 40 | EXPECT_TRUE(sfinae_has_fixed_rank(c) == true); 41 | } 42 | 43 | TEST(sfinae, get_rank) 44 | { 45 | xt::rtensor A = xt::zeros({2}); 46 | xt::rtensor B = xt::zeros({2, 2}); 47 | xt::rarray C = xt::zeros({2, 2}); 48 | 49 | EXPECT_TRUE(xt::get_rank::value == 1ul); 50 | EXPECT_TRUE(xt::get_rank::value == 2ul); 51 | EXPECT_TRUE(xt::get_rank::value == SIZE_MAX); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/unittest.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | 3 | Rcpp::sourceCpp("rcpp_tests.cpp", cacheDir="__cache__") 4 | 5 | x <- array(as.numeric(1:100), dim=c(10, 10)) 6 | 7 | test_that("cpp_inplace", { 8 | expect_equal(x[1, 1], 1) 9 | expect_equal(x[10, 3], 30) 10 | expect_equal(modify_cpp(x), 1) 11 | expect_equal(x[2, 3], 22) 12 | expect_equal(x[1, 1], -1000) 13 | expect_equal(x[10, 3], 1000) 14 | }) 15 | 16 | x <- array(as.numeric(1:100), dim=c(10, 10)) 17 | y <- array(as.numeric(1:100), dim=c(10, 10)) 18 | 19 | test_that("cpp_add", { 20 | expect_equal(cpp_add(x, y), x + y) 21 | }) 22 | 23 | x <- array(as.numeric(1:30), dim=c(1, 10, 3)) 24 | 25 | test_that("cpp_reshape", { 26 | expect_equal(dim(x), c(1, 10, 3)) 27 | reshape_cpp(x) 28 | expect_equal(dim(x), c(3, 10)) 29 | }) 30 | 31 | x <- array(1:10, c(2, 5)) 32 | 33 | test_that("call_int", { 34 | call_int(x) 35 | expect_equal(x[2, 2], 35) 36 | }) 37 | 38 | x <- array(TRUE, c(2, 5)) 39 | 40 | test_that("call_lgl", { 41 | call_lgl(x) 42 | expect_equal(x[2, 2], FALSE) 43 | }) 44 | 45 | x <- array(as.complex(1:10), c(2, 5)) 46 | 47 | x[1, 1] <- 0 + 1i 48 | x[2, 3] <- 1 + 5i 49 | 50 | test_that("call_stdcomplex", { 51 | call_stdcomplex(x) 52 | expect_equal(x[1, 3], -10+-100i) 53 | }) 54 | 55 | #test_that("reduce_1d", { 56 | # res1d <- reduce_1d() 57 | # expect_equal(res1d, 10) 58 | #}) 59 | -------------------------------------------------------------------------------- /xtensor-rConfig.cmake.in: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Copyright (c) Wolf Vollprecht, Johan Mabille and Sylvain Corlay # 3 | # Copyright (c) QuantStack # 4 | # # 5 | # Distributed under the terms of the BSD 3-Clause License. # 6 | # # 7 | # The full license is in the file LICENSE, distributed with this software. # 8 | ############################################################################ 9 | 10 | # xtensor-r cmake module 11 | # This module sets the following variables in your project:: 12 | # 13 | # xtensor-r_FOUND - true if xtensor-r found on the system 14 | # xtensor-r_INCLUDE_DIRS - the directory containing xtensor-r headers 15 | # xtensor-r_LIBRARY - empty 16 | 17 | @PACKAGE_INIT@ 18 | 19 | set(PN xtensor-python) 20 | set_and_check(${PN}_INCLUDE_DIRS "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@") 21 | set(${PN}_LIBRARY "") 22 | check_required_components(${PN}) 23 | --------------------------------------------------------------------------------