diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 5e2ac542a..000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,51 +0,0 @@ -build: false - -platform: - - x64 - - x86 - -image: - - Previous Visual Studio 2017 - - Visual Studio 2015 - -environment: - matrix: - - MINICONDA: C:\xtensor-conda - -init: - - "ECHO %MINICONDA%" - - if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" set VCVARPATH="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - - if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" set VCARGUMENT=%PLATFORM% - - if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Previous Visual Studio 2017" if "%PLATFORM%" == "x64" set VCVARPATH="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" - - if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Previous Visual Studio 2017" if "%PLATFORM%" == "x86" set VCVARPATH="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" - - echo "%VCVARPATH% %VCARGUMENT%" - - "%VCVARPATH% %VCARGUMENT%" - - ps: if($env:Platform -eq "x64"){Start-FileDownload 'http://repo.continuum.io/miniconda/Miniconda3-latest-Windows-x86_64.exe' C:\Miniconda.exe; echo "Done"} - - ps: if($env:Platform -eq "x86"){Start-FileDownload 'http://repo.continuum.io/miniconda/Miniconda3-latest-Windows-x86.exe' C:\Miniconda.exe; echo "Done"} - - cmd: C:\Miniconda.exe /S /D=C:\xtensor-conda - - "set PATH=%MINICONDA%;%MINICONDA%\\Scripts;%MINICONDA%\\Library\\bin;%PATH%" - -install: - - conda config --set always_yes yes --set changeps1 no - - conda update -q conda - - conda info -a - - conda install gtest=1.8.0 cmake -c conda-forge - - conda install xtl==0.4.16 -c QuantStack - - conda install xsimd -c QuantStack - - conda install nlohmann_json -c QuantStack - #- cmake -G "NMake Makefiles" -D CMAKE_INSTALL_PREFIX=%MINICONDA%\\LIBRARY -DBUILD_TESTS=ON -DXTENSOR_USE_XSIMD=ON -DDISABLE_VS2017=ON . - #- cmake -G "NMake Makefiles" -D CMAKE_INSTALL_PREFIX=%MINICONDA%\\LIBRARY -DBUILD_TESTS=ON -DDISABLE_VS2017=ON . - #- if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" if "%PLATFORM%" == "x64" cmake -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=%MINICONDA%\\LIBRARY -DBUILD_TESTS=ON -DXTENSOR_USE_XSIMD=ON . - #- if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" if "%PLATFORM%" == "x86" cmake -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=%MINICONDA%\\LIBRARY -DBUILD_TESTS=ON . - #- if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Previous Visual Studio 2017" cmake -G "NMake Makefiles" -D CMAKE_INSTALL_PREFIX=%MINICONDA%\\LIBRARY -DBUILD_TESTS=ON -DDISABLE_VS2017=ON . - - ps: if($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2015" -And $env:Platform -eq "x64") { - cmake -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=%MINICONDA%\\LIBRARY -DBUILD_TESTS=ON -DXTENSOR_USE_XSIMD=ON . - } - else { - cmake -G "NMake Makefiles" -D CMAKE_INSTALL_PREFIX=%MINICONDA%\\LIBRARY -DBUILD_TESTS=ON -DDISABLE_VS2017=ON . - } - - nmake test_xtensor_lib - - cd test - -build_script: - - .\test_xtensor_lib diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..3cdca3d53 --- /dev/null +++ b/.clang-format @@ -0,0 +1,90 @@ +BasedOnStyle: Mozilla + +AccessModifierOffset: '-4' +AlignAfterOpenBracket: BlockIndent +AlignEscapedNewlines: Left +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +# Forbid one line lambdas because clang-format makes a weird split when +# single instructions lambdas are too long. +AllowShortLambdasOnASingleLine: Empty +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: AfterComma +BreakStringLiterals: false +ColumnLimit: '110' +ConstructorInitializerIndentWidth: '4' +ContinuationIndentWidth: '4' +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Always +EmptyLineBeforeAccessModifier: Always +ExperimentalAutoDetectBinPacking: true +IncludeBlocks: Regroup +IncludeCategories: +- Regex: <[^.]+> + Priority: 1 +- Regex: + Priority: 3 +- Regex: <.+> + Priority: 2 +- Regex: '"xtensor/.+"' + Priority: 4 +- Regex: '".+"' + Priority: 5 +IndentCaseLabels: true +IndentWidth: '4' +IndentWrappedFunctionNames: false +InsertBraces: true +InsertTrailingCommas: Wrapped +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +Language: Cpp +MaxEmptyLinesToKeep: '2' +NamespaceIndentation: All +ObjCBlockIndentWidth: '4' +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PackConstructorInitializers: Never +PenaltyBreakAssignment: 100000 +PenaltyBreakBeforeFirstCallParameter: 0 +PenaltyBreakComment: 10 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakTemplateDeclaration: 0 +PenaltyExcessCharacter: 10 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 10 +PointerAlignment: Left +QualifierAlignment: Custom # Experimental +QualifierOrder: [inline, static, constexpr, const, volatile, type] +ReflowComments: true +SeparateDefinitionBlocks: Always +SortIncludes: CaseInsensitive +SortUsingDeclarations: true +SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: '2' +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: c++20 +TabWidth: '4' +UseTab: Never diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..3de597778 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +# Checklist + +- [ ] The title and commit message(s) are descriptive. +- [ ] Small commits made to fix your PR have been squashed to avoid history pollution. +- [ ] Tests have been added for new features or bug fixes. +- [ ] API of new functions and classes are documented. + +# Description + + diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml new file mode 100644 index 000000000..9ec6f8f33 --- /dev/null +++ b/.github/workflows/benchmarks.yml @@ -0,0 +1,73 @@ +name: benchmarks +on: + workflow_dispatch: + pull_request: + push: + branches: [master] +concurrency: + group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} + cancel-in-progress: true +defaults: + run: + shell: bash -e -l {0} +jobs: + build: + runs-on: ubuntu-24.04 + name: ${{ matrix.sys.compiler }} ${{ matrix.sys.version }} - ${{ matrix.sys.name }} + strategy: + fail-fast: false + matrix: + sys: + - {compiler: clang, version: '20', name: xsimd, flags: -DXTENSOR_USE_XSIMD=ON} + - {compiler: clang, version: '20', name: xsimd-tbb, flags: -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON} + - {compiler: gcc, version: '14', name: xsimd, flags: -DXTENSOR_USE_XSIMD=ON} + - {compiler: gcc, version: '14', name: xsimd-tbb, flags: -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON} + + steps: + - name: Install GCC + if: matrix.sys.compiler == 'gcc' + uses: egor-tensin/setup-gcc@v1 + with: + version: ${{matrix.sys.version}} + platform: x64 + + - name: Install LLVM and Clang + if: matrix.sys.compiler == 'clang' + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{matrix.sys.version}} + sudo apt-get install -y clang-tools-${{matrix.sys.version}} + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${{matrix.sys.version}} 200 + sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${{matrix.sys.version}} 200 + sudo update-alternatives --install /usr/bin/clang-scan-deps clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} 200 + sudo update-alternatives --set clang /usr/bin/clang-${{matrix.sys.version}} + sudo update-alternatives --set clang++ /usr/bin/clang++-${{matrix.sys.version}} + sudo update-alternatives --set clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set conda environment + uses: mamba-org/setup-micromamba@main + with: + environment-name: myenv + environment-file: environment-dev.yml + init-shell: bash + cache-downloads: true + create-args: | + ${{ (matrix.sys.name == 'tbb' || matrix.sys.name == 'xsimd-tbb' ) && 'tbb-devel' || '' }} + + - name: Configure using CMake + run: | + if [[ "${{matrix.sys.compiler}}" = "gcc" ]]; then export CC=gcc-${{matrix.sys.version}}; export CXX=g++-${{matrix.sys.version}}; else export CC=clang; export CXX=clang++; fi + cmake -G Ninja -Bbuild -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DBUILD_BENCHMARK=ON ${{ matrix.sys.flags }} + + - name: Build + working-directory: build + run: cmake --build . --target benchmark_xtensor --parallel 8 + + - name: Run benchmark + timeout-minutes: 10 # Consider increasing timeout + working-directory: build/benchmark + run: ./benchmark_xtensor diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml new file mode 100644 index 000000000..05d385180 --- /dev/null +++ b/.github/workflows/codspeed.yml @@ -0,0 +1,52 @@ +name: CodSpeed + +on: + push: + branches: [master] + pull_request: # Allow CodSpeed to trigger backtest performance analysis + + workflow_dispatch: + + +permissions: + contents: read + id-token: write + +concurrency: + group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e -l {0} + +jobs: + benchmarks: + name: Run benchmarks + runs-on: namespace-profile-benchmark;container.privileged=true;container.host-pid-namespace=true + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Set conda environment + uses: mamba-org/setup-micromamba@main + with: + environment-name: myenv + environment-file: environment-dev.yml + init-shell: bash + cache-downloads: true + + - name: Build benchmarks + run: | + cmake -G Ninja -Bbuild \ + -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX \ + -DBUILD_BENCHMARK=ON \ + -DXTENSOR_USE_XSIMD=ON \ + -DCODSPEED_MODE=simulation + cmake --build build --target benchmark_xtensor --parallel 8 + + - name: Run benchmarks + uses: CodSpeedHQ/action@v4 + with: + mode: simulation + run: ./build/benchmark/benchmark_xtensor diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml new file mode 100644 index 000000000..f86b5256a --- /dev/null +++ b/.github/workflows/gh-pages.yml @@ -0,0 +1,48 @@ +name: gh-pages + +on: + push: + branches: + - master + +defaults: + run: + shell: bash -l {0} + +jobs: + + publish: + + runs-on: ubuntu-latest + + defaults: + run: + shell: bash -l {0} + + steps: + + - name: Basic GitHub action setup + uses: actions/checkout@v2 + + - name: Set mamba environment + uses: mamba-org/setup-micromamba@main + with: + environment-file: docs/ghp_environment.yml + environment-name: xtensor-doc + init-shell: bash + cache-downloads: true + + - name: Run doxygen + working-directory: docs + run: doxygen + + - name: Deploy to GitHub Pages + if: success() + uses: crazy-max/ghaction-github-pages@v2 + with: + target_branch: gh-pages + build_dir: docs/html + jekyll: false + keep_history: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/issue-close.yml b/.github/workflows/issue-close.yml new file mode 100644 index 000000000..25f105dd5 --- /dev/null +++ b/.github/workflows/issue-close.yml @@ -0,0 +1,33 @@ +name: Close inactive issues and PRs +on: + schedule: + - cron: 30 1 * * * + +jobs: + close-issues: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v8 + with: + any-of-issue-labels: Needs clarification, Answered, Stale? + days-before-issue-stale: 365 + days-before-issue-close: 14 + stale-issue-label: Stale + stale-issue-message: | + This issue is stale because it has been open for 365 days with no activity. + It will be automatically closed in 14 days. + close-issue-message: | + This issue was closed because it has been inactive for 14 days since being marked as stale. + any-of-pr-labels: Needs clarification, Answered, Needs revision, Stale? + days-before-pr-stale: 60 + days-before-pr-close: 14 + stale-pr-label: Stale + stale-pr-message: | + This pr is stale because it has been open for 60 days with no activity. + It will be automatically closed in 14 days. + close-pr-message: | + This issue was closed because it has been inactive for 14 days since being marked as stale. + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 000000000..1a66aa273 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,102 @@ +name: Linux +on: + workflow_dispatch: + pull_request: + push: + branches: [master] +concurrency: + group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} + cancel-in-progress: true +defaults: + run: + shell: bash -e -l {0} +jobs: + build: + runs-on: ${{ matrix.os }} + name: ${{ matrix.os }} ${{ matrix.sys.compiler }} ${{ matrix.sys.version }} - ${{ matrix.sys.name }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-24.04, ubuntu-24.04-arm] + sys: + - {compiler: clang, version: '17', name: assert, flags: -DXTENSOR_ENABLE_ASSERT=ON} + - {compiler: clang, version: '18', name: column-major, flags: -DDEFAULT_COLUMN_MAJOR=ON} + - {compiler: clang, version: '19', name: assert, flags: -DXTENSOR_ENABLE_ASSERT=ON} + - {compiler: clang, version: '20', name: column-major, flags: -DDEFAULT_COLUMN_MAJOR=ON} + - {compiler: clang, version: '21', name: assert, flags: -DXTENSOR_ENABLE_ASSERT=ON} + - {compiler: clang, version: '21', name: column-major, flags: -DDEFAULT_COLUMN_MAJOR=ON} + - {compiler: clang, version: '22', name: assert, flags: -DXTENSOR_ENABLE_ASSERT=ON} + - {compiler: clang, version: '22', name: column-major, flags: -DDEFAULT_COLUMN_MAJOR=ON} + - {compiler: gcc, version: '11', name: openmp, flags: -DXTENSOR_USE_OPENMP=ON} + - {compiler: gcc, version: '11', name: noexcept, flags: -DXTENSOR_DISABLE_EXCEPTIONS=ON} + - {compiler: gcc, version: '12', name: xsimd, flags: -DXTENSOR_USE_XSIMD=ON} + - {compiler: gcc, version: '13', name: xsimd-tbb, flags: -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON} + - {compiler: gcc, version: '13', name: tbb, flags: -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=$CONDA_PREFIX/include -DTBB_LIBRARY=$CONDA_PREFIX/lib} + - {compiler: gcc, version: '14', name: xsimd-tbb, flags: -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON} + - {compiler: gcc, version: '14', name: tbb, flags: -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=$CONDA_PREFIX/include -DTBB_LIBRARY=$CONDA_PREFIX/lib} + # TODO: Activate following gcc versions when switching github runner to ubuntu 26.04 + # - {compiler: gcc, version: '15', name: xsimd-tbb, flags: -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON} + # - {compiler: gcc, version: '15', name: tbb, flags: -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=$CONDA_PREFIX/include -DTBB_LIBRARY=$CONDA_PREFIX/lib} + # - {compiler: gcc, version: '16', name: xsimd-tbb, flags: -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON} + # - {compiler: gcc, version: '16', name: tbb, flags: -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=$CONDA_PREFIX/include -DTBB_LIBRARY=$CONDA_PREFIX/lib} + exclude: + - os: ubuntu-24.04-arm + sys: + compiler: gcc + version: '12' + - os: ubuntu-24.04-arm + sys: + compiler: gcc + version: '11' + + steps: + - name: Install GCC + if: matrix.sys.compiler == 'gcc' + uses: egor-tensin/setup-gcc@v2 + with: + version: ${{matrix.sys.version}} + platform: x64 + + - name: Install LLVM and Clang + if: matrix.sys.compiler == 'clang' + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{matrix.sys.version}} + sudo apt-get install -y clang-tools-${{matrix.sys.version}} + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${{matrix.sys.version}} 200 + sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${{matrix.sys.version}} 200 + sudo update-alternatives --install /usr/bin/clang-scan-deps clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} 200 + sudo update-alternatives --set clang /usr/bin/clang-${{matrix.sys.version}} + sudo update-alternatives --set clang++ /usr/bin/clang++-${{matrix.sys.version}} + sudo update-alternatives --set clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} + + - name: Checkout code + uses: actions/checkout@v6 + + - name: Set conda environment + uses: mamba-org/setup-micromamba@main + with: + environment-name: myenv + environment-file: environment-dev.yml + init-shell: bash + cache-downloads: true + create-args: | + ${{ (matrix.sys.name == 'tbb' || matrix.sys.name == 'xsimd-tbb' ) && 'tbb-devel' || '' }} + + - name: Configure using CMake + run: | + if [[ "${{matrix.sys.compiler}}" = "gcc" ]]; then export CC=gcc-${{matrix.sys.version}}; export CXX=g++-${{matrix.sys.version}}; else export CC=clang; export CXX=clang++; fi + cmake -G Ninja -Bbuild -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DBUILD_TESTS=ON ${{ matrix.sys.flags }} + + - name: Install + working-directory: build + run: cmake --install . + + - name: Build + working-directory: build + run: cmake --build . --target test_xtensor_lib + + - name: Run tests + working-directory: build + run: ctest -R ^xtest$ --output-on-failure diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml new file mode 100644 index 000000000..5dbce477e --- /dev/null +++ b/.github/workflows/osx.yml @@ -0,0 +1,50 @@ +name: OSX +on: + workflow_dispatch: + pull_request: + push: + branches: [master] +concurrency: + group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} + cancel-in-progress: true +defaults: + run: + shell: bash -e -l {0} +jobs: + build: + runs-on: macos-${{ matrix.os }} + name: macos-${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - 14 + - 15 + + steps: + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set conda environment + uses: mamba-org/setup-micromamba@main + with: + environment-name: myenv + environment-file: environment-dev.yml + init-shell: bash + cache-downloads: true + + - name: Configure using CMake + run: cmake -Bbuild -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DBUILD_TESTS=ON + + - name: Install + working-directory: build + run: cmake --install . + + - name: Build + working-directory: build + run: cmake --build . --target test_xtensor_lib --parallel 8 + + - name: Run tests + working-directory: build + run: ctest -R ^xtest$ --output-on-failure diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml new file mode 100644 index 000000000..c008e832c --- /dev/null +++ b/.github/workflows/sanitizers.yml @@ -0,0 +1,110 @@ +name: Sanitizers +on: + workflow_dispatch: + pull_request: + push: + branches: [master] +concurrency: + group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} + cancel-in-progress: true +defaults: + run: + shell: bash -e -l {0} +jobs: + build: + runs-on: ${{ matrix.os }} + name: sanitizer / ${{ matrix.sys.compiler }} ${{ matrix.sys.version }} / ${{ matrix.config.name }} / ${{ matrix.sys.name }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-24.04] + sys: + - {compiler: clang, version: '21', name: asan, sanitizer: address} + - {compiler: clang, version: '21', name: lsan, sanitizer: leak} + - {compiler: clang, version: '21', name: ubsan, sanitizer: undefined} + config: + - {name: Debug} + + steps: + + - name: Install LLVM and Clang + if: matrix.sys.compiler == 'clang' + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{matrix.sys.version}} + sudo apt-get install -y clang-tools-${{matrix.sys.version}} + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${{matrix.sys.version}} 200 + sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${{matrix.sys.version}} 200 + sudo update-alternatives --install /usr/bin/clang-scan-deps clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} 200 + sudo update-alternatives --set clang /usr/bin/clang-${{matrix.sys.version}} + sudo update-alternatives --set clang++ /usr/bin/clang++-${{matrix.sys.version}} + sudo update-alternatives --set clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} + + - name: Checkout code + uses: actions/checkout@v6 + + - name: Set conda environment + uses: mamba-org/setup-micromamba@main + with: + environment-name: myenv + environment-file: environment-dev.yml + init-shell: bash + cache-downloads: true + + - name: Configure using CMake + run: | + export CC=clang + export CXX=clang++ + cmake -G Ninja \ + -Bbuild \ + -DCMAKE_BUILD_TYPE=${{matrix.config.name}} \ + -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX \ + -DBUILD_TESTS=ON \ + -DUSE_SANITIZER=${{ matrix.sys.sanitizer }} + + - name: Build tests + working-directory: build + run: cmake --build . --config ${{matrix.config.name}} --target test_xtensor_lib --parallel 8 + + - name: Run tests + working-directory: build + run: | + SAN=${{ matrix.sys.sanitizer }} + case "$SAN" in + address) + export ASAN_OPTIONS=log_path=asan_log_:alloc_dealloc_mismatch=0:halt_on_error=0:handle_abort=0 + export ASAN_SAVE_DUMPS=AsanDump.dmp + ;; + leak) + export LSAN_OPTIONS=log_path=lsan_log_:halt_on_error=0 + ;; + undefined) + export UBSAN_OPTIONS=log_path=ubsan_log_:halt_on_error=0:print_stacktrace=1 + ;; + esac + ctest -R ^xtest$ --output-on-failure + + - name: Upload sanitizer log + if: always() + uses: actions/upload-artifact@v6 + with: + name: sanitizer-log-${{ matrix.sys.sanitizer }}-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }} + path: '**/*san_log_*' + if-no-files-found: ignore + + - name: Upload sanitizer dump + if: always() + uses: actions/upload-artifact@v6 + with: + name: sanitizer-dump-${{ matrix.sys.sanitizer }}-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }} + path: '**/AsanDump.dmp' + if-no-files-found: ignore + + - name: Return errors if sanitizer log content is not empty + if: always() + run: | + if [ -n "$(find build/test -name '*san_log_*' -type f -size +0 2>/dev/null)" ]; then + echo "Sanitizer detected errors. See the log for details." + exit 1 + fi diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 000000000..64fe21244 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,22 @@ +name: Static Analysis + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: pre-commit/action@v3.0.1 + + include-check: + runs-on: ubuntu-latest + name: Check unused standard includes + steps: + - uses: actions/checkout@v6 + - run: pip install diskarzhan + - run: diskarzhan `find include -name '*.hpp'` diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 000000000..c04adc626 --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,64 @@ +name: Windows +on: + workflow_dispatch: + pull_request: + push: + branches: [master] +concurrency: + group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} + cancel-in-progress: true +defaults: + run: + shell: bash -e -l {0} +jobs: + build: + runs-on: ${{ matrix.runs-on }} + name: ${{ matrix.sys.compiler }} + strategy: + fail-fast: false + matrix: + runs-on: [windows-latest] + sys: + - {compiler: default} + # Enable again and fix remaining issues after refactoring + #- {compiler: clang} + + steps: + + - name: Setup MSVC + if: matrix.sys.compiler == 'default' + uses: ilammy/msvc-dev-cmd@v1 + + - name: Setup clang + if: matrix.sys.compiler == 'clang' + run: | + echo "CC=clang" >> $GITHUB_ENV + echo "CXX=clang++" >> $GITHUB_ENV + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set conda environment + uses: mamba-org/setup-micromamba@main + with: + environment-name: myenv + environment-file: environment-dev.yml + init-shell: bash + cache-downloads: false + create-args: | + ninja + + - name: Configure using CMake + run: cmake -Bbuild -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DBUILD_TESTS=ON -G Ninja + + - name: Install + working-directory: build + run: cmake --install . + + - name: Build + working-directory: build + run: cmake --build . --target test_xtensor_lib --parallel 8 + + - name: Run tests + working-directory: build + run: ctest -R ^xtest$ --output-on-failure diff --git a/.gitignore b/.gitignore index a57e2c3b3..4a5bcec30 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# Doxygen output +docs/html/ +docs/xml/ + # Prerequisites *.d @@ -29,6 +33,10 @@ # Vim tmp files *.swp +*~ + +# Generated directory +include/tmp/ # Build directory build/ @@ -49,5 +57,12 @@ docs/*.tmp # Jupyter artefacts .ipynb_checkpoints/ +# Pytho artefacts +__pycache__ + # Generated files *.pc +.vscode/settings.json + +# Allow tag JSONs under etc/xeus-cpp +!etc/xeus-cpp/tags.d/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..bfc98b9cf --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,48 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: end-of-file-fixer + - id: trailing-whitespace + - id: mixed-line-ending + args: [--fix=lf] + exclude: \.bat$ + - id: check-json + - id: pretty-format-json + args: [--autofix, --top-keys=version] + - id: check-yaml + types: [file] + files: \.(yaml|yml|clang-format) + - id: detect-private-key + - id: check-merge-conflict +- repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.5.4 + hooks: + - id: forbid-tabs + - id: remove-tabs + args: [--whitespaces-count, '4'] +- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks + rev: v2.16.0 + hooks: + - id: pretty-format-yaml + args: [--autofix, --indent, '2'] + types: [file] + files: \.(yaml|yml|clang-format) + additional_dependencies: [setuptools] +- repo: https://github.com/tdegeus/cpp_comment_format + rev: v0.2.1 + hooks: + - id: cpp_comment_format +- repo: https://github.com/tdegeus/conda_envfile + rev: v0.4.2 + hooks: + - id: conda_envfile_parse + files: environment.yaml +# Externally provided executables (so we can use them with editors as well). +- repo: https://github.com/pre-commit/mirrors-clang-format + rev: v17.0.6 + hooks: + - id: clang-format + files: .*\.[hc]pp$ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a11787c40..000000000 --- a/.travis.yml +++ /dev/null @@ -1,156 +0,0 @@ -language: cpp -dist: trusty -env: -matrix: - fast_finish: true - include: - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.9 - env: COMPILER=gcc GCC=4.9 - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-5 - env: COMPILER=gcc GCC=5 DISABLE_XSIMD=1 - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 - env: COMPILER=gcc GCC=6 ENABLE_TBB=1 - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 - env: COMPILER=gcc GCC=6 BOUND_CHECKS=1 BUILD_BENCHMARK=1 - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 - env: COMPILER=gcc GCC=6 COLUMN_MAJOR_LAYOUT=1 - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.9 - - clang-3.6 - env: COMPILER=clang CLANG=3.6 DISABLE_XSIMD=1 - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-3.9 - packages: - - g++-4.9 - - clang-3.9 - env: COMPILER=clang CLANG=3.9 - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-4.0 - packages: - - g++-4.9 - - clang-4.0 - env: COMPILER=clang CLANG=4.0 DISABLE_XSIMD=1 - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-5.0 - packages: - - g++-4.9 - - clang-5.0 - env: COMPILER=clang CLANG=5.0 ENABLE_TBB=1 DISABLE_XSIMD=1 - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-6.0 - packages: - - clang-6.0 - env: COMPILER=clang CLANG=6.0 - - os: osx - osx_image: xcode8 - compiler: clang -env: - global: - - MINCONDA_VERSION="latest" - - MINCONDA_LINUX="Linux-x86_64" - - MINCONDA_OSX="MacOSX-x86_64" -before_install: - - | - # Configure build variables - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - if [[ "$COMPILER" == "gcc" ]]; then - export CXX=g++-$GCC CC=gcc-$GCC; - fi - if [[ "$COMPILER" == "clang" ]]; then - export CXX=clang++-$CLANG CC=clang-$CLANG; - fi - elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - export CXX=clang++ CC=clang; - fi -install: - # Define the version of miniconda to download - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - MINCONDA_OS=$MINCONDA_LINUX; - elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - MINCONDA_OS=$MINCONDA_OSX; - fi - - wget "http://repo.continuum.io/miniconda/Miniconda3-$MINCONDA_VERSION-$MINCONDA_OS.sh" -O miniconda.sh; - - bash miniconda.sh -b -p $HOME/miniconda - - export PATH="$HOME/miniconda/bin:$PATH" - - hash -r - - conda config --set always_yes yes --set changeps1 no - - conda update -q conda - - conda install gtest=1.8.0 cmake -c conda-forge - - conda install xtl==0.4.16 -c QuantStack - - conda install xsimd -c QuantStack - - conda install nlohmann_json -c QuantStack - - if [[ "$ENABLE_TBB" == 1 ]]; then - conda install tbb-devel -c conda-forge; - fi - # Testing - - mkdir build - - cd build - - if [[ "$BOUND_CHECKS" == 1 ]]; then - cmake -DXTENSOR_ENABLE_ASSERT=ON -DDOWNLOAD_GTEST=ON -DBUILD_BENCHMARK=ON ..; - elif [[ "$COLUMN_MAJOR_LAYOUT" == 1 ]]; then - cmake -DBUILD_TESTS=ON -DDEFAULT_COLUMN_MAJOR=ON ..; - elif [[ "$DISABLE_XSIMD" == 1 ]]; then - cmake -DBUILD_TESTS=ON ..; - elif [[ "$ENABLE_TBB" == 1 ]]; then - cmake -DDOWNLOAD_GTEST=ON -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=/home/travis/miniconda/include -DTBB_LIBRARY=/home/travis/miniconda/lib ..; - else - cmake -DXTENSOR_USE_XSIMD=ON -DBUILD_TESTS=ON ..; - fi - - make -j2 test_xtensor_lib - - if [[ "$BUILD_BENCHMARK" == 1 ]]; then - make -j2 benchmark_xtensor ; - fi - - cd test -script: - - ./test_xtensor_lib diff --git a/CMakeLists.txt b/CMakeLists.txt index feee99e88..331fb48c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,20 +1,32 @@ ############################################################################ -# Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht # +# Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht # +# Copyright (c) QuantStack # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ -cmake_minimum_required(VERSION 3.1) -project(xtensor) +cmake_minimum_required(VERSION 3.15..3.29) +project(xtensor CXX) set(XTENSOR_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) +# xtensor tag files +set(XTENSOR_DATA_DIR "share/xeus-cpp") +set(XTENSOR_TAGFILES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/share/xeus-cpp/tagfiles) + +set(XTENSOR_CONF_DIR "etc/xeus-cpp") +set(XTENSOR_TAGCONFS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/etc/xeus-cpp/tags.d) + +file(COPY "${XTENSOR_TAGFILES_DIR}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/share/xeus-cpp") +file(COPY "${XTENSOR_TAGCONFS_DIR}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/etc/xeus-cpp") + + # Versionning # =========== -file(STRINGS "${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_config.hpp" xtensor_version_defines +file(STRINGS "${XTENSOR_INCLUDE_DIR}/xtensor/core/xtensor_config.hpp" xtensor_version_defines REGEX "#define XTENSOR_VERSION_(MAJOR|MINOR|PATCH)") foreach(ver ${xtensor_version_defines}) if(ver MATCHES "#define XTENSOR_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") @@ -28,99 +40,187 @@ message(STATUS "Building xtensor v${${PROJECT_NAME}_VERSION}") # Dependencies # ============ -set(xtl_REQUIRED_VERSION 0.4.16) -find_package(xtl ${xtl_REQUIRED_VERSION} REQUIRED) - -message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl") +set(xtl_REQUIRED_VERSION 0.8.0) +if(TARGET xtl) + set(xtl_VERSION ${XTL_VERSION_MAJOR}.${XTL_VERSION_MINOR}.${XTL_VERSION_PATCH}) + # Note: This is not SEMVER compatible comparison + if(${xtl_VERSION} VERSION_LESS ${xtl_REQUIRED_VERSION}) + message(ERROR "Mismatch xtl versions. Found '${xtl_VERSION}' but requires: '${xtl_REQUIRED_VERSION}'") + else() + message(STATUS "Found xtl v${xtl_VERSION}") + endif() +else() + find_package(xtl ${xtl_REQUIRED_VERSION} REQUIRED) + message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl") +endif() find_package(nlohmann_json 3.1.1 QUIET) +# Optional dependencies +# ===================== + +OPTION(XTENSOR_USE_XSIMD "simd acceleration for xtensor" OFF) +OPTION(XTENSOR_USE_TBB "enable parallelization using intel TBB" OFF) +OPTION(XTENSOR_USE_OPENMP "enable parallelization using OpenMP" OFF) +if(XTENSOR_USE_TBB AND XTENSOR_USE_OPENMP) + message( + FATAL + "XTENSOR_USE_TBB and XTENSOR_USE_OPENMP cannot both be active at once" + ) +endif() + +if(XTENSOR_USE_XSIMD) + set(xsimd_REQUIRED_VERSION 14.2.0) + if(TARGET xsimd) + set(xsimd_VERSION ${XSIMD_VERSION_MAJOR}.${XSIMD_VERSION_MINOR}.${XSIMD_VERSION_PATCH}) + # Note: This is not SEMVER compatible comparison + if(${xsimd_VERSION} VERSION_LESS ${xsimd_REQUIRED_VERSION}) + message(ERROR "Mismatch xsimd versions. Found '${xsimd_VERSION}' but requires: '${xsimd_REQUIRED_VERSION}'") + else() + message(STATUS "Found xsimd v${xsimd_VERSION}") + endif() + else() + find_package(xsimd ${xsimd_REQUIRED_VERSION} REQUIRED) + message(STATUS "Found xsimd: ${xsimd_INCLUDE_DIRS}/xsimd") + endif() +endif() + +if(XTENSOR_USE_TBB) + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + find_package(TBB REQUIRED) + message(STATUS "Found intel TBB: ${TBB_INCLUDE_DIRS}") +endif() + +if(XTENSOR_USE_OPENMP) + find_package(OpenMP REQUIRED) + if (OPENMP_FOUND) + # Set openmp variables now + + # Create private target just for this lib + # https://cliutils.gitlab.io/modern-cmake/chapters/packages/OpenMP.html + # Probably not safe for cmake < 3.4 .. + find_package(Threads REQUIRED) + add_library(OpenMP::OpenMP_CXX_xtensor IMPORTED INTERFACE) + set_property( + TARGET + OpenMP::OpenMP_CXX_xtensor + PROPERTY + INTERFACE_COMPILE_OPTIONS ${OpenMP_CXX_FLAGS} + ) + # Only works if the same flag is passed to the linker; use CMake 3.9+ otherwise (Intel, AppleClang) + set_property( + TARGET + OpenMP::OpenMP_CXX_xtensor + PROPERTY + INTERFACE_LINK_LIBRARIES ${OpenMP_CXX_FLAGS} Threads::Threads) + + message(STATUS "OpenMP Found") + else() + message(FATAL "Failed to locate OpenMP") + endif() +endif() + # Build # ===== set(XTENSOR_HEADERS - ${XTENSOR_INCLUDE_DIR}/xtensor/xaccumulator.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xadapt.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xarray.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xassign.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xaxis_iterator.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xbroadcast.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xbuffer_adaptor.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xbuilder.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xcomplex.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xconcepts.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xcontainer.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xcsv.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xdynamic_view.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xeval.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xexception.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression_holder.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xfixed.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xfunction.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xfunctor_view.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xgenerator.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xhistogram.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xindex_view.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xinfo.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xio.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xiterable.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xiterator.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xjson.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xlayout.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xmanipulation.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xmasked_value.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xmasked_view.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xmath.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xnoalias.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xnorm.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xnpy.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xoffset_view.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xoperation.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly_base.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly_storage.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xrandom.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xreducer.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xscalar.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xsemantic.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xshape.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xslice.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xsort.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xstorage.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xstrided_view.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xstrided_view_base.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xstrides.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xtensor.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_config.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_forward.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_simd.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xutils.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xvectorize.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xview.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xview_utils.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/chunk/xchunked_array.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/chunk/xchunked_assign.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/chunk/xchunked_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/containers/xadapt.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/containers/xarray.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/containers/xbuffer_adaptor.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/containers/xcontainer.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/containers/xfixed.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/containers/xscalar.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/containers/xstorage.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/containers/xtensor.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xaccessible.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xassign.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xeval.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xexpression.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xexpression_traits.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xfunction.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xiterable.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xiterator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xlayout.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xmath.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xmultiindex_iterator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xnoalias.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xoperation.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xsemantic.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xshape.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xstrides.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xtensor_config.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xtensor_forward.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/core/xvectorize.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/generators/xbuilder.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/generators/xgenerator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/generators/xrandom.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/io/xcsv.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/io/xinfo.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/io/xio.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/io/xjson.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/io/xmime.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/io/xnpy.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/misc/xcomplex.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/misc/xexpression_holder.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/misc/xfft.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/misc/xhistogram.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/misc/xmanipulation.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/misc/xpad.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/misc/xset_operation.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/misc/xsort.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/optional/xoptional.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/optional/xoptional_assembly.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/optional/xoptional_assembly_base.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/optional/xoptional_assembly_storage.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/reducers/xaccumulator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/reducers/xblockwise_reducer.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/reducers/xblockwise_reducer_functors.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/reducers/xnorm.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/reducers/xreducer.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/utils/xexception.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/utils/xtensor_simd.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/utils/xutils.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xaxis_iterator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xaxis_slice_iterator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xbroadcast.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xdynamic_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xfunctor_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xindex_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xmasked_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xoffset_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xrepeat.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xslice.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xstrided_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xstrided_view_base.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xview.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/views/xview_utils.hpp ) add_library(xtensor INTERFACE) -target_include_directories(xtensor INTERFACE $ - $) + +target_include_directories(xtensor INTERFACE + $ + $ + $) + +target_compile_features(xtensor INTERFACE cxx_std_20) + target_link_libraries(xtensor INTERFACE xtl) OPTION(XTENSOR_ENABLE_ASSERT "xtensor bound check" OFF) OPTION(XTENSOR_CHECK_DIMENSION "xtensor dimension check" OFF) -OPTION(XTENSOR_USE_XSIMD "simd acceleration for xtensor" OFF) -OPTION(XTENSOR_USE_TBB "enable parallelization using intel TBB" OFF) +OPTION(XTENSOR_FORCE_TEMPORARY_MEMORY_IN_ASSIGNMENTS "xtensor force the use of temporary memory when assigning instead of an automatic overlap check" ON) OPTION(BUILD_TESTS "xtensor test suite" OFF) OPTION(BUILD_BENCHMARK "xtensor benchmark" OFF) -OPTION(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF) OPTION(DOWNLOAD_GBENCHMARK "download google benchmark and build from source" ON) OPTION(DEFAULT_COLUMN_MAJOR "set default layout to column major" OFF) -OPTION(DISABLE_VS2017 "disables the compilation of some test with Visual Studio 2017" OFF) +OPTION(CPP23 "enables C++23 (experimental)" OFF) +OPTION(XTENSOR_DISABLE_EXCEPTIONS "Disable C++ exceptions" OFF) +OPTION(DISABLE_MSVC_ITERATOR_CHECK "Disable the MVSC iterator check" ON) -if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) - set(BUILD_TESTS ON) -endif() if(XTENSOR_ENABLE_ASSERT OR XTENSOR_CHECK_DIMENSION) add_definitions(-DXTENSOR_ENABLE_ASSERT) @@ -130,31 +230,20 @@ if(XTENSOR_CHECK_DIMENSION) add_definitions(-DXTENSOR_ENABLE_CHECK_DIMENSION) endif() -if(XTENSOR_USE_XSIMD) - add_definitions(-DXTENSOR_USE_XSIMD) - find_package(xsimd 7.0 REQUIRED) - message(STATUS "Found xsimd: ${xsimd_INCLUDE_DIRS}/xsimd") - target_link_libraries(xtensor INTERFACE xsimd) -endif() - -if(XTENSOR_USE_TBB) - set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") - add_definitions(-DXTENSOR_USE_TBB) - find_package(TBB REQUIRED) - message(STATUS "Found intel TBB: ${TBB_INCLUDE_DIRS}") - include_directories(${TBB_INCLUDE_DIRS}) - target_link_libraries(xtensor INTERFACE ${TBB_LIBRARIES}) +if(XTENSOR_FORCE_TEMPORARY_MEMORY_IN_ASSIGNMENTS) + add_definitions(-DXTENSOR_FORCE_TEMPORARY_MEMORY_IN_ASSIGNMENTS) endif() if(DEFAULT_COLUMN_MAJOR) add_definitions(-DXTENSOR_DEFAULT_LAYOUT=layout_type::column_major) endif() -if(DISABLE_VS2017) - add_definitions(-DDISABLE_VS2017) +if(MSVC AND DISABLE_MSVC_ITERATOR_CHECK) + add_compile_definitions($<$:_ITERATOR_DEBUG_LEVEL=0>) endif() if(BUILD_TESTS) + enable_testing() add_subdirectory(test) endif() @@ -162,6 +251,11 @@ if(BUILD_BENCHMARK) add_subdirectory(benchmark) endif() +if(XTENSOR_USE_OPENMP) + # Link xtensor itself to OpenMP to propagate to user projects + target_link_libraries(xtensor INTERFACE OpenMP::OpenMP_CXX_xtensor) +endif() + # Installation # ============ @@ -175,10 +269,10 @@ install(TARGETS xtensor export(EXPORT ${PROJECT_NAME}-targets FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") -install(FILES ${XTENSOR_HEADERS} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xtensor) +install(DIRECTORY ${XTENSOR_INCLUDE_DIR}/xtensor + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -set(XTENSOR_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE +set(XTENSOR_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for xtensorConfig.cmake") configure_package_config_file(${PROJECT_NAME}Config.cmake.in @@ -205,4 +299,47 @@ configure_file(${PROJECT_NAME}.pc.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/") + DESTINATION "${CMAKE_INSTALL_DATADIR}/pkgconfig/") + +install(DIRECTORY ${XTENSOR_TAGFILES_DIR} + DESTINATION ${XTENSOR_DATA_DIR}) + +install(DIRECTORY ${XTENSOR_TAGCONFS_DIR} + DESTINATION ${XTENSOR_CONF_DIR}) + +# Write single include +# ==================== + +function(PREPEND var prefix) + set(listVar "") + foreach(f ${ARGN}) + list(APPEND listVar "${prefix}${f}") + endforeach(f) + set(${var} "${listVar}" PARENT_SCOPE) +endfunction() + +function(POSTFIX var postfix) + set(listVar "") + foreach(f ${ARGN}) + list(APPEND listVar "${f}${postfix}") + endforeach(f) + set(${var} "${listVar}" PARENT_SCOPE) +endfunction() + +set(XTENSOR_SINGLE_INCLUDE ${XTENSOR_HEADERS}) +string(REPLACE "${XTENSOR_INCLUDE_DIR}/" "" XTENSOR_SINGLE_INCLUDE "${XTENSOR_SINGLE_INCLUDE}") +list(REMOVE_ITEM XTENSOR_SINGLE_INCLUDE + xtensor/misc/xexpression_holder.hpp + xtensor/io/xjson.hpp + xtensor/io/xmime.hpp + xtensor/io/xnpy.hpp) + +PREPEND(XTENSOR_SINGLE_INCLUDE "#include <" ${XTENSOR_SINGLE_INCLUDE}) +POSTFIX(XTENSOR_SINGLE_INCLUDE ">" ${XTENSOR_SINGLE_INCLUDE}) +string(REPLACE ";" "\n" XTENSOR_SINGLE_INCLUDE "${XTENSOR_SINGLE_INCLUDE}") +string(CONCAT XTENSOR_SINGLE_INCLUDE "#ifndef XTENSOR\n" "#define XTENSOR\n\n" "${XTENSOR_SINGLE_INCLUDE}" "\n\n#endif\n") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/xtensor.hpp" "${XTENSOR_SINGLE_INCLUDE}") + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/xtensor.hpp" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/LICENSE b/LICENSE index 0e953348c..03d48a3bc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Copyright (c) 2016, Johan Mabille and Sylvain Corlay +Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht +Copyright (c) 2016, QuantStack All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index 33c01baf4..19c5f9fe1 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # ![xtensor](docs/source/xtensor.svg) -[![Travis](https://travis-ci.org/QuantStack/xtensor.svg?branch=master)](https://travis-ci.org/QuantStack/xtensor) -[![Appveyor](https://ci.appveyor.com/api/projects/status/quf1hllkedr0rxbk?svg=true)](https://ci.appveyor.com/project/QuantStack/xtensor) +[![GHA Linux](https://github.com/xtensor-stack/xtensor/actions/workflows/linux.yml/badge.svg)](https://github.com/xtensor-stack/xtensor/actions/workflows/linux.yml) +[![GHA OSX](https://github.com/xtensor-stack/xtensor/actions/workflows/osx.yml/badge.svg)](https://github.com/xtensor-stack/xtensor/actions/workflows/osx.yml) +[![GHA Windows](https://github.com/xtensor-stack/xtensor/actions/workflows/windows.yml/badge.svg)](https://github.com/xtensor-stack/xtensor/actions/workflows/windows.yml) [![Documentation](http://readthedocs.org/projects/xtensor/badge/?version=latest)](https://xtensor.readthedocs.io/en/latest/?badge=latest) -[![Binder](https://img.shields.io/badge/launch-binder-brightgreen.svg)](https://mybinder.org/v2/gh/QuantStack/xtensor/stable?filepath=notebooks/xtensor.ipynb) -[![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) +[![Doxygen -> gh-pages](https://github.com/xtensor-stack/xtensor/workflows/gh-pages/badge.svg)](https://xtensor-stack.github.io/xtensor) +[![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/xtensor-stack/xtensor/stable?filepath=notebooks%2Fxtensor.ipynb) +[![Zulip](https://img.shields.io/badge/social_chat-zulip-blue.svg)](https://xtensor.zulipchat.com/#narrow/channel/539553-Ask-anything) +[![CodSpeed](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/xtensor-stack/xtensor?utm_source=badge) Multi-dimensional arrays with broadcasting and lazy computing. @@ -26,62 +29,89 @@ be plugged into our expression system can easily be written. In fact, `xtensor` can be used to **process NumPy data structures inplace** using Python's [buffer protocol](https://docs.python.org/3/c-api/buffer.html). Similarly, we can operate on Julia and R arrays. For more details on the NumPy, -Julia and R bindings, check out the [xtensor-python](https://github.com/QuantStack/xtensor-python), -[xtensor-julia](https://github.com/QuantStack/Xtensor.jl) and -[xtensor-r](https://github.com/QuantStack/xtensor-r) projects respectively. +Julia and R bindings, check out the [xtensor-python](https://github.com/xtensor-stack/xtensor-python), +[xtensor-julia](https://github.com/xtensor-stack/Xtensor.jl) and +[xtensor-r](https://github.com/xtensor-stack/xtensor-r) projects respectively. -`xtensor` requires a modern C++ compiler supporting C++14. The following C++ -compilers are supported: +Up to version 0.26.0, `xtensor` requires a C++ compiler supporting C++14. +`xtensor` 0.26.x requires a C++ compiler supporting C++17. +`xtensor` 0.27.x requires a C++ compiler supporting C++20. - - On Windows platforms, Visual C++ 2015 Update 2, or more recent - - On Unix platforms, gcc 4.9 or a recent version of Clang ## Installation -`xtensor` is a header-only library. We provide a package for the conda package -manager. +### Package managers + +We provide a package for the mamba (or conda) package manager: ```bash -conda install -c conda-forge xtensor +mamba install -c conda-forge xtensor ``` -Or you can directly install it from the sources: +### Install from sources + +`xtensor` is a header-only library. + +You can directly install it from the sources: ```bash cmake -DCMAKE_INSTALL_PREFIX=your_install_prefix make install ``` +### Installing xtensor using vcpkg + +You can download and install xtensor using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: + +```bash +git clone https://github.com/Microsoft/vcpkg.git +cd vcpkg +./bootstrap-vcpkg.sh +./vcpkg integrate install +./vcpkg install xtensor +``` + +The xtensor port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. + ## Trying it online -To try out xtensor interactively in your web browser, just click on the binder -link: +You can play with `xtensor` interactively in a Jupyter notebook right now! Just click on the binder link below: + +[![Binder](docs/source/binder-logo.svg)](https://mybinder.org/v2/gh/xtensor-stack/xtensor/stable?filepath=notebooks/xtensor.ipynb) + +The C++ support in Jupyter is powered by the [xeus-cling](https://github.com/jupyter-xeus/xeus-cling) C++ kernel. Together with xeus-cling, xtensor enables a similar workflow to that of NumPy with the IPython Jupyter kernel. -[![Binder](docs/source/binder-logo.svg)](https://mybinder.org/v2/gh/QuantStack/xtensor/stable?filepath=notebooks/xtensor.ipynb) +![xeus-cling](docs/source/xeus-cling-screenshot.png) ## Documentation -To get started with using `xtensor`, check out the full documentation +For more information on using `xtensor`, check out the reference documentation http://xtensor.readthedocs.io/ ## Dependencies -`xtensor` depends on the [xtl](https://github.com/QuantStack/xtl) library and -has an optional dependency on the [xsimd](https://github.com/QuantStack/xsimd) +`xtensor` depends on the [xtl](https://github.com/xtensor-stack/xtl) library and +has an optional dependency on the [xsimd](https://github.com/xtensor-stack/xsimd) library: | `xtensor` | `xtl` |`xsimd` (optional) | |-----------|---------|-------------------| -| master | ^0.4.16 | ^7.0.0 | -| 0.18.2 | ^0.4.16 | ^7.0.0 | -| 0.18.1 | ^0.4.16 | ^7.0.0 | -| 0.18.0 | ^0.4.16 | ^7.0.0 | -| 0.17.4 | ^0.4.16 | ^6.1.4 | -| 0.17.3 | ^0.4.15 | ^6.1.4 | -| 0.17.2 | ^0.4.15 | ^6.1.4 | -| 0.17.1 | ^0.4.14 | ^6.1.4 | -| 0.17.0 | ^0.4.13 | ^6.1.4 | +| master | ^0.8.0 | ^13.2.0 | +| 0.27.1 | ^0.8.0 | ^13.2.0 | +| 0.27.0 | ^0.8.0 | ^13.2.0 | +| 0.26.0 | ^0.8.0 | ^13.2.0 | +| 0.25.0 | ^0.7.5 | ^11.0.0 | +| 0.24.7 | ^0.7.0 | ^10.0.0 | +| 0.24.6 | ^0.7.0 | ^10.0.0 | +| 0.24.5 | ^0.7.0 | ^10.0.0 | +| 0.24.4 | ^0.7.0 | ^10.0.0 | +| 0.24.3 | ^0.7.0 | ^8.0.3 | +| 0.24.2 | ^0.7.0 | ^8.0.3 | +| 0.24.1 | ^0.7.0 | ^8.0.3 | +| 0.24.0 | ^0.7.0 | ^8.0.3 | +| 0.23.x | ^0.7.0 | ^7.4.8 | +| 0.22.0 | ^0.6.23 | ^7.4.8 | The dependency on `xsimd` is required if you want to enable SIMD acceleration in `xtensor`. This can be done by defining the macro `XTENSOR_USE_XSIMD` @@ -277,9 +307,9 @@ Besides, two access operators are provided: Xtensor operations make use of SIMD acceleration depending on what instruction sets are available on the platform at hand (SSE, AVX, AVX512, Neon). -### [![xsimd](docs/source/xsimd-small.svg)](https://github.com/QuantStack/xsimd) +### [![xsimd](docs/source/xsimd-small.svg)](https://github.com/xtensor-stack/xsimd) -The [xsimd](https://github.com/QuantStack/xsimd) project underlies the +The [xsimd](https://github.com/xtensor-stack/xsimd) project underlies the detection of the available instruction sets, and provides generic high-level wrappers and memory allocators for client libraries such as xtensor. @@ -307,9 +337,9 @@ performance of the application. ## Language bindings -### [![xtensor-python](docs/source/xtensor-python-small.svg)](https://github.com/QuantStack/xtensor-python) +### [![xtensor-python](docs/source/xtensor-python-small.svg)](https://github.com/xtensor-stack/xtensor-python) -The [xtensor-python](https://github.com/QuantStack/xtensor-python) project +The [xtensor-python](https://github.com/xtensor-stack/xtensor-python) project provides the implementation of two `xtensor` containers, `pyarray` and `pytensor` which effectively wrap NumPy arrays, allowing inplace modification, including reshapes. @@ -317,9 +347,9 @@ including reshapes. Utilities to automatically generate NumPy-style universal functions, exposed to Python from scalar functions are also provided. -### [![xtensor-julia](docs/source/xtensor-julia-small.svg)](https://github.com/QuantStack/xtensor-julia) +### [![xtensor-julia](docs/source/xtensor-julia-small.svg)](https://github.com/xtensor-stack/xtensor-julia) -The [xtensor-julia](https://github.com/QuantStack/xtensor-julia) project +The [xtensor-julia](https://github.com/xtensor-stack/xtensor-julia) project provides the implementation of two `xtensor` containers, `jlarray` and `jltensor` which effectively wrap julia arrays, allowing inplace modification, including reshapes. @@ -327,9 +357,9 @@ including reshapes. Like in the Python case, utilities to generate NumPy-style universal functions are provided. -### [![xtensor-r](docs/source/xtensor-r-small.svg)](https://github.com/QuantStack/xtensor-r) +### [![xtensor-r](docs/source/xtensor-r-small.svg)](https://github.com/xtensor-stack/xtensor-r) -The [xtensor-r](https://github.com/QuantStack/xtensor-r) project provides the +The [xtensor-r](https://github.com/xtensor-stack/xtensor-r) project provides the implementation of two `xtensor` containers, `rarray` and `rtensor` which effectively wrap R arrays, allowing inplace modification, including reshapes. @@ -338,17 +368,17 @@ universal functions are provided. ## Library bindings -### [![xtensor-blas](docs/source/xtensor-blas-small.svg)](https://github.com/QuantStack/xtensor-blas) +### [![xtensor-blas](docs/source/xtensor-blas-small.svg)](https://github.com/xtensor-stack/xtensor-blas) -The [xtensor-blas](https://github.com/QuantStack/xtensor-blas) project provides +The [xtensor-blas](https://github.com/xtensor-stack/xtensor-blas) project provides bindings to BLAS libraries, enabling linear-algebra operations on xtensor expressions. -### [![xtensor-io](docs/source/xtensor-io-small.svg)](https://github.com/QuantStack/xtensor-io) +### [![xtensor-io](docs/source/xtensor-io-small.svg)](https://github.com/xtensor-stack/xtensor-io) -The [xtensor-io](https://github.com/QuantStack/xtensor-io) project enables the +The [xtensor-io](https://github.com/xtensor-stack/xtensor-io) project enables the loading of a variety of file formats into xtensor expressions, such as image -files, sound files, as well as NumPy npy and npz files. +files, sound files, HDF5 files, as well as NumPy npy and npz files. ## Building and running the tests diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 9b19c750d..0d0ce5766 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -6,30 +6,46 @@ # The full license is in the file LICENSE, distributed with this software. # ############################################################################ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.22) +include(FetchContent) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) project(xtensor-benchmark) find_package(xtensor REQUIRED CONFIG) - set(XTENSOR_INCLUDE_DIR ${xtensor_INCLUDE_DIR}) + set(XTENSOR_INCLUDE_DIR ${xtensor_INCLUDE_DIRS}) endif () -message(STATUS "Forcing tests build type to Release") -set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) +if(CODSPEED_MODE AND NOT CODSPEED_MODE STREQUAL "off") + message(STATUS "CodSpeed mode enabled (${CODSPEED_MODE}) - using RelWithDebInfo build type") + set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE) +else() + message(STATUS "Forcing tests build type to Release") + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) +endif() include(CheckCXXCompilerFlag) string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -O3 -g -Wunused-parameter -Wextra -Wreorder") - CHECK_CXX_COMPILER_FLAG("-std=c++14" HAS_CPP14_FLAG) - - if (HAS_CPP14_FLAG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") - else() - message(FATAL_ERROR "Unsupported compiler -- xtensor requires C++14 support!") + # Skip -march=native for CodSpeed simulation mode (valgrind does not + # support all native instruction sets) + if(NOT (CODSPEED_MODE STREQUAL "simulation")) + CHECK_CXX_COMPILER_FLAG(-march=native arch_native_supported) + if(arch_native_supported AND NOT CMAKE_CXX_FLAGS MATCHES "-march") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") + endif() + endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -g -Wunused-parameter -Wextra -Wreorder") + + if(NOT "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC") + CHECK_CXX_COMPILER_FLAG("-std=c++20" HAS_CPP20_FLAG) + if (HAS_CPP20_FLAG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20") + else() + message(FATAL_ERROR "Unsupported compiler -- xtensor requires C++17 support!") + endif() endif() # Enable link time optimization and set the default symbol @@ -68,32 +84,19 @@ endif() if(DOWNLOAD_GBENCHMARK OR GBENCHMARK_SRC_DIR) - if(DOWNLOAD_GBENCHMARK) - # Download and unpack googlebenchmark at configure time - configure_file(downloadGBenchmark.cmake.in googlebenchmark-download/CMakeLists.txt) - else() - # Copy local source of googlebenchmark at configure time - configure_file(copyGBenchmark.cmake.in googlebenchmark-download/CMakeLists.txt) - endif() - execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . - RESULT_VARIABLE result - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-download ) - if(result) - message(FATAL_ERROR "CMake step for googlebenchmark failed: ${result}") - endif() - execute_process(COMMAND ${CMAKE_COMMAND} --build . - RESULT_VARIABLE result - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-download ) - if(result) - message(FATAL_ERROR "Build step for googlebenchmark failed: ${result}") - endif() - - # Add googlebenchmark directly to our build. This defines - # the gtest and gtest_main targets. - add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-src - ${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-build) - - set(GBENCHMARK_INCLUDE_DIRS "${googlebenchmark_SOURCE_DIR}/include") + FetchContent_Declare(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG main) + + FetchContent_Declare(googlebenchmark + GIT_REPOSITORY https://github.com/CodSpeedHQ/codspeed-cpp.git + GIT_TAG main + SOURCE_SUBDIR google_benchmark) + + FetchContent_MakeAvailable( + googletest + googlebenchmark) + set(GBENCHMARK_INCLUDE_DIRS "${googlebenchmark_SOURCE_DIR}/google_benchmark/include") set(GBENCHMARK_LIBRARIES benchmark) else() find_package(benchmark REQUIRED) @@ -123,12 +126,23 @@ set(XTENSOR_BENCHMARK benchmark_view_access.cpp benchmark_view_assignment.cpp benchmark_view_adapt.cpp + benchmark_stl.cpp main.cpp ) + set(XTENSOR_BENCHMARK_TARGET benchmark_xtensor) add_executable(${XTENSOR_BENCHMARK_TARGET} EXCLUDE_FROM_ALL ${XTENSOR_BENCHMARK} ${XTENSOR_HEADERS}) -target_link_libraries(${XTENSOR_BENCHMARK_TARGET} xtensor ${GBENCHMARK_LIBRARIES}) +target_link_libraries(${XTENSOR_BENCHMARK_TARGET} PUBLIC xtensor ${GBENCHMARK_LIBRARIES}) + +if(XTENSOR_USE_TBB) + target_compile_definitions(${XTENSOR_BENCHMARK_TARGET} PUBLIC XTENSOR_USE_TBB) + target_include_directories(${XTENSOR_BENCHMARK_TARGET} PUBLIC ${TBB_INCLUDE_DIRS}) + target_link_libraries(${XTENSOR_BENCHMARK_TARGET} PUBLIC ${TBB_LIBRARIES}) +endif() +if(XTENSOR_USE_OPENMP) + target_compile_definitions(${XTENSOR_BENCHMARK_TARGET} PUBLIC XTENSOR_USE_OPENMP) +endif() add_custom_target(xbenchmark COMMAND benchmark_xtensor diff --git a/benchmark/benchmark_adapter.cpp b/benchmark/benchmark_adapter.cpp index f80b2892c..3a76dcb7e 100644 --- a/benchmark/benchmark_adapter.cpp +++ b/benchmark/benchmark_adapter.cpp @@ -1,28 +1,28 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #include -// #include "xtensor/xshape.hpp" -#include "xtensor/xstorage.hpp" -#include "xtensor/xutils.hpp" -#include "xtensor/xadapt.hpp" -#include "xtensor/xnoalias.hpp" +// #include "xtensor/core/core/xshape.hpp" +#include "xtensor/containers/xadapt.hpp" +#include "xtensor/containers/xstorage.hpp" +#include "xtensor/core/xnoalias.hpp" +#include "xtensor/utils/xutils.hpp" namespace xt { template void shape_array_adapter(benchmark::State& state) { - const V a({1,2,3,4}); - const V b({1,2,3,4}); + const V a({1, 2, 3, 4}); + const V b({1, 2, 3, 4}); using value_type = typename V::value_type; - + for (auto _ : state) { xtensor result(std::array({4})); @@ -63,7 +63,7 @@ namespace xt auto ab = xt::adapt(b); auto ar = xt::adapt(res); auto fun = aa + ab; - std::copy(fun.storage_cbegin(), fun.storage_cend(), ar.storage_begin()); + std::copy(fun.linear_cbegin(), fun.linear_cend(), ar.linear_begin()); benchmark::DoNotOptimize(ar.data()); } } @@ -81,8 +81,15 @@ namespace xt auto ab = xt::adapt(b); auto ar = xt::adapt(res); auto fun = aa + ab; - std::transform(fun.storage_cbegin(), fun.storage_cend(), ar.storage_begin(), - [](typename decltype(fun)::value_type x) { return static_cast(x); }); + std::transform( + fun.linear_cbegin(), + fun.linear_cend(), + ar.linear_begin(), + [](typename decltype(fun)::value_type x) + { + return static_cast(x); + } + ); benchmark::DoNotOptimize(ar.data()); } } diff --git a/benchmark/benchmark_assign.cpp b/benchmark/benchmark_assign.cpp index 3e4ac1ad0..b9efb341e 100644 --- a/benchmark/benchmark_assign.cpp +++ b/benchmark/benchmark_assign.cpp @@ -1,19 +1,19 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #ifndef BENCHMARK_ASSIGN_HPP #define BENCHMARK_ASSIGN_HPP #include -#include "xtensor/xnoalias.hpp" -#include "xtensor/xtensor.hpp" -#include "xtensor/xarray.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/containers/xtensor.hpp" +#include "xtensor/core/xnoalias.hpp" namespace xt { @@ -39,24 +39,22 @@ namespace xt } template - inline void init_xtensor_benchmark(V& lhs, V& rhs, V& res, - std::size_t size0, size_t size1) + inline void init_xtensor_benchmark(V& lhs, V& rhs, V& res, std::size_t size0, size_t size1) { - lhs.resize({ size0, size1 }); - rhs.resize({ size0, size1 }); - res.resize({ size0, size1 }); + lhs.resize({size0, size1}); + rhs.resize({size0, size1}); + res.resize({size0, size1}); init_benchmark_data(lhs, rhs, size0, size1); } template - inline void init_dl_xtensor_benchmark(V& lhs, V& rhs, V& res, - std::size_t size0, size_t size1) + inline void init_dl_xtensor_benchmark(V& lhs, V& rhs, V& res, std::size_t size0, size_t size1) { using strides_type = typename V::strides_type; - strides_type str = { size1, 1 }; - lhs.resize({ size0, size1 }, str); - rhs.resize({ size0, size1 }, str); - res.resize({ size0, size1 }, str); + strides_type str = {size1, 1}; + lhs.resize({size0, size1}, str); + rhs.resize({size0, size1}, str); + res.resize({size0, size1}, str); init_benchmark_data(lhs, rhs, size0, size1); } @@ -161,7 +159,7 @@ namespace xt for (auto _ : state) { auto fun = 3.0 * x - 2.0 * y; - std::copy(fun.storage_cbegin(), fun.storage_cend(), res.storage_begin()); + std::copy(fun.linear_cbegin(), fun.linear_cend(), res.linear_begin()); benchmark::DoNotOptimize(res.data()); } } @@ -210,20 +208,19 @@ namespace xt } } - - BENCHMARK_TEMPLATE(assign_c_assign, xt::xtensor)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_x_assign, xt::xtensor)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_xiter_copy, xt::xtensor)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_xstorageiter_copy, xt::xtensor)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_c_assign_ii, xt::xtensor)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_x_assign_ii, xt::xtensor)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_x_assign_iii, xt::xtensor)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_c_assign_iii, xt::xtensor)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_x_assign, xt::xarray)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_x_assign, xt::xarray)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_x_assign, xt::xtensor)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_c_scalar_computed, xt::xtensor)->Range(32, 32<<3); - BENCHMARK_TEMPLATE(assign_x_scalar_computed, xt::xtensor)->Range(32, 32<<3); + BENCHMARK_TEMPLATE(assign_c_assign, xt::xtensor)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_x_assign, xt::xtensor)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_xiter_copy, xt::xtensor)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_xstorageiter_copy, xt::xtensor)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_c_assign_ii, xt::xtensor)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_x_assign_ii, xt::xtensor)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_x_assign_iii, xt::xtensor)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_c_assign_iii, xt::xtensor)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_x_assign, xt::xarray)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_x_assign, xt::xarray)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_x_assign, xt::xtensor)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_c_scalar_computed, xt::xtensor)->Range(32, 32 << 3); + BENCHMARK_TEMPLATE(assign_x_scalar_computed, xt::xtensor)->Range(32, 32 << 3); } } diff --git a/benchmark/benchmark_builder.cpp b/benchmark/benchmark_builder.cpp index 021f09dfb..e25de39cb 100644 --- a/benchmark/benchmark_builder.cpp +++ b/benchmark/benchmark_builder.cpp @@ -1,16 +1,16 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #include -#include "xtensor/xnoalias.hpp" -#include "xtensor/xtensor.hpp" -#include "xtensor/xarray.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/containers/xtensor.hpp" +#include "xtensor/core/xnoalias.hpp" namespace xt { @@ -42,18 +42,18 @@ namespace xt { for (auto _ : state) { - xt::uvector a {}; + xt::uvector a{}; a.resize(10000); std::iota(a.begin(), a.end(), 0); benchmark::DoNotOptimize(a.data()); } } - + template inline auto builder_arange_for_loop_assign(benchmark::State& state) { for (auto _ : state) - { + { auto expr = xt::arange(0, 10000); T res = T::from_shape({10000}); for (std::size_t i = 0; i < 10000; ++i) @@ -91,7 +91,7 @@ namespace xt auto xend = expr.cend(); auto reit = res.begin(); auto it = expr.cbegin(); - for(ptrdiff_t n = 10000; n > 0; --n) + for (ptrdiff_t n = 10000; n > 0; --n) { *reit = *it; ++it; @@ -127,13 +127,12 @@ namespace xt inline auto builder_ones(benchmark::State& state) { for (auto _ : state) - { + { xt::xarray res = xt::ones({200, 200}); benchmark::DoNotOptimize(res.data()); } } - inline auto builder_ones_assign_iterator(benchmark::State& state) { auto xo = xt::ones({200, 200}); @@ -155,8 +154,12 @@ namespace xt xt::xtensor res(xt::static_shape({200, 200})); auto xo = xt::ones({200, 200}) * 0.15; for (std::size_t i = 0; i < xo.shape()[0]; ++i) + { for (std::size_t j = 0; j < xo.shape()[1]; ++j) + { res(i, j) = xo(i, j); + } + } benchmark::DoNotOptimize(res.storage().data()); } } diff --git a/benchmark/benchmark_container.cpp b/benchmark/benchmark_container.cpp index eafdfe5cf..af51d1d19 100644 --- a/benchmark/benchmark_container.cpp +++ b/benchmark/benchmark_container.cpp @@ -1,19 +1,19 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ -#include #include +#include #include #include -#include "xtensor/xarray.hpp" -#include "xtensor/xtensor.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/containers/xtensor.hpp" namespace xt { @@ -25,9 +25,9 @@ namespace xt template inline void init_benchmark(E& x, E& y, E& res, typename E::size_type size) { - x.resize({ size }); - y.resize({ size }); - res.resize({ size }); + x.resize({size}); + y.resize({size}); + res.resize({size}); using value_type = typename E::value_type; using size_type = typename E::size_type; diff --git a/benchmark/benchmark_creation.cpp b/benchmark/benchmark_creation.cpp index 12c423216..4410d2325 100644 --- a/benchmark/benchmark_creation.cpp +++ b/benchmark/benchmark_creation.cpp @@ -1,17 +1,17 @@ /**************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * - * * * + * * * Distributed under the terms of the BSD 3-Clause License. * - * * * + * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include -#include "xtensor/xbuilder.hpp" -#include "xtensor/xarray.hpp" -#include "xtensor/xtensor.hpp" -#include "xtensor/xfixed.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/containers/xfixed.hpp" +#include "xtensor/containers/xtensor.hpp" +#include "xtensor/generators/xbuilder.hpp" namespace xt { @@ -64,4 +64,4 @@ namespace xt BENCHMARK_TEMPLATE(benchmark_from_shape, xtensor); BENCHMARK_TEMPLATE(benchmark_creation, xarray); BENCHMARK_TEMPLATE(benchmark_creation, xtensor); -} \ No newline at end of file +} diff --git a/benchmark/benchmark_increment_stepper.cpp b/benchmark/benchmark_increment_stepper.cpp index 699aac211..1557692e2 100644 --- a/benchmark/benchmark_increment_stepper.cpp +++ b/benchmark/benchmark_increment_stepper.cpp @@ -1,15 +1,15 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #include -#include "xtensor/xarray.hpp" -#include "xtensor/xrandom.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/generators/xrandom.hpp" #define SHAPE 30, 30 #define RANGE 3, 100 @@ -42,6 +42,7 @@ namespace xt benchmark::DoNotOptimize(c); } } + BENCHMARK(stepper_stepper)->Range(RANGE); void stepper_stepper_ref(benchmark::State& state) @@ -65,6 +66,7 @@ namespace xt benchmark::DoNotOptimize(c); } } + BENCHMARK(stepper_stepper_ref)->Range(RANGE); } } diff --git a/benchmark/benchmark_lambda_expressions.cpp b/benchmark/benchmark_lambda_expressions.cpp index abe454b8d..6c6c40a49 100644 --- a/benchmark/benchmark_lambda_expressions.cpp +++ b/benchmark/benchmark_lambda_expressions.cpp @@ -1,18 +1,18 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #include -#include "xtensor/xnoalias.hpp" -#include "xtensor/xbuilder.hpp" -#include "xtensor/xmath.hpp" -#include "xtensor/xtensor.hpp" -#include "xtensor/xarray.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/containers/xtensor.hpp" +#include "xtensor/core/xmath.hpp" +#include "xtensor/core/xnoalias.hpp" +#include "xtensor/generators/xbuilder.hpp" namespace xt { @@ -66,9 +66,9 @@ namespace xt } } - BENCHMARK(lambda_cube)->Range(32, 32<<3); - BENCHMARK(xexpression_cube)->Range(32, 32<<3); - BENCHMARK(lambda_higher_pow)->Range(32, 32<<3); - BENCHMARK(xsimd_higher_pow)->Range(32, 32<<3); - BENCHMARK(xexpression_higher_pow)->Range(32, 32<<3); -} \ No newline at end of file + BENCHMARK(lambda_cube)->Range(32, 32 << 3); + BENCHMARK(xexpression_cube)->Range(32, 32 << 3); + BENCHMARK(lambda_higher_pow)->Range(32, 32 << 3); + BENCHMARK(xsimd_higher_pow)->Range(32, 32 << 3); + BENCHMARK(xexpression_higher_pow)->Range(32, 32 << 3); +} diff --git a/benchmark/benchmark_math.cpp b/benchmark/benchmark_math.cpp index cd888af84..c365551ea 100644 --- a/benchmark/benchmark_math.cpp +++ b/benchmark/benchmark_math.cpp @@ -1,10 +1,10 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #include #include @@ -13,9 +13,9 @@ #include -#include "xtensor/xarray.hpp" -#include "xtensor/xnoalias.hpp" -#include "xtensor/xtensor.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/containers/xtensor.hpp" +#include "xtensor/core/xnoalias.hpp" // For how many sizes should math functions be tested? #define MATH_RANGE 64, 64 @@ -47,9 +47,9 @@ namespace xt template inline void init_xtensor_benchmark(V& lhs, V& rhs, V& res, std::size_t size0, size_t size1) { - lhs.resize({ size0, size1 }); - rhs.resize({ size0, size1 }); - res.resize({ size0, size1 }); + lhs.resize({size0, size1}); + rhs.resize({size0, size1}); + res.resize({size0, size1}); init_benchmark_data(lhs, rhs, size0, size1); } @@ -92,7 +92,7 @@ namespace xt for (auto _ : state) { auto fct = f(lhs, rhs); - std::copy(fct.storage_begin(), fct.storage_end(), res.storage_begin()); + std::copy(fct.linear_begin(), fct.linear_end(), res.linear_begin()); benchmark::DoNotOptimize(res.data()); } } @@ -152,31 +152,56 @@ namespace xt * Benchmark functors * **********************/ -#define DEFINE_OP_FUNCTOR_2OP(OP, NAME)\ - struct NAME##_fn {\ - template \ - inline auto operator()(const T& lhs, const T& rhs) const { return lhs OP rhs; }\ - inline static std::string name() { return #NAME; }\ +#define DEFINE_OP_FUNCTOR_2OP(OP, NAME) \ + struct NAME##_fn \ + { \ + template \ + inline auto operator()(const T& lhs, const T& rhs) const \ + { \ + return lhs OP rhs; \ + } \ + inline static std::string name() \ + { \ + return #NAME; \ + } \ } -#define DEFINE_FUNCTOR_1OP(FN)\ - struct FN##_fn {\ - template \ - inline auto operator()(const T& x) const { using std::FN; using xt::FN; return FN(x); }\ - inline static std::string name() { return #FN; }\ +#define DEFINE_FUNCTOR_1OP(FN) \ + struct FN##_fn \ + { \ + template \ + inline auto operator()(const T& x) const \ + { \ + using std::FN; \ + using xt::FN; \ + return FN(x); \ + } \ + inline static std::string name() \ + { \ + return #FN; \ + } \ } -#define DEFINE_FUNCTOR_2OP(FN)\ - struct FN##_fn{\ - template \ - inline auto operator()(const T&lhs, const T& rhs) const { using std::FN; using xt::FN; return FN(lhs, rhs); }\ - inline static std::string name() { return #FN; }\ +#define DEFINE_FUNCTOR_2OP(FN) \ + struct FN##_fn \ + { \ + template \ + inline auto operator()(const T& lhs, const T& rhs) const \ + { \ + using std::FN; \ + using xt::FN; \ + return FN(lhs, rhs); \ + } \ + inline static std::string name() \ + { \ + return #FN; \ + } \ } DEFINE_OP_FUNCTOR_2OP(+, add); DEFINE_OP_FUNCTOR_2OP(-, sub); DEFINE_OP_FUNCTOR_2OP(*, mul); - DEFINE_OP_FUNCTOR_2OP(/ , div); + DEFINE_OP_FUNCTOR_2OP(/, div); DEFINE_FUNCTOR_1OP(exp); DEFINE_FUNCTOR_1OP(exp2); @@ -334,7 +359,8 @@ namespace xt a.resize({sz, sz}); b.resize({sz, sz}); - xtensor res; res.resize({sz, sz}); + xtensor res; + res.resize({sz, sz}); for (auto _ : state) { @@ -351,7 +377,8 @@ namespace xt a.resize({sz, sz}); b.resize({sz, sz}); - xtensor res; res.resize({sz, sz}); + xtensor res; + res.resize({sz, sz}); for (auto _ : state) { diff --git a/benchmark/benchmark_random.cpp b/benchmark/benchmark_random.cpp index 93c0e17b3..e5279988d 100644 --- a/benchmark/benchmark_random.cpp +++ b/benchmark/benchmark_random.cpp @@ -1,25 +1,25 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #ifndef BENCHMARK_RANDOM_HPP #define BENCHMARK_RANDOM_HPP #include -#include "xtensor/xnoalias.hpp" -#include "xtensor/xtensor.hpp" -#include "xtensor/xarray.hpp" -#include "xtensor/xrandom.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/containers/xtensor.hpp" +#include "xtensor/core/xnoalias.hpp" +#include "xtensor/generators/xrandom.hpp" namespace xt { namespace random_bench - { + { void random_assign_xtensor(benchmark::State& state) { for (auto _ : state) diff --git a/benchmark/benchmark_reducer.cpp b/benchmark/benchmark_reducer.cpp index 9017bc327..c4304782f 100644 --- a/benchmark/benchmark_reducer.cpp +++ b/benchmark/benchmark_reducer.cpp @@ -1,15 +1,15 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #include -#include "xtensor/xarray.hpp" -#include "xtensor/xreducer.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/reducers/xreducer.hpp" namespace xt { @@ -30,33 +30,33 @@ namespace xt { for (auto _ : state) { - res = sum(x, axes, evaluation_strategy::immediate()); + res = sum(x, axes, evaluation_strategy::immediate); benchmark::DoNotOptimize(res.data()); } } - xarray u = ones({ 10, 100000 }); - xarray v = ones({ 100000, 10 }); - xarray res2 = ones({ 1 }); + xarray u = ones({10, 100000}); + xarray v = ones({100000, 10}); + xarray res2 = ones({1}); - std::vector axis0 = { 0 }; - std::vector axis1 = { 1 }; - std::vector axis_both = { 0, 1 }; + std::vector axis0 = {0}; + std::vector axis1 = {1}; + std::vector axis_both = {0, 1}; - static auto res0 = xarray::from_shape({ 100000 }); - static auto res1 = xarray::from_shape({ 10 }); + static auto res0 = xarray::from_shape({100000}); + static auto res1 = xarray::from_shape({10}); - BENCHMARK_CAPTURE(reducer_reducer, 10x100000/axis 0, u, res0, axis0); - BENCHMARK_CAPTURE(reducer_reducer, 10x100000/axis 1, u, res1, axis1); - BENCHMARK_CAPTURE(reducer_reducer, 100000x10/axis 1, v, res1, axis0); - BENCHMARK_CAPTURE(reducer_reducer, 100000x10/axis 0, v, res0, axis1); - BENCHMARK_CAPTURE(reducer_reducer, 100000x10/axis both, v, res2, axis_both); + BENCHMARK_CAPTURE(reducer_reducer, 10x100000 / axis 0, u, res0, axis0); + BENCHMARK_CAPTURE(reducer_reducer, 10x100000 / axis 1, u, res1, axis1); + BENCHMARK_CAPTURE(reducer_reducer, 100000x10 / axis 1, v, res1, axis0); + BENCHMARK_CAPTURE(reducer_reducer, 100000x10 / axis 0, v, res0, axis1); + BENCHMARK_CAPTURE(reducer_reducer, 100000x10 / axis both, v, res2, axis_both); - BENCHMARK_CAPTURE(reducer_immediate_reducer, 10x100000/axis 0, u, res0, axis0); - BENCHMARK_CAPTURE(reducer_immediate_reducer, 10x100000/axis 1, u, res1, axis1); - BENCHMARK_CAPTURE(reducer_immediate_reducer, 100000x10/axis 1, v, res1, axis0); - BENCHMARK_CAPTURE(reducer_immediate_reducer, 100000x10/axis 0, v, res0, axis1); - BENCHMARK_CAPTURE(reducer_immediate_reducer, 100000x10/axis both, v, res2, axis_both); + BENCHMARK_CAPTURE(reducer_immediate_reducer, 10x100000 / axis 0, u, res0, axis0); + BENCHMARK_CAPTURE(reducer_immediate_reducer, 10x100000 / axis 1, u, res1, axis1); + BENCHMARK_CAPTURE(reducer_immediate_reducer, 100000x10 / axis 1, v, res1, axis0); + BENCHMARK_CAPTURE(reducer_immediate_reducer, 100000x10 / axis 0, v, res0, axis1); + BENCHMARK_CAPTURE(reducer_immediate_reducer, 100000x10 / axis both, v, res2, axis_both); template inline auto reducer_manual_strided_reducer(benchmark::State& state, const E& x, E& res, const X& axes) @@ -92,9 +92,9 @@ namespace xt } } - BENCHMARK_CAPTURE(reducer_manual_strided_reducer, 10x100000/axis 0, u, res0, axis0); - BENCHMARK_CAPTURE(reducer_manual_strided_reducer, 10x100000/axis 1, u, res1, axis1); - BENCHMARK_CAPTURE(reducer_manual_strided_reducer, 100000x10/axis 1, v, res1, axis0); - BENCHMARK_CAPTURE(reducer_manual_strided_reducer, 100000x10/axis 0, v, res0, axis1); + BENCHMARK_CAPTURE(reducer_manual_strided_reducer, 10x100000 / axis 0, u, res0, axis0); + BENCHMARK_CAPTURE(reducer_manual_strided_reducer, 10x100000 / axis 1, u, res1, axis1); + BENCHMARK_CAPTURE(reducer_manual_strided_reducer, 100000x10 / axis 1, v, res1, axis0); + BENCHMARK_CAPTURE(reducer_manual_strided_reducer, 100000x10 / axis 0, v, res0, axis1); } } diff --git a/benchmark/benchmark_stl.cpp b/benchmark/benchmark_stl.cpp new file mode 100644 index 000000000..9ae160712 --- /dev/null +++ b/benchmark/benchmark_stl.cpp @@ -0,0 +1,157 @@ +/*************************************************************************** + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#include + +#include "xtensor/containers/xtensor.hpp" +#include "xtensor/core/xmath.hpp" +#include "xtensor/generators/xrandom.hpp" + +namespace xt +{ + namespace + { + constexpr std::array cContainerAssignShape{2000, 2000}; + + template + auto generateRandomInt16From0To100(Shape&& x) + { + return xt::random::randint(x, 0, 100); + } + } + + static void Xtensor_Uint16_2000x2000_DivideBy2_StdTransform(benchmark::State& aState) + { + xt::xtensor vInput = generateRandomInt16From0To100(cContainerAssignShape); + auto vOutput = xt::xtensor::from_shape(cContainerAssignShape); + + for (auto _ : aState) + { + std::transform( + vInput.begin(), + vInput.end(), + vOutput.begin(), + [](auto&& aInputValue) + { + return aInputValue / 2; + } + ); + } + } + + static void Xtensor_Uint16_2000x2000_DivideBy2_Xtensor(benchmark::State& aState) + { + xt::xtensor vInput = generateRandomInt16From0To100(cContainerAssignShape); + auto vOutput = xt::xtensor::from_shape(cContainerAssignShape); + + for (auto _ : aState) + { + vOutput = vInput / 2; + } + } + + static void Xtensor_Uint16_2000x2000_DivideBy2Double_StdTransform(benchmark::State& aState) + { + xt::xtensor vInput = generateRandomInt16From0To100(cContainerAssignShape); + auto vOutput = xt::xtensor::from_shape(cContainerAssignShape); + + for (auto _ : aState) + { + std::transform( + vInput.begin(), + vInput.end(), + vOutput.begin(), + [](auto&& aInputValue) + { + return aInputValue / 2.0; + } + ); + } + } + + static void Xtensor_Uint16_2000x2000_DivideBy2Double_Xtensor(benchmark::State& aState) + { + xt::xtensor vInput = generateRandomInt16From0To100(cContainerAssignShape); + auto vOutput = xt::xtensor::from_shape(cContainerAssignShape); + + for (auto _ : aState) + { + vOutput = vInput / 2.0; + } + } + + static void Xtensor_Uint16_2000x2000_MultiplyBy2_StdTransform(benchmark::State& aState) + { + xt::xtensor vInput = generateRandomInt16From0To100(cContainerAssignShape); + auto vOutput = xt::xtensor::from_shape(cContainerAssignShape); + + for (auto _ : aState) + { + std::transform( + vInput.begin(), + vInput.end(), + vOutput.begin(), + [](auto&& aInputValue) + { + return aInputValue * 2; + } + ); + } + } + + static void Xtensor_Uint16_2000x2000_MultiplyBy2_Xtensor(benchmark::State& aState) + { + xt::xtensor vInput = generateRandomInt16From0To100(cContainerAssignShape); + auto vOutput = xt::xtensor::from_shape(cContainerAssignShape); + + for (auto _ : aState) + { + vOutput = vInput * 2; + } + } + + static void Xtensor_Uint16_2000x2000_Maximum_StdTransform(benchmark::State& aState) + { + xt::xtensor vInput1 = generateRandomInt16From0To100(cContainerAssignShape); + xt::xtensor vInput2 = generateRandomInt16From0To100(cContainerAssignShape); + auto vOutput = xt::xtensor::from_shape(cContainerAssignShape); + + for (auto _ : aState) + { + auto vInput2It = vInput2.begin(); + std::transform( + vInput1.begin(), + vInput1.end(), + vOutput.begin(), + [&vInput2It](auto&& aInput1Value) + { + return std::max(aInput1Value, *vInput2It++); + } + ); + } + } + + static void Xtensor_Uint16_2000x2000_Maximum_Xtensor(benchmark::State& aState) + { + xt::xtensor vInput1 = generateRandomInt16From0To100(cContainerAssignShape); + xt::xtensor vInput2 = generateRandomInt16From0To100(cContainerAssignShape); + auto vOutput = xt::xtensor::from_shape(cContainerAssignShape); + + for (auto _ : aState) + { + vOutput = xt::maximum(vInput1, vInput2); + } + } + + BENCHMARK(Xtensor_Uint16_2000x2000_Maximum_Xtensor); + BENCHMARK(Xtensor_Uint16_2000x2000_Maximum_StdTransform); + BENCHMARK(Xtensor_Uint16_2000x2000_MultiplyBy2_Xtensor); + BENCHMARK(Xtensor_Uint16_2000x2000_MultiplyBy2_StdTransform); + BENCHMARK(Xtensor_Uint16_2000x2000_DivideBy2Double_Xtensor); + BENCHMARK(Xtensor_Uint16_2000x2000_DivideBy2Double_StdTransform); +} diff --git a/benchmark/benchmark_view_access.cpp b/benchmark/benchmark_view_access.cpp index 59b60296d..78569955e 100644 --- a/benchmark/benchmark_view_access.cpp +++ b/benchmark/benchmark_view_access.cpp @@ -8,14 +8,14 @@ #include -// #include "xtensor/xshape.hpp" -#include "xtensor/xadapt.hpp" -#include "xtensor/xnoalias.hpp" -#include "xtensor/xrandom.hpp" -#include "xtensor/xbuilder.hpp" -#include "xtensor/xstorage.hpp" -#include "xtensor/xutils.hpp" -#include "xtensor/xview.hpp" +// #include "xtensor/core/core/xshape.hpp" +#include "xtensor/containers/xadapt.hpp" +#include "xtensor/containers/xstorage.hpp" +#include "xtensor/core/xnoalias.hpp" +#include "xtensor/generators/xbuilder.hpp" +#include "xtensor/generators/xrandom.hpp" +#include "xtensor/utils/xutils.hpp" +#include "xtensor/views/xview.hpp" namespace xt { @@ -23,10 +23,12 @@ namespace xt class simple_array { public: + using self_type = simple_array; using shape_type = std::array; simple_array() = default; + explicit simple_array(const std::array& shape) : m_shape(shape) { @@ -66,11 +68,13 @@ namespace xt } return memory[offset]; } + xt::uvector memory; std::array m_shape, m_strides; }; - void xview_access_calc(benchmark::State &state) { + void xview_access_calc(benchmark::State& state) + { xt::xtensor A = xt::random::rand({100, 100, 4, 4}); xt::xtensor elemvec = xt::random::rand({100, 4, 4}); xt::xtensor eps = xt::empty({2, 2}); @@ -87,15 +91,14 @@ namespace xt // - evaluate symmetrized dyadic product (loops unrolled for efficiency) // grad(i,j) += dNx(m,i) * u(m,j) // eps (j,i) = 0.5 * ( grad(i,j) + grad(j,i) ) - eps(0, 0) = dNx(0, 0) * u(0, 0) + dNx(1, 0) * u(1, 0) + - dNx(2, 0) * u(2, 0) + dNx(3, 0) * u(3, 0); - eps(1, 1) = dNx(0, 1) * u(0, 1) + dNx(1, 1) * u(1, 1) + - dNx(2, 1) * u(2, 1) + dNx(3, 1) * u(3, 1); - eps(0, 1) = - (dNx(0, 1) * u(0, 0) + dNx(1, 1) * u(1, 0) + dNx(2, 1) * u(2, 0) + - dNx(3, 1) * u(3, 0) + dNx(0, 0) * u(0, 1) + dNx(1, 0) * u(1, 1) + - dNx(2, 0) * u(2, 1) + dNx(3, 0) * u(3, 1)) / - 2.; + eps(0, 0) = dNx(0, 0) * u(0, 0) + dNx(1, 0) * u(1, 0) + dNx(2, 0) * u(2, 0) + + dNx(3, 0) * u(3, 0); + eps(1, 1) = dNx(0, 1) * u(0, 1) + dNx(1, 1) * u(1, 1) + dNx(2, 1) * u(2, 1) + + dNx(3, 1) * u(3, 1); + eps(0, 1) = (dNx(0, 1) * u(0, 0) + dNx(1, 1) * u(1, 0) + dNx(2, 1) * u(2, 0) + + dNx(3, 1) * u(3, 0) + dNx(0, 0) * u(0, 1) + dNx(1, 0) * u(1, 1) + + dNx(2, 0) * u(2, 1) + dNx(3, 0) * u(3, 1)) + / 2.; eps(1, 0) = eps(0, 1); benchmark::DoNotOptimize(eps.storage()); } @@ -103,7 +106,8 @@ namespace xt } } - void raw_access_calc(benchmark::State &state) { + void raw_access_calc(benchmark::State& state) + { xt::xtensor A = xt::random::rand({100, 100, 4, 4}); xt::xtensor elemvec = xt::random::rand({100, 4, 4}); xt::xtensor eps = xt::empty({2, 2}); @@ -117,15 +121,15 @@ namespace xt // - evaluate symmetrized dyadic product (loops unrolled for efficiency) // grad(i,j) += dNx(m,i) * u(m,j) // eps (j,i) = 0.5 * ( grad(i,j) + grad(j,i) ) - eps(0, 0) = A(e, k, 0, 0) * elemvec(e, 0, 0) + A(e, k, 1, 0) * elemvec(e, 1, 0) + - A(e, k, 2, 0) * elemvec(e, 2, 0) + A(e, k, 3, 0) * elemvec(e, 3, 0); - eps(1, 1) = A(e, k, 0, 1) * elemvec(e, 0, 1) + A(e, k, 1, 1) * elemvec(e, 1, 1) + - A(e, k, 2, 1) * elemvec(e, 2, 1) + A(e, k, 3, 1) * elemvec(e, 3, 1); - eps(0, 1) = (A(e, k, 0, 1) * elemvec(e, 0, 0) + A(e, k, 1, 1) * elemvec(e, 1, 0) + - A(e, k, 2, 1) * elemvec(e, 2, 0) + A(e, k, 3, 1) * elemvec(e, 3, 0) + - A(e, k, 0, 0) * elemvec(e, 0, 1) + A(e, k, 1, 0) * elemvec(e, 1, 1) + - A(e, k, 2, 0) * elemvec(e, 2, 1) + A(e, k, 3, 0) * elemvec(e, 3, 1)) / - 2.; + eps(0, 0) = A(e, k, 0, 0) * elemvec(e, 0, 0) + A(e, k, 1, 0) * elemvec(e, 1, 0) + + A(e, k, 2, 0) * elemvec(e, 2, 0) + A(e, k, 3, 0) * elemvec(e, 3, 0); + eps(1, 1) = A(e, k, 0, 1) * elemvec(e, 0, 1) + A(e, k, 1, 1) * elemvec(e, 1, 1) + + A(e, k, 2, 1) * elemvec(e, 2, 1) + A(e, k, 3, 1) * elemvec(e, 3, 1); + eps(0, 1) = (A(e, k, 0, 1) * elemvec(e, 0, 0) + A(e, k, 1, 1) * elemvec(e, 1, 0) + + A(e, k, 2, 1) * elemvec(e, 2, 0) + A(e, k, 3, 1) * elemvec(e, 3, 0) + + A(e, k, 0, 0) * elemvec(e, 0, 1) + A(e, k, 1, 0) * elemvec(e, 1, 1) + + A(e, k, 2, 0) * elemvec(e, 2, 1) + A(e, k, 3, 0) * elemvec(e, 3, 1)) + / 2.; eps(1, 0) = eps(0, 1); benchmark::DoNotOptimize(eps.storage()); } @@ -133,7 +137,8 @@ namespace xt } } - void unchecked_access_calc(benchmark::State &state) { + void unchecked_access_calc(benchmark::State& state) + { xt::xtensor A = xt::random::rand({100, 100, 4, 4}); xt::xtensor elemvec = xt::random::rand({100, 4, 4}); xt::xtensor eps = xt::empty({2, 2}); @@ -147,26 +152,23 @@ namespace xt // - evaluate symmetrized dyadic product (loops unrolled for efficiency) // grad(i,j) += dNx(m,i) * u(m,j) // eps (j,i) = 0.5 * ( grad(i,j) + grad(j,i) ) - eps.unchecked(0, 0) = - A.unchecked(e, k, 0, 0) * elemvec.unchecked(e, 0, 0) + - A.unchecked(e, k, 1, 0) * elemvec.unchecked(e, 1, 0) + - A.unchecked(e, k, 2, 0) * elemvec.unchecked(e, 2, 0) + - A.unchecked(e, k, 3, 0) * elemvec.unchecked(e, 3, 0); - eps.unchecked(1, 1) = - A.unchecked(e, k, 0, 1) * elemvec.unchecked(e, 0, 1) + - A.unchecked(e, k, 1, 1) * elemvec.unchecked(e, 1, 1) + - A.unchecked(e, k, 2, 1) * elemvec.unchecked(e, 2, 1) + - A.unchecked(e, k, 3, 1) * elemvec.unchecked(e, 3, 1); - eps.unchecked(0, 1) = - (A.unchecked(e, k, 0, 1) * elemvec.unchecked(e, 0, 0) + - A.unchecked(e, k, 1, 1) * elemvec.unchecked(e, 1, 0) + - A.unchecked(e, k, 2, 1) * elemvec.unchecked(e, 2, 0) + - A.unchecked(e, k, 3, 1) * elemvec.unchecked(e, 3, 0) + - A.unchecked(e, k, 0, 0) * elemvec.unchecked(e, 0, 1) + - A.unchecked(e, k, 1, 0) * elemvec.unchecked(e, 1, 1) + - A.unchecked(e, k, 2, 0) * elemvec.unchecked(e, 2, 1) + - A.unchecked(e, k, 3, 0) * elemvec.unchecked(e, 3, 1)) / - 2.; + eps.unchecked(0, 0) = A.unchecked(e, k, 0, 0) * elemvec.unchecked(e, 0, 0) + + A.unchecked(e, k, 1, 0) * elemvec.unchecked(e, 1, 0) + + A.unchecked(e, k, 2, 0) * elemvec.unchecked(e, 2, 0) + + A.unchecked(e, k, 3, 0) * elemvec.unchecked(e, 3, 0); + eps.unchecked(1, 1) = A.unchecked(e, k, 0, 1) * elemvec.unchecked(e, 0, 1) + + A.unchecked(e, k, 1, 1) * elemvec.unchecked(e, 1, 1) + + A.unchecked(e, k, 2, 1) * elemvec.unchecked(e, 2, 1) + + A.unchecked(e, k, 3, 1) * elemvec.unchecked(e, 3, 1); + eps.unchecked(0, 1) = (A.unchecked(e, k, 0, 1) * elemvec.unchecked(e, 0, 0) + + A.unchecked(e, k, 1, 1) * elemvec.unchecked(e, 1, 0) + + A.unchecked(e, k, 2, 1) * elemvec.unchecked(e, 2, 0) + + A.unchecked(e, k, 3, 1) * elemvec.unchecked(e, 3, 0) + + A.unchecked(e, k, 0, 0) * elemvec.unchecked(e, 0, 1) + + A.unchecked(e, k, 1, 0) * elemvec.unchecked(e, 1, 1) + + A.unchecked(e, k, 2, 0) * elemvec.unchecked(e, 2, 1) + + A.unchecked(e, k, 3, 0) * elemvec.unchecked(e, 3, 1)) + / 2.; eps.unchecked(1, 0) = eps.unchecked(0, 1); benchmark::DoNotOptimize(eps.storage()); } @@ -174,7 +176,8 @@ namespace xt } } - void simplearray_access_calc(benchmark::State &state) { + void simplearray_access_calc(benchmark::State& state) + { simple_array A(std::array{100, 100, 4, 2}); simple_array elemvec(std::array{100, 4, 2}); simple_array eps(std::array{2, 2}); @@ -188,23 +191,15 @@ namespace xt // - evaluate sy mmetrized dyadic product (loops unrolled for efficiency) // grad(i,j) += dNx(m,i) * u(m,j) // eps (j,i) = 0.5 * ( grad(i,j) + grad(j,i) ) - eps(0, 0) = A(e, k, 0, 0) * elemvec(e, 0, 0) + - A(e, k, 1, 0) * elemvec(e, 1, 0) + - A(e, k, 2, 0) * elemvec(e, 2, 0) + - A(e, k, 3, 0) * elemvec(e, 3, 0); - eps(1, 1) = A(e, k, 0, 1) * elemvec(e, 0, 1) + - A(e, k, 1, 1) * elemvec(e, 1, 1) + - A(e, k, 2, 1) * elemvec(e, 2, 1) + - A(e, k, 3, 1) * elemvec(e, 3, 1); - eps(0, 1) = (A(e, k, 0, 1) * elemvec(e, 0, 0) + - A(e, k, 1, 1) * elemvec(e, 1, 0) + - A(e, k, 2, 1) * elemvec(e, 2, 0) + - A(e, k, 3, 1) * elemvec(e, 3, 0) + - A(e, k, 0, 0) * elemvec(e, 0, 1) + - A(e, k, 1, 0) * elemvec(e, 1, 1) + - A(e, k, 2, 0) * elemvec(e, 2, 1) + - A(e, k, 3, 0) * elemvec(e, 3, 1)) / - 2.; + eps(0, 0) = A(e, k, 0, 0) * elemvec(e, 0, 0) + A(e, k, 1, 0) * elemvec(e, 1, 0) + + A(e, k, 2, 0) * elemvec(e, 2, 0) + A(e, k, 3, 0) * elemvec(e, 3, 0); + eps(1, 1) = A(e, k, 0, 1) * elemvec(e, 0, 1) + A(e, k, 1, 1) * elemvec(e, 1, 1) + + A(e, k, 2, 1) * elemvec(e, 2, 1) + A(e, k, 3, 1) * elemvec(e, 3, 1); + eps(0, 1) = (A(e, k, 0, 1) * elemvec(e, 0, 0) + A(e, k, 1, 1) * elemvec(e, 1, 0) + + A(e, k, 2, 1) * elemvec(e, 2, 0) + A(e, k, 3, 1) * elemvec(e, 3, 0) + + A(e, k, 0, 0) * elemvec(e, 0, 1) + A(e, k, 1, 0) * elemvec(e, 1, 1) + + A(e, k, 2, 0) * elemvec(e, 2, 1) + A(e, k, 3, 0) * elemvec(e, 3, 1)) + / 2.; eps(1, 0) = eps(0, 1); benchmark::DoNotOptimize(eps.memory); } @@ -212,9 +207,9 @@ namespace xt } } - #define M_NELEM 3600 - #define M_NNE 4 - #define M_NDIM 2 +#define M_NELEM 3600 +#define M_NNE 4 +#define M_NDIM 2 template class jumping_random @@ -224,8 +219,8 @@ namespace xt using shape_type = typename X::shape_type; jumping_random() - : m_dofs(shape_type{3721, 2}), - m_conn(shape_type{3600, 4}) + : m_dofs(shape_type{3721, 2}) + , m_conn(shape_type{3600, 4}) { m_dofs = xt::clip(xt::reshape_view(xt::arange(2 * 3721), {3721, 2}), 0, 7199); @@ -241,28 +236,47 @@ namespace xt auto calc_dofval(xt::xtensor& elemvec, xt::xtensor& dofval) { dofval.fill(0.0); - for (size_t e = 0 ; e < M_NELEM ; ++e) - for (size_t m = 0 ; m < M_NNE ; ++m) - for (size_t i = 0 ; i < M_NDIM; ++i) + for (size_t e = 0; e < M_NELEM; ++e) + { + for (size_t m = 0; m < M_NNE; ++m) + { + for (size_t i = 0; i < M_NDIM; ++i) + { dofval(m_dofs(m_conn(e, m), i)) += elemvec(e, m, i); + } + } + } } auto calc_dofval_simple(simple_array& elemvec, simple_array& dofval) { dofval.fill(0.0); - for (size_t e = 0 ; e < M_NELEM ; ++e) - for (size_t m = 0 ; m < M_NNE ; ++m) - for (size_t i = 0 ; i < M_NDIM; ++i) + for (size_t e = 0; e < M_NELEM; ++e) + { + for (size_t m = 0; m < M_NNE; ++m) + { + for (size_t i = 0; i < M_NDIM; ++i) + { dofval(m_dofs(m_conn(e, m), i)) += elemvec(e, m, i); + } + } + } } auto calc_unchecked_dofval(xt::xtensor& elemvec, xt::xtensor& dofval) { dofval.fill(0.0); - for (size_t e = 0 ; e < M_NELEM ; ++e) - for (size_t m = 0 ; m < M_NNE ; ++m) - for (size_t i = 0 ; i < M_NDIM; ++i) - dofval.unchecked(m_dofs.unchecked(m_conn.unchecked(e, m), i)) += elemvec.unchecked(e, m, i); + for (size_t e = 0; e < M_NELEM; ++e) + { + for (size_t m = 0; m < M_NNE; ++m) + { + for (size_t i = 0; i < M_NDIM; ++i) + { + auto d = m_dofs.unchecked(m_conn.unchecked(e, m), i); + dofval.unchecked(d) += elemvec.unchecked(e, m, i); + } + } + } } X m_dofs, m_conn; @@ -317,4 +331,4 @@ namespace xt BENCHMARK_TEMPLATE(jumping_access_unchecked, layout_type::row_major); BENCHMARK_TEMPLATE(jumping_access_unchecked, layout_type::column_major); BENCHMARK(jumping_access_simplearray); -} \ No newline at end of file +} diff --git a/benchmark/benchmark_view_adapt.cpp b/benchmark/benchmark_view_adapt.cpp index 06f25a80a..2523cb725 100644 --- a/benchmark/benchmark_view_adapt.cpp +++ b/benchmark/benchmark_view_adapt.cpp @@ -1,44 +1,44 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #ifndef BENCHMARK_VIEW_ADAPT_HPP #define BENCHMARK_VIEW_ADAPT_HPP #include -#include "xtensor/xnoalias.hpp" -#include "xtensor/xtensor.hpp" -#include "xtensor/xview.hpp" -#include "xtensor/xfixed.hpp" -#include "xtensor/xrandom.hpp" -#include "xtensor/xadapt.hpp" +#include "xtensor/containers/xadapt.hpp" +#include "xtensor/containers/xfixed.hpp" +#include "xtensor/containers/xtensor.hpp" +#include "xtensor/core/xnoalias.hpp" +#include "xtensor/generators/xrandom.hpp" +#include "xtensor/views/xview.hpp" namespace xt { namespace benchmark_view_adapt { - using T2 = xt::xtensor_fixed>; + using T2 = xt::xtensor_fixed>; - T2 foo(const T2 &A) + T2 foo(const T2& A) { return 2. * A; } void random_view(benchmark::State& state) { - xt::xtensor A = xt::random::randn({2000,8,2,2}); - xt::xtensor B = xt::empty(A.shape()); + xt::xtensor A = xt::random::randn({2000, 8, 2, 2}); + xt::xtensor B = xt::empty(A.shape()); for (auto _ : state) { - for ( size_t i = 0 ; i < A.shape()[0] ; ++i ) + for (size_t i = 0; i < A.shape()[0]; ++i) { - for ( size_t j = 0 ; j < A.shape()[1] ; ++j ) + for (size_t j = 0; j < A.shape()[1]; ++j) { auto a = xt::view(A, i, j); auto b = xt::view(B, i, j); @@ -52,17 +52,17 @@ namespace xt void random_adapt(benchmark::State& state) { - xt::xtensor A = xt::random::randn({2000,8,2,2}); - xt::xtensor B = xt::empty(A.shape()); + xt::xtensor A = xt::random::randn({2000, 8, 2, 2}); + xt::xtensor B = xt::empty(A.shape()); for (auto _ : state) { - for ( size_t i = 0 ; i < A.shape()[0] ; ++i ) + for (size_t i = 0; i < A.shape()[0]; ++i) { - for ( size_t j = 0 ; j < A.shape()[1] ; ++j ) + for (size_t j = 0; j < A.shape()[1]; ++j) { - auto a = xt::adapt(&A(i,j,0,0), xt::xshape<2,2>()); - auto b = xt::adapt(&B(i,j,0,0), xt::xshape<2,2>()); + auto a = xt::adapt(&A(i, j, 0, 0), xt::xshape<2, 2>()); + auto b = xt::adapt(&B(i, j, 0, 0), xt::xshape<2, 2>()); xt::noalias(b) = foo(a); } diff --git a/benchmark/benchmark_view_assignment.cpp b/benchmark/benchmark_view_assignment.cpp index 20a502109..3d5ae314b 100644 --- a/benchmark/benchmark_view_assignment.cpp +++ b/benchmark/benchmark_view_assignment.cpp @@ -1,18 +1,18 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #include -#include "xtensor/xnoalias.hpp" -#include "xtensor/xtensor.hpp" -#include "xtensor/xarray.hpp" -#include "xtensor/xfixed.hpp" -#include "xtensor/xrandom.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/containers/xfixed.hpp" +#include "xtensor/containers/xtensor.hpp" +#include "xtensor/core/xnoalias.hpp" +#include "xtensor/generators/xrandom.hpp" namespace xt { @@ -61,23 +61,24 @@ namespace xt } } - inline void assign_create_strided_view(benchmark::State& state) - { - xt::xtensor tens = xt::random::rand({100, 100, 3, 3}); - for (auto _ : state) - { - for (std::size_t i = 0; i < tens.shape()[0]; ++i) - { - for (std::size_t j = 0; j < tens.shape()[1]; ++j) - { - auto v = xt::strided_view(tens, {i, j, all(), all()}); - xt::xtensor vas = v; - benchmark::ClobberMemory(); - } - } - } - } - + /** + * inline void assign_create_strided_view(benchmark::State& state) + * { + * xt::xtensor tens = xt::random::rand({100, 100, 3, 3}); + * for (auto _ : state) + * { + * for (std::size_t i = 0; i < tens.shape()[0]; ++i) + * { + * for (std::size_t j = 0; j < tens.shape()[1]; ++j) + * { + * auto v = xt::strided_view(tens, {i, j, all(), all()}); + * xt::xtensor vas = v; + * benchmark::ClobberMemory(); + * } + * } + * } + * } + */ inline void assign_create_manual_view(benchmark::State& state) { xt::xtensor tens = xt::random::rand({100, 100, 3, 3}); @@ -151,9 +152,9 @@ namespace xt BENCHMARK(create_strided_view_outofplace); BENCHMARK(create_strided_view_inplace); BENCHMARK(assign_create_manual_noview); - BENCHMARK(assign_create_strided_view); + // BENCHMARK(assign_create_strided_view); BENCHMARK(assign_create_view); BENCHMARK(assign_create_manual_view); - BENCHMARK(data_offset); + // BENCHMARK(data_offset); BENCHMARK(data_offset_view); -} \ No newline at end of file +} diff --git a/benchmark/benchmark_views.cpp b/benchmark/benchmark_views.cpp index 5e8a45cad..f2c34d510 100644 --- a/benchmark/benchmark_views.cpp +++ b/benchmark/benchmark_views.cpp @@ -1,29 +1,29 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ -#include #include +#include #include #include -#include "xtensor/xarray.hpp" -#include "xtensor/xnoalias.hpp" -#include "xtensor/xstrided_view.hpp" -#include "xtensor/xmanipulation.hpp" -#include "xtensor/xstrides.hpp" -#include "xtensor/xtensor.hpp" -#include "xtensor/xview.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/containers/xtensor.hpp" +#include "xtensor/core/xnoalias.hpp" +#include "xtensor/core/xstrides.hpp" +#include "xtensor/misc/xmanipulation.hpp" +#include "xtensor/views/xstrided_view.hpp" +#include "xtensor/views/xview.hpp" namespace xt { // Thanks to Ullrich Koethe for these benchmarks - // https://github.com/QuantStack/xtensor/issues/695 + // https://github.com/xtensor-stack/xtensor/issues/695 namespace view_benchmarks { constexpr int SIZE = 1000; @@ -31,10 +31,10 @@ namespace xt template void view_dynamic_iterator(benchmark::State& state) { - xt::xtensor data = xt::ones({SIZE,SIZE}); + xt::xtensor data = xt::ones({SIZE, SIZE}); xt::xtensor res = xt::ones({SIZE}); - auto v = xt::strided_view(data, xt::xstrided_slice_vector{xt::all(), SIZE/2}); + auto v = xt::strided_view(data, xt::xstrided_slice_vector{xt::all(), SIZE / 2}); for (auto _ : state) { std::copy(v.begin(), v.end(), res.begin()); @@ -45,10 +45,10 @@ namespace xt template void view_iterator(benchmark::State& state) { - xt::xtensor data = xt::ones({SIZE,SIZE}); + xt::xtensor data = xt::ones({SIZE, SIZE}); xt::xtensor res = xt::ones({SIZE}); - auto v = xt::view(data, xt::all(), SIZE/2); + auto v = xt::view(data, xt::all(), SIZE / 2); for (auto _ : state) { std::copy(v.begin(), v.end(), res.begin()); @@ -59,13 +59,13 @@ namespace xt template void view_loop(benchmark::State& state) { - xt::xtensor data = xt::ones({SIZE,SIZE}); + xt::xtensor data = xt::ones({SIZE, SIZE}); xt::xtensor res = xt::ones({SIZE}); - auto v = xt::strided_view(data, xt::xstrided_slice_vector{xt::all(), SIZE/2}); + auto v = xt::strided_view(data, xt::xstrided_slice_vector{xt::all(), SIZE / 2}); for (auto _ : state) { - for(std::size_t k = 0; k < v.shape()[0]; ++k) + for (std::size_t k = 0; k < v.shape()[0]; ++k) { res(k) = v(k); } @@ -76,13 +76,13 @@ namespace xt template void view_loop_view(benchmark::State& state) { - xt::xtensor data = xt::ones({SIZE,SIZE}); + xt::xtensor data = xt::ones({SIZE, SIZE}); xt::xtensor res = xt::ones({SIZE}); auto v = xt::view(data, xt::all(), SIZE / 2); for (auto _ : state) { - for(std::size_t k = 0; k < v.shape()[0]; ++k) + for (std::size_t k = 0; k < v.shape()[0]; ++k) { res(k) = v(k); } @@ -93,13 +93,13 @@ namespace xt template void view_loop_raw(benchmark::State& state) { - xt::xtensor data = xt::ones({SIZE,SIZE}); + xt::xtensor data = xt::ones({SIZE, SIZE}); xt::xtensor res = xt::ones({SIZE}); for (auto _ : state) { std::size_t j = SIZE / 2; - for(std::size_t k = 0; k < SIZE; ++k) + for (std::size_t k = 0; k < SIZE; ++k) { res(k) = data(k, j); } @@ -110,10 +110,10 @@ namespace xt template void view_assign(benchmark::State& state) { - xt::xtensor data = xt::ones({SIZE,SIZE}); + xt::xtensor data = xt::ones({SIZE, SIZE}); xt::xtensor res = xt::ones({SIZE}); - auto v = xt::strided_view(data, xt::xstrided_slice_vector{xt::all(), SIZE/2}); + auto v = xt::strided_view(data, xt::xstrided_slice_vector{xt::all(), SIZE / 2}); for (auto _ : state) { xt::noalias(res) = v; @@ -124,10 +124,10 @@ namespace xt template void view_assign_view(benchmark::State& state) { - xt::xtensor data = xt::ones({SIZE,SIZE}); + xt::xtensor data = xt::ones({SIZE, SIZE}); xt::xtensor res = xt::ones({SIZE}); - auto v = xt::view(data, xt::all(), SIZE/2); + auto v = xt::view(data, xt::all(), SIZE / 2); auto r = xt::view(res, xt::all()); for (auto _ : state) { @@ -139,10 +139,10 @@ namespace xt template void view_assign_strided_view(benchmark::State& state) { - xt::xtensor data = xt::ones({SIZE,SIZE}); + xt::xtensor data = xt::ones({SIZE, SIZE}); xt::xtensor res = xt::ones({SIZE}); - auto v = xt::strided_view(data, xt::xstrided_slice_vector{xt::all(), SIZE/2}); + auto v = xt::strided_view(data, xt::xstrided_slice_vector{xt::all(), SIZE / 2}); auto r = xt::strided_view(res, xt::xstrided_slice_vector{xt::all()}); for (auto _ : state) @@ -155,10 +155,10 @@ namespace xt template void view_assign_view_noalias(benchmark::State& state) { - xt::xtensor data = xt::ones({SIZE,SIZE}); + xt::xtensor data = xt::ones({SIZE, SIZE}); xt::xtensor res = xt::ones({SIZE}); - auto v = xt::view(data, xt::all(), SIZE/2); + auto v = xt::view(data, xt::all(), SIZE / 2); auto r = xt::view(res, xt::all()); for (auto _ : state) { @@ -170,10 +170,10 @@ namespace xt template void view_assign_strided_view_noalias(benchmark::State& state) { - xt::xtensor data = xt::ones({SIZE,SIZE}); + xt::xtensor data = xt::ones({SIZE, SIZE}); xt::xtensor res = xt::ones({SIZE}); - auto v = xt::strided_view(data, xt::xstrided_slice_vector{xt::all(), SIZE/2}); + auto v = xt::strided_view(data, xt::xstrided_slice_vector{xt::all(), SIZE / 2}); auto r = xt::strided_view(res, xt::xstrided_slice_vector{xt::all()}); for (auto _ : state) @@ -195,6 +195,75 @@ namespace xt BENCHMARK_TEMPLATE(view_assign_strided_view_noalias, float); } + namespace finite_diff + { + inline auto stencil_threedirections(benchmark::State& state, size_t size) + { + for (auto _ : state) + { + const std::array shape = {size, size, size}; + xt::xtensor a(shape), b(shape); + auto core = xt::range(1, size - 1); + xt::noalias(xt::view(b, core, core, core) + ) = 1.0 / 7.0 + * (xt::view(a, core, core, core) + xt::view(a, core, core, xt::range(2, size)) + + xt::view(a, core, core, xt::range(0, size - 2)) + + xt::view(a, core, xt::range(2, size), core) + + xt::view(a, core, xt::range(0, size - 2), core) + + xt::view(a, xt::range(2, size), core, core) + + xt::view(a, xt::range(0, size - 2), core, core)); + benchmark::DoNotOptimize(b); + } + } + + inline auto stencil_twodirections(benchmark::State& state, size_t size) + { + for (auto _ : state) + { + const std::array shape = {size, size, size}; + xt::xtensor a(shape), b(shape); + auto core = xt::range(1, size - 1); + xt::noalias(xt::view(b, core, core, core) + ) = 1.0 / 7.0 + * (xt::view(a, core, core, core) + xt::view(a, core, xt::range(2, size), core) + + xt::view(a, core, xt::range(0, size - 2), core) + + xt::view(a, xt::range(2, size), core, core) + + xt::view(a, xt::range(0, size - 2), core, core)); + benchmark::DoNotOptimize(b); + } + } + + inline auto stencil_onedirection(benchmark::State& state, size_t size) + { + for (auto _ : state) + { + const std::array shape = {size, size, size}; + xt::xtensor a(shape), b(shape); + auto core = xt::range(1, size - 1); + xt::noalias(xt::view(b, core, core, core) + ) = 1.0 / 2.0 + * (xt::view(a, xt::range(2, size), core, core) + - xt::view(a, xt::range(0, size - 2), core, core)); + benchmark::DoNotOptimize(b); + } + } + + BENCHMARK_CAPTURE(stencil_threedirections, stencil_threedirections_50, 50); + BENCHMARK_CAPTURE(stencil_threedirections, stencil_threedirections_100, 100); + BENCHMARK_CAPTURE(stencil_threedirections, stencil_threedirections_200, 200); + BENCHMARK_CAPTURE(stencil_threedirections, stencil_threedirections_300, 300); + BENCHMARK_CAPTURE(stencil_threedirections, stencil_threedirections_500, 500); + BENCHMARK_CAPTURE(stencil_twodirections, stencil_twodirections_50, 50); + BENCHMARK_CAPTURE(stencil_twodirections, stencil_twodirections_100, 100); + BENCHMARK_CAPTURE(stencil_twodirections, stencil_twodirections_200, 200); + BENCHMARK_CAPTURE(stencil_twodirections, stencil_twodirections_300, 300); + BENCHMARK_CAPTURE(stencil_twodirections, stencil_twodirections_500, 500); + BENCHMARK_CAPTURE(stencil_onedirection, stencil_onedirections_50, 50); + BENCHMARK_CAPTURE(stencil_onedirection, stencil_onedirections_100, 100); + BENCHMARK_CAPTURE(stencil_onedirection, stencil_onedirections_200, 200); + BENCHMARK_CAPTURE(stencil_onedirection, stencil_onedirections_300, 300); + BENCHMARK_CAPTURE(stencil_onedirection, stencil_onedirections_500, 500); + } namespace stridedview { diff --git a/benchmark/benchmark_xshape.cpp b/benchmark/benchmark_xshape.cpp index 237140ba9..6656b912f 100644 --- a/benchmark/benchmark_xshape.cpp +++ b/benchmark/benchmark_xshape.cpp @@ -1,10 +1,10 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #ifndef BENCHMARK_SHAPE_HPP @@ -12,9 +12,8 @@ #include -#include "xtensor/xshape.hpp" -#include "xtensor/xstorage.hpp" - +#include "xtensor/containers/xstorage.hpp" +#include "xtensor/core/xshape.hpp" namespace xt { @@ -43,7 +42,7 @@ namespace xt template void xshape_access(benchmark::State& state) { - T a({3,2,1,3}); + T a({3, 2, 1, 3}); for (auto _ : state) { a[0] = a[1] * a[2] + a[3]; @@ -67,4 +66,4 @@ namespace xt } } -#endif \ No newline at end of file +#endif diff --git a/benchmark/copyGBenchmark.cmake.in b/benchmark/copyGBenchmark.cmake.in index d753bd155..e11eaed96 100644 --- a/benchmark/copyGBenchmark.cmake.in +++ b/benchmark/copyGBenchmark.cmake.in @@ -6,7 +6,7 @@ # The full license is in the file LICENSE, distributed with this software. # ############################################################################ -cmake_minimum_required(VERSION 2.8.2) +cmake_minimum_required(VERSION 3.5) project(googlebenchmark-download NONE) @@ -19,4 +19,4 @@ ExternalProject_Add(benchmark BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" -) \ No newline at end of file +) diff --git a/benchmark/downloadGBenchmark.cmake.in b/benchmark/downloadGBenchmark.cmake.in index f6b7b6999..7af348b1e 100644 --- a/benchmark/downloadGBenchmark.cmake.in +++ b/benchmark/downloadGBenchmark.cmake.in @@ -6,18 +6,19 @@ # The full license is in the file LICENSE, distributed with this software. # ############################################################################ -cmake_minimum_required(VERSION 2.8.2) +cmake_minimum_required(VERSION 3.5) project(googlebenchmark-download NONE) include(ExternalProject) ExternalProject_Add(googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git - GIT_TAG v1.3.0 + GIT_TAG v1.9.4 SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-build" CONFIGURE_COMMAND "" BUILD_COMMAND "" + CMAKE_ARGS "BENCHMARK_DOWNLOAD_DEPENDENCIES=TRUE" INSTALL_COMMAND "" TEST_COMMAND "" -) \ No newline at end of file +) diff --git a/benchmark/main.cpp b/benchmark/main.cpp index 1b184e127..39491c225 100644 --- a/benchmark/main.cpp +++ b/benchmark/main.cpp @@ -1,17 +1,17 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #include #include -#include "xtensor/xtensor.hpp" -#include "xtensor/xarray.hpp" +#include "xtensor/containers/xarray.hpp" +#include "xtensor/containers/xtensor.hpp" #ifdef XTENSOR_USE_XSIMD #ifdef __GNUC__ @@ -42,6 +42,9 @@ int main(int argc, char** argv) { print_stats(); benchmark::Initialize(&argc, argv); - if (benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; + if (benchmark::ReportUnrecognizedArguments(argc, argv)) + { + return 1; + } benchmark::RunSpecifiedBenchmarks(); } diff --git a/cmake/FindTBB.cmake b/cmake/FindTBB.cmake index f4b6b333b..0fafa84f7 100644 --- a/cmake/FindTBB.cmake +++ b/cmake/FindTBB.cmake @@ -184,7 +184,12 @@ if(NOT TBB_FOUND) ################################## if(TBB_INCLUDE_DIRS) - file(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _tbb_version_file) + if(EXISTS "${TBB_INCLUDE_DIRS}/tbb/version.h") + # since version 2021.1 + file(READ "${TBB_INCLUDE_DIRS}/oneapi/tbb/version.h" _tbb_version_file) + else() + file(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _tbb_version_file) + endif() string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" TBB_VERSION_MAJOR "${_tbb_version_file}") string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" @@ -300,4 +305,4 @@ if(NOT TBB_FOUND) unset(TBB_LIB_PATH_SUFFIX) unset(TBB_DEFAULT_SEARCH_DIR) -endif() \ No newline at end of file +endif() diff --git a/cmake/sanitizers.cmake b/cmake/sanitizers.cmake new file mode 100644 index 000000000..11c7a1075 --- /dev/null +++ b/cmake/sanitizers.cmake @@ -0,0 +1,50 @@ +set(AVALAIBLE_SANITIZERS "address;leak;memory;thread;undefined") +OPTION(USE_SANITIZER "Enable sanitizer(s). Options are: ${AVALAIBLE_SANITIZERS}. Case insensitive; multiple options delimited by comma or space possible." "") +string(TOLOWER "${USE_SANITIZER}" USE_SANITIZER) + +if((CMAKE_BUILD_TYPE IN_LIST "Debug;RelWithDebInfo") AND USE_SANITIZER) + message(FATAL_ERROR "❌ Sanitizer only supported in Debug and RelWithDebInfo build types.") +endif() + +if(USE_SANITIZER) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$,$>,$<$:EditAndContinue>,$<$:ProgramDatabase>>") + + if(USE_SANITIZER MATCHES "address") + list(APPEND SANITIZER_COMPILE_OPTIONS /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION) + else() + message(FATAL_ERROR "❌ Sanitizer not supported by MSVC: ${USE_SANITIZER}. It only supports 'address'.") + endif() + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") + if(USE_SANITIZER MATCHES "address") + list(APPEND SANITIZER_COMPILE_OPTIONS /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION) + list(APPEND SANITIZER_LINK_LIBRARIES clang_rt.asan_dynamic-x86_64 clang_rt.asan_dynamic_runtime_thunk-x86_64) + else() + message(FATAL_ERROR "❌ Sanitizer not supported by Clang-MSVC: ${USE_SANITIZER}. It only supports 'address'.") + endif() + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + foreach(sanitizer ${USE_SANITIZER}) + if(NOT ${sanitizer} IN_LIST AVALAIBLE_SANITIZERS) + message(FATAL_ERROR "❌ Sanitizer not supported: ${sanitizer}. It should be one of: ${AVALAIBLE_SANITIZERS}.") + endif() + list(APPEND SANITIZER_COMPILE_OPTIONS -fsanitize=${sanitizer}) + list(APPEND SANITIZER_LINK_OPTIONS -fsanitize=${sanitizer}) + if (${sanitizer} MATCHES "undefined") + list(APPEND SANITIZER_COMPILE_OPTIONS -fno-sanitize=signed-integer-overflow) + endif() + if (${sanitizer} MATCHES "memory") + list(APPEND SANITIZER_LINK_LIBRARIES -fsanitize-memory-track-origins -fPIE -pie) + list(APPEND SANITIZER_LINK_OPTIONS -fsanitize-memory-track-origins -fPIE -pie) + endif() + endforeach() + list(APPEND SANITIZER_COMPILE_OPTIONS -fno-omit-frame-pointer) + else() + message(FATAL_ERROR "❌ Sanitizer: Unsupported compiler: ${CMAKE_CXX_COMPILER_ID}") + endif() + + list(REMOVE_DUPLICATES SANITIZER_COMPILE_OPTIONS) + list(REMOVE_DUPLICATES SANITIZER_LINK_OPTIONS) + list(REMOVE_DUPLICATES SANITIZER_LINK_LIBRARIES) + + message(STATUS "🔍 Using sanitizer: ${USE_SANITIZER}") +endif() diff --git a/docs/Doxyfile b/docs/Doxyfile index 409ba8752..d0b8d6e08 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1,14 +1,23 @@ -PROJECT_NAME = "xtensor" -XML_OUTPUT = xml -INPUT = ../include -GENERATE_LATEX = NO -GENERATE_MAN = NO -GENERATE_RTF = NO -CASE_SENSE_NAMES = NO -GENERATE_HTML = NO -GENERATE_XML = YES -RECURSIVE = YES -QUIET = YES +PROJECT_NAME = "xtensor" +XML_OUTPUT = xml +INPUT = ../include +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +GENERATE_HTML = YES +GENERATE_XML = YES +RECURSIVE = YES +QUIET = YES JAVADOC_AUTOBRIEF = YES WARN_IF_UNDOCUMENTED = NO MACRO_EXPANSION = YES +PREDEFINED = IN_DOXYGEN +EXCLUDE_SYMBOLS = detail +GENERATE_TREEVIEW = YES +SOURCE_BROWSER = YES +# WARN_IF_UNDOCUMENTED = YES + +# Allow for rst directives and advanced functions e.g. grid tables +ALIASES = "rst=\verbatim embed:rst:leading-asterisk" +ALIASES += "endrst=\endverbatim" diff --git a/docs/ghp_environment.yml b/docs/ghp_environment.yml new file mode 100644 index 000000000..9584ae39d --- /dev/null +++ b/docs/ghp_environment.yml @@ -0,0 +1,4 @@ +channels: +- conda-forge +dependencies: +- doxygen diff --git a/docs/make.bat b/docs/make.bat index 0df92b465..07de3322c 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -3,48 +3,48 @@ REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build + set SPHINXBUILD=sphinx-build ) set BUILDDIR=build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source set I18NSPHINXOPTS=%SPHINXOPTS% source if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - echo. coverage to run coverage check of the documentation if enabled - goto end + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + goto end ) if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end ) @@ -58,15 +58,15 @@ goto sphinx_ok set SPHINXBUILD=python -m sphinx.__init__ %SPHINXBUILD% 2> nul if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 ) :sphinx_ok @@ -74,191 +74,191 @@ if errorlevel 9009 ( if "%1" == "html" ( doxygen - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end ) if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end ) if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end ) if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end ) if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end ) if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. - goto end + goto end ) if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\packagename.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\packagename.ghc - goto end + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\packagename.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\packagename.ghc + goto end ) if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end ) if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end ) if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end ) if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end ) if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end ) if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end ) if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end ) if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end ) if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end ) if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end ) if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. - goto end + goto end ) if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. - goto end + goto end ) if "%1" == "coverage" ( - %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage - if errorlevel 1 exit /b 1 - echo. - echo.Testing of coverage in the sources finished, look at the ^ + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ results in %BUILDDIR%/coverage/python.txt. - goto end + goto end ) if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end ) if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end ) :end diff --git a/docs/environment.yml b/docs/rtd_environment.yml similarity index 51% rename from docs/environment.yml rename to docs/rtd_environment.yml index 3b9b55633..54fb700ca 100644 --- a/docs/environment.yml +++ b/docs/rtd_environment.yml @@ -1,7 +1,8 @@ name: xtensor-docs channels: - - conda-forge +- conda-forge dependencies: - - breathe +- breathe +- sphinx_rtd_theme diff --git a/docs/source/_static/goatcounter.js b/docs/source/_static/goatcounter.js new file mode 100644 index 000000000..a26dd2a26 --- /dev/null +++ b/docs/source/_static/goatcounter.js @@ -0,0 +1,9 @@ +(function() { + window.counter = 'https://xtensor_readthedocs_io.goatcounter.com/count' + + var script = document.createElement('script'); + script.async = 1; + script.src = '//gc.zgo.at/count.js'; + var ins = document.getElementsByTagName('script')[0]; + ins.parentNode.insertBefore(script, ins) +})(); diff --git a/docs/source/adaptor.rst b/docs/source/adaptor.rst index b5e5d4ba1..64fd7caf3 100644 --- a/docs/source/adaptor.rst +++ b/docs/source/adaptor.rst @@ -7,21 +7,21 @@ Adapting 1-D containers ======================= -`xtensor` can adapt one-dimensional containers in place, and provide them a tensor interface. +*xtensor* can adapt one-dimensional containers in place, and provide them a tensor interface. Only random access containers can be adapted. Adapting std::vector -------------------- The following example shows how to bring an ``std::vector`` into the expression system of -`xtensor`: +*xtensor*: .. code:: #include #include - #include "xtensor/xarray.hpp" - #include "xtensor/xadapt.hpp" + #include + #include std::vector v = {1., 2., 3., 4., 5., 6. }; std::vector shape = { 2, 3 }; @@ -44,13 +44,13 @@ the corresponding value in ``v``: Adapting C-style arrays ----------------------- -`xtensor` provides two ways for adapting C-style array; the first one does not take the +*xtensor* provides two ways for adapting a C-style array; the first one does not take the ownership of the array: .. code:: #include - #include "xtensor/xadapt.hpp" + #include void compute(double* data, std::size_t size) { @@ -76,14 +76,14 @@ ownership of the array: // prints 0 2 (data is still available here) } -However if you replace ``xt::no_ownership`` with ``xt::acquire_ownership``, the adaptor will take +However if you replace :cpp:enumerator:`xt::no_ownership` with :cpp:enumerator:`xt::acquire_ownership`, the adaptor will take the ownership of the array, meaning it will be deleted when the adaptor is destroyed: .. code:: #include - #include "xtensor/xarray.hpp" - #include "xtensor/xadapt.hpp" + #include + #include void compute(double*& data, std::size_t size) { @@ -119,9 +119,9 @@ adaptor before calling ``compute`` and pass it to the function: .. code:: #include - #include "xtensor/xarray.hpp" - #include "xtensor/xadapt.hpp" - + #include + #include + template void compute(A& a) { @@ -129,7 +129,7 @@ adaptor before calling ``compute`` and pass it to the function: b.reshape({2, 1}); a = a * b; // size has changed, shape is now { 2, 2 } } - + int main() { std::size_t size = 2; @@ -144,3 +144,89 @@ adaptor before calling ``compute`` and pass it to the function: std::cout << std::endl; // prints 0 1 0 2 } + +Adapting stack-allocated arrays +------------------------------- + +Adapting C arrays allocated on the stack is as simple as adapting ``std::vector``: + +.. code:: + + #include + #include + #include + #include + + double v[6] = {1., 2., 3., 4., 5., 6. }; + std::vector shape = { 2, 3 }; + auto a1 = xt::adapt(v, shape); + + xt::xarray a2 = {{ 1., 2., 3.}, + { 4., 5., 6.}}; + + xt::xarray res = a1 + a2; + // res = {{ 2., 4., 6. }, { 8., 10., 12. }}; + +``v`` is not copied into ``a1``, so if you change a value in ``a1``, you're actually changing +the corresponding value in ``v``: + +.. code:: + + a1(0, 0) = 20.; + // now v is { 20., 2., 3., 4., 5., 6. } + +Adapting C++ smart pointers +--------------------------- + +If you want to manage your data with shared or unique pointers, you can use the +:cpp:func:`xt::adapt_smart_ptr` function of xtensor. +It will automatically increment the reference count of shared pointers upon creation, and decrement upon deletion. + +.. code:: + + #include + #include + #include + + std::shared_ptr sptr(new double[8], std::default_delete()); + sptr.get()[2] = 321.; + auto xptr = xt::adapt_smart_ptr(sptr, {4, 2}); + xptr(1, 3) = 123.; + std::cout << xptr; + +Or if you operate on shared pointers that do not directly point to the underlying +buffer, you can pass the data pointer and the smart pointer (to manage the underlying +memory) as follows: + +.. code:: + + #include + #include + #include + + struct Buffer { + Buffer(std::vector& buf) : m_buf(buf) {} + ~Buffer() { std::cout << "deleted" << std::endl; } + std::vector m_buf; + }; + + auto data = std::vector{1,2,3,4,5,6,7,8}; + auto shared_buf = std::make_shared(data); + auto unique_buf = std::make_unique(data); + + std::cout << shared_buf.use_count() << std::endl; + { + auto obj = xt::adapt_smart_ptr(shared_buf.get()->m_buf.data(), + {2, 4}, shared_buf); + // Use count increased to 2 + std::cout << shared_buf.use_count() << std::endl; + std::cout << obj << std::endl; + } + // Use count reset to 1 + std::cout << shared_buf.use_count() << std::endl; + + { + auto obj = xt::adapt_smart_ptr(unique_buf.get()->m_buf.data(), + {2, 4}, std::move(unique_buf)); + std::cout << obj << std::endl; + } diff --git a/docs/source/api/accumulating_functions.rst b/docs/source/api/accumulating_functions.rst index 64ed2bdbf..1842912e1 100644 --- a/docs/source/api/accumulating_functions.rst +++ b/docs/source/api/accumulating_functions.rst @@ -9,18 +9,7 @@ Accumulating functions **xtensor** provides the following accumulating functions for xexpressions: -Defined in ``xtensor/xmath.hpp`` +Defined in ``xtensor/core/xmath.hpp`` -.. _cumsum-function-reference: -.. doxygenfunction:: cumsum(E&&) - :project: xtensor - -.. doxygenfunction:: cumsum(E&&, std::ptrdiff_t) - :project: xtensor - -.. _cumprod-function-reference: -.. doxygenfunction:: cumprod(E&&) - :project: xtensor - -.. doxygenfunction:: cumprod(E&&, std::ptrdiff_t) - :project: xtensor \ No newline at end of file +.. doxygengroup:: acc_functions + :members: diff --git a/docs/source/api/basic_functions.rst b/docs/source/api/basic_functions.rst index 6fc54a6c1..c6e8020b8 100644 --- a/docs/source/api/basic_functions.rst +++ b/docs/source/api/basic_functions.rst @@ -9,53 +9,7 @@ Basic functions **xtensor** provides the following basic functions for xexpressions and scalars: -Defined in ``xtensor/xmath.hpp`` - -.. _abs-function-reference: -.. doxygenfunction:: abs(E&&) - :project: xtensor - -.. _fabs-function-reference: -.. doxygenfunction:: fabs(E&&) - :project: xtensor - -.. _fmod-function-reference: -.. doxygenfunction:: fmod(E1&&, E2&&) - :project: xtensor - -.. _remainder-func-ref: -.. doxygenfunction:: remainder(E1&&, E2&&) - :project: xtensor - -.. _fma-function-reference: -.. doxygenfunction:: fma(E1&&, E2&&, E3&&) - :project: xtensor - -.. _maximum-func-ref: -.. doxygenfunction:: maximum(E1&&, E2&&) - :project: xtensor - -.. _minimum-func-ref: -.. doxygenfunction:: minimum(E1&&, E2&&) - :project: xtensor - -.. _fmax-function-reference: -.. doxygenfunction:: fmax(E1&&, E2&&) - :project: xtensor - -.. _fmin-function-reference: -.. doxygenfunction:: fmin(E1&&, E2&&) - :project: xtensor - -.. _fdim-function-reference: -.. doxygenfunction:: fdim(E1&&, E2&&) - :project: xtensor - -.. _clip-function-reference: -.. doxygenfunction:: clip(E1&&, E2&&, E3&&) - :project: xtensor - -.. _sign-function-reference: -.. doxygenfunction:: sign(E&&) - :project: xtensor +Defined in ``xtensor/core/xmath.hpp`` +.. doxygengroup:: basic_functions + :members: diff --git a/docs/source/api/classif_functions.rst b/docs/source/api/classif_functions.rst index 6cbf6a7cb..f39602b2b 100644 --- a/docs/source/api/classif_functions.rst +++ b/docs/source/api/classif_functions.rst @@ -9,25 +9,7 @@ Classification functions **xtensor** provides the following classification functions for xexpressions and scalars: -Defined in ``xtensor/xmath.hpp`` - -.. _isfinite-func-ref: -.. doxygenfunction:: isfinite(E&&) - :project: xtensor - -.. _isinf-func-ref: -.. doxygenfunction:: isinf(E&&) - :project: xtensor - -.. _isnan-func-ref: -.. doxygenfunction:: isnan(E&&) - :project: xtensor - -.. _isclose-func-ref: -.. doxygenfunction:: isclose(E1&&, E2&&, double, double, bool) - :project: xtensor - -.. _allclose-func-ref: -.. doxygenfunction:: allclose(E1&&, E2&, double, double) - :project: xtensor +Defined in ``xtensor/core/xmath.hpp`` +.. doxygengroup:: classif_functions + :members: diff --git a/docs/source/api/container_index.rst b/docs/source/api/container_index.rst index d21898633..ef8c0ba84 100644 --- a/docs/source/api/container_index.rst +++ b/docs/source/api/container_index.rst @@ -7,15 +7,22 @@ Containers and views ==================== +Containers are in-memory expressions that share a common implementation of most of the methods of the xexpression API. +The final container classes (:cpp:type:`xt::xarray`, :cpp:type:`xt::xtensor`) mainly implement constructors and value semantic, most of the +xexpression API is actually implemented in ``xstrided_container`` and ``xcontainer``. + .. toctree:: xcontainer + xaccessible xiterable xarray xarray_adaptor + xchunked_array xtensor xtensor_adaptor xfixed + xadapt xoptional_assembly_base xoptional_assembly xoptional_assembly_adaptor @@ -25,3 +32,5 @@ Containers and views xbroadcast xindex_view xfunctor_view + xrepeat + xfft diff --git a/docs/source/api/error_functions.rst b/docs/source/api/error_functions.rst index 350d9cb0b..be2312f08 100644 --- a/docs/source/api/error_functions.rst +++ b/docs/source/api/error_functions.rst @@ -9,21 +9,7 @@ Error and gamma functions **xtensor** provides the following error and gamma functions for xexpressions: -Defined in ``xtensor/xmath.hpp`` - -.. _erf-function-reference: -.. doxygenfunction:: erf(E&&) - :project: xtensor - -.. _erfc-function-reference: -.. doxygenfunction:: erfc(E&&) - :project: xtensor - -.. _tgamma-func-ref: -.. doxygenfunction:: tgamma(E&&) - :project: xtensor - -.. _lgamma-func-ref: -.. doxygenfunction:: lgamma(E&&) - :project: xtensor +Defined in ``xtensor/core/xmath.hpp`` +.. doxygengroup:: err_functions + :members: diff --git a/docs/source/api/exponential_functions.rst b/docs/source/api/exponential_functions.rst index ce082d3c1..65caeed74 100644 --- a/docs/source/api/exponential_functions.rst +++ b/docs/source/api/exponential_functions.rst @@ -9,33 +9,7 @@ Exponential functions **xtensor** provides the following exponential functions for xexpressions: -Defined in ``xtensor/xmath.hpp`` - -.. _exp-function-reference: -.. doxygenfunction:: exp(E&&) - :project: xtensor - -.. _exp2-function-reference: -.. doxygenfunction:: exp2(E&&) - :project: xtensor - -.. _expm1-func-ref: -.. doxygenfunction:: expm1(E&&) - :project: xtensor - -.. _log-function-reference: -.. doxygenfunction:: log(E&&) - :project: xtensor - -.. _log2-function-reference: -.. doxygenfunction:: log2(E&&) - :project: xtensor - -.. _log10-func-ref: -.. doxygenfunction:: log10(E&&) - :project: xtensor - -.. _log1p-func-ref: -.. doxygenfunction:: log1p(E&&) - :project: xtensor +Defined in ``xtensor/core/xmath.hpp`` +.. doxygengroup:: exp_functions + :members: diff --git a/docs/source/api/expression_index.rst b/docs/source/api/expression_index.rst index 4f2c80e6c..c257117db 100644 --- a/docs/source/api/expression_index.rst +++ b/docs/source/api/expression_index.rst @@ -7,6 +7,10 @@ Expressions and semantic ======================== +:cpp:type:`xt::xexpression` and the semantic classes contain all the methods required to perform evaluation and +assignment of expressions. They define the computed assignment operators, the assignment methods for +``noalias`` and the downcast methods. + .. toctree:: xexpression diff --git a/docs/source/api/function_index.rst b/docs/source/api/function_index.rst index 5c31a4008..b4e3a22cf 100644 --- a/docs/source/api/function_index.rst +++ b/docs/source/api/function_index.rst @@ -16,5 +16,7 @@ Functions and generators xbuilder xmanipulation xsort + xset_operation xrandom xhistogram + xpad diff --git a/docs/source/api/hyperbolic_functions.rst b/docs/source/api/hyperbolic_functions.rst index 8898ea1e8..757c77409 100644 --- a/docs/source/api/hyperbolic_functions.rst +++ b/docs/source/api/hyperbolic_functions.rst @@ -9,29 +9,7 @@ Hyperbolic functions **xtensor** provides the following hyperbolic functions for xexpressions: -Defined in ``xtensor/xmath.hpp`` - -.. _sinh-function-reference: -.. doxygenfunction:: sinh(E&&) - :project: xtensor - -.. _cosh-function-reference: -.. doxygenfunction:: cosh(E&&) - :project: xtensor - -.. _tanh-function-reference: -.. doxygenfunction:: tanh(E&&) - :project: xtensor - -.. _asinh-func-ref: -.. doxygenfunction:: asinh(E&&) - :project: xtensor - -.. _acosh-func-ref: -.. doxygenfunction:: acosh(E&&) - :project: xtensor - -.. _atanh-func-ref: -.. doxygenfunction:: atanh(E&&) - :project: xtensor +Defined in ``xtensor/core/xmath.hpp`` +.. doxygengroup:: hyper_functions + :members: diff --git a/docs/source/api/index_related.rst b/docs/source/api/index_related.rst new file mode 100644 index 000000000..f7de8fdc2 --- /dev/null +++ b/docs/source/api/index_related.rst @@ -0,0 +1,15 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Index related functions +======================= + +Defined in ``xtensor/core/xoperation.hpp`` + +The logical operator group documents the index-producing overloads of +``xt::where``, ``xt::nonzero`` and ``xt::argwhere``. + +``xt::from_indices`` is documented on the ``xtensor`` API page. diff --git a/docs/source/api/iterator_index.rst b/docs/source/api/iterator_index.rst new file mode 100644 index 000000000..7640a740a --- /dev/null +++ b/docs/source/api/iterator_index.rst @@ -0,0 +1,16 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Iterators +========= + +In addition to the iterators defined in the different types of expressions, *xtensor* provides +classes that allow to iterate over slices of an expression along a specified axis. + +.. toctree:: + + xaxis_iterator + xaxis_slice_iterator diff --git a/docs/source/api/nan_functions.rst b/docs/source/api/nan_functions.rst index 2a5a05c9a..918039bce 100644 --- a/docs/source/api/nan_functions.rst +++ b/docs/source/api/nan_functions.rst @@ -9,30 +9,7 @@ NaN functions **xtensor** provides the following functions that deal with NaNs in xexpressions: -Defined in ``xtensor/xmath.hpp`` +Defined in ``xtensor/core/xmath.hpp`` -.. _nan-to-num-function-reference: -.. doxygenfunction:: nan_to_num(E&&) - :project: xtensor - -.. _nansum-function-reference: -.. doxygenfunction:: nansum(E&&, X&&, EVS) - :project: xtensor - -.. _nanprod-function-reference: -.. doxygenfunction:: nanprod(E&&, X&&, EVS) - :project: xtensor - -.. _nancumsum-function-reference: -.. doxygenfunction:: nancumsum(E&&) - :project: xtensor - -.. doxygenfunction:: nancumsum(E&&, std::ptrdiff_t) - :project: xtensor - -.. _nancumprod-function-reference: -.. doxygenfunction:: nancumprod(E&&) - :project: xtensor - -.. doxygenfunction:: nancumprod(E&&, std::ptrdiff_t) - :project: xtensor +.. doxygengroup:: nan_functions + :members: diff --git a/docs/source/api/nearint_operations.rst b/docs/source/api/nearint_operations.rst index 02340039a..59dd61d19 100644 --- a/docs/source/api/nearint_operations.rst +++ b/docs/source/api/nearint_operations.rst @@ -9,29 +9,7 @@ Nearest integer floating point operations **xtensor** provides the following rounding operations for xexpressions: -Defined in ``xtensor/xmath.hpp`` - -.. _ceil-function-reference: -.. doxygenfunction:: ceil(E&&) - :project: xtensor - -.. _floor-func-ref: -.. doxygenfunction:: floor(E&&) - :project: xtensor - -.. _trunc-func-ref: -.. doxygenfunction:: trunc(E&&) - :project: xtensor - -.. _round-func-ref: -.. doxygenfunction:: round(E&&) - :project: xtensor - -.. _nearbyint-func-ref: -.. doxygenfunction:: nearbyint(E&&) - :project: xtensor - -.. _rint-function-reference: -.. doxygenfunction:: rint(E&&) - :project: xtensor +Defined in ``xtensor/core/xmath.hpp`` +.. doxygengroup:: nearint_functions + :members: diff --git a/docs/source/api/operators.rst b/docs/source/api/operators.rst index c6b67ff4b..00df9458d 100644 --- a/docs/source/api/operators.rst +++ b/docs/source/api/operators.rst @@ -7,120 +7,19 @@ Operators and related functions =============================== -Defined in ``xtensor/xmath.hpp`` and ``xtensor/xoperation.hpp`` +Defined in ``xtensor/core/xmath.hpp`` and ``xtensor/core/xoperation.hpp`` -.. _identity-op-ref: -.. doxygenfunction:: operator+(E&&) - :project: xtensor +.. doxygengroup:: arithmetic_operators + :members: -.. _neg-op-ref: -.. doxygenfunction:: operator-(E&&) - :project: xtensor +.. doxygengroup:: logical_operators + :members: -.. _plus-op-ref: -.. doxygenfunction:: operator+(E1&&, E2&&) - :project: xtensor +.. doxygengroup:: comparison_operators + :members: -.. _minus-op-ref: -.. doxygenfunction:: operator-(E1&&, E2&&) - :project: xtensor +.. doxygengroup:: bitwise_operators + :members: -.. _mul-op-ref: -.. doxygenfunction:: operator*(E1&&, E2&&) - :project: xtensor - -.. _div-op-ref: -.. doxygenfunction:: operator/(E1&&, E2&&) - :project: xtensor - -.. _or-op-ref: -.. doxygenfunction:: operator||(E1&&, E2&&) - :project: xtensor - -.. _and-op-ref: -.. doxygenfunction:: operator&&(E1&&, E2&&) - :project: xtensor - -.. _not-op-ref: -.. doxygenfunction:: operator!(E&&) - :project: xtensor - -.. _where-op-ref: -.. doxygenfunction:: where(E1&&, E2&&, E3&&) - :project: xtensor - -.. _nonzero-op-ref: -.. doxygenfunction:: nonzero(const T&) - :project: xtensor - -.. _wherec-op-ref: -.. doxygenfunction:: where(const T&) - :project: xtensor - -.. _any-op-ref: -.. doxygenfunction:: any(E&&) - :project: xtensor - -.. _all-op-ref: -.. doxygenfunction:: all(E&&) - :project: xtensor - -.. _less-op-ref: -.. doxygenfunction:: operator<(E1&&, E2&&) - :project: xtensor - -.. _less-eq-op-ref: -.. doxygenfunction:: operator<=(E1&&, E2&&) - :project: xtensor - -.. _greater-op-ref: -.. doxygenfunction:: operator>(E1&&, E2&&) - :project: xtensor - -.. _greater-eq-op-ref: -.. doxygenfunction:: operator>=(E1&&, E2&&) - :project: xtensor - -.. _equal-op-ref: -.. doxygenfunction:: operator==(const xexpression&, const xexpression&) - :project: xtensor - -.. _nequal-op-ref: -.. doxygenfunction:: operator!=(const xexpression&, const xexpression&) - :project: xtensor - -.. _equal-fn-ref: -.. doxygenfunction:: equal(E1&&, E2&&) - :project: xtensor - -.. _nequal-fn-ref: -.. doxygenfunction:: not_equal(E1&&, E2&&) - :project: xtensor - -.. _bitwise-and-op-ref: -.. doxygenfunction:: operator&(E1&&, E2&&) - :project: xtensor - -.. _bitwise-or-op-ref: -.. doxygenfunction:: operator|(E1&&, E2&&) - :project: xtensor - -.. _bitwise-xor-op-ref: -.. doxygenfunction:: operator^(E1&&, E2&&) - :project: xtensor - -.. _bitwise-not-op-ref: -.. doxygenfunction:: operator~(E&&) - :project: xtensor - -.. _left-shift-op-ref: -.. doxygenfunction:: left_shift(E1&&, E2&&) - :project: xtensor - -.. _right-shift-op-ref: -.. doxygenfunction:: right_shift(E1&&, E2&&) - :project: xtensor - -.. _cast-ref: -.. doxygenfunction:: cast(E&&) - :project: xtensor +.. doxygengroup:: casting_operators + :members: diff --git a/docs/source/api/power_functions.rst b/docs/source/api/power_functions.rst index 45d53e95f..5ac5a1546 100644 --- a/docs/source/api/power_functions.rst +++ b/docs/source/api/power_functions.rst @@ -10,30 +10,7 @@ Power functions **xtensor** provides the following power functions for xexpressions and scalars: -Defined in ``xtensor/xmath.hpp`` - -.. _pow-function-reference: -.. doxygenfunction:: pow(E1&&, E2&&) - :project: xtensor - -.. doxygenfunction:: pow(E&&) - :project: xtensor - -.. doxygenfunction:: square(E1&&) - :project: xtensor - -.. doxygenfunction:: cube(E1&&) - :project: xtensor - -.. _sqrt-function-reference: -.. doxygenfunction:: sqrt(E&&) - :project: xtensor - -.. _cbrt-function-reference: -.. doxygenfunction:: cbrt(E&&) - :project: xtensor - -.. _hypot-func-ref: -.. doxygenfunction:: hypot(E1&&, E2&&) - :project: xtensor +Defined in ``xtensor/core/xmath.hpp`` +.. doxygengroup:: pow_functions + :members: diff --git a/docs/source/api/reducing_functions.rst b/docs/source/api/reducing_functions.rst index 4709d9573..89c0baff5 100644 --- a/docs/source/api/reducing_functions.rst +++ b/docs/source/api/reducing_functions.rst @@ -9,82 +9,7 @@ Reducing functions **xtensor** provides the following reducing functions for xexpressions: -Defined in ``xtensor/xmath.hpp`` +Defined in ``xtensor/core/xmath.hpp`` and ``xtensor/reducers/xnorm.hpp``. -.. _sum-function-reference: -.. doxygenfunction:: sum(E&&, X&&, EVS) - :project: xtensor - -.. _prod-function-reference: -.. doxygenfunction:: prod(E&&, X&&, EVS) - :project: xtensor - -.. _mean-function-reference: -.. doxygenfunction:: mean(E&&, X&&, EVS) - :project: xtensor - -.. _variance-function-reference: -.. doxygenfunction:: variance(E&&, X&&, EVS) - :project: xtensor - -.. _stddev-function-reference: -.. doxygenfunction:: stddev(E&&, X&&, EVS) - :project: xtensor - -.. _diff-function-reference: -.. doxygenfunction:: diff(const xexpression&, unsigned int, std::ptrdiff_t) - :project: xtensor - -.. _amax-function-reference: -.. doxygenfunction:: amax(E&&, X&&, EVS) - :project: xtensor - -.. _amin-function-reference: -.. doxygenfunction:: amin(E&&, X&&, EVS) - :project: xtensor - -.. _trapz-function-reference: -.. doxygenfunction:: trapz(const xexpression&, double, std::ptrdiff_t) - :project: xtensor - -.. _trapz-function-reference2: -.. doxygenfunction:: trapz(const xexpression&, const xexpression&, std::ptrdiff_t) - :project: xtensor - -Defined in ``xtensor/xnorm.hpp`` - -.. _norm-l0-func-ref: -.. doxygenfunction:: norm_l0(E&&, X&&, EVS) - :project: xtensor - -.. _norm-l1-func-ref: -.. doxygenfunction:: norm_l1(E&&, X&&, EVS) - :project: xtensor - -.. _norm-sq-func-ref: -.. doxygenfunction:: norm_sq(E&&, X&&, EVS) - :project: xtensor - -.. _norm-l2-func-ref: -.. doxygenfunction:: norm_l2(E&&, X&&, EVS) - :project: xtensor - -.. _norm-linf-func-ref: -.. doxygenfunction:: norm_linf(E&&, X&&, EVS) - :project: xtensor - -.. _nlptop-func-ref: -.. doxygenfunction:: norm_lp_to_p(E&&, double, X&&, EVS) - :project: xtensor - -.. _norm-lp-func-ref: -.. doxygenfunction:: norm_lp(E&&, double, X&&, EVS) - :project: xtensor - -.. _nind-l1-ref: -.. doxygenfunction:: norm_induced_l1(E&&, EVS) - :project: xtensor - -.. _nilinf-ref: -.. doxygenfunction:: norm_induced_linf(E&&, EVS) - :project: xtensor +.. doxygengroup:: red_functions + :members: diff --git a/docs/source/api/shape.rst b/docs/source/api/shape.rst new file mode 100644 index 000000000..a35434ac9 --- /dev/null +++ b/docs/source/api/shape.rst @@ -0,0 +1,13 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Shape/index manipulation +======================== + +.. toctree:: + + xshape + xstrides diff --git a/docs/source/api/trigonometric_functions.rst b/docs/source/api/trigonometric_functions.rst index 84ae190c2..e76d151b5 100644 --- a/docs/source/api/trigonometric_functions.rst +++ b/docs/source/api/trigonometric_functions.rst @@ -9,33 +9,7 @@ Trigonometric functions **xtensor** provides the following trigonometric functions for xexpressions and scalars: -Defined in ``xtensor/xmath.hpp`` - -.. _sin-function-reference: -.. doxygenfunction:: sin(E&&) - :project: xtensor - -.. _cos-function-reference: -.. doxygenfunction:: cos(E&&) - :project: xtensor - -.. _tan-function-reference: -.. doxygenfunction:: tan(E&&) - :project: xtensor - -.. _asin-function-reference: -.. doxygenfunction:: asin(E&&) - :project: xtensor - -.. _acos-function-reference: -.. doxygenfunction:: acos(E&&) - :project: xtensor - -.. _atan-function-reference: -.. doxygenfunction:: atan(E&&) - :project: xtensor - -.. _atan2-func-ref: -.. doxygenfunction:: atan2(E1&&, E2&&) - :project: xtensor +Defined in ``xtensor/core/xmath.hpp`` +.. doxygengroup:: trigo_functions + :members: diff --git a/docs/source/api/xaccessible.rst b/docs/source/api/xaccessible.rst new file mode 100644 index 000000000..237fc029d --- /dev/null +++ b/docs/source/api/xaccessible.rst @@ -0,0 +1,16 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xaccessible +=========== + +Defined in ``xtensor/core/xaccessible.hpp`` + +.. doxygenclass:: xt::xconst_accessible + :members: + +.. doxygenclass:: xt::xaccessible + :members: diff --git a/docs/source/api/xaccumulator.rst b/docs/source/api/xaccumulator.rst index 18ded9152..906f5288e 100644 --- a/docs/source/api/xaccumulator.rst +++ b/docs/source/api/xaccumulator.rst @@ -7,10 +7,8 @@ xaccumulator ============ -Defined in ``xtensor/xaccumulator.hpp`` +Defined in ``xtensor/reducers/xaccumulator.hpp`` .. doxygenfunction:: xt::accumulate(F&&, E&&, EVS) - :project: xtensor .. doxygenfunction:: xt::accumulate(F&&, E&&, std::ptrdiff_t, EVS) - :project: xtensor diff --git a/docs/source/api/xadapt.rst b/docs/source/api/xadapt.rst new file mode 100644 index 000000000..86f9e4eb2 --- /dev/null +++ b/docs/source/api/xadapt.rst @@ -0,0 +1,16 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xadapt +====== + +Defined in ``xtensor/containers/xadapt.hpp`` + +.. cpp:namespace-push:: xt + +.. doxygengroup:: xt_xadapt + +.. cpp:namespace-pop:: diff --git a/docs/source/api/xarray.rst b/docs/source/api/xarray.rst index cc55e0235..18e06692e 100644 --- a/docs/source/api/xarray.rst +++ b/docs/source/api/xarray.rst @@ -7,14 +7,11 @@ xarray ====== -Defined in ``xtensor/xarray.hpp`` +Defined in ``xtensor/containers/xarray.hpp`` .. doxygenclass:: xt::xarray_container - :project: xtensor :members: .. doxygentypedef:: xt::xarray - :project: xtensor .. doxygentypedef:: xt::xarray_optional - :project: xtensor diff --git a/docs/source/api/xarray_adaptor.rst b/docs/source/api/xarray_adaptor.rst index 82b7dedcd..d1110c7ba 100644 --- a/docs/source/api/xarray_adaptor.rst +++ b/docs/source/api/xarray_adaptor.rst @@ -7,25 +7,7 @@ xarray_adaptor ============== -Defined in ``xtensor/xarray.hpp`` +Defined in ``xtensor/containers/xarray.hpp`` .. doxygenclass:: xt::xarray_adaptor - :project: xtensor :members: - -adapt (xarray_adaptor) -======================= - -Defined in ``xtensor/xadapt.hpp`` - -.. doxygenfunction:: xt::adapt(C&&, const SC&, layout_type) - :project: xtensor - -.. doxygenfunction:: xt::adapt(C&&, SC&&, SS&&) - :project: xtensor - -.. doxygenfunction:: xt::adapt(P&&, typename A::size_type, O, const SC&, layout_type, const A&) - :project: xtensor - -.. doxygenfunction:: xt::adapt(P&&, typename A::size_type, O, SC&&, SS&&, const A&) - :project: xtensor diff --git a/docs/source/api/xaxis_iterator.rst b/docs/source/api/xaxis_iterator.rst new file mode 100644 index 000000000..e43bae3ee --- /dev/null +++ b/docs/source/api/xaxis_iterator.rst @@ -0,0 +1,26 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xaxis_iterator +============== + +Defined in ``xtensor/views/xaxis_iterator.hpp`` + +.. doxygenclass:: xt::xaxis_iterator + :members: + +.. doxygenfunction:: operator==(const xaxis_iterator&, const xaxis_iterator&) + + +.. doxygenfunction:: operator!=(const xaxis_iterator&, const xaxis_iterator&) + +.. doxygenfunction:: axis_begin(E&&) + +.. doxygenfunction:: axis_begin(E&&, typename std::decay_t::size_type) + +.. doxygenfunction:: axis_end(E&&) + +.. doxygenfunction:: axis_end(E&&, typename std::decay_t::size_type) diff --git a/docs/source/api/xaxis_slice_iterator.rst b/docs/source/api/xaxis_slice_iterator.rst new file mode 100644 index 000000000..4882fc292 --- /dev/null +++ b/docs/source/api/xaxis_slice_iterator.rst @@ -0,0 +1,27 @@ + +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xaxis_slice_iterator +==================== + +Defined in ``xtensor/views/xaxis_slice_iterator.hpp`` + +.. doxygenclass:: xt::xaxis_slice_iterator + :members: + +.. doxygenfunction:: operator==(const xaxis_slice_iterator&, const xaxis_slice_iterator&) + + +.. doxygenfunction:: operator!=(const xaxis_slice_iterator&, const xaxis_slice_iterator&) + +.. doxygenfunction:: axis_slice_begin(E&&) + +.. doxygenfunction:: axis_slice_begin(E&&, typename std::decay_t::size_type) + +.. doxygenfunction:: axis_slice_end(E&&) + +.. doxygenfunction:: axis_slice_end(E&&, typename std::decay_t::size_type) diff --git a/docs/source/api/xbroadcast.rst b/docs/source/api/xbroadcast.rst index 35f1f9041..e5fe1790f 100644 --- a/docs/source/api/xbroadcast.rst +++ b/docs/source/api/xbroadcast.rst @@ -7,11 +7,9 @@ xbroadcast ========== -Defined in ``xtensor/xbroadcast.hpp`` +Defined in ``xtensor/views/xbroadcast.hpp`` .. doxygenclass:: xt::xbroadcast - :project: xtensor :members: .. doxygenfunction:: xt::broadcast(E&&, const S&) - :project: xtensor diff --git a/docs/source/api/xbuilder.rst b/docs/source/api/xbuilder.rst index d47e082eb..b315c3730 100644 --- a/docs/source/api/xbuilder.rst +++ b/docs/source/api/xbuilder.rst @@ -7,70 +7,52 @@ xbuilder ======== -Defined in ``xtensor/xbuilder.hpp`` +Defined in ``xtensor/generators/xbuilder.hpp`` .. doxygenfunction:: xt::ones(S) - :project: xtensor .. doxygenfunction:: xt::ones(const I (&)[L]) - :project: xtensor .. doxygenfunction:: xt::zeros(S) - :project: xtensor .. doxygenfunction:: xt::zeros(const I (&)[L]) - :project: xtensor .. doxygenfunction:: xt::empty(const S&) - :project: xtensor -.. doxygenfunction:: xt::full_like(const xexpression&) - :project: xtensor +.. doxygenfunction:: xt::full_like(const xexpression&, typename E::value_type) .. doxygenfunction:: xt::empty_like(const xexpression&) - :project: xtensor .. doxygenfunction:: xt::zeros_like(const xexpression&) - :project: xtensor .. doxygenfunction:: xt::ones_like(const xexpression&) - :project: xtensor .. doxygenfunction:: xt::eye(const std::vector&, int) - :project: xtensor .. doxygenfunction:: xt::eye(std::size_t, int) - :project: xtensor -.. doxygenfunction:: xt::arange(T, T, T) - :project: xtensor +.. doxygenfunction:: xt::arange(T, T, S) .. doxygenfunction:: xt::arange(T) - :project: xtensor .. doxygenfunction:: xt::linspace - :project: xtensor .. doxygenfunction:: xt::logspace - :project: xtensor -.. doxygenfunction:: xt::concatenate - :project: xtensor +.. doxygenfunction:: xt::concatenate(std::tuple&&, std::size_t) .. doxygenfunction:: xt::stack - :project: xtensor + +.. doxygenfunction:: xt::hstack + +.. doxygenfunction:: xt::vstack .. doxygenfunction:: xt::meshgrid - :project: xtensor .. doxygenfunction:: xt::diag - :project: xtensor .. doxygenfunction:: xt::diagonal - :project: xtensor .. doxygenfunction:: xt::tril - :project: xtensor .. doxygenfunction:: xt::triu - :project: xtensor diff --git a/docs/source/api/xchunked_array.rst b/docs/source/api/xchunked_array.rst new file mode 100644 index 000000000..f3971bf4f --- /dev/null +++ b/docs/source/api/xchunked_array.rst @@ -0,0 +1,14 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvaidan Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xchunked_array +============== + +.. cpp:namespace-push:: xt + +.. doxygengroup:: xt_xchunked_array + +.. cpp:namespace-pop:: diff --git a/docs/source/api/xcontainer.rst b/docs/source/api/xcontainer.rst index 780a4d591..24fbf6c47 100644 --- a/docs/source/api/xcontainer.rst +++ b/docs/source/api/xcontainer.rst @@ -7,29 +7,24 @@ layout ====== -Defined in ``xtensor/xlayout.hpp`` +Defined in ``xtensor/core/xlayout.hpp`` .. doxygenenum:: xt::layout_type - :project: xtensor .. doxygenfunction:: xt::compute_layout(Args... args) - :project: xtensor xcontainer ========== -Defined in ``xtensor/xcontainer.hpp`` +Defined in ``xtensor/containers/xcontainer.hpp`` .. doxygenclass:: xt::xcontainer - :project: xtensor :members: xstrided_container ================== -Defined in ``xtensor/xcontainer.hpp`` +Defined in ``xtensor/containers/xcontainer.hpp`` .. doxygenclass:: xt::xstrided_container - :project: xtensor :members: - diff --git a/docs/source/api/xcontainer_semantic.rst b/docs/source/api/xcontainer_semantic.rst index 736f65564..c69866083 100644 --- a/docs/source/api/xcontainer_semantic.rst +++ b/docs/source/api/xcontainer_semantic.rst @@ -7,8 +7,7 @@ xcontainer_semantic =================== -Defined in ``xtensor/xsemantic.hpp`` +Defined in ``xtensor/core/xsemantic.hpp`` .. doxygenclass:: xt::xcontainer_semantic - :project: xtensor :members: diff --git a/docs/source/api/xcsv.rst b/docs/source/api/xcsv.rst index 5e5d12d18..bc762b00f 100644 --- a/docs/source/api/xcsv.rst +++ b/docs/source/api/xcsv.rst @@ -7,10 +7,8 @@ xcsv: read/write CSV files ========================== -Defined in ``xtensor/xcsv.hpp`` +Defined in ``xtensor/io/xcsv.hpp`` .. doxygenfunction:: xt::load_csv - :project: xtensor .. doxygenfunction:: xt::dump_csv - :project: xtensor diff --git a/docs/source/api/xeval.rst b/docs/source/api/xeval.rst index 74e103c62..c70420965 100644 --- a/docs/source/api/xeval.rst +++ b/docs/source/api/xeval.rst @@ -7,7 +7,8 @@ xeval ===== -Defined in ``xtensor/xeval.hpp`` +.. cpp:namespace-push:: xt -.. doxygenfunction:: xt::eval(E&& e) - :project: xtensor +.. doxygengroup:: xt_xeval + +.. cpp:namespace-pop:: diff --git a/docs/source/api/xexpression.rst b/docs/source/api/xexpression.rst index 5b6d6273b..61f117592 100644 --- a/docs/source/api/xexpression.rst +++ b/docs/source/api/xexpression.rst @@ -7,15 +7,16 @@ xexpression =========== -Defined in ``xtensor/xexpression.hpp`` +Defined in ``xtensor/core/xexpression.hpp`` .. doxygenclass:: xt::xexpression - :project: xtensor :members: .. doxygenclass:: xt::xshared_expression - :project: xtensor :members: .. doxygenfunction:: make_xshared - :project: xtensor \ No newline at end of file + +.. doxygenfunction:: share(xexpression&) + +.. doxygenfunction:: share(xexpression&&) diff --git a/docs/source/api/xfft.rst b/docs/source/api/xfft.rst new file mode 100644 index 000000000..a05766ff7 --- /dev/null +++ b/docs/source/api/xfft.rst @@ -0,0 +1,16 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xfft +==== + +Defined in ``xtensor/misc/xfft.hpp`` + +.. doxygenfunction:: xt::fft::fft(E&&, std::ptrdiff_t) + +.. doxygenfunction:: xt::fft::ifft(E&&, std::ptrdiff_t) + +.. doxygenfunction:: xt::fft::convolve(E1&&, E2&&, std::ptrdiff_t) diff --git a/docs/source/api/xfixed.rst b/docs/source/api/xfixed.rst index ec56a9bda..b9afc6d7b 100644 --- a/docs/source/api/xfixed.rst +++ b/docs/source/api/xfixed.rst @@ -7,12 +7,9 @@ xtensor_fixed ============= -Defined in ``xtensor/xfixed.hpp`` +Defined in ``xtensor/containers/xfixed.hpp`` .. doxygenclass:: xt::xfixed_container - :project: xtensor :members: .. doxygentypedef:: xt::xtensor_fixed - :project: xtensor - diff --git a/docs/source/api/xfunction.rst b/docs/source/api/xfunction.rst index 035d49e62..e572e463b 100644 --- a/docs/source/api/xfunction.rst +++ b/docs/source/api/xfunction.rst @@ -7,13 +7,11 @@ xfunction ========= -Defined in ``xtensor/xfunction.hpp`` +Defined in ``xtensor/core/xfunction.hpp`` .. doxygenclass:: xt::xfunction - :project: xtensor :members: -Defined in ``xtensor/xmath.hpp`` +Defined in ``xtensor/core/xmath.hpp`` .. doxygenfunction:: make_lambda_xfunction - :project: xtensor diff --git a/docs/source/api/xfunctor_view.rst b/docs/source/api/xfunctor_view.rst index be4a7607b..53ee7573d 100644 --- a/docs/source/api/xfunctor_view.rst +++ b/docs/source/api/xfunctor_view.rst @@ -7,16 +7,12 @@ xfunctor_view ============= -Defined in ``xtensor/xfunctor_view.hpp`` +.. cpp:namespace-push:: xt -.. doxygenclass:: xt::xfunctor_view - :project: xtensor +.. doxygengroup:: xt_xfunctor_view :members: + :undoc-members: -Defined in ``xtensor/xcomplex.hpp`` +.. doxygengroup:: xt_xcomplex -.. doxygenfunction:: xt::real(E&&) - :project: xtensor - -.. doxygenfunction:: xt::imag(E&&) - :project: xtensor +.. cpp:namespace-pop:: diff --git a/docs/source/api/xgenerator.rst b/docs/source/api/xgenerator.rst index ed45631ba..8d96da7f3 100644 --- a/docs/source/api/xgenerator.rst +++ b/docs/source/api/xgenerator.rst @@ -7,9 +7,7 @@ xgenerator ========== -Defined in ``xtensor/xgenerator.hpp`` +Defined in ``xtensor/generators/xgenerator.hpp`` .. doxygenclass:: xt::xgenerator - :project: xtensor :members: - diff --git a/docs/source/api/xhistogram.rst b/docs/source/api/xhistogram.rst index a268e3141..4d1e3e639 100644 --- a/docs/source/api/xhistogram.rst +++ b/docs/source/api/xhistogram.rst @@ -7,37 +7,16 @@ xhistogram ========== -Defined in ``xtensor/xhistogram.hpp`` +Defined in ``xtensor/misc/xhistogram.hpp`` -.. doxygenenum:: xt::histogram_algorithm - :project: xtensor +.. doxygengroup:: digitize + :members: -.. doxygenfunction:: xt::histogram(E1&&, E2&&, E3&&, bool) - :project: xtensor +.. doxygengroup:: histogram + :members: .. doxygenfunction:: xt::bincount(E1&&, E2&&, std::size_t) - :project: xtensor -.. doxygenfunction:: xt::histogram_bin_edges(E1&&, E2&&, E3, E3, std::size_t, histogram_algorithm) - :project: xtensor +.. doxygenfunction:: xt::bin_items(size_t, E&&) -Further overloads ------------------ - -.. doxygenfunction:: xt::histogram(E1&&, E2&&, bool) - :project: xtensor - -.. doxygenfunction:: xt::histogram(E1&&, std::size_t, bool) - :project: xtensor - -.. doxygenfunction:: xt::histogram(E1&&, std::size_t, E2&&, bool) - :project: xtensor - -.. doxygenfunction:: xt::histogram_bin_edges(E1&&, E2, E2, std::size_t, histogram_algorithm) - :project: xtensor - -.. doxygenfunction:: xt::histogram_bin_edges(E1&&, E2&&, std::size_t, histogram_algorithm) - :project: xtensor - -.. doxygenfunction:: xt::histogram_bin_edges(E1&&, std::size_t, histogram_algorithm) - :project: xtensor +.. doxygenfunction:: xt::bin_items(size_t, size_t) diff --git a/docs/source/api/xindex_view.rst b/docs/source/api/xindex_view.rst index 1d47bb3a7..d47ab3733 100644 --- a/docs/source/api/xindex_view.rst +++ b/docs/source/api/xindex_view.rst @@ -7,21 +7,16 @@ xindex_view =========== -Defined in ``xtensor/xindex_view.hpp`` +Defined in ``xtensor/views/xindex_view.hpp`` .. doxygenclass:: xt::xindex_view - :project: xtensor :members: .. doxygenclass:: xt::xfiltration - :project: xtensor :members: .. doxygenfunction:: xt::index_view(E&&, I&&) - :project: xtensor .. doxygenfunction:: xt::filter - :project: xtensor .. doxygenfunction:: xt::filtration - :project: xtensor diff --git a/docs/source/api/xio.rst b/docs/source/api/xio.rst index 179b191b9..7af4c5d09 100644 --- a/docs/source/api/xio.rst +++ b/docs/source/api/xio.rst @@ -7,15 +7,15 @@ xio: pretty printing ==================== -Defined in ``xtensor/xio.hpp`` +Defined in ``xtensor/io/xio.hpp`` This file defines functions for pretty printing xexpressions. It defines appropriate overloads for the ``<<`` operator for std::ostreams and xexpressions. .. code:: - #include - #include + #include + #include int main() { @@ -24,7 +24,7 @@ overloads for the ``<<`` operator for std::ostreams and xexpressions. return 0; } -Will print +Will print .. code:: @@ -34,27 +34,19 @@ Will print With the following functions, the global print options can be set: .. doxygenfunction:: xt::print_options::set_line_width - :project: xtensor .. doxygenfunction:: xt::print_options::set_threshold - :project: xtensor .. doxygenfunction:: xt::print_options::set_edge_items - :project: xtensor .. doxygenfunction:: xt::print_options::set_precision - :project: xtensor On can also locally overwrite the print options with io manipulators: .. doxygenclass:: xt::print_options::line_width - :project: xtensor .. doxygenclass:: xt::print_options::threshold - :project: xtensor .. doxygenclass:: xt::print_options::edge_items - :project: xtensor .. doxygenclass:: xt::print_options::precision - :project: xtensor diff --git a/docs/source/api/xiterable.rst b/docs/source/api/xiterable.rst index 294461cef..f0ad5637d 100644 --- a/docs/source/api/xiterable.rst +++ b/docs/source/api/xiterable.rst @@ -7,17 +7,13 @@ xiterable ========= -Defined in ``xtensor/xiterable.hpp`` +Defined in ``xtensor/core/xiterable.hpp`` .. doxygenclass:: xt::xconst_iterable - :project: xtensor :members: .. doxygenclass:: xt::xiterable - :project: xtensor :members: .. doxygenclass:: xt::xcontiguous_iterable - :project: xtensor :members: - diff --git a/docs/source/api/xjson.rst b/docs/source/api/xjson.rst index 0de7017aa..138c5b9de 100644 --- a/docs/source/api/xjson.rst +++ b/docs/source/api/xjson.rst @@ -7,10 +7,12 @@ xjson: serialize to/from JSON ============================= -Defined in ``xtensor/xjson.hpp`` +Defined in ``xtensor/io/xjson.hpp`` -.. doxygenfunction:: xt::to_json(nlohmann::json&, const E&); - :project: xtensor +Available overload families +--------------------------- -.. doxygenfunction:: xt::from_json(nlohmann::json&, const E&); - :project: xtensor +- ``xt::to_json(nlohmann::basic_json&, const E&)`` +- ``xt::from_json(const nlohmann::basic_json&, E&)`` + +``xt::from_json`` is provided for both container and view semantics. diff --git a/docs/source/api/xmanipulation.rst b/docs/source/api/xmanipulation.rst index 9e9f50860..779010da5 100644 --- a/docs/source/api/xmanipulation.rst +++ b/docs/source/api/xmanipulation.rst @@ -7,49 +7,10 @@ xmanipulation ============= -Defined in ``xtensor/xmanipulation.hpp`` +Defined in ``xtensor/misc/xmanipulation.hpp`` -.. doxygenfunction:: xt::transpose(E&&) - :project: xtensor +.. cpp:namespace-push:: xt -.. doxygenfunction:: xt::transpose(E&&, S&&, Tag) - :project: xtensor +.. doxygengroup:: xt_xmanipulation -.. doxygenfunction:: xt::ravel - :project: xtensor - -.. doxygenfunction:: xt::flatten - :project: xtensor - -.. doxygenfunction:: xt::trim_zeros - :project: xtensor - -.. doxygenfunction:: xt::squeeze(E&&) - :project: xtensor - -.. doxygenfunction:: xt::squeeze(E&&, S&&, Tag) - :project: xtensor - -.. doxygenfunction:: xt::expand_dims - :project: xtensor - -.. doxygenfunction:: xt::split - :project: xtensor - -.. doxygenfunction:: xt::atleast_Nd - :project: xtensor - -.. doxygenfunction:: xt::atleast_1d - :project: xtensor - -.. doxygenfunction:: xt::atleast_2d - :project: xtensor - -.. doxygenfunction:: xt::atleast_3d - :project: xtensor - -.. doxygenfunction:: xt::rot90 - :project: xtensor - -.. doxygenfunction:: xt::flip - :project: xtensor +.. cpp:namespace-pop:: diff --git a/docs/source/api/xmasked_view.rst b/docs/source/api/xmasked_view.rst index 7d199a817..b7df88ec3 100644 --- a/docs/source/api/xmasked_view.rst +++ b/docs/source/api/xmasked_view.rst @@ -7,8 +7,7 @@ xmasked_view ============ -Defined in ``xtensor/xmasked_view.hpp`` +Defined in ``xtensor/views/xmasked_view.hpp`` .. doxygenclass:: xt::xmasked_view - :project: xtensor :members: diff --git a/docs/source/api/xmath.rst b/docs/source/api/xmath.rst index c5601daa4..934879b8a 100644 --- a/docs/source/api/xmath.rst +++ b/docs/source/api/xmath.rst @@ -33,280 +33,353 @@ Mathematical functions operators -+-----------------------------------------+------------------------------------------+ -| :ref:`operator+ ` | identity | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator- ` | opposite | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator+ ` | addition | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator- ` | substraction | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator* ` | multiplication | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator/ ` | division | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator|| ` | logical or | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator&& ` | logical and | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator! ` | logical not | -+-----------------------------------------+------------------------------------------+ -| :ref:`where ` | ternary selection | -+-----------------------------------------+------------------------------------------+ -| :ref:`nonzero ` | indices selection | -+-----------------------------------------+------------------------------------------+ -| :ref:`where ` | indices selection | -+-----------------------------------------+------------------------------------------+ -| :ref:`any ` | return true if any value is truthy | -+-----------------------------------------+------------------------------------------+ -| :ref:`all ` | return true if all the values are truthy | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator\< ` | element-wise lesser than | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator\<= ` | element-wise less or equal | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator> ` | element-wise greater than | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator>= ` | element-wise greater or equal | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator== ` | expression equality | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator!= ` | expression inequality | -+-----------------------------------------+------------------------------------------+ -| :ref:`equal ` | element-wise equality | -+-----------------------------------------+------------------------------------------+ -| :ref:`not_equal ` | element-wise inequality | -+-----------------------------------------+------------------------------------------+ -| :ref:`cast ` | element-wise `static_cast` | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator& ` | bitwise and | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator| ` | bitwise or | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator^ ` | bitwise xor | -+-----------------------------------------+------------------------------------------+ -| :ref:`operator~ ` | bitwise not | -+-----------------------------------------+------------------------------------------+ -| :ref:`left_shift ` | bitwise shift left | -+-----------------------------------------+------------------------------------------+ -| :ref:`right_shift ` | bitwise shift right | -+-----------------------------------------+------------------------------------------+ +.. table:: + :widths: 30 70 + + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator+` | identity | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator-` | opposite | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator+` | addition | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator-` | substraction | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator*` | multiplication | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator/` | division | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator||` | logical or | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator&&` | logical and | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator!` | logical not | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::where` | ternary selection | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::any` | return true if any value is truthy | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::all` | return true if all the values are truthy | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator\<` | element-wise lesser than | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator\<=` | element-wise less or equal | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator>` | element-wise greater than | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator>=` | element-wise greater or equal | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator==` | expression equality | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator!=` | expression inequality | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::equal` | element-wise equality | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::not_equal` | element-wise inequality | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::less` | element-wise lesser than | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::less_equal` | element-wise less or equal | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::greater` | element-wise greater than | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::greater_equal` | element-wise greater or equal | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::cast` | element-wise ``static_cast`` | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator&` | bitwise and | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator|` | bitwise or | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator^` | bitwise xor | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator~` | bitwise not | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::left_shift` | bitwise shift left | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::right_shift` | bitwise shift right | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator\<\<` | bitwise shift left | + +-------------------------------+------------------------------------------+ + | :cpp:func:`xt::operator\>\>` | bitwise shift right | + +-------------------------------+------------------------------------------+ + +.. toctree:: + + index_related + +.. table:: + :widths: 30 70 + + +------------------------------+----------------------+ + | :cpp:func:`xt::where` | indices selection | + +------------------------------+----------------------+ + | :cpp:func:`xt::nonzero` | indices selection | + +------------------------------+----------------------+ + | :cpp:func:`xt::argwhere` | indices selection | + +------------------------------+----------------------+ + | :cpp:func:`xt::from_indices` | biulder from indices | + +------------------------------+----------------------+ .. toctree:: basic_functions -+---------------------------------------+----------------------------------------------------+ -| :ref:`abs ` | absolute value | -+---------------------------------------+----------------------------------------------------+ -| :ref:`fabs ` | absolute value | -+---------------------------------------+----------------------------------------------------+ -| :ref:`fmod ` | remainder of the floating point division operation | -+---------------------------------------+----------------------------------------------------+ -| :ref:`remainder ` | signed remainder of the division operation | -+---------------------------------------+----------------------------------------------------+ -| :ref:`fma ` | fused multiply-add operation | -+---------------------------------------+----------------------------------------------------+ -| :ref:`minimum ` | element-wise minimum | -+---------------------------------------+----------------------------------------------------+ -| :ref:`maximum ` | element-wise maximum | -+---------------------------------------+----------------------------------------------------+ -| :ref:`fmin ` | element-wise minimum for floating point values | -+---------------------------------------+----------------------------------------------------+ -| :ref:`fmax ` | element-wise maximum for floating point values | -+---------------------------------------+----------------------------------------------------+ -| :ref:`fdim ` | element-wise positive difference | -+---------------------------------------+----------------------------------------------------+ -| :ref:`clip ` | element-wise clipping operation | -+---------------------------------------+----------------------------------------------------+ -| :ref:`sign ` | element-wise indication of the sign | -+---------------------------------------+----------------------------------------------------+ +.. table:: + :widths: 30 70 + + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::abs` | absolute value | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::fabs` | absolute value | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::fmod` | remainder of the floating point division operation | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::remainder` | signed remainder of the division operation | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::fma` | fused multiply-add operation | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::minimum` | element-wise minimum | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::maximum` | element-wise maximum | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::fmin` | element-wise minimum for floating point values | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::fmax` | element-wise maximum for floating point values | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::fdim` | element-wise positive difference | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::clip` | element-wise clipping operation | + +---------------------------+----------------------------------------------------+ + | :cpp:func:`xt::sign` | element-wise indication of the sign | + +---------------------------+----------------------------------------------------+ .. toctree:: exponential_functions -+---------------------------------------+----------------------------------------------------+ -| :ref:`exp ` | natural exponential function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`exp2 ` | base 2 exponential function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`expm1 ` | natural exponential function, minus one | -+---------------------------------------+----------------------------------------------------+ -| :ref:`log ` | natural logarithm function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`log2 ` | base 2 logarithm function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`log10 ` | base 10 logarithm function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`log1p ` | natural logarithm of one plus function | -+---------------------------------------+----------------------------------------------------+ +.. table:: + :widths: 30 70 + + +-----------------------+-----------------------------------------+ + | :cpp:func:`xt::exp` | natural exponential function | + +-----------------------+-----------------------------------------+ + | :cpp:func:`xt::exp2` | base 2 exponential function | + +-----------------------+-----------------------------------------+ + | :cpp:func:`xt::expm1` | natural exponential function, minus one | + +-----------------------+-----------------------------------------+ + | :cpp:func:`xt::log` | natural logarithm function | + +-----------------------+-----------------------------------------+ + | :cpp:func:`xt::log2` | base 2 logarithm function | + +-----------------------+-----------------------------------------+ + | :cpp:func:`xt::log10` | base 10 logarithm function | + +-----------------------+-----------------------------------------+ + | :cpp:func:`xt::log1p` | natural logarithm of one plus function | + +-----------------------+-----------------------------------------+ .. toctree:: power_functions -+---------------------------------------+----------------------------------------------------+ -| :ref:`pow ` | power function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`sqrt ` | square root function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`cbrt ` | cubic root function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`hypot ` | hypotenuse function | -+---------------------------------------+----------------------------------------------------+ +.. table:: + :widths: 30 70 + + +-----------------------+----------------------+ + | :cpp:func:`xt::pow` | power function | + +-----------------------+----------------------+ + | :cpp:func:`xt::sqrt` | square root function | + +-----------------------+----------------------+ + | :cpp:func:`xt::cbrt` | cubic root function | + +-----------------------+----------------------+ + | :cpp:func:`xt::hypot` | hypotenuse function | + +-----------------------+----------------------+ .. toctree:: trigonometric_functions -+---------------------------------------+----------------------------------------------------+ -| :ref:`sin ` | sine function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`cos ` | cosine function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`tan ` | tangent function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`asin ` | arc sine function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`acos ` | arc cosine function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`atan ` | arc tangent function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`atan2 ` | arc tangent function, determining quadrants | -+---------------------------------------+----------------------------------------------------+ +.. table:: + :widths: 30 70 + + +-----------------------+---------------------------------------------+ + | :cpp:func:`xt::sin` | sine function | + +-----------------------+---------------------------------------------+ + | :cpp:func:`xt::cos` | cosine function | + +-----------------------+---------------------------------------------+ + | :cpp:func:`xt::tan` | tangent function | + +-----------------------+---------------------------------------------+ + | :cpp:func:`xt::asin` | arc sine function | + +-----------------------+---------------------------------------------+ + | :cpp:func:`xt::acos` | arc cosine function | + +-----------------------+---------------------------------------------+ + | :cpp:func:`xt::atan` | arc tangent function | + +-----------------------+---------------------------------------------+ + | :cpp:func:`xt::atan2` | arc tangent function, determining quadrants | + +-----------------------+---------------------------------------------+ .. toctree:: hyperbolic_functions -+---------------------------------------+----------------------------------------------------+ -| :ref:`sinh ` | hyperbolic sine function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`cosh ` | hyperbolic cosine function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`tanh ` | hyperbolic tangent function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`asinh ` | inverse hyperbolic sine function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`acosh ` | inverse hyperbolic cosine function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`atanh ` | inverse hyperbolic tangent function | -+---------------------------------------+----------------------------------------------------+ +.. table:: + :widths: 30 70 + + +-----------------------+-------------------------------------+ + | :cpp:func:`xt::sinh` | hyperbolic sine function | + +-----------------------+-------------------------------------+ + | :cpp:func:`xt::cosh` | hyperbolic cosine function | + +-----------------------+-------------------------------------+ + | :cpp:func:`xt::tanh` | hyperbolic tangent function | + +-----------------------+-------------------------------------+ + | :cpp:func:`xt::asinh` | inverse hyperbolic sine function | + +-----------------------+-------------------------------------+ + | :cpp:func:`xt::acosh` | inverse hyperbolic cosine function | + +-----------------------+-------------------------------------+ + | :cpp:func:`xt::atanh` | inverse hyperbolic tangent function | + +-----------------------+-------------------------------------+ .. toctree:: error_functions -+---------------------------------------+----------------------------------------------------+ -| :ref:`erf ` | error function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`erfc ` | complementary error function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`tgamma ` | gamma function | -+---------------------------------------+----------------------------------------------------+ -| :ref:`lgamma ` | natural logarithm of the gamma function | -+---------------------------------------+----------------------------------------------------+ +.. table:: + :widths: 30 70 + + +------------------------+-----------------------------------------+ + | :cpp:func:`xt::erf` | error function | + +------------------------+-----------------------------------------+ + | :cpp:func:`xt::erfc` | complementary error function | + +------------------------+-----------------------------------------+ + | :cpp:func:`xt::tgamma` | gamma function | + +------------------------+-----------------------------------------+ + | :cpp:func:`xt::lgamma` | natural logarithm of the gamma function | + +------------------------+-----------------------------------------+ .. toctree:: nearint_operations -+---------------------------------------+----------------------------------------------------+ -| :ref:`ceil ` | nearest integers not less | -+---------------------------------------+----------------------------------------------------+ -| :ref:`floor ` | nearest integers not greater | -+---------------------------------------+----------------------------------------------------+ -| :ref:`trunc ` | nearest integers not greater in magnitude | -+---------------------------------------+----------------------------------------------------+ -| :ref:`round ` | nearest integers, rounding away from zero | -+---------------------------------------+----------------------------------------------------+ -| :ref:`nearbyint ` | nearest integers using current rounding mode | -+---------------------------------------+----------------------------------------------------+ -| :ref:`rint ` | nearest integers using current rounding mode | -+---------------------------------------+----------------------------------------------------+ +.. table:: + :widths: 30 70 + + +---------------------------+----------------------------------------------+ + | :cpp:func:`xt::ceil` | nearest integers not less | + +---------------------------+----------------------------------------------+ + | :cpp:func:`xt::floor` | nearest integers not greater | + +---------------------------+----------------------------------------------+ + | :cpp:func:`xt::trunc` | nearest integers not greater in magnitude | + +---------------------------+----------------------------------------------+ + | :cpp:func:`xt::round` | nearest integers, rounding away from zero | + +---------------------------+----------------------------------------------+ + | :cpp:func:`xt::nearbyint` | nearest integers using current rounding mode | + +---------------------------+----------------------------------------------+ + | :cpp:func:`xt::rint` | nearest integers using current rounding mode | + +---------------------------+----------------------------------------------+ .. toctree:: classif_functions -+---------------------------------------+----------------------------------------------------+ -| :ref:`isfinite ` | checks for finite values | -+---------------------------------------+----------------------------------------------------+ -| :ref:`isinf ` | checks for infinite values | -+---------------------------------------+----------------------------------------------------+ -| :ref:`isnan ` | checks for NaN values | -+---------------------------------------+----------------------------------------------------+ -| :ref:`isclose ` | element-wise closeness detection | -+---------------------------------------+----------------------------------------------------+ -| :ref:`allclose ` | closeness reduction | -+---------------------------------------+----------------------------------------------------+ +.. table:: + :widths: 30 70 + + +--------------------------+----------------------------------+ + | :cpp:func:`xt::isfinite` | checks for finite values | + +--------------------------+----------------------------------+ + | :cpp:func:`xt::isinf` | checks for infinite values | + +--------------------------+----------------------------------+ + | :cpp:func:`xt::isnan` | checks for NaN values | + +--------------------------+----------------------------------+ + | :cpp:func:`xt::isclose` | element-wise closeness detection | + +--------------------------+----------------------------------+ + | :cpp:func:`xt::allclose` | closeness reduction | + +--------------------------+----------------------------------+ .. toctree:: reducing_functions -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`sum ` | sum of elements over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`prod ` | product of elements over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`mean ` | mean of elements over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`variance ` | variance of elements over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`stddev ` | standard deviation of elements over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`diff ` | Calculate the n-th discrete difference along the given axis | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`amax ` | amax of elements over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`amin ` | amin of elements over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`trapz ` | Integrate along the given axis using the composite trapezoidal rule | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`norm_l0 ` | L0 pseudo-norm over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`norm_l1 ` | L1 norm over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`norm_sq ` | Squared L2 norm over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`norm_l2 ` | L2 norm over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`norm_linf ` | Infinity norm over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`norm_lp_to_p ` | p_th power of Lp norm over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`norm_lp ` | Lp norm over given axes | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`norm_induced_l1 ` | Induced L1 norm of a matrix | -+-----------------------------------------------+---------------------------------------------------------------------+ -| :ref:`norm_induced_linf ` | Induced L-infinity norm of a matrix | -+-----------------------------------------------+---------------------------------------------------------------------+ +.. table:: + :widths: 30 70 + + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::sum` | sum of elements over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::prod` | product of elements over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::mean` | mean of elements over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::average` | weighted average along the specified axis | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::variance` | variance of elements over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::stddev` | standard deviation of elements over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::diff` | Calculate the n-th discrete difference along the given axis | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::amax` | amax of elements over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::amin` | amin of elements over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::trapz` | Integrate along the given axis using the composite trapezoidal rule | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::norm_l0` | L0 pseudo-norm over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::norm_l1` | L1 norm over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::norm_sq` | Squared L2 norm over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::norm_l2` | L2 norm over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::norm_linf` | Infinity norm over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::norm_lp_to_p` | p_th power of Lp norm over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::norm_lp` | Lp norm over given axes | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::norm_induced_l1` | Induced L1 norm of a matrix | + +-----------------------------------+---------------------------------------------------------------------+ + | :cpp:func:`xt::norm_induced_linf` | Induced L-infinity norm of a matrix | + +-----------------------------------+---------------------------------------------------------------------+ .. toctree:: accumulating_functions -+---------------------------------------------+-------------------------------------------------+ -| :ref:`cumsum ` | cumulative sum of elements over a given axis | -+---------------------------------------------+-------------------------------------------------+ -| :ref:`cumprod ` | cumulative product of elements over given axes | -+---------------------------------------------+-------------------------------------------------+ +.. table:: + :widths: 30 70 + + +-------------------------+------------------------------------------------+ + | :cpp:func:`xt::cumsum` | Cumulative sum of elements over a given axis | + +-------------------------+------------------------------------------------+ + | :cpp:func:`xt::cumprod` | Cumulative product of elements over given axes | + +-------------------------+------------------------------------------------+ .. toctree:: nan_functions -+---------------------------------------------------+------------------------------------------------------------+ -| :ref:`nan_to_num ` | convert NaN and +/- inf to finite numbers | -+---------------------------------------------------+------------------------------------------------------------+ -| :ref:`nansum ` | sum of elements over a given axis, replacing NaN with 0 | -+---------------------------------------------------+------------------------------------------------------------+ -| :ref:`nanprod ` | product of elements over given axes, replacing NaN with 1 | -+---------------------------------------------------+------------------------------------------------------------+ -| :ref:`nancumsum ` | cumsum of elements over a given axis, replacing NaN with 0 | -+---------------------------------------------------+------------------------------------------------------------+ -| :ref:`nancumprod ` | cumprod of elements over given axes, replacing NaN with 1 | -+---------------------------------------------------+------------------------------------------------------------+ +.. table:: + :widths: 30 70 + + +----------------------------+----------------------------------------------------------------------+ + | :cpp:func:`xt::nan_to_num` | Convert NaN and +/- inf to finite numbers | + +----------------------------+----------------------------------------------------------------------+ + | :cpp:func:`xt::nanmin` | Min of elements over a given axis, ignoring NaNs | + +----------------------------+----------------------------------------------------------------------+ + | :cpp:func:`xt::nanmax` | Max of elements over a given axis, ignoring NaNs | + +----------------------------+----------------------------------------------------------------------+ + | :cpp:func:`xt::nansum` | Sum of elements over a given axis, replacing NaN with 0 | + +----------------------------+----------------------------------------------------------------------+ + | :cpp:func:`xt::nanprod` | Product of elements over given axes, replacing NaN with 1 | + +----------------------------+----------------------------------------------------------------------+ + | :cpp:func:`xt::nancumsum` | Cumulative sum of elements over a given axis, replacing NaN with 0 | + +----------------------------+----------------------------------------------------------------------+ + | :cpp:func:`xt::nancumprod` | Cumulative product of elements over given axes, replacing NaN with 1 | + +----------------------------+----------------------------------------------------------------------+ + | :cpp:func:`xt::nanmean` | Mean of elements over given axes, ignoring NaNs | + +----------------------------+----------------------------------------------------------------------+ + | :cpp:func:`xt::nanvar` | Variance of elements over given axes, ignoring NaNs | + +----------------------------+----------------------------------------------------------------------+ + | :cpp:func:`xt::nanstd` | Standard deviation of elements over given axes, ignoring NaNs | + +----------------------------+----------------------------------------------------------------------+ diff --git a/docs/source/api/xnpy.rst b/docs/source/api/xnpy.rst index 39096ebb6..0c1f3320a 100644 --- a/docs/source/api/xnpy.rst +++ b/docs/source/api/xnpy.rst @@ -7,10 +7,12 @@ xnpy: read/write NPY files ========================== -Defined in ``xtensor/xnpy.hpp`` +Defined in ``xtensor/io/xnpy.hpp`` -.. doxygenfunction:: xt::load_npy - :project: xtensor +.. doxygenfunction:: xt::load_npy(std::istream&) -.. doxygenfunction:: xt::dump_npy - :project: xtensor +.. doxygenfunction:: xt::load_npy(const std::string&) + +.. doxygenfunction:: xt::dump_npy(const std::string&, const xexpression&) + +.. doxygenfunction:: xt::dump_npy(const xexpression&) diff --git a/docs/source/api/xoptional_assembly.rst b/docs/source/api/xoptional_assembly.rst index bfdaed18d..e40d6bd9a 100644 --- a/docs/source/api/xoptional_assembly.rst +++ b/docs/source/api/xoptional_assembly.rst @@ -7,8 +7,7 @@ xoptional_assembly ================== -Defined in ``xtensor/xoptional_assembly.hpp`` +Defined in ``xtensor/optional/xoptional_assembly.hpp`` .. doxygenclass:: xt::xoptional_assembly - :project: xtensor :members: diff --git a/docs/source/api/xoptional_assembly_adaptor.rst b/docs/source/api/xoptional_assembly_adaptor.rst index 6e2f31bd8..f58c06690 100644 --- a/docs/source/api/xoptional_assembly_adaptor.rst +++ b/docs/source/api/xoptional_assembly_adaptor.rst @@ -7,8 +7,7 @@ xoptional_assembly_adaptor ========================== -Defined in ``xtensor/xoptional_assembly.hpp`` +Defined in ``xtensor/optional/xoptional_assembly.hpp`` .. doxygenclass:: xt::xoptional_assembly_adaptor - :project: xtensor :members: diff --git a/docs/source/api/xoptional_assembly_base.rst b/docs/source/api/xoptional_assembly_base.rst index 78978a5dc..37fa07427 100644 --- a/docs/source/api/xoptional_assembly_base.rst +++ b/docs/source/api/xoptional_assembly_base.rst @@ -7,8 +7,7 @@ xoptional_assembly_base ======================= -Defined in ``xtensor/xoptional_assembly_base.hpp`` +Defined in ``xtensor/optional/xoptional_assembly_base.hpp`` .. doxygenclass:: xt::xoptional_assembly_base - :project: xtensor :members: diff --git a/docs/source/api/xpad.rst b/docs/source/api/xpad.rst new file mode 100644 index 000000000..971a14d04 --- /dev/null +++ b/docs/source/api/xpad.rst @@ -0,0 +1,22 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xpad +==== + +Defined in ``xtensor/misc/xpad.hpp`` + +.. doxygenenum:: xt::pad_mode + +.. doxygenfunction:: xt::pad(E&& , const std::vector>&, pad_mode, V) + +.. doxygenfunction:: xt::pad(E&& , const std::vector&, pad_mode, V) + +.. doxygenfunction:: xt::pad(E&& , S, pad_mode, V) + +.. doxygenfunction:: xt::tile(E&& , std::initializer_list) + +.. doxygenfunction:: xt::tile(E&& , S) diff --git a/docs/source/api/xrandom.rst b/docs/source/api/xrandom.rst index 4f3be9cf5..c2040e48c 100644 --- a/docs/source/api/xrandom.rst +++ b/docs/source/api/xrandom.rst @@ -7,28 +7,49 @@ xrandom ======= -Defined in ``xtensor/xrandom.hpp`` +Defined in ``xtensor/generators/xrandom.hpp`` + +.. warning:: xtensor uses a lazy generator for random numbers. You need to assign them or use ``eval`` to keep the generated values consistent. .. doxygenfunction:: xt::random::get_default_random_engine - :project: xtensor .. doxygenfunction:: xt::random::seed - :project: xtensor .. doxygenfunction:: xt::random::rand(const S&, T, T, E&) - :project: xtensor .. doxygenfunction:: xt::random::randint(const S&, T, T, E&) - :project: xtensor .. doxygenfunction:: xt::random::randn(const S&, T, T, E&) - :project: xtensor -.. doxygenfunction:: xt::random::choice - :project: xtensor +.. doxygenfunction:: xt::random::binomial(const S&, T, D, E&) + +.. doxygenfunction:: xt::random::geometric(const S&, D, E&) + +.. doxygenfunction:: xt::random::negative_binomial(const S&, T, D, E&) + +.. doxygenfunction:: xt::random::poisson(const S&, D, E&) + +.. doxygenfunction:: xt::random::exponential(const S&, T, E&) + +.. doxygenfunction:: xt::random::gamma(const S&, T, T, E&) + +.. doxygenfunction:: xt::random::weibull(const S&, T, T, E&) + +.. doxygenfunction:: xt::random::extreme_value(const S&, T, T, E&) + +.. doxygenfunction:: xt::random::lognormal(const S&, T, T, E&) + +.. doxygenfunction:: xt::random::chi_squared(const S&, T, E&) + +.. doxygenfunction:: xt::random::cauchy(const S&, T, T, E&) + +.. doxygenfunction:: xt::random::fisher_f(const S&, T, T, E&) + +.. doxygenfunction:: xt::random::student_t(const S&, T, E&) + +.. doxygenfunction:: xt::random::choice(const xexpression&, std::size_t, bool, E&) +.. doxygenfunction:: xt::random::choice(const xexpression&, std::size_t, const xexpression&, bool, E&) .. doxygenfunction:: xt::random::shuffle - :project: xtensor .. doxygenfunction:: xt::random::permutation(T, E&) - :project: xtensor diff --git a/docs/source/api/xreducer.rst b/docs/source/api/xreducer.rst index 1b513d4fd..4e896e099 100644 --- a/docs/source/api/xreducer.rst +++ b/docs/source/api/xreducer.rst @@ -7,11 +7,14 @@ xreducer ======== -Defined in ``xtensor/xreducer.hpp`` +Defined in ``xtensor/reducers/xreducer.hpp`` .. doxygenclass:: xt::xreducer - :project: xtensor :members: -.. doxygenfunction:: xt::reduce(F&&, E&&, X&&, EVS) - :project: xtensor +Available overload families +--------------------------- + +- ``xt::reduce(f, e, axes, options)`` +- ``xt::reduce(f, e, options)`` +- ``xt::reduce(f, e, const I (&axes)[N], options)`` diff --git a/docs/source/api/xrepeat.rst b/docs/source/api/xrepeat.rst new file mode 100644 index 000000000..5e3db7c82 --- /dev/null +++ b/docs/source/api/xrepeat.rst @@ -0,0 +1,13 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xrepeat +======= + +Defined in ``xtensor/views/xrepeat.hpp`` + +.. doxygenclass:: xt::xrepeat + :members: diff --git a/docs/source/api/xsemantic_base.rst b/docs/source/api/xsemantic_base.rst index 2fdbea795..c6062cf91 100644 --- a/docs/source/api/xsemantic_base.rst +++ b/docs/source/api/xsemantic_base.rst @@ -7,8 +7,7 @@ xsemantic_base ============== -Defined in ``xtensor/xsemantic.hpp`` +Defined in ``xtensor/core/xsemantic.hpp`` .. doxygenclass:: xt::xsemantic_base - :project: xtensor :members: diff --git a/docs/source/api/xset_operation.rst b/docs/source/api/xset_operation.rst new file mode 100644 index 000000000..14ea65cda --- /dev/null +++ b/docs/source/api/xset_operation.rst @@ -0,0 +1,21 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xset_operation +============== + +Defined in ``xtensor/misc/xset_operation.hpp`` + +``xt::searchsorted(a, v, right)`` returns insertion indices for values ``v`` +in the sorted array ``a``. + +Available functions +------------------- + +- ``xt::isin(element, test_elements)`` +- ``xt::in1d(element, test_elements)`` +- ``xt::isin(element, begin, end)`` +- ``xt::in1d(element, begin, end)`` diff --git a/docs/source/api/xshape.rst b/docs/source/api/xshape.rst new file mode 100644 index 000000000..72f28b2ea --- /dev/null +++ b/docs/source/api/xshape.rst @@ -0,0 +1,16 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xshape +====== + +Defined in ``xtensor/core/xshape.hpp`` + +.. cpp:namespace-push:: xt + +.. doxygengroup:: xt_xshape + +.. cpp:namespace-pop:: diff --git a/docs/source/api/xsort.rst b/docs/source/api/xsort.rst index bbaaf79a4..082532d52 100644 --- a/docs/source/api/xsort.rst +++ b/docs/source/api/xsort.rst @@ -7,31 +7,10 @@ xsort ===== -Defined in ``xtensor/xsort.hpp`` +Defined in ``xtensor/misc/xsort.hpp`` -.. doxygenfunction:: xt::sort(const xexpression&, placeholders::xtuph) - :project: xtensor +.. cpp:namespace-push:: xt -.. doxygenfunction:: xt::sort(const xexpression&, std::ptrdiff_t) - :project: xtensor +.. doxygengroup:: xt_xsort -.. doxygenfunction:: xt::argsort(const xexpression&, placeholders::xtuph) - :project: xtensor - -.. doxygenfunction:: xt::argsort(const xexpression&, std::ptrdiff_t) - :project: xtensor - -.. doxygenfunction:: xt::argmin(const xexpression&) - :project: xtensor - -.. doxygenfunction:: xt::argmin(const xexpression&, std::size_t) - :project: xtensor - -.. doxygenfunction:: xt::argmax(const xexpression&) - :project: xtensor - -.. doxygenfunction:: xt::argmax(const xexpression&, std::size_t) - :project: xtensor - -.. doxygenfunction:: xt::unique(const xexpression&) - :project: xtensor +.. cpp:namespace-pop:: diff --git a/docs/source/api/xstrided_view.rst b/docs/source/api/xstrided_view.rst index b169df31a..351b09da9 100644 --- a/docs/source/api/xstrided_view.rst +++ b/docs/source/api/xstrided_view.rst @@ -7,20 +7,15 @@ xstrided_view ============= -Defined in ``xtensor/xstrided_view.hpp`` +Defined in ``xtensor/views/xstrided_view.hpp`` .. doxygenclass:: xt::xstrided_view - :project: xtensor :members: .. doxygentypedef:: xt::xstrided_slice_vector - :project: xtensor .. doxygenfunction:: xt::strided_view(E&&, S&&, X&&, std::size_t, layout_type) - :project: xtensor .. doxygenfunction:: xt::strided_view(E&&, const xstrided_slice_vector&) - :project: xtensor .. doxygenfunction:: xt::reshape_view(E&&, S&&, layout_type) - :project: xtensor diff --git a/docs/source/api/xstrides.rst b/docs/source/api/xstrides.rst new file mode 100644 index 000000000..a09540557 --- /dev/null +++ b/docs/source/api/xstrides.rst @@ -0,0 +1,16 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +xstrides +======== + +Defined in ``xtensor/core/xstrides.hpp`` + +.. cpp:namespace-push:: xt + +.. doxygengroup:: xt_xstrides + +.. cpp:namespace-pop:: diff --git a/docs/source/api/xtensor.rst b/docs/source/api/xtensor.rst index ad7ca96bf..f896da812 100644 --- a/docs/source/api/xtensor.rst +++ b/docs/source/api/xtensor.rst @@ -7,14 +7,17 @@ xtensor ======= -Defined in ``xtensor/xtensor.hpp`` +Defined in ``xtensor/containers/xtensor.hpp`` .. doxygenclass:: xt::xtensor_container - :project: xtensor :members: .. doxygentypedef:: xt::xtensor - :project: xtensor .. doxygentypedef:: xt::xtensor_optional - :project: xtensor + +.. doxygenfunction:: xt::from_indices + +.. doxygenfunction:: xt::flatten_indices + +.. doxygenfunction:: xt::ravel_indices diff --git a/docs/source/api/xtensor_adaptor.rst b/docs/source/api/xtensor_adaptor.rst index 26d2d0862..84e21f23e 100644 --- a/docs/source/api/xtensor_adaptor.rst +++ b/docs/source/api/xtensor_adaptor.rst @@ -7,31 +7,7 @@ xtensor_adaptor =============== -Defined in ``xtensor/xtensor.hpp`` +Defined in ``xtensor/containers/xtensor.hpp`` .. doxygenclass:: xt::xtensor_adaptor - :project: xtensor :members: - -adapt (xtensor_adaptor) -======================== - -Defined in ``xtensor/xadapt.hpp`` - -.. doxygenfunction:: xt::adapt(C&&, layout_type) - :project: xtensor - -.. doxygenfunction:: xt::adapt(C&&, const SC&, layout_type) - :project: xtensor - -.. doxygenfunction:: xt::adapt(C&&, SC&&, SS&&) - :project: xtensor - -.. doxygenfunction:: xt::adapt(P&&, typename A::size_type, O, layout_type, const A&) - :project: xtensor - -.. doxygenfunction:: xt::adapt(P&&, typename A::size_type, O, const SC&, layout_type, const A&) - :project: xtensor - -.. doxygenfunction:: xt::adapt(P&&, typename A::size_type, O, SC&&, SS&&, const A&) - :project: xtensor diff --git a/docs/source/api/xview.rst b/docs/source/api/xview.rst index 063d144c0..d9e72ad72 100644 --- a/docs/source/api/xview.rst +++ b/docs/source/api/xview.rst @@ -7,34 +7,28 @@ xview ===== -Defined in ``xtensor/xview.hpp`` +Defined in ``xtensor/views/xview.hpp`` .. doxygenclass:: xt::xview - :project: xtensor - :members: .. doxygenfunction:: xt::view - :project: xtensor -Defined in ``xtensor/xslice.hpp`` +.. doxygenfunction:: xt::row + +.. doxygenfunction:: xt::col + +Defined in ``xtensor/views/xslice.hpp`` .. doxygenfunction:: xt::range(A, B) - :project: xtensor .. doxygenfunction:: xt::range(A, B, C) - :project: xtensor .. doxygenfunction:: xt::all - :project: xtensor .. doxygenfunction:: xt::newaxis - :project: xtensor .. doxygenfunction:: xt::ellipsis - :project: xtensor .. doxygenfunction:: xt::keep(T&&) - :project: xtensor .. doxygenfunction:: xt::drop(T&&) - :project: xtensor diff --git a/docs/source/api/xview_semantic.rst b/docs/source/api/xview_semantic.rst index ad951f84f..211b27223 100644 --- a/docs/source/api/xview_semantic.rst +++ b/docs/source/api/xview_semantic.rst @@ -7,8 +7,7 @@ xview_semantic ============== -Defined in ``xtensor/xsemantic.hpp`` +Defined in ``xtensor/core/xsemantic.hpp`` .. doxygenclass:: xt::xview_semantic - :project: xtensor :members: diff --git a/docs/source/binder-logo.svg b/docs/source/binder-logo.svg index bd8e188ee..d288b74fd 100644 --- a/docs/source/binder-logo.svg +++ b/docs/source/binder-logo.svg @@ -1,36 +1,36 @@ - - + + - - - - - - - - - - - - - - - - - - + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="424.236px" + height="131.176px" viewBox="0 0 212.118 65.883" enable-background="new 0 0 212.118 65.883" xml:space="preserve"> + + + + + + + + + + + + + + + + + + diff --git a/docs/source/bindings.rst b/docs/source/bindings.rst new file mode 100644 index 000000000..54a2a09f0 --- /dev/null +++ b/docs/source/bindings.rst @@ -0,0 +1,286 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Designing language bindings with xtensor +======================================== + +xtensor and its :ref:`related-projects` make it easy to implement a feature once in C++ and expose it +to the main languages of data science, such as Python, Julia and R with little extra work. Although, +if that sounds simple in principle, difficulties may appear when it comes to define the API of the +C++ library. +The following illustrates the different options we have with the case of a single function ``compute`` +that must be callable from all the languages. + +Generic API +----------- + +Since the xtensor bindings provide different container types for holding tensors (pytensor, rtensor +and jltensor), if we want our function to be callable from all the languages, it must accept a generic +argument: + +.. code:: + + template + void compute(E&& e); + +However, this is a bit too generic and we may want to enforce that this function only accepts xtensor +arguments. Since all xtensor containers inherit from the “xexpression” CRTP base class, we can easily +express that constraint with the following signature: + +.. code:: + + template + void compute(const xexpression& e) + { + // Now the implementation must use e() instead of e + } + +Notice that with this change, we lose the ability to call the function with non-constant references or +rvalue references. If we want them back, we need to add the following overloads: + +.. code:: + + template + void compute(xexpression& e); + + template + void compute(xexpression&& e); + +In the following we assume that the constant reference overload is enough. We can now expose the compute +function to the other languages, let’s illustrate this with Python bindings: + +.. code:: + + PYBIND11_MODULE(pymod, m) + { + xt::import_numpy(); + + m.def("compute", &compute>); + } + +Full qualified API +------------------ + +Accepting any kind of expression can still be too permissive; assume we want to restrict this function to +2-dimensional tensor containers only. In that case, a solution is to provide an API function that forwards +the call to a common generic implementation: + +.. code:: + + namespace detail + { + template + void compute_impl(E&&); + } + + template + void compute(const xtensor& t) + { + detail::compute_impl(t); + } + +Exposing it to the Python is just as simple: + +.. code:: + + template + void compute(const pytensor& t) + { + detail::compute_impl(t); + } + + PYBIND11_MODULE(pymod, m) + { + xt::import_numpy(); + + m.def("compute", &compute); + } + +Although this solution is really simple, it requires writing four additional functions for the API. Besides, +if later, you decide to support array containers, you need to add four more functions. Therefore this solution +should be considered for libraries with a small number of functions to expose, and whose APIs are unlikely to +change in the future. + +Container selection +------------------- + +A way to keep the restriction on the parameter type while limiting the required amount of typing in the bindings +is to rely on additional structures that will “select” the right type for us. + +The idea is to define a structure for selecting the type of containers (tensor, array) and a structure to select +the library implementation of that container (xtensor, pytensor in the case of a tensor container): + +.. code:: + + // library container selector + struct xtensor_c + { + }; + + // container selector, must be specialized for each + // library container selector + template + struct tensor_container; + + // Specialization for xtensor library (or C++) + template + struct tensor_container + { + using type = xt::xtensor; + }; + + template + using tensor_container_t = typename tensor_container::type; + +The function signature then becomes + +.. code:: + + template + void compute(const tensor_container_t& t); + +The Python bindings only require that we specialize the ``tensor_container`` structure + +.. code:: + + struct pytensor_c + { + }; + + template + struct tensor_container + { + using type = pytensor; + }; + + PYBIND11_MODULE(pymod, m) + { + xt::import_numpy(); + + m.def("compute", &compute); + } + +Even if we need to specialize the “tensor_container” structure for each language, the specialization can be +reused for other functions and thus reduce the amount of typing required. This comes at a cost though: we’ve +lost type inference on the C++ side. + +.. code:: + + xt::xtensor t {{1., 2., 3.}, {4., 5., 6.}}; + + compute(t); // works + compute(t); // error (couldn't infer template argument 'T') + +Besides, if later we want to support arrays, we need to add an “array_container” structure and its specializations, +and an overload of the compute function: + +.. code:: + + template + struct array_container; + + template + struct array_container + { + using type = xt::xarray; + }; + + template + using array_container_t = typename array_container::type; + + template + void compute(const array_container_t& t); + +Type restriction with SFINAE +---------------------------- + +The major drawback of the previous option is the loss of type inference in C++. The only means to get it back +is to reintroduce a generic parameter type. However, we can make the compiler generate an invalid type so the +function is removed from the overload resolution set when the actual type of the argument does not satisfy +some constraint. This principle is known as SFINAE (Substitution Failure Is Not An Error). Modern C++ provide +metafunctions to help us make use of SFINAE: + +.. code:: + + template + struct is_tensor : std::false_type + { + }; + + template + struct is_tensor> : std::true_type + { + }; + + template class C = is_tensor, + std::enable_if_t::value, bool> = true> + void compute(const T& t); + +Here when ``C::value`` is true, the ``enable_if_t`` invocation generates the bool type. Otherwise, it does +not generate anything, leading to an invalid function declaration. The compiler removes this declaration from +the overload resolution set and no error happens if another “compute” overload is a good match for the call. +Otherwise, the compiler emits an error. + +The default value is here to avoid the need to pass a boolean value when invoking the ``compute`` function; this +value is of no use, we only rely on the SFINAE trick. + +This declaration has a slight problem: adding ``enable_if_t`` to the signature of each function we want to expose +is cumbersome. Let’s make this part more expressive: + +.. code:: + + template class C, class T> + using check_constraints = std::enable_if_t::value, bool>; + template class C = is_tensor, + check_constraints = true> + void compute(const T& t); + +All good, we have type inference and an expressive syntax for declaring our function. Besides, if we want to relax +the constraint so the function can accept both tensors and arrays, all we have to do is to replace the default value +for C: + +.. code:: + + // Equivalent to is_tensor::value || is_array::value + template + struct is_container : xtl::disjunction, is_array> + { + }; + + template class C = is_container, + check_constraints = true> + void compute(const T& t); + +This is far more flexible than the previous option. This flexibility comes at a minor cost: exposing the function to +the Python is slightly more verbose: + +.. code:: + + template + struct is_tensor> : std::true_type + { + }; + + PYBIND11_MODULE(pymod, m) + { + xt::import_numpy(); + + m.def("compute", &compute>); + } + +Conclusion +---------- + +Each solution has its pros and cons and choosing one of them should be done according to the flexibility you want to +impose on your API and the constraints you are imposed by the implementation. For instance, a method that requires a +lot of typing in the bindings might not suit for libraries with a huge number of functions to expose, while a full +generic API might be problematic if the implementation expects containers only. Below is a summary of the advantages +and drawbacks of the different options: + +- Generic API: full genericity, no additional typing required in the bindings, but maybe too permissive. +- Full qualified API: simple, accepts only the specified parameter type, but requires a lot of typing for the bindings. +- Container selection: quite simple, requires less typing than the previous method, but loses type inference on the C++ side and lacks some flexibility. +- Type restriction with SFINAE: more flexible than the previous option, gets type inference back, but slightly more complex to implement. diff --git a/docs/source/build-options.rst b/docs/source/build-options.rst index 5dbeaec3f..25e32ceb9 100644 --- a/docs/source/build-options.rst +++ b/docs/source/build-options.rst @@ -4,70 +4,120 @@ The full license is in the file LICENSE, distributed with this software. +.. _build-configuration: + Build and configuration ======================= -Build ------ +Configuration +------------- + +*xtensor* can be configured via macros which must be defined *before* including +any of its headers. This can be achieved the following ways: + +- either define them in the CMakeLists of your project, with ``target_compile_definitions`` + cmake command. +- or create a header where you define all the macros you want and then include the headers you + need. Then include this header whenever you need *xtensor* in your project. + +The following macros are already defined in *xtensor* but can be overwritten: + +- ``XTENSOR_DEFAULT_DATA_CONTAINER(T, A)``: defines the type used as the default data container for tensors and arrays. ``T`` + is the ``value_type`` of the container and ``A`` its ``allocator_type``. +- ``XTENSOR_DEFAULT_SHAPE_CONTAINER(T, EA, SA)``: defines the type used as the default shape container for tensors and arrays. + ``T`` is the ``value_type`` of the data container, ``EA`` its ``allocator_type``, and ``SA`` is the ``allocator_type`` + of the shape container. +- ``XTENSOR_DEFAULT_LAYOUT``: defines the default layout (row_major, column_major, dynamic) for tensors and arrays. We *strongly* + discourage using this macro, which is provided for testing purpose. Prefer defining alias types on tensor and array + containers instead. +- ``XTENSOR_DEFAULT_TRAVERSAL``: defines the default traversal order (row_major, column_major) for algorithms and iterators on tensors + and arrays. We *strongly* discourage using this macro, which is provided for testing purpose. + +The following macros are helpers for debugging, they are not defined by default: -``xtensor`` build supports the following options: +- ``XTENSOR_ENABLE_ASSERT``: enables assertions in *xtensor*, such as bound check. +- ``XTENSOR_ENABLE_CHECK_DIMENSION``: enables the dimensions check in *xtensor*. Note that this option should not be turned + on if you expect ``operator()`` to perform broadcasting. -- ``BUILD_TESTS``: enables the ``xtest`` and ``xbenchmark`` targets (see below). -- ``DOWNLOAD_GTEST``: downloads ``gtest`` and builds it locally instead of using a binary installation. -- ``GTEST_SRC_DIR``: indicates where to find the ``gtest`` sources instead of downloading them. -- ``XTENSOR_ENABLE_ASSERT``: activates the assertions in ``xtensor``. -- ``XTENSOR_CHECK_DIMENSION``: turns on ``XTENSOR_ENABLE_ASSERT`` and activates dimension checks in ``xtensor``. - Note that the dimensions check should not be activated if you expect ``operator()`` to perform broadcasting. -- ``XTENSOR_USE_XSIMD``: enables simd acceleration in ``xtensor``. This requires that you have xsimd_ installed +.. _external-dependencies: + +External dependencies +--------------------- + +The last group of macros is for using external libraries to achieve maximum performance (see next section for additional +requirements): + +- ``XTENSOR_USE_XSIMD``: enables SIMD acceleration in *xtensor*. This requires that you have xsimd_ installed on your system. +- ``XTENSOR_USE_TBB``: enables parallel assignment loop. This requires that you have tbb_ installed + on your system. +- ``XTENSOR_DISABLE_EXCEPTIONS``: disables c++ exceptions. +- ``XTENSOR_USE_OPENMP``: enables parallel assignment loop using OpenMP. This requires that OpenMP is available on your system. -All these options are disabled by default. Enabling ``DOWNLOAD_GTEST`` or -setting ``GTEST_SRC_DIR`` enables ``BUILD_TESTS``. +Defining these macros in the CMakeLists of your project before searching for *xtensor* will trigger automatic finding +of dependencies, so you don't have to include the ``find_package(xsimd)`` and ``find_package(TBB)`` commands in your +CMakeLists: -If the ``BUILD_TESTS`` option is enabled, the following targets are available: +.. code:: cmake -- xtest: builds an run the test suite. -- xbenchmark: builds and runs the benchmarks. + set(XTENSOR_USE_XSIMD 1) + set(XTENSOR_USE_TBB 1) + # xsimd and TBB dependencies are automatically + # searched when the following is executed + find_package(xtensor REQUIRED) -For instance, building the test suite of ``xtensor`` with assertions enabled: + # the target now sets the proper defines (e.g. "XTENSOR_USE_XSIMD") + target_link_libraries(... xtensor) -.. code:: - mkdir build - cd build - cmake -DBUILD_TESTS=ON -DXTENSOR_ENABLE_ASSERT=ON ../ - make xtest +Build and optimization +---------------------- -Building the test suite of ``xtensor`` where the sources of ``gtest`` are -located in e.g. ``/usr/share/gtest``: +Windows +~~~~~~~ -.. code:: +Windows users must activate the ``/bigobj`` flag, otherwise it's almost certain that the compilation fails. More generally, +the following options are recommended: - mkdir build - cd build - cmake -DGTEST_SRC_DIR=/usr/share/gtest ../ - make xtest +.. code:: cmake -.. _configuration-label: + target_link_libraries(... xtensor xtensor::optimize) + set(CMAKE_EXE_LINKER_FLAGS /MANIFEST:NO) -Configuration -------------- + # OR -``xtensor`` can be configured via macros, which must be defined *before* -including any of its header. Here is a list of available macros: + target_compile_options(target_name PRIVATE /EHsc /MP /bigobj) + set(CMAKE_EXE_LINKER_FLAGS /MANIFEST:NO) -- ``XTENSOR_ENABLE_ASSERT``: enables assertions in xtensor, such as bound check. -- ``XTENSOR_ENABLE_CHECK_DIMENSION``: enables the dimensions check in ``xtensor``. Note that this option should not be turned - on if you expect ``operator()`` to perform broadcasting. -- ``XTENSOR_USE_XSIMD``: enables SIMD acceleration in ``xtensor``. This requires that you have xsimd_ installed - on your system. -- ``XTENSOR_DEFAULT_DATA_CONTAINER(T, A)``: defines the type used as the default data container for tensors and arrays. ``T`` - is the ``value_type`` of the container and ``A`` its ``allocator_type``. -- ``XTENSOR_DEFAULT_SHAPE_CONTAINER(T, EA, SA)``: defines the type used as the default shape container for tensors and arrays. - ``T`` is the ``value_type`` of the data container, ``EA`` its ``allocator_type``, and ``SA`` is the ``allocator_type`` - of the shape container. -- ``XTENSOR_DEFAULT_LAYOUT``: defines the default layout (row_major, column_major, dynamic) for tensors and arrays. We *strongly* - discourage using this macro, which is provided for testing purpose. Prefer defining alias types on tensor and array - containers instead. +If you defined ``XTENSOR_USE_XSIMD``, you must also specify which instruction set you target: + +.. code:: cmake + + target_compile_options(target_name PRIVATE /arch:AVX2) + # OR + target_compile_options(target_name PRIVATE /arch:AVX) + # OR + target_compile_options(target_name PRIVATE /arch:ARMv7VE) + +If you build on an old system that does not support any of these instruction sets, you don't have to specify +anything, the system will do its best to enable the most recent supported instruction set. + +Linux/OSX +~~~~~~~~~ + +Whether you enabled ``XTENSOR_USE_XSIMD`` or not, it is highly recommended to build with ``-march=native`` option, +if your compiler supports it: + +.. code:: cmake + + target_link_libraries(... xtensor xtensor::optimize) + + # OR + + target_compile_options(target_name PRIVATE -march=native) + +Notice that this option prevents building on a machine and distributing the resulting binary on another machine with +a different architecture (i.e. not supporting the same instruction set). -.. _xsimd: https://github.com/QuantStack/xsimd +.. _xsimd: https://github.com/xtensor-stack/xsimd +.. _tbb: https://github.com/uxlfoundation/oneTBB diff --git a/docs/source/builder.rst b/docs/source/builder.rst index 4872b61bc..04b193def 100644 --- a/docs/source/builder.rst +++ b/docs/source/builder.rst @@ -7,45 +7,76 @@ Expression builders =================== -`xtensor` provides functions to ease the build of common N-dimensional expressions. The expressions -returned by these functions implement the laziness of `xtensor`, that is, they don't hold any value. +*xtensor* provides functions to ease the build of common N-dimensional expressions. The expressions +returned by these functions implement the laziness of *xtensor*, that is, they don't hold any value. Values are computed upon request. Ones and zeros -------------- -- ``zeros(shape)``: generates an expression containing zeros of the specified shape. -- ``ones(shape)``: generates an expression containing ones of the specified shape. -- ``eye(shape, k=0)``: generates an expression of the specified shape, with ones on the k-th diagonal. -- ``eye(n, k = 0)``: generates an expression with ones on the k-th diagonal. +- :cpp:func:`xt::zeros(shape) `: generates an expression containing zeros of the specified shape. +- :cpp:func:`xt::ones(shape) `: generates an expression containing ones of the specified shape. +- :cpp:func:`xt::eye(shape, k=0) `: generates an expression of the specified shape, with ones on the k-th diagonal. +- :cpp:func:`xt::eye(n, k = 0) `: generates an expression of shape ``(n, n)`` with ones on the k-th diagonal. Numerical ranges ---------------- -- ``arange(start=0, stop, step=1)``: generates numbers evenly spaced within given half-open interval. -- ``linspace(start, stop, num_samples)``: generates num_samples evenly spaced numbers over given interval. -- ``logspace(start, stop, num_samples)``: generates num_samples evenly spaced on a log scale over given interval +- :cpp:func:`xt::arange(start=0, stop, step=1) `: generates numbers evenly spaced within given half-open interval. +- :cpp:func:`xt::linspace(start, stop, num_samples) `: generates num_samples evenly spaced numbers over given interval. +- :cpp:func:`xt::logspace(start, stop, num_samples) `: generates num_samples evenly spaced on a log scale over given interval Joining expressions ------------------- -- ``concatenate(tuple, axis=0)``: concatenates a list of expressions along the given axis. -- ``stack(tuple, axis=0)``: stacks a list of expressions along the given axis. +- :cpp:func:`xt::concatenate(tuple, axis=0) `: concatenates a list of expressions along the given axis. +- :cpp:func:`xt::stack(tuple, axis=0) `: stacks a list of expressions along the given axis. +- :cpp:func:`xt::hstack(tuple) `: stacks expressions in sequence horizontally (i.e. column-wise). +- :cpp:func:`xt::vstack(tuple) `: stacks expressions in sequence vertically (i.e. row wise). Random distributions -------------------- -- ``rand(shape, lower, upper)``: generates an expression of the specified shape, containing uniformly - distributed random numbers in the half-open interval [lower, upper). -- ``randint(shape, lower, upper)``: generates an expression of the specified shape, containing uniformly - distributed random integers in the half-open interval [lower, upper). -- ``randn(shape, mean, std_dev)``: generates an expression of the specified shape, containing numbers - sampled from the Normal random number distribution. +.. warning:: xtensor uses a lazy generator for random numbers. + You need to assign them or use :cpp:func:`xt::eval` to keep the generated values consistent. + +- :cpp:func:`xt::random::rand(shape, lower, upper) `: generates an expression of the specified + shape, containing uniformly distributed random numbers in the half-open interval [lower, upper). +- :cpp:func:`xt::random::randint(shape, lower, upper) `: generates an expression of the specified + shape, containing uniformly distributed random integers in the half-open interval [lower, upper). +- :cpp:func:`xt::random::randn(shape, mean, std_dev) `: generates an expression of the specified + shape, containing numbers sampled from the Normal random number distribution. +- :cpp:func:`xt::random::binomial(shape, trials, prob) `: generates an expression of the specified + shape, containing numbers sampled from the binomial random number distribution. +- :cpp:func:`xt::random::geometric(shape, prob) `: generates an expression of the specified shape, + containing numbers sampled from the geometric random number distribution. +- :cpp:func:`xt::random::negative_binomial(shape, k, prob) `: generates an expression + of the specified shape, containing numbers sampled from the negative binomial random number distribution. +- :cpp:func:`xt::random::poisson(shape, rate) `: generates an expression of the specified shape, + containing numbers sampled from the Poisson random number distribution. +- :cpp:func:`xt::random::exponential(shape, rate) `: generates an expression of the specified + shape, containing numbers sampled from the exponential random number distribution. +- :cpp:func:`xt::random::gamma(shape, alpha, beta) `: generates an expression of the specified shape, + containing numbers sampled from the gamma random number distribution. +- :cpp:func:`xt::random::weibull(shape, a, b) `: generates an expression of the specified shape, + containing numbers sampled from the Weibull random number distribution. +- :cpp:func:`xt::random::extreme_value(shape, a, b) `: generates an expression of the + specified shape, containing numbers sampled from the extreme value random number distribution. +- :cpp:func:`xt::random::lognormal(shape, a, b) `: generates an expression of the specified + shape, containing numbers sampled from the Log-Normal random number distribution. +- :cpp:func:`xt::random::chi_squared(shape, a, b) `: generates an expression of the specified + shape, containing numbers sampled from the chi-squared random number distribution. +- :cpp:func:`xt::random::cauchy(shape, a, b) `: generates an expression of the specified shape, + containing numbers sampled from the Cauchy random number distribution. +- :cpp:func:`xt::random::fisher_f(shape, m, n) `: generates an expression of the specified shape, + containing numbers sampled from the Fisher-f random number distribution. +- :cpp:func:`xt::random::student_t(shape, n) `: generates an expression of the specified shape, + containing numbers sampled from the Student-t random number distribution. Meshes ------ -- ``meshgrid(x1, x2,...)```: generates N-D coordinate expressions given one-dimensional coordinate arrays ``x1``, ``x2``... +- :cpp:func:`xt::meshgrid(x1, x2,...) `: generates N-D coordinate expressions given + one-dimensional coordinate arrays ``x1``, ``x2``... If specified vectors have lengths ``Ni = len(xi)``, meshgrid returns ``(N1, N2, N3,..., Nn)``-shaped arrays, with the elements of xi repeated to fill the matrix along the first dimension for x1, the second for x2 and so on. - diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 82df393f4..982773051 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -7,43 +7,1487 @@ Changelog ========= +0.27.1 +------ + +- Add tagfiles to support fetching documentation with xeus-cpp-lite + `# 2862 https://github.com/xtensor-stack/xtensor/pull/2862` + +0.27.0 +------ + +- Replaced apply_cv with xtl::apply_cv and deleted duplicated code + `# 2836 https://github.com/xtensor-stack/xtensor/pull/2836` +- Implement apply with std 17 + `# 2835 https://github.com/xtensor-stack/xtensor/pull/2835` +- feat: Use cpp20 by default + `# 2839 https://github.com/xtensor-stack/xtensor/pull/2839` +- Set C++20 in clang-format + `# 2843 https://github.com/xtensor-stack/xtensor/pull/2843` +- Update docs to reflect new directory structure. + `# 2845 https://github.com/xtensor-stack/xtensor/pull/2845` +- Adding concept to a part of the code + `# 2842 https://github.com/xtensor-stack/xtensor/pull/2842` +- fix: update benchmarks + `# 2848 https://github.com/xtensor-stack/xtensor/pull/2848` +- Revive benchmarks + `# 2854 https://github.com/xtensor-stack/xtensor/pull/2854` +- Set cmake min version to represent used features. + `# 2852 https://github.com/xtensor-stack/xtensor/pull/2852` +- Enabling rich display for xeus-cpp-lite + `# 2853 https://github.com/xtensor-stack/xtensor/pull/2853` +- Add braces around initializers + `# 2855 https://github.com/xtensor-stack/xtensor/pull/2855` +- Adding concept to a part of the code (part 2) + `# 2846 https://github.com/xtensor-stack/xtensor/pull/2846` +- cmake: write xtensor.hpp to local dir to keep global build dir clean + `# 2857 https://github.com/xtensor-stack/xtensor/pull/2857` + +0.26.0 +------ + +- Adding the ability to enable memory overlap check in assignment to avoid unneeded temporary memory allocation + `# 2768 https://github.com/xtensor-stack/xtensor/pull/2768` +- Pure xtensor FFT implementation + `# 2782 https://github.com/xtensor-stack/xtensor/pull/2782` +- Update for C++ 20 compatibility + `# 2774 https://github.com/xtensor-stack/xtensor/pull/2774` +- Fixed CI added OSX 13 and GCC 12 + `# 2796 https://github.com/xtensor-stack/xtensor/pull/2796` +- Fix compile issue with clang 19.1.1 + `# 2813 https://github.com/xtensor-stack/xtensor/pull/2813` +- Avoid warnings in compiler version checks + `# 2781 https://github.com/xtensor-stack/xtensor/pull/2781` +- Bump OSX Version 12 -> 13 to avoid deprecated environment + `# 2818 https://github.com/xtensor-stack/xtensor/pull/2818` +- Update gh-pages.yml + `# 2824 https://github.com/xtensor-stack/xtensor/pull/2824` +- Upgraded to xsimd 13.2.0 + `# 2825 https://github.com/xtensor-stack/xtensor/pull/2825` +- Added missing configuration key for RTD + `# 2826 https://github.com/xtensor-stack/xtensor/pull/2826` +- Code reorganization + `# 2829 https://github.com/xtensor-stack/xtensor/pull/2829` +- Adding fix for incorrect usage of xt::has_assign_conversion in xassig + `# 2830 https://github.com/xtensor-stack/xtensor/pull/2830` +- Upgraded to xtl 0.8.0 and C++17 + `# 2831 https://github.com/xtensor-stack/xtensor/pull/2831` +- Migrated to more recent compilers + `# 2832 https://github.com/xtensor-stack/xtensor/pull/2832` +- Fix for Clang19 + `# 2833 https://github.com/xtensor-stack/xtensor/pull/2833` + +0.25.0 +------ + +- Fix conversion warning in xrepeat + `# 2732 https://github.com/xtensor-stack/xtensor/pull/2732` +- Upraded to xsimd 11 + `# 2735 https://github.com/xtensor-stack/xtensor/pull/2735` +- Update to use XTENSOR_DEFAULT_ALIGNMENT when using XSIMD + `# 2739 https://github.com/xtensor-stack/xtensor/pull/2739` +- Removed failing test xinfo on clang 16 + `# 2740 https://github.com/xtensor-stack/xtensor/pull/2740` +- [CI] Switching to mamba-org/setup-micromamba + `# 2742 https://github.com/xtensor-stack/xtensor/pull/2742` +- Bump cmake version and resolve build issues + `# 2744 https://github.com/xtensor-stack/xtensor/pull/2744` +- Make reshape_view accept -1 as a wildcard dimension + `# 2746 https://github.com/xtensor-stack/xtensor/pull/2746` +- Fixing bug in argmin/argmax called with axis on rank-1 container + `# 2753 https://github.com/xtensor-stack/xtensor/pull/2753` +- pre-commit autoupdate + `# 2754 https://github.com/xtensor-stack/xtensor/pull/2754` +- Use L suffix for long double constants + `# 2762 https://github.com/xtensor-stack/xtensor/pull/2762` +- Use 1/4 step for testing arange + `# 2763 https://github.com/xtensor-stack/xtensor/pull/2763` +- [Optimization] Updated concatenate_access and stack_access to remove allocations + `# 2759 https://github.com/xtensor-stack/xtensor/pull/2759` +- [CI] Added more compilers + `# 2767 https://github.com/xtensor-stack/xtensor/pull/2767` +- Minor xindex_view to_array cleanup + `# 2765 https://github.com/xtensor-stack/xtensor/pull/2765` + +0.24.7 +------ + +- Adjust version of required xsimd in README + `# 2670 https://github.com/xtensor-stack/xtensor/pull/2670` +- Add CI through github actions. + `# 2692 https://github.com/xtensor-stack/xtensor/pull/2692` +- Added unwrap + `# 2710 https://github.com/xtensor-stack/xtensor/pull/2710` +- Removed repeated work from ci-extra build + `# 2711 https://github.com/xtensor-stack/xtensor/pull/2711` +- Removed bad macro definitions + `# 2712 https://github.com/xtensor-stack/xtensor/pull/2712` +- Fixing some iterator issues + `# 2564 https://github.com/xtensor-stack/xtensor/pull/2564` +- Fixed static analysis build + `# 2720 https://github.com/xtensor-stack/xtensor/pull/2720` +- Support external linkage for "recurser_run" + `# 2714 https://github.com/xtensor-stack/xtensor/pull/2714` +- add possibility to use std::stable_sort with xt::argsort + `# 2681 https://github.com/xtensor-stack/xtensor/pull/2681` + +0.24.6 +------ + +- Improving documentation xstrides + `# 2664 https://github.com/xtensor-stack/xtensor/pull/2664` +- Parallel and more aggressive strided assigner + `# 2660 https://github.com/xtensor-stack/xtensor/pull/2660` +- Removing duplicates from documentation + `# 2669 https://github.com/xtensor-stack/xtensor/pull/2669` +- Adding aliases xt::xtensor_pointer and xt::xarray_pointer + `# 2665 https://github.com/xtensor-stack/xtensor/pull/2665` +- Fix and refactor partition + `# 2652 https://github.com/xtensor-stack/xtensor/pull/2652` +- Fix and update pre-commit + `# 2657 https://github.com/xtensor-stack/xtensor/pull/2657` + +0.24.5 +------ + +- Add space before pragma diagnostic + `# 2654 https://github.com/xtensor-stack/xtensor/pull/2654` +- Update xtl requirement in cmake + `# 2649 https://github.com/xtensor-stack/xtensor/pull/2649` +- Fix a bug where .fill doesn't work for a xcontainer that is non-contiguous + `# 2650 https://github.com/xtensor-stack/xtensor/pull/2650` + + +0.24.4 +------ + +- Align qualifiers using clang-format + `# 2647 https://github.com/xtensor-stack/xtensor/pull/2647` +- Add xt::quantile + `# 2614 https://github.com/xtensor-stack/xtensor/pull/2614` +- Add swapaxes and moveaxis + `# 2638 https://github.com/xtensor-stack/xtensor/pull/2638` +- Enforce { ... } + `# 2641 https://github.com/xtensor-stack/xtensor/pull/2641` +- Manual style fixes + `# 2642 https://github.com/xtensor-stack/xtensor/pull/2642` +- Do not step further than last element in xreducer_stepper aggregation + `# 2636 https://github.com/xtensor-stack/xtensor/pull/2636` +- Upgraded to xsimd 10.0.0 + `# 2635 https://github.com/xtensor-stack/xtensor/pull/2635` +- Explicitly declare test_xtensor_core_lib as STATIC + `# 2586 https://github.com/xtensor-stack/xtensor/pull/2586` +- fix npy_file move assignment + `# 2585 https://github.com/xtensor-stack/xtensor/pull/2585` +- Install as arch-independent + `# 2588 https://github.com/xtensor-stack/xtensor/pull/2588` +- Change extended tests test header + `# 2630 https://github.com/xtensor-stack/xtensor/pull/2630` +- argmax crashes when compiled using Visual Studio compiler with O1/O2 optimizations + `# 2568 https://github.com/xtensor-stack/xtensor/pull/2568` +- Fix xindexed_view::to_end + `# 2627 https://github.com/xtensor-stack/xtensor/pull/2627` +- Change xindex_view reference type to handle const data + `# 2622 https://github.com/xtensor-stack/xtensor/pull/2622` +- Fix TBB target in CMake exported interface + `# 2617 https://github.com/xtensor-stack/xtensor/pull/2617` +- Document missing xsort functions + `# 2608 https://github.com/xtensor-stack/xtensor/pull/2608` +- Specialize get_strides_type for xbuffer_adaptor + `# 2606 https://github.com/xtensor-stack/xtensor/pull/2606` +- find external packages (threads) after defining project + `# 2575 https://github.com/xtensor-stack/xtensor/pull/2575` + +0.24.3 +------ + +- Rename and fix storage iterator + `#2534 https://github.com/xtensor-stack/xtensor/pull/2534` +- rename storage_rbegin, storage_rend, ... to linear_rbegin, ... + `#2535 https://github.com/xtensor-stack/xtensor/pull/2535` +- Enabling reference value types for xfunction. + `#2532 https://github.com/xtensor-stack/xtensor/pull/2532` +- fixing linear iterator docs. + `#2538 https://github.com/xtensor-stack/xtensor/pull/2538` +- Minor improvements for Windows (MSVC, ClangCl) support + `#2531 https://github.com/xtensor-stack/xtensor/pull/2531` +- changing static layout in xtsrided_view temporary_type to container's layout + `#2553 https://github.com/xtensor-stack/xtensor/pull/2553` +- Upgraded to xsimd 9.0.1 + `#2573 https://github.com/xtensor-stack/xtensor/pull/2573` + +0.24.2 +------ + +- Fixed the documentation of adapt functions + `#2496 https://github.com/xtensor-stack/xtensor/pull/2496` +- Updated C++20 option for visual studio builds C++2a no longer a valid std option + `#2497 https://github.com/xtensor-stack/xtensor/pull/2497` +- Simplifying argmin and argmax where possible + `#2499 https://github.com/xtensor-stack/xtensor/pull/2499` +- Removed unused code + `#2502 https://github.com/xtensor-stack/xtensor/pull/2502` +- Fixed build error in MSVC 2019 by decaying decltype to base type + `#2506 https://github.com/xtensor-stack/xtensor/pull/2506` +- Added xt::convolve + `#2507 https://github.com/xtensor-stack/xtensor/pull/2507` +- Adding reset_data to xbuffer_adaptor and reset_buffer to adaptor to replace the pointer without any reallocation + `#2521 https://github.com/xtensor-stack/xtensor/pull/2521` +- Workaround for EDG C++ frontend bug + `#2528 https://github.com/xtensor-stack/xtensor/pull/2528` +- Adding cast to deal with xtensor-python's signedness of shape + `#2510 https://github.com/xtensor-stack/xtensor/pull/2510` +- Adding missing rank to xtensor_adaptor + `#2520 https://github.com/xtensor-stack/xtensor/pull/2520` +- Fixing compiler warning + `#2522 https://github.com/xtensor-stack/xtensor/pull/2522` + +0.24.1 +------ + +- Define tbb threshold + `#2455 https://github.com/xtensor-stack/xtensor/pull/2455` +- Export link interface to tbb + `#2456 https://github.com/xtensor-stack/xtensor/pull/2456` +- has_trivial_default_constructor has been removed from libstdc++ since version 7. + `#2459 https://github.com/xtensor-stack/xtensor/pull/2459` +- Added missing headers in CMake + `#2462 https://github.com/xtensor-stack/xtensor/pull/2462` +- Workaround for CMake implementations that do not use C and CXX languages + `#2467 https://github.com/xtensor-stack/xtensor/pull/2467` +- Fix erroneous less_equal usage in is_sorted calls + `#2471 https://github.com/xtensor-stack/xtensor/pull/2471` +- Adding xt::missing to operator() + `#2488 https://github.com/xtensor-stack/xtensor/pull/2488` +- Silence unused variable warning GCC + `#2494 https://github.com/xtensor-stack/xtensor/pull/2494` +- Adding xt::missing functionality to .periodic(...), .at(...), and .in_bounds(...) + `#2493 https://github.com/xtensor-stack/xtensor/pull/2493` +- Fixing internal types + `#2492 https://github.com/xtensor-stack/xtensor/pull/2492` +- Adding size assertion .flat(i) + adding a few tests on size assertions + `#2388 https://github.com/xtensor-stack/xtensor/pull/2388` +- Adding free function xt::strides + `#2489 https://github.com/xtensor-stack/xtensor/pull/2489` + +0.24.0 +------ + +- Comparison of shapes with differnt types is now supported + `#2393 https://github.com/xtensor-stack/xtensor/pull/2393` +- Ported tests to doctest + `#2405 https://github.com/xtensor-stack/xtensor/pull/2405` +- Updated docs of argmin and argmax + `#2425 https://github.com/xtensor-stack/xtensor/pull/2425` +- blockwise reducers intital implementation + `#2415 https://github.com/xtensor-stack/xtensor/pull/2415` +- Fixed comparison of double in some tests + `#2436 https://github.com/xtensor-stack/xtensor/pull/2436` +- Upgraded to xsimd 8 + `#2438 https://github.com/xtensor-stack/xtensor/pull/2438` + +0.23.10 +------- + +- Performance fix: set m_strides_computed = true after computing + `#2377 https://github.com/xtensor-stack/xtensor/pull/2377` +- argsort: catching zeros stride leading axis (bugfix) + `#2238 https://github.com/xtensor-stack/xtensor/pull/2238` +- Adding ``.flat(i)`` + `#2356 https://github.com/xtensor-stack/xtensor/pull/2356` +- Fixed ``check_index`` function + `#2378 https://github.com/xtensor-stack/xtensor/pull/2378` +- Fixing & -> && in histogram + `#2386 https://github.com/xtensor-stack/xtensor/pull/2386` +- Adding ``front()`` and ``back()`` convenience methods + `#2385 https://github.com/xtensor-stack/xtensor/pull/2385` +- Adding description of index operators + `#2387 https://github.com/xtensor-stack/xtensor/pull/2387` +- flip: adding overload without axis (mimics NumPy) + `#2373 https://github.com/xtensor-stack/xtensor/pull/2373` +- average: fixing overload issue for axis argument + `#2374 https://github.com/xtensor-stack/xtensor/pull/2374` + +0.23.9 +------ + +- Fix data_offset method in xview to compute the strides only once + `#2371 https://github.com/xtensor-stack/xtensor/pull/2371` + +0.23.8 +------ + +- Specialize operator= when RHS is chunked + `#2367 https://github.com/xtensor-stack/xtensor/pull/2367` + +0.23.7 +------ + +- Fixed chunked_iterator + `#2365 https://github.com/xtensor-stack/xtensor/pull/2365` + +0.23.6 +------ + +- Update installation instructions to mention mamba + `#2357 https://github.com/xtensor-stack/xtensor/pull/2357` +- Fixed grid_shape return type + `#2360 https://github.com/xtensor-stack/xtensor/pull/2360` +- Added assertion in resize method + `#2361 https://github.com/xtensor-stack/xtensor/pull/2361` +- Added const chunk iterators + `#2362 https://github.com/xtensor-stack/xtensor/pull/2362` +- Fixed chunk assignment + `#2363 https://github.com/xtensor-stack/xtensor/pull/2363` + +0.23.5 +------ + +- No need to explicitly install blas anymore with latest xtensor-blas + `#2343 https://github.com/xtensor-stack/xtensor/pull/2343` +- FIX for xtensor-stack/xtl/issues/245 + `#2344 https://github.com/xtensor-stack/xtensor/pull/2344` +- Implement grid view + `#2346 https://github.com/xtensor-stack/xtensor/pull/2346` +- Refactoring of xchunked_view + `#2353 https://github.com/xtensor-stack/xtensor/pull/2353` + +0.23.4 +------ + +- Fix edge chunk assignment + `#2342 https://github.com/xtensor-stack/xtensor/pull/2342` + +0.23.3 +------ + +- Use the correct version file for TBB since 2021.1 + `#2334 https://github.com/xtensor-stack/xtensor/pull/2334` +- Add missing API RTD for nan functions + `#2333 https://github.com/xtensor-stack/xtensor/pull/2333` +- Fixed layout issue in container classes + `#2335 https://github.com/xtensor-stack/xtensor/pull/2335` +- Fixed assignment of a tensor_view on a pseudo-container + `#2336 https://github.com/xtensor-stack/xtensor/pull/2336` +- Fixed return type of data method + `#2338 https://github.com/xtensor-stack/xtensor/pull/2338` +- Fixed assignment to flatten view + `#2339 https://github.com/xtensor-stack/xtensor/pull/2339` + +0.23.2 +------ + +- MSVC Build: Wrapped linker flags in quotes + `#2299 https://github.com/xtensor-stack/xtensor/pull/2299` +- Added can_assign and enable_assignable_expression + `#2323 https://github.com/xtensor-stack/xtensor/pull/2323` +- Fix automatically generated tests + `#2313 https://github.com/xtensor-stack/xtensor/pull/2313` +- Fix linspace endpoint bug + `#2306 https://github.com/xtensor-stack/xtensor/pull/2306` +- Added fallback to old behavior in FindTBB.cmake + `#2325 https://github.com/xtensor-stack/xtensor/pull/2325` +- Implement nanmin and nanmax + `#2314 https://github.com/xtensor-stack/xtensor/pull/2314` +- Clean up and add more tests for nanmin and nanmax + `#2326 https://github.com/xtensor-stack/xtensor/pull/2326` +- Fix linespace with only one point + `#2327 https://github.com/xtensor-stack/xtensor/pull/2327` +- Fixed ambiguous call of tile + `#2329 https://github.com/xtensor-stack/xtensor/pull/2329` + +0.23.1 +------ + +- Fix compilation warnings on unused local typedefs + `#2295 https://github.com/xtensor-stack/xtensor/pull/2295` +- Disable a failing shuffle test for clang + `#2294 https://github.com/xtensor-stack/xtensor/pull/2294` +- Fix simd assign_data + `#2292 https://github.com/xtensor-stack/xtensor/pull/2292` +- Fix -Wshadow and -Wunused-local-typedef warning + `#2293 https://github.com/xtensor-stack/xtensor/pull/2293` +- Documentation improvement Part #B + `#2287 https://github.com/xtensor-stack/xtensor/pull/2287` + +0.23.0 +------ + +Breaking changes +~~~~~~~~~~~~~~~~ + +- Remove chunked array extension mechanism + `#2283 `_ +- Upgraded to xtl 0.7.0 + `#2284 `_ + +Other changes +~~~~~~~~~~~~~ + +- Harmonize #include statements in doc + `#2280 `_ +- Added missing shape_type in xfunctor_stepper + `#2285 `_ + +0.22.0 +------ + +Breaking changes +~~~~~~~~~~~~~~~~ + +- Drop support of 3.* Clang versions + `#2251 `_ +- Fix reducers assignment + `#2254 `_ +- Removed reducer ``big_promote_type`` + `#2277 `_ + +Other changes +~~~~~~~~~~~~~ + +- Improve histogram performance with equal bin sizes + `#2088 `_ +- Added missing header in xfixed + `#2225 `_ +- Implement xt::random::choice with weights vector + `#2241 `_ +- Testing alignment + `#2246 `_ +- Add reducers tests + `#2252 `_ +- Fix binary operators on complex + `#2253 `_ +- Removed not implemented assign method from xchunked_array + `#2256 `_ +- Support initialized list for chunked_array shapes + `#2258 `_ +- Add as_strided free function + `#2261 `_ +- Fix histogram compatibility with containers beyond xtensor + `#2263 `_ +- Fixed broadcasting with keep_slice that holds a single element + `#2270 `_ +- Make xt::cast and xtl::optional compatible + `#2271 `_ +- Fix minor warnings detected by clang + `#2272 `_ +- Extra assert in mean computation wrt. ddof + `#2273 `_ +- Provide a -Werror mode and ensure xtensor passes with it + `#2274 `_ +- Moved layout_remove_any to xlayout.hpp + `#2275 `_ +- Provide a -Werror mode and ensure xtensor passes with it + `#2274 `_ +- Slight reorganization of the documentation + `#2276 `_ +- Updated reducer docs according to recent changes + `#2278 `_ +- Added template parameter for initial value type in accumulators + `#2279 `_ + +0.21.10 +------- + +- Document chunked arrays + `#2102 `_ +- Removed ``zarray`` files + `#2221 `_ +- Improved ``xeval`` + `#2223 `_ +- Fixed various warnings + `#2224 `_ + +0.21.9 +------ + +- Adding macro ``XTENSOR_SELECT_ALIGN`` + `#2152 `_ +- xcontainer.hpp: Renamed a shadowing type name inside a function + `#2208 `_ +- Add chunk_memory_layout to chunked_array factory + `#2211 `_ +- CMake: Modernized GTest-integration + `#2212 `_ +- ``xnpy.hpp``: fix multiple definition of 'host_endian_char' variable when included in different linked objects + `#2214 `_ +- Made global variable const to force internal linkage + `#2216 `_ +- Use xtl::endianness instead of bundling it + `#2218 `_ +- Fix call to resize of chunk container + `#2219 `_ + +0.21.8 +------ + +- Fix undefined behavior while testing shifts + `#2175 `_ +- Fix ``zarray`` initialization from ``zarray`` + `#2180 `_ +- Portable and generic implementation of endianess detection + `#2182 `_ +- Fix xnpy save padding computation + `#2183 `_ +- Only use ``-march=native`` if it's available + `#2184 `_ +- Fix ``xchunked_array`` assignment + `#2177 `_ +- Add specific ``xchunked_array`` constructor for ``xchunk_store_manager`` + `#2188 `_ +- Make xnpy tests aware of both little and big endian targets + `#2189 `_ +- Fixed constructors of ``xchunked_array`` + `#2190 `_ +- First implementation of ``zchunked_wrapper`` + `#2193 `_ +- Don't mark dirty a resized or reshaped ``xfile_array`` + `#2194 `_ +- Replaced catch-all constructor of ``zarray`` with more restrictive ones + `#2195 `_ +- Fixed SFINAE based on ``xchunked_store_manager`` + `#2197 `_ +- Fix generated cmake config to include missing required lib + `#2200 `_ +- Add ``set_chunk_shape`` to the first chunk of the pool + `#2198 `_ +- Chunked array refactoring + `#2201 `_ +- Refactored ``xchunked_array`` semantic + `#2202 `_ +- Added missing header to CMakeLists.txt + `#2203 `_ +- Fixed ``load_simd`` for ``xcomplex`` + `#2204 `_ +- Upgraded to xtl 0.6.20 + `#2206 `_ +- changed std traits to new ``xtl::xtraits`` + `#2205 `_ +- ``xstorage.hpp``: Renamed a shadowing variable inside a function + `#2207 `_ + +0.21.7 +------ + +- Removed zheaders from single header + `#2157 `_ +- Implemented insertion of range and intializer list in svector + `#2165 `_ +- Adding has_shape + `#2163 `_ +- Adding get_rank and has_fixed_rank + `#2162 `_ +- Zrefactoring + `#2140 `_ +- Added missing header + `#2169 `_ +- Extending docs random + `#2173 `_ + +0.21.6 +------ + +- Added implementation of ``isin`` and ``in1d`` + `#2021 `_ +- Wrote single include header + `#2031 `_ +- Added details for ``xt::random`` to docs + `#2043 `_ +- Added ``digitize``, ``searchsorted``, and ``bin_items`` + `#2037 `_ +- Fixed error with zero tensor size in ``xt::mean`` + `#2047 `_ +- Fixed initialization order in ``xfunction`` + `#2050 `_ +- ``adapt_smart_ptr`` overloads now accept STL-like container as shape + `#2052 `_ +- Added ``xchunked_array`` + `#2076 `_ +- ``xchunked_array`` inherits from ``xiterable`` + `#2082 `_ +- ``xchunked_array`` inherits from ``xcontainer_semantic`` + `#2083 `_ +- Fixed assignment operator of ``xchunked_array`` + `#2084 `_ +- Added constructors from ``xexpression`` and ``chunk_shape`` to ``xchunked_array`` + `#2087 `_ +- Fixed chunk layout + `#2091 `_ +- Copy constructor gets expression's chunk_shape if it is chunked + `#2092 `_ +- Replaced template parameter chunk_type with chunk_storage + `#2095 `_ +- Implemented on-disk chunked array + `#2096 `_ +- Implemented chunk pool in xchunk_store_manager + `#2099 `_ +- ``xfile_array`` is now an expression + `#2107 `_ +- ``xchunked_array`` code cleanup + `#2109 `_ +- ``xchunked_store_manager`` code cleanup + `#2110 `_ +- Refactored ``xfile_array`` + `#2117 `_ +- Added simd accessors to ``xfil_array_container`` + `#2118 `_ +- Abstracted file format through a formal class + `#2115 `_ +- Added ``xchunked_array`` extension template + `#2122 `_ +- Refactored ``xdisk_io_handler`` + `#2123 `_ +- Fixed exception for file write operation + `#2125 `_ +- Implemented ``zarray`` + `#2127 `_ +- Implemented the skeleton of the dynamic expression system + `#2129 `_ +- Implemented zfunctions, equivalent of xfunction for dynamic expression system + `#2130 `_ +- Implemented ``allocate_result`` in ``zfunction`` + `#2132 `_ +- Implemented assign mechanism for ``zarray`` + `#2133 `_ +- Added xindex_path to transform indexes into path + `#2131 `_ +- Fixing various compiler warnings + `#2145 `_ +- Removed conversion and initialization warnings + `#2141 `_ + +0.21.5 +------ + +- Fix segfault when using ``xt::drop`` on an empty list of indices + `#1990 `_ +- Implemented missing methods in ``xrepeat`` class + `#1993 `_ +- Added extension base to ``xrepeat`` and clean up ``xbroadcast`` + `#1994 `_ +- Fix return type of ``nanmean`` and add unittest + `#1996 `_ +- Add result type template argument for ``stddev``, ``variance``, ``nanstd`` and ``nanvar`` + `#1999 `_ +- Fix variance overload + `#2002 `_ +- Added missing ``xaxis_slice_iterator`` header to CMakeLists.txt + `#2009 `_ +- Fixed xview on const keep and const drop slices + `#2010 `_ +- Added ``static_assert`` to ``adapt`` methods + `#2015 `_ +- Removed allocator deprecated calls + `#2018 `_ +- Added missing overload of ``push_back`` to ``svector`` + `#2024 `_ +- Initialized all members of ``xfunciton_cache_impl`` + `#2026 `_ + +0.21.4 +------ + +- Fix warning -Wsign-conversion in ``xview`` + `#1902 `_ +- Fixed issue due to thread_local storage on some architectures + `#1905 `_ +- benchmark/CMakeLists.txt: fixed a tiny spelling mistake + `#1904 `_ +- nd-iterator implementation + `#1891 `_ +- Add GoatCounter analytics for the documentation + `#1908 `_ +- Added ``noexcept`` in ``svector`` + `#1919 `_ +- Add implementation of repeat (similar to NumPy) + `#1896 `_ +- Fix initialization of out shape in ``xt::tile`` + `#1923 `_ +- ``xaxis_slice_iterator`` – Iterates over 1D slices oriented along the specified axis + `#1916 `_ +- Fixed cxx11 lib guard + `#1925 `_ +- Fixed CXX11 ABI when _GLIBCXX_USE_DUAL_ABI is set to 0 + `#1927 `_ +- Enabling array-bounds warning + `#1933 `_ +- Fixed warnings + `#1934 `_ +- Compile with g++ instead of gcc, clarify include directories + `#1938 `_ +- broadcast function now accepts fixed shapes + `#1939 `_ +- Don't print decimal point after ``inf`` or ``nan`` + `#1940 `_ +- Improved performance of ``xt::tile`` + `#1943 `_ +- Refactoring CI + `#1942 `_ +- Documentation build: Switched to channel QuantStack + `#1948 `_ +- Removed warnings due to gtest upgrade + `#1949 `_ +- Fixed flatten view of view + `#1950 `_ +- Improved narrative documentation of reducers + `#1958 `_ +- Add test for printing xarray of type ``size_t`` + `#1947 `_ +- Added documentation for iterators + `#1961 `_ +- Fixed ``check_element_index`` behavior for 0-D expressions + `#1965 `_ +- Fixed ``element`` method of xreducer + `#1966 `_ +- Fixed ``cast`` for third-party types + `#1967 `_ +- fix ``xoperation`` + `#1790 `_ +- Added installation instruction with MinGW + `#1969 `_ +- ``xrepeat`` now stores ``const_xclosure_t`` instead of ``E`` + `#1968 `_ +- Fixed ``argpartition`` leading axis test + `#1971 `_ +- Added tests with C++20 enabled + `#1974 `_ +- Added documentation for ``repeat`` + `#1975 `_ +- Fixed sort and partition + `#1976 `_ +- xt::view now supports negative indices + `#1979 `_ + +0.21.3 +------ + +- Allow use of cmake add_subdirectory(xtensor) by checking for xtl target + `#1865 `_ +- Simplifying CMake config + `#1856 `_ +- Fixed ``reshape`` with signed integers + `#1867 `_ +- Disabled MSVC iterator checks + `#1874 `_ +- Added covariance function + `#1847 `_ +- Fix for older cmake + `#1880 `_ +- Added row and col facade for 2-D contianers + `#1876 `_ +- Implementation of ``xt::tile`` + `#1888 `_ +- Fixed ``reshape`` return + `#1886 `_ +- Enabled ``add_subdirectory`` for *xsimd* + `#1889 `_ +- Support ``ddof`` argument for ``xt::variance`` + `#1893 `_ +- Set -march=native only if the user did not set another -march already + `#1899 `_ +- Assemble new container in ``xpad`` + `#1808 `_ + +0.21.2 +------ + +- Upgraded to gtest 1.10.0 + `#1859 `_ +- Upgraded to xsimd 7.4.4 + `#1864 `_ +- Removed allocator deprecated calls + `#1862 `_ + +0.21.1 +------ + +- Added circular includes check + `#1853 `_ +- Removed cricular dependencies + `#1854 `_ + +0.21.0 +------ + +Breaking changes +~~~~~~~~~~~~~~~~ + +- Dynamic SIMD assign + `#1762 `_ + +Other changes +~~~~~~~~~~~~~ + +- Updated links to other projects + `#1773 `_ +- Updated license + `#1774 `_ +- Updated related projects + `#1775 `_ +- Fixed ``has_simd_interface`` for non existing ``simd_return_type`` + `#1779 `_ +- Added average overload for default equal weights + `#1789 `_ +- Implemented concatenation of ``fixed_shape`` tensors + `#1793 `_ +- Replaced ``new`` with ``unique_ptr`` in headers + `#1800 `_ +- Fixed reallocation when an ``xbuffer`` is copied over + `#1799 `_ +- Added hte ability to use the library with ``-fnoexception`` + `#1801 `_ +- Minor efficiency improvement + `#1807 `_ +- Unified ``xt::concatenate`` and ``xt::concatenate_fixed`` + `#1805 `_ +- Have ``reshape`` method return a reference to self + `#1813 `_ +- Enabling tests of ``xtensor_fixed`` on Windows with clang. + `#1815 `_ +- Disabled SIMD assignment when bool conversion occurs + `#1818 `_ +- Speed up views, added SIMD interface to strided views + `#1627 `_ +- Fixed assignment of scalar to complex + `#1828 `_ +- Fixed concurrency issue in ``flat_expression_adaptor`` + `#1831 `_ +- Implemented an equivalent to ``numpy.roll`` + `#1823 `_ +- Upgraded to ``xtl 0.6.9`` + `#1839 `_ +- Fixed type of OpenMP's index variable on Windows + `#1838 `_ +- Implemented ``hstack`` and ``vstack`` + `#1841 `_ +- Implemented ``hsplit`` and ``vsplit`` + `#1842 `_ +- Fixed behavior of ``diff`` when ``n`` is greater thant the number of elements + `#1843 `_ +- Added treshold to OpenMP parallelization + `#1849 `_ +- Added missing assign operator in ``xmasked_view`` + `#1850 `_ +- Updated CMake target + `#1851 `_ + +0.20.10 +------- + +- Simplified functors definition + `#1756 `_ +- Fixed ``container_simd_return_type`` + `#1759 `_ +- Fixed reducer init for ``xtensor_fixed`` value type + `#1761 `_ + +0.20.9 +------ + +- Added alias to check if type is ``xsemantic_base`` + `#1673 `_ +- Added missing include ``xoperation.hpp`` + `#1674 `_ +- Moved XSIMD and TBB dependencies to tests only + `#1676 `_ +- Added missing coma + `#1680 `_ +- Added NumPy-like parameter in ``load_csv`` + `#1682 `_ +- Added ``shape()`` method to ``xshape.hpp`` + `#1592 `_ +- Added shape print tip to docs + `#1693 `_ +- Fix lvalue npy_file heap corruption in MSVC + `#1697 `_ +- Fix UB when parsing 1-dimension npy + `#1696 `_ +- Fixed compiler error (missing ``shape`` method in ``xbroadcast`` and ``xscalar``) + `#1699 `_ +- Added: deg2rad, rad2deg, degrees, radians + `#1700 `_ +- Despecialized xt::to_json and xt::from_json + `#1691 `_ +- Added coverity + `#1577 `_ +- Additional configuration for future coverity branch + `#1712 `_ +- More tests for coverity + `#1714 `_ +- Update README.md for Conan installation instructions + `#1717 `_ +- Reset stream's flags after output operation + `#1718 `_ +- Added missing include in ``xview.hpp`` + `#1719 `_ +- Removed usage of allocator's members that are deprecated in C++17 + `#1720 `_ +- Added tests for mixed assignment + `#1721 `_ +- Fixed ``step_simd`` when underlying iterator holds an ``xscalar_stepper`` + `#1724 `_ +- Fixed accumulator for empty arrays + `#1725 `_ +- Use ``temporary_type`` in implementation of ``xt::diff`` + `#1727 `_ +- CMakeLists.txt: bumped up xsimd required version to 7.2.6 + `#1728 `_ +- Fixed reducers on empty arrays + `#1729 `_ +- Implemented additional random distributions + `#1708 `_ +- Fixed reducers: passing the same axis many times now throws + `#1730 `_ +- Made ``xfixed_container`` optionally sharable + `#1733 `_ +- ``step_simd`` template parameter is now the value type instead of the simd type + `#1736 `_ +- Implemented OpenMP Parallelization. + `#1739 `_ +- Readme improvements + `#1741 `_ +- Vectorized ``xt::where`` + `#1738 `_ +- Fix typos and wording in documentation + `#1745 `_ +- Upgraded to xtl 0.6.6. and xsimd 7.4.0 + `#1747 `_ +- Improve return value type for ``nanmean`` + `#1749 `_ +- Allows (de)serialization of xexpressions in NumPy formatted strings and streams + `#1751 `_ +- Enabled vectorization of boolean operations + `#1748 `_ +- Added the list of contributors + `#1755 `_ + +0.20.8 +------ + +- Added traversal order to ``argwhere`` and ``filter`` + `#1672 `_ +- ``flatten`` now returns the new type ``xtensor_view`` + `#1671 `_ +- Error case handling in ``concatenate`` + `#1669 `_ +- Added assign operator from ``temporary_type`` in ``xiterator_adaptor`` + `#1668 `_ +- Improved ``index_view`` examples + `#1667 `_ +- Updated build option section of the documentation + `#1666 `_ +- Made ``xsequence_view`` convertible to arbitrary sequence type providing iterators + `#1657 `_ +- Added overload of ``is_linear`` for expressions without ``strides`` method + `#1655 `_ +- Fixed reverse ``arange`` + `#1653 `_ +- Add warnings for random number generation + `#1652 `_ +- Added common pitfalls section in the documentation + `#1649 `_ +- Added missing ``shape`` overload in ``xfunction`` + `#1650 `_ +- Made ``xconst_accessible::shape(std::size_t)`` visible in ``xview`` + `#1645 `_ +- Diff: added bounds-check on maximal recursion + `#1640 `_ +- Add ``xframe`` to related projects + `#1635 `_ +- Update ``indice.rst`` + `#1626 `_ +- Remove unecessary arguments + `#1624 `_ +- Replace ``auto`` with explicit return type in ``make_xshared`` + `#1621 `_ +- Add `z5` to related projects + `#1620 `_ +- Fixed long double complex offset views + `#1614 `_ +- Fixed ``xpad`` bugs + `#1607 `_ +- Workaround for annoying bug in VS2017 + `#1602 `_ + +0.20.7 +------ + +- Fix reshape view assignment and allow setting traversal order + `#1598 `_ + +0.20.6 +------ + +- Added XTENSOR_DEFAULT_ALIGNMENT macro + `#1597 `_ +- Added missing comparison operators for const_array + `#1596 `_ +- Fixed reducer for expression with shape containing 0 + `#1595 `_ +- Very minor spelling checks in comments + `#1591 `_ +- tests can be built in debug mode + `#1589 `_ +- strided views constructors forward shape argument + `#1587 `_ +- Remove unused type alias + `#1585 `_ +- Fixed reducers with empty list of axes + `#1582 `_ +- Fix typo in builder docs + `#1581 `_ +- Fixed return type of data in xstrided_view + `#1580 `_ +- Fixed reducers on expression with shape containing 1 as first elements + `#1579 `_ +- Fixed xview::element for range with more elements than view's dimension + `#1578 `_ +- Fixed broadcasting of shape containing 0-sized dimensions + `#1575 `_ +- Fixed norm return type for complex + `#1574 `_ +- Fixed iterator incremented or decremented by 0 + `#1572 `_ +- Added complex exponential test + `#1571 `_ +- Strided views refactoring + `#1569 `_ +- Add clang-cl support + `#1559 `_ + +0.20.5 +------ + +- Fixed ``conj`` + `#1556 `_ +- Fixed ``real``, ``imag``, and ``functor_view`` + `#1554 `_ +- Allows to include *xsimd* without defining ``XTENSOR_USE_XSIMD`` + `#1548 `_ +- Fixed ``argsort`` in column major + `#1547 `_ +- Fixed ``assign_to`` for ``arange`` on ``double`` + `#1541 `_ +- Fix example code in container.rst + `#1544 `_ +- Removed return value from ``step_leading`` + `#1536 `_ +- Bugfix: amax + `#1533 `_ +- Removed extra ; + `#1527 `_ + +0.20.4 +------ + +- Buffer adaptor default constructor + `#1524 `_ + +0.20.3 +------ + +- Fix xbuffer adaptor + `#1523 `_ + +0.20.2 +------ + +- Fixed broadcast linear assign + `#1493 `_ +- Fixed ``do_stirdes_match`` + `#1497 `_ +- Removed unused capture + `#1499 `_ +- Upgraded to *xtl* 0.6.2 + `#1502 `_ +- Added missing methods in ``xshared_expression`` + `#1503 `_ +- Fixed iterator types of ``xcontainer`` + `#1504 `_ +- Typo correction in external-structure.rst + `#1505 `_ +- Added extension base to adaptors + `#1507 `_ +- Fixed shared expression iterator methods + `#1509 `_ +- Strided view fixes + `#1512 `_ +- Improved range documentation + `#1515 `_ +- Fixed ``ravel`` and ``flatten`` implementation + `#1511 `_ +- Fixed ``xfixed_adaptor`` temporary assign + `#1516 `_ +- Changed struct -> class in ``xiterator_adaptor`` + `#1513 `_ +- Fxed ``argmax`` for expressions with strides 0 + `#1519 `_ +- Add ``has_linear_assign`` to ``sdynamic_view`` + `#1520 `_ + +0.20.1 +------ + +- Add a test for mimetype rendering and fix forward declaration + `#1490 `_ +- Fix special case of view iteration + `#1491 `_ + +0.20.0 +------ + +Breaking changes +~~~~~~~~~~~~~~~~ + +- Removed ``xmasked_value`` and ``promote_type_t`` + `#1389 `_ +- Removed deprecated type ``slice_vector`` + `#1459 `_ +- Upgraded to *xtl* 0.6.1 + `#1468 `_ +- Added ``keep_dims`` option to reducers + `#1474 `_ +- ``do_strides_match`` now accept an addition base stride value + `#1479 `_ + +Other changes +~~~~~~~~~~~~~ + +- Add ``partition``, ``argpartition`` and ``median`` + `#991 `_ +- Fix tets on avx512 + `#1410 `_ +- Implemented ``xcommon_tensor_t`` with tests + `#1412 `_ +- Code reorganization + `#1416 `_ +- ``reshape`` now accepts ``initializer_list`` parameter + `#1417 `_ +- Improved documentation + `#1419 `_ +- Fixed ``noexcept`` specifier + `#1418 `_ +- ``view`` now accepts lvalue slices + `#1420 `_ +- Removed warnings + `#1422 `_ +- Added ``reshape`` member to ``xgenerator`` to make ``arange`` more flexible + `#1421 `_ +- Add ``std::decay_t`` to ``shape_type`` in strided view + `#1425 `_ +- Generic reshape for ``xgenerator`` + `#1426 `_ +- Fix out of bounds accessing in ``xview::compute_strides`` + `#1437 `_ +- Added quick reference section to documentation + `#1438 `_ +- Improved getting started CMakeLists.txt + `#1440 `_ +- Added periodic indices + `#1430 `_ +- Added build section to narrative documentation + `#1442 `_ +- Fixed ``linspace`` corner case + `#1443 `_ +- Fixed type-o in documentation + `#1446 `_ +- Added ``xt::xpad`` + `#1441 `_ +- Added warning in ``resize`` documentation + `#1447 `_ +- Added ``in_bounds`` method + `#1444 `_ +- ``xstrided_view_base`` is now a CRTP base class + `#1453 `_ +- Turned ``xfunctor_applier_base`` into a CRTP base class + `#1455 `_ +- Removed out of bound access in ``data_offset`` + `#1456 `_ +- Added ``xaccessible`` base class + `#1451 `_ +- Refactored ``operator[]`` + `#1460 `_ +- Splitted ``xaccessible`` + `#1461 `_ +- Refactored ``size`` + `#1462 `_ +- Implemented ``nanvar`` and ``nanstd`` with tests + `#1424 `_ +- Removed warnings + `#1463 `_ +- Added ``periodic`` and ``in_bounds`` method to ``xoptional_assembly_base`` + `#1464 `_ +- Updated documentation according to last changes + `#1465 `_ +- Fixed ``flatten_sort_result_type`` + `#1470 `_ +- Fixed ``unique`` with expressions not defining ``temporary_type`` + `#1472 `_ +- Fixed ``xstrided_view_base`` constructor + `#1473 `_ +- Avoid signed integer overflow in integer printer + `#1475 `_ +- Fixed ``xview::inner_backstrides_type`` + `#1480 `_ +- Fixed compiler warnings + `#1481 `_ +- ``slice_implementation_getter`` now forwards its lice argument + `#1486 `_ +- ``linspace`` can now be reshaped + `#1488 `_ + +0.19.4 +------ + +- Add missing include + `#1391 `_ +- Fixes in xfunctor_view + `#1393 `_ +- Add tests for xfunctor_view + `#1395 `_ +- Add `empty` method to fixed_shape + `#1396 `_ +- Add accessors to slice members + `#1401 `_ +- Allow adaptors on shared pointers + `#1218 `_ +- Fix `eye` with negative index + `#1406 `_ +- Add documentation for shared pointer adaptor + `#1407 `_ +- Add `nanmean` function + `#1408 `_ + +0.19.3 +------ + +- Fix arange + `#1361 `_. +- Adaptors for C stack-allocated arrays + `#1363 `_. +- Add support for optionals in ``conditional_ternary`` + `#1365 `_. +- Add tests for ternary operator on xoptionals + `#1368 `_. +- Enable ternary operation for a mix of ``xoptional`` and ``value`` + `#1370 `_. +- ``reduce`` now accepts a single reduction function + `#1371 `_. +- Implemented share method + `#1372 `_. +- Documentation of shared improved + `#1373 `_. +- ``make_lambda_xfunction`` more generic + `#1374 `_. +- minimum/maximum for ``xoptional`` + `#1378 `_. +- Added missing methods in ``uvector`` and ``svector`` + `#1379 `_. +- Clip ``xoptional_assembly`` + `#1380 `_. +- Improve gtest cmake + `#1382 `_. +- Implement ternary operator for scalars + `#1385 `_. +- Added missing ``at`` method in ``uvector`` and ``svector`` + `#1386 `_. +- Fixup binder environment + `#1387 `_. +- Fixed ``resize`` and ``swap`` of ``svector`` + `#1388 `_. + +0.19.2 +------ + +- Enable CI for C++17 + `#1324 `_. +- Fix assignment of masked views + `#1328 `_. +- Set CMAKE_CXX_STANDARD instead of CMAKE_CXX_FLAGS + `#1330 `_. +- Allow specifying traversal order to argmin and argmax + `#1331 `_. +- Update section on differences with NumPy + `#1336 `_. +- Fix accumulators for shapes containing 1 + `#1337 `_. +- Decouple XTENSOR_DEFAULT_LAYOUT and XTENSOR_DEFAULT_TRAVERSAL + `#1339 `_. +- Prevent embiguity with `xsimd::reduce` + `#1343 `_. +- Require *xtl* 0.5.3 + `#1346 `_. +- Use concepts instead of SFINAE + `#1347 `_. +- Document good practice for xtensor-based API design + `#1348 `_. +- Fix rich display of tensor expressions + `#1353 `_. +- Fix xview on fixed tensor + `#1354 `_. +- Fix issue with `keep_slice` in case of `dynamic_view` on `view` + `#1355 `_. +- Prevent installation of gtest artifacts + `#1357 `_. + +0.19.1 +------ + +- Add string specialization to ``lexical_cast`` + `#1281 `_. +- Added HDF5 reference for ``xtensor-io`` + `#1284 `_. +- Fixed view index remap issue + `#1288 `_. +- Fixed gcc 8.2 deleted functions + `#1289 `_. +- Fixed reducer for 0d input + `#1292 `_. +- Fixed ``check_element_index`` + `#1295 `_. +- Added comparison functions + `#1297 `_. +- Add some tests to ensure chrono works with xexpressions + `#1272 `_. +- Refactor ``functor_view`` + `#1276 `_. +- Documentation improved + `#1302 `_. +- Implementation of shift operators + `#1304 `_. +- Make functor adaptor stepper work for proxy specializations + `#1305 `_. +- Replaced ``auto&`` with ``auto&&`` in ``assign_to`` + `#1306 `_. +- Fix namespace in ``xview_utils.hpp`` + `#1308 `_. +- Introducing ``flatten_indices`` and ``unravel_indices`` + `#1300 `_. +- Default layout parameter for ``ravel`` + `#1311 `_. +- Fixed ``xvie_stepper`` + `#1317 `_. +- Fixed assignment of view on view + `#1314 `_. +- Documented indices + `#1318 `_. +- Fixed shift operators return type + `#1319 `_. + +0.19.0 +------ + +Breaking changes +~~~~~~~~~~~~~~~~ + +- Upgraded to ``xtl 0.5`` + `#1275 `_. + +Other changes +~~~~~~~~~~~~~ + +- Removed type-o in docs, minor code style consistency update + `#1255 `_. +- Removed most of the warnings + `#1261 `_. +- Optional bitwise fixed + `#1263 `_. +- Prevent macro expansion in ``std::max`` + `#1265 `_. +- Update numpy.rst + `#1267 `_. +- Update getting_started.rst + `#1268 `_. +- keep and drop ``step_size`` fixed + `#1270 `_. +- Fixed typo in ``xadapt`` + `#1277 `_. +- Fixed typo + `#1278 `_. + +0.18.3 +------ + +- Exporting optional dependencies + `#1253 `_. +- 0-D HTML rendering + `#1252 `_. +- Include nlohmann_json in xio for mime bundle repr + `#1251 `_. +- Fixup xview scalar assignment + `#1250 `_. +- Implemented `from_indices` + `#1240 `_. +- xtensor_forward.hpp cleanup + `#1243 `_. +- default layout-type for `unravel_from_strides` and `unravel_index` + `#1239 `_. +- xfunction iterator fix + `#1241 `_. +- xstepper fixes + `#1237 `_. +- print_options io manipulators + `#1231 `_. +- Add syntactic sugar for reducer on single axis + `#1228 `_. +- Added view vs. adapt benchmark + `#1229 `_. +- added precisions to the installation instructions + `#1226 `_. +- removed data interface from dynamic view + `#1225 `_. +- add xio docs + `#1223 `_. +- Fixup xview assignment + `#1216 `_. +- documentation updated to be consistent with last changes + `#1214 `_. +- prevents macro expansion of std::max + `#1213 `_. +- Fix minor typos + `#1212 `_. +- Added missing assign operator in xstrided_view + `#1210 `_. +- argmax on axis with single element fixed + `#1209 `_. + 0.18.2 ------ - expression tag system fixed - `#1207 `_. + `#1207 `_. - optional extension for generator - `#1206 `_. + `#1206 `_. - optional extension for ``xview`` - `#1205 `_. + `#1205 `_. - optional extension for ``xstrided_view`` - `#1204 `_. + `#1204 `_. - optional extension for reducer - `#1203 `_. + `#1203 `_. - optional extension for ``xindex_view`` - `#1202 `_. + `#1202 `_. - optional extension for ``xfunctor_view`` - `#1201 `_. + `#1201 `_. - optional extension for broadcast - `#1198 `_. + `#1198 `_. - extension API and code cleanup - `#1197 `_. + `#1197 `_. - ``xscalar`` optional refactoring - `#1196 `_. + `#1196 `_. - Extension mechanism - `#1192 `_. + `#1192 `_. - Many small fixes - `#1191 `_. + `#1191 `_. - Slight refactoring in ``step_size`` logic - `#1188 `_. + `#1188 `_. - Fixup call of const overload in assembly storage - `#1187 `_. + `#1187 `_. 0.18.1 ------ - Fixup xio forward declaration - `#1185 `_. + `#1185 `_. 0.18.0 ------ @@ -52,174 +1496,174 @@ Breaking changes ~~~~~~~~~~~~~~~~ - Assign and trivial_broadcast refactoring - `#1150 `_. + `#1150 `_. - Moved array manipulation functions (``transpose``, ``ravel``, ``flatten``, ``trim_zeros``, ``squeeze``, ``expand_dims``, ``split``, ``atleast_Nd``, ``atleast_1d``, ``atleast_2d``, ``atleast_3d``, ``flip``) from ``xstrided_view.hpp`` to ``xmanipulation.hpp`` - `#1153 `_. + `#1153 `_. - iterator API improved - `#1155 `_. + `#1155 `_. - Fixed ``where`` and ``nonzero`` function behavior to mimic the behavior from NumPy - `#1157 `_. + `#1157 `_. - xsimd and functor refactoring - `#1173 `_. + `#1173 `_. New features ~~~~~~~~~~~~ - Implement ``rot90`` - `#1153 `_. + `#1153 `_. - Implement ``argwhere`` and ``flatnonzero`` - `#1157 `_. + `#1157 `_. - Implemented ``xexpression_holder`` - `#1164 `_. + `#1164 `_. Other changes ~~~~~~~~~~~~~ - Warnings removed - `#1159 `_. -- Added missing include - `#1162 `_. + `#1159 `_. +- Added missing include + `#1162 `_. - Removed unused type alias in ``xmath/average`` - `#1163 `_. + `#1163 `_. - Slices improved - `#1168 `_. + `#1168 `_. - Fixed ``xdrop_slice`` - `#1181 `_. + `#1181 `_. 0.17.4 ------ - perfect forwarding in ``xoptional_function`` constructor - `#1101 `_. + `#1101 `_. - fix issue with ``base_simd`` - `#1103 `_. + `#1103 `_. - ``XTENSOR_ASSERT`` fixed on Windows - `#1104 `_. + `#1104 `_. - Implement ``xmasked_value`` - `#1032 `_. + `#1032 `_. - Added ``setdiff1d`` using stl interface - `#1109 `_. + `#1109 `_. - Added test case for ``setdiff1d`` - `#1110 `_. -- Added missing reference to ``diff`` in ``From numpy to xtensor`` section - `#1116 `_. + `#1110 `_. +- Added missing reference to ``diff`` in ``From NumPy to xtensor`` section + `#1116 `_. - Add ``amax`` and ``amin`` to the documentation - `#1121 `_. + `#1121 `_. - ``histogram`` and ``histogram_bin_edges`` implementation - `#1108 `_. -- Added numpy comparison for interp - `#1111 `_. + `#1108 `_. +- Added NumPy comparison for interp + `#1111 `_. - Allow multiple return type reducer functions - `#1113 `_. -- Fixes ``average`` bug + adds Numpy based tests - `#1118 `_. + `#1113 `_. +- Fixes ``average`` bug + adds NumPy based tests + `#1118 `_. - Static ``xfunction`` cache for fixed sizes - `#1105 `_. + `#1105 `_. - Add negative reshaping axis - `#1120 `_. + `#1120 `_. - Updated ``xmasked_view`` using ``xmasked_value`` - `#1074 `_. + `#1074 `_. - Clean documentation for views - `#1131 `_. -- Build with ``xsimd`` on Windows fixed - `#1127 `_. + `#1131 `_. +- Build with *xsimd* on Windows fixed + `#1127 `_. - Implement ``mime_bundle_repr`` for ``xmasked_view`` - `#1132 `_. + `#1132 `_. - Modify shuffle to use identical algorithms for any number of dimensions - `#1135 `_. + `#1135 `_. - Warnings removal on windows - `#1139 `_. + `#1139 `_. - Add permutation function to random - `#1141 `_. + `#1141 `_. - ``xfunction_iterator`` permutation - `#933 `_. + `#933 `_. - Add ``bincount`` to ``xhistogram`` - `#1140 `_. + `#1140 `_. - Add contiguous iterable base class and remove layout param from storage iterator - `#1057 `_. + `#1057 `_. - Add ``storage_iterator`` to view and strided view - `#1045 `_. + `#1045 `_. - Removes ``data_element`` from ``xoptional`` - `#1137 `_. + `#1137 `_. - ``xtensor`` default constructor and scalar assign fixed - `#1148 `_. + `#1148 `_. - Add ``resize / reshape`` to ``xfixed_container`` - `#1147 `_. + `#1147 `_. - Iterable refactoring - `#1149 `_. + `#1149 `_. - ``inner_strides_type`` imported in ``xstrided_view`` - `#1151 `_. + `#1151 `_. 0.17.3 ------ - ``xslice`` fix - `#1099 `_. + `#1099 `_. - added missing ``static_layout`` in ``xmasked_view`` - `#1100 `_. + `#1100 `_. 0.17.2 ------ - Add experimental TBB support for parallelized multicore assign - `#948 `_. + `#948 `_. - Add inline statement to all functions in xnpy - `#1097 `_. + `#1097 `_. - Fix strided assign for certain assignments - `#1095 `_. + `#1095 `_. - CMake, remove gtest warnings - `#1085 `_. + `#1085 `_. - Add conversion operators to slices - `#1093 `_. + `#1093 `_. - Add optimization to unchecked accessors when contiguous layout is known - `#1060 `_. + `#1060 `_. - Speedup assign by computing ``any`` layout on vectors - `#1063 `_. + `#1063 `_. - Skip resizing for fixed shapes - `#1072 `_. + `#1072 `_. - Add xsimd apply to xcomplex functors (conj, norm, arg) - `#1086 `_. + `#1086 `_. - Propagate contiguous layout through views - `#1039 `_. + `#1039 `_. - Fix C++17 ambiguity for GCC 7 - `#1081 `_. + `#1081 `_. - Correct shape type in argmin, fix svector growth - `#1079 `_. + `#1079 `_. - Add ``interp`` function to xmath - `#1071 `_. + `#1071 `_. - Fix valgrind warnings + memory leak in xadapt - `#1078 `_. + `#1078 `_. - Remove more clang warnings & errors on OS X - `#1077 `_. + `#1077 `_. - Add move constructor from xtensor <-> xarray - `#1051 `_. + `#1051 `_. - Add global support for negative axes in reducers/accumulators allow multiple axes in average - `#1010 `_. + `#1010 `_. - Fix reference usage in xio - `#1076 `_. + `#1076 `_. - Remove occurences of std::size_t and double - `#1073 `_. + `#1073 `_. - Add missing parantheses around min/max for MSVC - `#1061 `_. + `#1061 `_. 0.17.1 ------ - Add std namespace to size_t everywhere, remove std::copysign for MSVC - `#1053 `_. + `#1053 `_. - Fix (wrong) bracket warnings for older clang versions (e.g. clang 5 on OS X) - `#1050 `_. + `#1050 `_. - Fix strided view on view by using std::addressof - `#1049 `_. + `#1049 `_. - Add more adapt functions and shorthands - `#1043 `_. + `#1043 `_. - Improve CRTP base class detection - `#1041 `_. + `#1041 `_. - Fix rebind container ambiguous template for C++17 / GCC 8 regression - `#1038 `_. + `#1038 `_. - Fix functor return value - `#1035 `_. + `#1035 `_. 0.17.0 ------ @@ -228,169 +1672,169 @@ Breaking changes ~~~~~~~~~~~~~~~~ - Changed strides to ``std::ptrdiff_t`` - `#925 `_. + `#925 `_. - Renamed ``count_nonzeros`` in ``count_nonzero`` - `#974 `_. + `#974 `_. - homogenize ``xfixed`` constructors - `#970 `_. + `#970 `_. - Improve ``random::choice`` - `#1011 `_. + `#1011 `_. New features ~~~~~~~~~~~~ - add ``signed char`` to npy deserialization format - `#1017 `_. + `#1017 `_. - simd assignment now requires convertible types instead of same type - `#1000 `_. + `#1000 `_. - shared expression and automatic xclosure detection - `#992 `_. + `#992 `_. - average function - `#987 `_. + `#987 `_. - added simd support for complex - `#985 `_. + `#985 `_. - argsort function - `#977 `_. + `#977 `_. - propagate fixed shape - `#922 `_. + `#922 `_. - added xdrop_slice - `#972 `_. + `#972 `_. - added doc for ``xmasked_view`` - `#971 `_. + `#971 `_. - added ``xmasked_view`` - `#969 `_. + `#969 `_. - added ``dynamic_view`` - `#966 `_. + `#966 `_. - added ability to use negative indices in keep slice - `#964 `_. + `#964 `_. - added an easy way to create lambda expressions, square and cube - `#961 `_. + `#961 `_. - noalias on rvalue - `#965 `_. + `#965 `_. Other changes ~~~~~~~~~~~~~ - ``xshared_expression`` fixed - `#1025 `_. + `#1025 `_. - fix ``make_xshared`` - `#1024 `_. + `#1024 `_. - add tests to evaluate shared expressions - `#1019 `_. + `#1019 `_. - fix ``where`` on ``xview`` - `#1012 `_. + `#1012 `_. - basic usage replaced with getting started - `#1004 `_. + `#1004 `_. - avoided installation failure in absence of ``nlohmann_json`` - `#1001 `_. + `#1001 `_. - code and documentation clean up - `#998 `_. + `#998 `_. - removed g++ "pedantic" compiler warnings - `#997 `_. + `#997 `_. - added missing header in basic_usage.rst - `#996 `_. + `#996 `_. - warning pass - `#990 `_. + `#990 `_. - added missing include in ``xview`` - `#989 `_. + `#989 `_. - added missing ```` include - `#983 `_. + `#983 `_. - xislice refactoring - `#962 `_. + `#962 `_. - added missing operators to noalias - `#932 `_. + `#932 `_. - cmake fix for Intel compiler on Windows - `#951 `_. + `#951 `_. - fixed xsimd abs deduction - `#946 `_. + `#946 `_. - added islice example to view doc - `#940 `_. + `#940 `_. 0.16.4 ------ - removed usage of ``std::transfomr`` in assign - `#868 `_. + `#868 `_. - add strided assignment - `#901 `_. + `#901 `_. - simd activated for conditional ternary functor - `#903 `_. + `#903 `_. - ``xstrided_view`` split - `#905 `_. + `#905 `_. - assigning an expression to a view throws if it has more dimensions - `#910 `_. + `#910 `_. - faster random - `#913 `_. + `#913 `_. - ``xoptional_assembly_base`` storage type - `#915 `_. + `#915 `_. - new tests and warning pass - `#916 `_. + `#916 `_. - norm immediate reducer - `#924 `_. + `#924 `_. - add ``reshape_view`` - `#927 `_. + `#927 `_. - fix immediate reducers with 0 strides - `#935 `_. + `#935 `_. 0.16.3 ------ - simd on mathematical functions fixed - `#886 `_. + `#886 `_. - ``fill`` method added to containers - `#887 `_. + `#887 `_. - access with more arguments than dimensions - `#889 `_. + `#889 `_. - unchecked method implemented - `#890 `_. + `#890 `_. - ``fill`` method implemented in view - `#893 `_. + `#893 `_. - documentation fixed and warnings removed - `#894 `_. + `#894 `_. - negative slices and new range syntax - `#895 `_. + `#895 `_. - ``xview_stepper`` with implicit ``xt::all`` bug fix - `#899 `_. + `#899 `_. 0.16.2 ------ - Add include of ``xview.hpp`` in example - `#884 `_. + `#884 `_. - Remove ``FS`` identifier - `#885 `_. + `#885 `_. 0.16.1 ------ - Workaround for Visual Studio Bug - `#858 `_. + `#858 `_. - Fixup example notebook - `#861 `_. + `#861 `_. - Prevent expansion of min and max macros on Windows - `#863 `_. + `#863 `_. - Renamed ``m_data`` to ``m_storage`` - `#864 `_. + `#864 `_. - Fix regression with respect to random access stepping with views - `#865 `_. + `#865 `_. - Remove use of CS, DS and ES qualifiers for Solaris builds - `#866 `_. + `#866 `_. - Removal of precision type - `#870 `_. + `#870 `_. - Make json tests optional, bump xtl/xsimd versions - `#871 `_. + `#871 `_. - Add more benchmarks - `#876 `_. + `#876 `_. - Forbid simd fixed - `#877 `_. + `#877 `_. - Add more asserts - `#879 `_. + `#879 `_. - Add missing ``batch_bool`` typedef - `#881 `_. + `#881 `_. - ``simd_return_type`` hack removed - `#882 `_. + `#882 `_. - Removed test guard and fixed dimension check in ``xscalar`` - `#883 `_. + `#883 `_. 0.16.0 ------ @@ -399,265 +1843,265 @@ Breaking changes ~~~~~~~~~~~~~~~~ - ``data`` renamed in ``storage``, ``raw_data`` renamed in ``data`` - `#792 `_. + `#792 `_. - Added layout template parameter to ``xstrided_view`` - `#796 `_. + `#796 `_. - Remove equality operator from stepper - `#824 `_. + `#824 `_. - ``dynamic_view`` renamed in ``strided_view`` - `#832 `_. + `#832 `_. - ``xtensorf`` renamed in ``xtensor_fixed`` - `#846 `_. + `#846 `_. New features ~~~~~~~~~~~~ - Added strided view selector - `#765 `_. + `#765 `_. - Added ``count_nonzeros`` - `#781 `_. + `#781 `_. - Added implicit conversion to scalar in ``xview`` - `#788 `_. + `#788 `_. - Added tracking allocators to ``xutils.hpp`` - `#789 `_. + `#789 `_. - ``xindexslice`` and ``shuffle`` function - `#804 `_. + `#804 `_. - Allow ``xadapt`` with dynamic layout - `#816 `_. + `#816 `_. - Added ``xtensorf`` initialization from C array - `#819 `_. + `#819 `_. - Added policy to allocation tracking for throw option - `#820 `_. + `#820 `_. - Free function ``empty`` for construction from shape - `#827 `_. + `#827 `_. - Support for JSON serialization and deserialization of xtensor expressions - `#830 `_. + `#830 `_. - Add ``trapz`` function - `#837 `_. + `#837 `_. - Add ``diff`` and ``trapz(y, x)`` functions - `#841 `_. + `#841 `_. Other changes ~~~~~~~~~~~~~ - Added fast path for specific assigns - `#767 `_. + `#767 `_. - Renamed internal macros to prevent collisions - `#772 `_. + `#772 `_. - ``dynamic_view`` unwrapping - `#775 `_. + `#775 `_. - ``xreducer_stepper`` copy semantic fixed - `#785 `_. + `#785 `_. - ``xfunction`` copy constructor fixed - `#787 `_. + `#787 `_. - warnings removed - `#791 `_. + `#791 `_. - ``xscalar_stepper`` fixed - `#802 `_. + `#802 `_. - Fixup ``xadapt`` on const pointers - `#809 `_. + `#809 `_. - Fix in owning buffer adaptors - `#810 `_. + `#810 `_. - Macros fixup - `#812 `_. + `#812 `_. - More fixes in ``xadapt`` - `#813 `_. + `#813 `_. - Mute unused variable warning - `#815 `_. + `#815 `_. - Remove comparison of steppers in assign loop - `#823 `_. + `#823 `_. - Fix reverse iterators - `#825 `_. + `#825 `_. - gcc-8 fix for template method calls - `#833 `_. + `#833 `_. - refactor benchmarks for upcoming release - `#842 `_. + `#842 `_. - ``flip`` now returns a view - `#843 `_. + `#843 `_. - initial warning pass - `#850 `_. + `#850 `_. - Fix warning on diff function - `#851 `_. + `#851 `_. - xsimd assignment fixed - `#852 `_. + `#852 `_. 0.15.9 ------ - missing layout method in xfixed - `#777 `_. + `#777 `_. - fixed uninitialized backstrides - `#774 `_. + `#774 `_. - update xtensor-blas in binder - `#773 `_. + `#773 `_. 0.15.8 ------ - comparison operators for slices - `#770 `_. + `#770 `_. - use default-assignable layout for strided views. - `#769 `_. + `#769 `_. 0.15.7 ------ - nan related functions - `#718 `_. + `#718 `_. - return types fixed in dynamic view helper - `#722 `_. + `#722 `_. - xview on constant expressions - `#723 `_. + `#723 `_. - added decays to make const ``value_type`` compile - `#727 `_. + `#727 `_. - iterator for constant ``strided_view`` fixed - `#729 `_. + `#729 `_. - ``strided_view`` on ``xfunction`` fixed - `#732 `_. + `#732 `_. - Fixes in ``xstrided_view`` - `#736 `_. + `#736 `_. - View semantic (broadcast on assign) fixed - `#742 `_. + `#742 `_. - Compilation prevented when using ellipsis with ``xview`` - `#743 `_. + `#743 `_. - Index of ``xiterator`` set to shape when reaching the end - `#744 `_. + `#744 `_. - ``xscalar`` fixed - `#748 `_. + `#748 `_. - Updated README and related projects - `#749 `_. + `#749 `_. - Perfect forwarding in ``xfunction`` and views - `#750 `_. + `#750 `_. - Missing include in ``xassign.hpp`` - `#752 `_. + `#752 `_. - More related projects in the README - `#754 `_. + `#754 `_. - Fixed stride computation for ``xtensorf`` - `#755 `_. + `#755 `_. - Added tests for backstrides - `#758 `_. + `#758 `_. - Clean up ``has_raw_data`` ins strided view - `#759 `_. + `#759 `_. - Switch to ``ptrdiff_t`` for slices - `#760 `_. + `#760 `_. - Fixed ``xview`` strides computation - `#762 `_. + `#762 `_. - Additional methods in slices, required for ``xframe`` - `#764 `_. + `#764 `_. 0.15.6 ------ - zeros, ones, full and empty_like functions - `#686 `_. + `#686 `_. - squeeze view - `#687 `_. + `#687 `_. - bitwise shift left and shift right - `#688 `_. + `#688 `_. - ellipsis, unique and trim functions - `#689 `_. + `#689 `_. - xview iterator benchmark - `#696 `_. + `#696 `_. - optimize stepper increment - `#697 `_. + `#697 `_. - minmax reducers - `#698 `_. + `#698 `_. - where fix with SIMD - `#704 `_. + `#704 `_. - additional doc for scalars and views - `#705 `_. + `#705 `_. - mixed arithmetic with SIMD - `#713 `_. + `#713 `_. - broadcast fixed - `#717 `_. + `#717 `_. 0.15.5 ------ - assign functions optimized - `#650 `_. + `#650 `_. - transposed view fixed - `#652 `_. + `#652 `_. - exceptions refactoring - `#654 `_. + `#654 `_. - performances improved - `#655 `_. + `#655 `_. - view data accessor fixed - `#660 `_. + `#660 `_. - new dynamic view using variant - `#656 `_. + `#656 `_. - alignment added to fixed xtensor - `#659 `_. + `#659 `_. - code cleanup - `#664 `_. + `#664 `_. - xtensorf and new dynamic view documentation - `#667 `_. + `#667 `_. - qualify namespace for compute_size - `#665 `_. + `#665 `_. - make xio use ``dynamic_view`` instead of ``view`` - `#662 `_. + `#662 `_. - transposed view on any expression - `#671 `_. + `#671 `_. - docs typos and grammar plus formatting - `#676 `_. + `#676 `_. - index view test assertion fixed - `#680 `_. + `#680 `_. - flatten view - `#678 `_. + `#678 `_. - handle the case of pointers to const element in ``xadapt`` - `#679 `_. + `#679 `_. - use quotes in #include statements for xtl - `#681 `_. + `#681 `_. - additional constructors for ``svector`` - `#682 `_. + `#682 `_. - removed ``test_xsemantics.hpp`` from test CMakeLists - `#684 `_. + `#684 `_. 0.15.4 ------ - fix gcc-7 error w.r.t. the use of ``assert`` - `#648 `_. + `#648 `_. 0.15.3 ------ - add missing headers to cmake installation and tests - `#647 `_. + `#647 `_. 0.15.2 ------ - ``xshape`` implementation - `#572 `_. + `#572 `_. - xfixed container - `#586 `_. + `#586 `_. - protected ``xcontainer::derived_cast`` - `#627 `_. + `#627 `_. - const reference fix - `#632 `_. + `#632 `_. - ``xgenerator`` access operators fixed - `#643 `_. + `#643 `_. - contiguous layout optiimzation - `#645 `_. + `#645 `_. 0.15.1 ------ - ``xarray_adaptor`` fixed - `#618 `_. + `#618 `_. - ``xtensor_adaptor`` fixed - `#620 `_. + `#620 `_. - fix in ``xreducer`` steppers - `#622 `_. + `#622 `_. - documentation improved - `#621 `_. - `#623 `_. - `#625 `_. + `#621 `_. + `#623 `_. + `#625 `_. - warnings removed - `#624 `_. + `#624 `_. 0.15.0 ------ @@ -666,34 +2110,34 @@ Breaking changes ~~~~~~~~~~~~~~~~ - change ``reshape`` to ``resize``, and add throwing ``reshape`` - `#598 `_. + `#598 `_. - moved to modern cmake - `#611 `_. + `#611 `_. New features ~~~~~~~~~~~~ - unravel function - `#589 `_. + `#589 `_. - random access iterators - `#596 `_. + `#596 `_. Other changes ~~~~~~~~~~~~~ - upgraded to google/benchmark version 1.3.0 - `#583 `_. + `#583 `_. - ``XTENSOR_ASSERT`` renamed into ``XTENSOR_TRY``, new ``XTENSOR_ASSERT`` - `#603 `_. + `#603 `_. - ``adapt`` fixed - `#604 `_. + `#604 `_. - VC14 warnings removed - `#608 `_. + `#608 `_. - ``xfunctor_iterator`` is now a random access iterator - `#609 `_. + `#609 `_. - removed ``old-style-cast`` warnings - `#610 `_. + `#610 `_. 0.14.1 ------ @@ -702,27 +2146,27 @@ New features ~~~~~~~~~~~~ - sort, argmin and argmax - `#549 `_. + `#549 `_. - ``xscalar_expression_tag`` - `#582 `_. + `#582 `_. Other changes ~~~~~~~~~~~~~ - accumulator improvements - `#570 `_. + `#570 `_. - benchmark cmake fixed - `#571 `_. + `#571 `_. - allocator_type added to container interface - `#573 `_. + `#573 `_. - allow conda-forge as fallback channel - `#575 `_. + `#575 `_. - arithmetic mixing optional assemblies and scalars fixed - `#578 `_. + `#578 `_. - arithmetic mixing optional assemblies and optionals fixed - `#579 `_. + `#579 `_. - ``operator==`` restricted to xtensor and xoptional expressions - `#580 `_. + `#580 `_. 0.14.0 ------ @@ -731,68 +2175,68 @@ Breaking changes ~~~~~~~~~~~~~~~~ - ``xadapt`` renamed into ``adapt`` - `#563 `_. + `#563 `_. - Naming consistency - `#565 `_. + `#565 `_. New features ~~~~~~~~~~~~ - add ``random::choice`` - `#547 `_. + `#547 `_. - evaluation strategy and accumulators. - `#550 `_. + `#550 `_. - modulus operator - `#556 `_. + `#556 `_. - ``adapt``: default overload for 1D arrays - `#560 `_. + `#560 `_. - Move semantic on ``adapt`` - `#564 `_. + `#564 `_. Other changes ~~~~~~~~~~~~~ - optional fixes to avoid ambiguous calls - `#541 `_. + `#541 `_. - narrative documentation about ``xt::adapt`` - `#544 `_. + `#544 `_. - ``xfunction`` refactoring - `#545 `_. + `#545 `_. - SIMD acceleration for AVX fixed - `#557 `_. + `#557 `_. - allocator fixes - `#558 `_. - `#559 `_. + `#558 `_. + `#559 `_. - return type of ``view::strides()`` fixed - `#568 `_. + `#568 `_. 0.13.2 ------ - Support for complex version of ``isclose`` - `#512 `_. + `#512 `_. - Fixup static layout in ``xstrided_view`` - `#536 `_. + `#536 `_. - ``xexpression::operator[]`` now take support any type of sequence - `#537 `_. + `#537 `_. - Fixing ``xinfo`` issues for Visual Studio. - `#529 `_. + `#529 `_. - Fix const-correctness in ``xstrided_view``. - `#526 `_. + `#526 `_. 0.13.1 ------ - More general floating point type - `#518 `_. + `#518 `_. - Do not require functor to be passed via rvalue reference - `#519 `_. + `#519 `_. - Documentation improved - `#520 `_. + `#520 `_. - Fix in xreducer - `#521 `_. + `#521 `_. 0.13.0 ------ @@ -801,52 +2245,52 @@ Breaking changes ~~~~~~~~~~~~~~~~ - The API for ``xbuffer_adaptor`` has changed. The template parameter is the type of the buffer, not just the value type - `#482 `_. -- Change ``edge_items`` print option to ``edgeitems`` for better numpy consistency - `#489 `_. -- xtensor now depends on ``xtl`` version `~0.3.3` - `#508 `_. + `#482 `_. +- Change ``edge_items`` print option to ``edgeitems`` for better NumPy consistency + `#489 `_. +- *xtensor* now depends on *xtl* version `~0.3.3` + `#508 `_. New features ~~~~~~~~~~~~ - Support for parsing the ``npy`` file format - `#465 `_. + `#465 `_. - Creation of optional expressions from value and boolean expressions (optional assembly) - `#496 `_. + `#496 `_. - Support for the explicit cast of expressions with different value types - `#491 `_. + `#491 `_. Other changes ~~~~~~~~~~~~~ - Addition of broadcasting bitwise operators - `#459 `_. + `#459 `_. - More efficient optional expression system - `#467 `_. + `#467 `_. - Migration of benchmarks to the Google benchmark framework - `#473 `_. + `#473 `_. - Container semantic and adaptor semantic merged - `#475 `_. + `#475 `_. - Various fixes and improvements of the strided views - `#480 `_. - `#481 `_. + `#480 `_. + `#481 `_. - Assignment now performs basic type conversion - `#486 `_. + `#486 `_. - Workaround for a compiler bug in Visual Studio 2017 - `#490 `_. + `#490 `_. - MSVC 2017 workaround - `#492 `_. + `#492 `_. - The ``size()`` method for containers now returns the total number of elements instead of the buffer size, which may differ when the smallest stride is greater than ``1`` - `#502 `_. -- The behavior of ``linspace`` with integral types has been made consistent with numpy - `#510 `_. + `#502 `_. +- The behavior of ``linspace`` with integral types has been made consistent with NumPy + `#510 `_. 0.12.1 ------ - Fix issue with slicing when using heterogeneous integral types - `#451 `_. + `#451 `_. 0.12.0 ------ @@ -854,60 +2298,60 @@ Other changes Breaking changes ~~~~~~~~~~~~~~~~ -- ``xtensor`` now depends on ``xtl`` version `0.2.x` - `#421 `_. +- *xtensor* now depends on *xtl* version `0.2.x` + `#421 `_. New features ~~~~~~~~~~~~ -- ``xtensor`` has an optional dependency on ``xsimd`` for enabling simd acceleration - `#426 `_. +- *xtensor* has an optional dependency on *xsimd* for enabling simd acceleration + `#426 `_. - All expressions have an additional safe access function (``at``) - `#420 `_. + `#420 `_. - norm functions - `#440 `_. + `#440 `_. - ``closure_pointer`` used in iterators returning temporaries so their ``operator->`` can be correctly defined - `#446 `_. + `#446 `_. -- expressions tags added so ``xtensor`` expression system can be extended - `#447 `_. +- expressions tags added so *xtensor* expression system can be extended + `#447 `_. Other changes ~~~~~~~~~~~~~ - Preconditions and exceptions - `#409 `_. + `#409 `_. - ``isclose`` is now symmetric - `#411 `_. + `#411 `_. - concepts added - `#414 `_. + `#414 `_. - narrowing cast for mixed arithmetic - `#432 `_. + `#432 `_. - ``is_xexpression`` concept fixed - `#439 `_. + `#439 `_. - ``void_t`` implementation fixed for compilers affected by C++14 defect CWG 1558 - `#448 `_. + `#448 `_. 0.11.3 ------ - Fixed bug in length-1 statically dimensioned tensor construction - `#431 `_. + `#431 `_. 0.11.2 ------ - Fixup compilation issue with latest clang compiler. (missing `constexpr` keyword) - `#407 `_. + `#407 `_. 0.11.1 ------ @@ -923,25 +2367,25 @@ Breaking changes - ``xbegin`` / ``xend``, ``xcbegin`` / ``xcend``, ``xrbegin`` / ``xrend`` and ``xcrbegin`` / ``xcrend`` methods replaced with classical ``begin`` / ``end``, ``cbegin`` / ``cend``, ``rbegin`` / ``rend`` and ``crbegin`` / ``crend`` methods. Old ``begin`` / ``end`` methods and their variants have been removed. - `#370 `_. + `#370 `_. - ``xview`` now uses a const stepper when its underlying expression is const. - `#385 `_. + `#385 `_. Other changes ~~~~~~~~~~~~~ - ``xview`` copy semantic and move semantic fixed. - `#377 `_. + `#377 `_. - ``xoptional`` can be implicitly constructed from a scalar. - `#382 `_. + `#382 `_. - build with Emscripten fixed. - `#388 `_. + `#388 `_. - STL version detection improved. - `#396 `_. + `#396 `_. - Implicit conversion between signed and unsigned integers fixed. - `#397 `_. + `#397 `_. diff --git a/docs/source/closure-semantics.rst b/docs/source/closure-semantics.rst index 92d0aaf0d..ad4d11504 100644 --- a/docs/source/closure-semantics.rst +++ b/docs/source/closure-semantics.rst @@ -9,17 +9,17 @@ Closure semantics ================= -The ``xtensor`` library is a tensor expression library implementing numpy-style broadcasting and universal functions but in a lazy fashion. +The *xtensor* library is a tensor expression library implementing NumPy-style broadcasting and universal functions but in a lazy fashion. If ``x`` and ``y`` are two tensor expressions with compatible shapes, the result of ``x + y`` is not a tensor but an expression that does -not hold any value. Values of ``x + y`` are computed upon access or when the result is assigned to a container such as ``xt::xtensor`` or -``xt::xarray``. The same holds for most functions in xtensor, views, broadcasting views, etc. +not hold any value. Values of ``x + y`` are computed upon access or when the result is assigned to a container such as :cpp:type:`xt::xtensor` or +:cpp:type:`xt::xarray`. The same holds for most functions in xtensor, views, broadcasting views, etc. In order to be able to perform the differed computation of ``x + y``, the returned expression must hold references, const references or copies of the members ``x`` and ``y``, depending on how arguments were passed to ``operator+``. The actual types held by the expressions are the **closure types**. -The concept of closure type is key in the implementation of ``xtensor`` and appears in all the expressions defined in xtensor, and the utility functions and metafunctions complement the tools of the standard library for the move semantics. +The concept of closure type is key in the implementation of *xtensor* and appears in all the expressions defined in xtensor, and the utility functions and metafunctions complement the tools of the standard library for the move semantics. Basic rules for determining closure types ----------------------------------------- @@ -32,7 +32,7 @@ The two main requirements are the following: It is important for the closure type not to be a reference when the passed argument is an rvalue, which can result in dangling references. Following the conventions of the C++ standard library for naming type traits, we provide two type traits classes providing an implementation of these rules -in the ``xutils.hpp`` header, ``closure_type``, and ``const_closure_type``. The latter adds the const qualifier to the reference even when the provided argument is not const. +in the ``xutils.hpp`` header, ``closure_type``, and ``const_closure_type``. The latter adds the ``const`` qualifier to the reference even when the provided argument is not const. .. code:: cpp @@ -78,7 +78,7 @@ Using this mechanism, we were able to Closure types and scalar wrappers --------------------------------- -A requirement for ``xtensor`` is the ability to mix scalars and tensors in tensor expressions. In order to do so, +A requirement for *xtensor* is the ability to mix scalars and tensors in tensor expressions. In order to do so, scalar values are wrapped into the ``xscalar`` wrapper, which is a cheap 0-D tensor expression holding a single scalar value. @@ -104,7 +104,7 @@ The logic for this is encoded into xtensor's ``xclosure`` type trait. using xclosure_t = typename xclosure::type; In doing so, we ensure const-correctness, we avoid dangling reference, and ensure that lvalues remain lvalues. -The `const_xclosure` follows the same scheme: +The ``const_xclosure`` follows the same scheme: .. code:: cpp @@ -174,7 +174,7 @@ upon access or assignment. - In order to perform the division, the expression must hold the values or references on the numerator and denominator. - Since ``s`` is a local variable, it will be destroyed upon leaving the scope of the function, and more importantly, it is an *lvalue*. -- A consequence of ``s`` being an lvalue and a local variable, is that the ``s / value_type(size)`` would end up holding a dangling const reference on ``s``. +- A consequence of ``s`` being an lvalue and a local variable, is that the ``s / value_type(size)`` would end up holding a dangling ``const`` reference on ``s``. - Hence we must call return ``std::move(s) / value_type(size)``. The other place in this example where the C++ move semantics is used is the line ``s = sum(std::forward(e))``. The goal is to have the unevaluated ``s`` expression @@ -184,7 +184,7 @@ hold a const reference or a value for ``e`` depending on the lvalue-ness of the Reusing expressions / sharing expressions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Sometimes it is necessary to use a xexpression in two seperate places in another xexpression. For example, when computing +Sometimes it is necessary to use a xexpression in two separate places in another xexpression. For example, when computing something like ``sin(A) + cos(A)`` we can see A being referenced twice. This works fine if we can guarantee that ``A`` has a long enough lifetime. However, when writing generic interfaces that accept rvalues we cannot always guarantee that ``A`` will live long enough. @@ -209,7 +209,7 @@ utility to achieve this: } Note: writing a lambda is just sugar for writing a functor. -Also, using `auto x` as the function argument enables automatic `xsimd` acceleration. +Also, using ``auto x`` as the function argument enables automatic *xsimd* acceleration. As the data flow through the lambda is entirely transparent to the compiler, using this construct is generally faster than using ``xshared_expressions``. The usage of ``xshared_expression`` also @@ -222,14 +222,36 @@ But under certain circumstances it might be required, e.g. to implement a fully inline auto average(E&& e, W&& weights, std::ptrdiff_t axis) noexcept { auto shared_weights = xt::make_xshared(std::move(weights)); - auto expr = xt::sum(e * shared_weights) , {axis}) / xt::sum(shared_weights); + auto expr = xt::sum(e * shared_weights , {axis}) / xt::sum(shared_weights); // the following line prints how often shared_weights is used - std::cout << shared_weights.use_count() << std::endl; // ==> 3 + std::cout << shared_weights.use_count() << std::endl; // ==> 4 return expr; } -We can see that, before returning from the function, three copies of ``shared_weights`` -exist: two in the two ``xt::sum`` functions, and one is the temporary. After returning -from the function, only two copies of the ``xshared_expression`` will exist. +We can see that, before returning from the function, four copies of ``shared_weights`` +exist: two in the two ``xt::sum`` functions, and one is the temporary. The last one lies +in ``weights`` itself, it is a technical requirement for the ``share`` syntax. After +returning from the function, only two copies of the ``xshared_expression`` will exist. As discussed before, ``xt::make_xshared`` has the same overhead as creating a ``std::shared_ptr`` which is used internally by the shared expression. + +Another syntax can be used if you don't want to have a temporary variable for the shared +expression: + +.. code:: cpp + + template + inline auto average(E&& e, W&& weights, std::ptrdiff_t axis) noexcept + { + auto expr = xt::sum(e * xt::share(weights) , {axis}) / xt::sum(xt::share(weights)); + // the following line prints how often shared_weights is used + std::cout << shared_weights.use_count() << std::endl; // ==> 3 + return expr; + } + +In that case only three copies of the shared weights exist. Notice that contrary to +``make_xshare``, ``share`` also accepts lvalues; this is to avoid the required ``std::move``, +however ``share`` will turn its argument into an rvalue and will move it into the shared +expression. Thus ``share`` invalidates its argument, and the only thing that can be done +with an expression upon which ``share`` has been called is another call to ``share``. Therefore +``share`` should be called on rvalue references or temporary expressions only. diff --git a/docs/source/compilers.rst b/docs/source/compilers.rst index da3adf57f..69673031e 100644 --- a/docs/source/compilers.rst +++ b/docs/source/compilers.rst @@ -41,7 +41,23 @@ definition. Visual Studio 2017 (15.7.1) seeing declarations as extra overloads ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In ``xvectorize.hpp``, Visual Studio 15.7.1 sees the forward declaration of ``vectorize(E&&)`` as a separate ovarload. +In ``xvectorize.hpp``, Visual Studio 15.7.1 sees the forward declaration of ``vectorize(E&&)`` as a separate overload. + +Visual Studio 2017 double non-class parameter pack expansion +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In ``xfixed.hpp`` we add a level of indirection to expand one parameter pack before the other. +Not doing this results in VS2017 complaining about a parameter pack that needs to be expanded in this +context while it actually is. + +Visual Studio 2022 (19.31+) workaround inline compiler optimization bug +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In ``xstrides.hpp``, added an early return inside ``compute_strides`` when ``shape.size() == 0`` to +prevent a run time crash from occuring. Without this guard statement, instructions from inside the +for loop were somehow being reached, despite being logically unreachable. +Original issue `here. `_ +Upstream issue `here. `_ GCC-4.9 and Clang < 3.8 and constexpr ``std::min`` and ``std::max`` ------------------------------------------------------------------- @@ -63,6 +79,14 @@ Workarounds for this compiler bug arise in various files of the code base. Everywhere, the handling of `Clang < 3.8` is wrapped with checks for the ``X_OLD_CLANG`` macro. +**The support of `Clang < 4.0` is dropped in xtensor 0.22.** + +Clang-cl and ``std::get`` +------------------------- + +`Clang-cl` does not allow to call ``std::get`` with ``*this`` as parameter from a class inheriting from std::tuple. +In that case, we explicitly upcast to ``std::tuple``. + GCC < 5.1 and ``std::is_trivially_default_constructible`` --------------------------------------------------------- @@ -75,7 +99,7 @@ In this case, we polyfill the proper standard names using the deprecated ``std::has_trivial_default_constructor``. This must also be done when the compiler is clang when it makes use of the GCC implementation of the STL, which is the default behavior on linux. Properly detecting the version of the -GCC STL used by clang cannot be done with the ``__GNUC__`` macro, which are +GCC STL used by clang cannot be done with the ``__GNUC__`` macro, which is overridden by clang. Instead, we check for the definition of the macro ``_GLIBCXX_USE_CXX11_ABI`` which is only defined with GCC versions greater than ``5``. @@ -96,3 +120,20 @@ As of version 6, GCC detects whether the obsolete functions are present in the C header ```` and uses them if they are, avoiding the clash. However, this means that the function might return int instead of bool as C++11 requires, which is a bug. + +GCC-8 and deleted functions +--------------------------- + +GCC-8 (8.2 specifically) doesn't seem to SFINAE deleted functions correctly. A +strided view on a dynamic_view errors with a message: use of deleted function. +It should pick the *other* implementation by SFINAE on the function +signature, because our ``has_strides`` meta-function should return +false. Instantiating the ``has_strides`` in the inner_types fixes the issue. +Original issue here: https://github.com/xtensor-stack/xtensor/issues/1273 + +Apple LLVM version >= 8.0.0 +--------------------------- + +``tuple_cat`` is bugged and propagates the constness of its tuple arguments to the types +inside the tuple. When checking if the resulting tuple contains a given type, the const +qualified type also needs to be checked. diff --git a/docs/source/conda.svg b/docs/source/conda.svg index 0755b2f46..643a65320 100644 --- a/docs/source/conda.svg +++ b/docs/source/conda.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/docs/source/conf.py b/docs/source/conf.py index e49808853..4f5fffb67 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -16,10 +16,11 @@ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] def setup(app): - app.add_stylesheet("main_stylesheet.css") + app.add_css_file("main_stylesheet.css") -extensions = ['breathe'] +extensions = ['breathe', 'sphinx_rtd_theme'] breathe_projects = { 'xtensor': '../xml' } +breathe_default_project = "xtensor" templates_path = ['_templates'] html_static_path = ['_static'] source_suffix = '.rst' @@ -36,3 +37,15 @@ def setup(app): todo_include_todos = False htmlhelp_basename = 'xtensordoc' +html_js_files = [ + 'goatcounter.js' +] + +# Automatically link to NumPy doc +extensions += ['sphinx.ext.intersphinx'] +intersphinx_mapping = { + "numpy": ("https://numpy.org/doc/stable/", None), + "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), + "xtensor-blas": ("https://xtensor-blas.readthedocs.io/en/stable", None), + "xtl": ("https://xtl.readthedocs.io/en/stable", None), +} diff --git a/docs/source/container.rst b/docs/source/container.rst index 9bf257783..74367b7a8 100644 --- a/docs/source/container.rst +++ b/docs/source/container.rst @@ -10,119 +10,181 @@ Arrays and tensors Internal memory layout ---------------------- -A multi-dimensional array of `xtensor` consists of a contiguous one-dimensional buffer combined with an indexing scheme that maps +A multi-dimensional array of *xtensor* consists of a contiguous one-dimensional buffer combined with an indexing scheme that maps unsigned integers to the location of an element in the buffer. The range in which the indices can vary is specified by the `shape` of the array. -The scheme used to map indices into a location in the buffer is a strided indexing scheme. In such a scheme, the index ``(i0, ..., in)`` corresponds to the offset ``sum(ik * sk)`` from the beginning of the one-dimensional buffer, where ``(s0, ..., sn)`` are the `strides` of the array. Some particular cases of strided schemes implement well known memory layouts: +The scheme used to map indices into a location in the buffer is a strided indexing scheme. In such a scheme, the index +``(i0, ..., in)`` corresponds to the offset ``sum(ik * sk)`` from the beginning of the one-dimensional buffer, where +``(s0, ..., sn)`` are the ``strides`` of the array. Some particular cases of strided schemes implement well-known memory layouts: - the row-major layout (or C layout) is a strided index scheme where the strides grow from right to left - the column-major layout (or Fortran layout) is a strided index scheme where the strides grow from left to right -``xtensor`` provides a ``layout_type`` enum that helps to specify the layout used by multi-dimensional arrays. This enum can be used in two ways: - -- at compile time, as a template argument. The value ``layout_type::dynamic`` allows specifying any strided index scheme at runtime (including row-major and column-major schemes), while ``layout_type::row_major`` and ``layout_type::column_major`` fixes the strided index scheme and disable ``resize`` and constructor overloads taking a set of strides or a layout value as parameter. The default value of the template parameter is ``XTENSOR_DEFAULT_LAYOUT``. -- at runtime if the previous template parameter was set to ``layout_type::dynamic``. In that case, ``resize`` and constructor overloads allow specifying a set of strides or a layout value to avoid strides computation. If neither strides nor layout is specified when instantiating or resizing a multi-dimensional array, strides corresponding to ``XTENSOR_DEFAULT_LAYOUT`` are used. +*xtensor* provides a :cpp:enum:`xt::layout_type` enum that helps to specify the layout used by multidimensional arrays. +This enum can be used in two ways: + +- at compile time, as a template argument. The value :cpp:enumerator:`xt::layout_type::dynamic` allows specifying any + strided index scheme at runtime (including row-major and column-major schemes), while :cpp:enumerator:`xt::layout_type::row_major` + and :cpp:enumerator:`xt::layout_type::column_major` fixes the strided index scheme and disable + :cpp:func:`resize() ` and constructor overloads taking a set of strides or a layout + value as parameter. + The default value of the template parameter is :c:macro:`XTENSOR_DEFAULT_LAYOUT`. +- at runtime if the previous template parameter was set to :cpp:enumerator:`xt::layout_type::dynamic`. + In that case, :cpp:func:`resize() ` and constructor overloads allow specifying a set of + strides or a layout value to avoid strides computation. + If neither strides nor layout is specified when instantiating or resizing a multi-dimensional array, strides + corresponding to :c:macro:`XTENSOR_DEFAULT_LAYOUT` are used. The following example shows how to initialize a multi-dimensional array of dynamic layout with specified strides: .. code:: #include - #include "xtensor/xarray.hpp" + #include std::vector shape = { 3, 2, 4 }; std::vector strides = { 8, 4, 1 }; xt::xarray a(shape, strides); -However, this requires to carefully compute the strides to avoid buffer overflow when accessing elements of the array. We can use the following shortcut to specify the strides instead of computing them: +However, this requires to carefully compute the strides to avoid buffer overflow when accessing elements of the array. +We can use the following shortcut to specify the strides instead of computing them: .. code:: #include - #include "xtensor/xarray.hpp" + #include std::vector shape = { 3, 2, 4 }; - xt::xarray a(shape, xt::layout::row_major); + xt::xarray a(shape, xt::layout_type::row_major); If the layout of the array can be fixed at compile time, we can make it even simpler: .. code:: #include - #include "xtensor/xarray.hpp" + #include std::vector shape = { 3, 2, 4 }; xt::xarray a(shape); // this shortcut is equivalent: // xt::xarray a(shape); -However, in the latter case, the layout of the array is forced to ``row_major`` at compile time, and therefore cannot be changed at runtime. +However, in the latter case, the layout of the array is forced to :cpp:enumerator:`xt::layout_type::row_major` at +compile time, and therefore cannot be changed at runtime. Runtime vs Compile-time dimensionality -------------------------------------- -Three container classes implementing multi-dimensional arrays are provided: ``xarray`` and ``xtensor`` and ``xtensor_fixed``. +Three container classes implementing multidimensional arrays are provided: :cpp:type:`xt::xarray` and +:cpp:type:`xt::xtensor` and :cpp:type:`xt::xtensor_fixed`. -- ``xarray`` can be reshaped dynamically to any number of dimensions. It is the container that is the most similar to numpy arrays. -- ``xtensor`` has a dimension set at compilation time, which enables many optimizations. For example, shapes and strides - of ``xtensor`` instances are allocated on the stack instead of the heap. -- ``xtensor_fixed`` has a shape fixed at compile time. This allows even more optimizations, such as allocating the storage for the container +- :cpp:type:`xt::xarray` can be reshaped dynamically to any number of dimensions. It is the container that is the most similar to NumPy arrays. +- :cpp:type:`xt::xtensor` has a dimension set at compilation time, which enables many optimizations. + For example, shapes and strides of :cpp:type:`xt::xtensor` instances are allocated on the stack instead of the heap. +- :cpp:type:`xt::xtensor_fixed` has a shape fixed at compile time. + This allows even more optimizations, such as allocating the storage for the container on the stack, as well as computing strides and backstrides at compile time, making the allocation of this container extremely cheap. -Let's use ``xtensor`` instead of ``xarray`` in the previous example: +Let's use :cpp:type:`xt::xtensor` instead of :cpp:type:`xt::xarray` in the previous example: .. code:: #include - #include "xtensor/xtensor.hpp" + #include std::array shape = { 3, 2, 4 }; xt::xtensor a(shape); - // whis is equivalent to + // this is equivalent to // xt::xtensor a(shape); -Or when using ``xtensor_fixed``: +Or when using :cpp:type:`xt::xtensor_fixed`: .. code:: - #include "xtensor/xfixed.hpp" + #include xt::xtensor_fixed> a(); // or xt::xtensor_fixed, xt::layout_type::row_major>() -``xarray``, ``xtensor`` and ``xtensor_fixed`` containers are all ``xexpression`` s and can be involved and mixed in mathematical expressions, assigned to each -other etc... They provide an augmented interface compared to other ``xexpression`` types: +:cpp:type:`xt::xarray`, :cpp:type:`xt::xtensor` and :cpp:type:`xt::xtensor_fixed` containers are all +:cpp:type:`xt::xexpression` s and can be involved and mixed in mathematical expressions, assigned to each +other etc... +They provide an augmented interface compared to other :cpp:type:`xt::xexpression` types: + +- Each method exposed in :cpp:type:`xt::xexpression` interface has its non-const counterpart exposed by + :cpp:type:`xt::xarray`, :cpp:type:`xt::xtensor` and :cpp:type:`xt::xtensor_fixed`. +- :cpp:func:`reshape() ` reshapes the container in place, and the global size of the container has to stay the same. +- :cpp:func:`resize() ` resizes the container in place, that is, if the global size of the container doesn't change, no memory allocation occurs. +- :cpp:func:`strides() ` returns the strides of the container, used to compute the position of an element in the underlying buffer. + +Reshape +------- + +The :cpp:func:`reshape() ` method accepts any kind of 1D-container, you don't have to +pass an instance of ``shape_type``. +It only requires the new shape to be compatible with the old one, that is, the number of elements in the container must +remain the same: + +.. code:: + + #include + + xt::xarray a = { 1, 2, 3, 4, 5, 6, 7, 8}; + // The following two lines ... + std::array sh1 = {2, 4}; + a.reshape(sh1); + // ... are equivalent to the following two lines ... + xt::xarray::shape_type sh2({2, 4}); + a.reshape(sh2); + // ... which are equivalent to the following + a.reshape({2, 4}); + +One of the values in the ``shape`` argument can be -1. +In this case, the value is inferred from the number of elements in the container and the remaining values in the ``shape``: + +.. code:: -- Each method exposed in ``xexpression`` interface has its non-const counterpart exposed by ``xarray``, ``xtensor`` and ``xtensor_fixed``. -- ``reshape()`` reshapes the container in place, and the global size of the container has to stay the same. -- ``resize()`` resizes the container in place, that is, if the global size of the container doesn't change, no memory allocation occurs. -- ``strides()`` returns the strides of the container, used to compute the position of an element in the underlying buffer. + #include + xt::xarray a = { 1, 2, 3, 4, 5, 6, 7, 8}; + a.reshape({2, -1}); + // a.shape() return {2, 4} Performance ----------- -The dynamic dimensionality of ``xarray`` comes at a cost. Since the dimension is unknown at build time, the sequences holding shape and strides of ``xarray`` instances are heap-allocated, which makes it significantly more expansive than ``xtensor``. Shape and strides of ``xtensor`` are stack-allocated which makes them more efficient. +The dynamic dimensionality of :cpp:type:`xt::xarray` comes at a cost. +Since the dimension is unknown at build time, the sequences holding shape and strides of :cpp:type:`xt::xarray` +instances are heap-allocated, which makes it significantly more expensive than :cpp:type:`xt::xtensor`. +Shape and strides of :cpp:type:`xt::xtensor` are stack-allocated which makes them more efficient. -More generally, the library implements a ``promote_shape`` mechanism at build time to determine the optimal sequence type to hold the shape of an expression. The shape type of a broadcasting expression whose members have a dimensionality determined at compile time will have a stack-allocated shape. If a single member of a broadcasting expression has a dynamic dimension (for example an ``xarray``), it bubbles up to the entire broadcasting expression which will have a heap-allocated shape. The same hold for views, broadcast expressions, etc... +More generally, the library implements a ``promote_shape`` mechanism at build time to determine the optimal sequence +type to hold the shape of an expression. +The shape type of a broadcasting expression whose members have a dimensionality determined at compile time will have a +stack-allocated shape. +If a single member of a broadcasting expression has a dynamic dimension (for example an :cpp:type:`xt::xarray`), +it bubbles up to the entire broadcasting expression which will have a heap-allocated shape. +The same hold for views, broadcast expressions, etc... Aliasing and temporaries ------------------------ -In some cases, an expression should not be directly assigned to a container. Instead, it has to be assigned to a temporary variable before being copied -into the destination container. This occurs when the destination container is involved in the expression and has to be resized. This phenomenon is -known as *aliasing*. +In some cases, an expression should not be directly assigned to a container. +Instead, it has to be assigned to a temporary variable before being copied into the destination container. +A typical case where this happens is when the destination container is involved in the expression and has to be resized. +This phenomenon is known as *aliasing*. -To prevent this, `xtensor` assigns the expression to a temporary variable before copying it. In the case of ``xarray``, this results in an extra dynamic memory -allocation and copy. +To prevent this, *xtensor* assigns the expression to a temporary variable before copying it. +In the case of :cpp:type:`xt::xarray`, this results in an extra dynamic memory allocation and copy. -However, if the left-hand side is not involved in the expression being assigned, no temporary variable should be required. `xtensor` cannot detect such cases -automatically and applies the "temporary variable rule" by default. A mechanism is provided to forcibly prevent usage of a temporary variable: +However, if the left-hand side is not involved in the expression being assigned, no temporary variable should be required. +*xtensor* cannot detect such cases automatically and applies the "temporary variable rule" by default. +A mechanism is provided to forcibly prevent usage of a temporary variable: .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xnoalias.hpp" + #include + #include // a, b, and c are xt::xarrays previously initialized xt::noalias(b) = a + c; @@ -137,7 +199,7 @@ The aliasing phenomenon is illustrated in the following example: .. code:: #include - #include "xtensor/xarray.hpp" + #include std::vector a_shape = {3, 2, 4}; xt::xarray a(a_shape); @@ -148,8 +210,11 @@ The aliasing phenomenon is illustrated in the following example: b = a + b; // b appears on both left-hand and right-hand sides of the statement -In the above example, the shape of ``a + b`` is ``{ 3, 2, 4 }``. Therefore, ``b`` must first be resized, which impacts how the right-hand side is computed. +In the above example, the shape of ``a + b`` is ``{ 3, 2, 4 }``. +Therefore, ``b`` must first be resized, which impacts how the right-hand side is computed. If the values of ``b`` were copied into the new buffer directly without an intermediary variable, then we would have -``new_b(0, i, j) == old_b(i, j) for (i,j) in [0,1] x [0, 3]``. After the resize of ``bb``, ``a(0, i, j) + b(0, i, j)`` is assigned to ``b(0, i, j)``, then, -due to broadcasting rules, ``a(1, i, j) + b(0, i, j)`` is assigned to ``b(1, i, j)``. The issue is ``b(0, i, j)`` has been changed by the previous assignment. +``new_b(0, i, j) == old_b(i, j) for (i,j) in [0,1] x [0, 3]``. +After the resize of ``bb``, ``a(0, i, j) + b(0, i, j)`` is assigned to ``b(0, i, j)``, then, +due to broadcasting rules, ``a(1, i, j) + b(0, i, j)`` is assigned to ``b(1, i, j)``. +The issue is ``b(0, i, j)`` has been changed by the previous assignment. diff --git a/docs/source/debian.svg b/docs/source/debian.svg index 50dcb70c8..923265199 100644 --- a/docs/source/debian.svg +++ b/docs/source/debian.svg @@ -1,86 +1,86 @@ - - - - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/dev-build-options.rst b/docs/source/dev-build-options.rst new file mode 100644 index 000000000..c4b12a8fe --- /dev/null +++ b/docs/source/dev-build-options.rst @@ -0,0 +1,103 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Build and configuration +======================= + +Build +----- + +*xtensor* build supports the following options: + +- ``BUILD_TESTS``: enables the ``xtest`` and ``xbenchmark`` targets (see below). +- ``DOWNLOAD_GTEST``: downloads ``gtest`` and builds it locally instead of using a binary installation. +- ``GTEST_SRC_DIR``: indicates where to find the ``gtest`` sources instead of downloading them. +- ``XTENSOR_ENABLE_ASSERT``: activates the assertions in *xtensor*. +- ``XTENSOR_CHECK_DIMENSION``: turns on ``XTENSOR_ENABLE_ASSERT`` and activates dimension checks in *xtensor*. + Note that the dimensions check should not be activated if you expect ``operator()`` to perform broadcasting. +- ``XTENSOR_USE_XSIMD``: enables simd acceleration in *xtensor*. This requires that you have xsimd_ installed + on your system. +- ``XTENSOR_USE_TBB``: enables parallel assignment loop. This requires that you have you have tbb_ installed + on your system. + + - Optionally use ``XTENSOR_TBB_THRESHOLD`` to set a minimum size to trigger parallel assignment (default is 0) + +- ``XTENSOR_USE_OPENMP``: enables parallel assignment loop using OpenMP. This requires that OpenMP is available on your system. + +All these options are disabled by default. Enabling ``DOWNLOAD_GTEST`` or +setting ``GTEST_SRC_DIR`` enables ``BUILD_TESTS``. + +If the ``BUILD_TESTS`` option is enabled, the following targets are available: + +- xtest: builds an run the test suite. +- xbenchmark: builds and runs the benchmarks. + +For instance, building the test suite of *xtensor* with assertions enabled: + +.. code:: + + mkdir build + cd build + cmake -DBUILD_TESTS=ON -DXTENSOR_ENABLE_ASSERT=ON ../ + make xtest + +Building the test suite of *xtensor* where the sources of ``gtest`` are +located in e.g. ``/usr/share/gtest``: + +.. code:: + + mkdir build + cd build + cmake -DGTEST_SRC_DIR=/usr/share/gtest ../ + make xtest + +.. _configuration-label: + +Configuration +------------- + +*xtensor* can be configured via macros, which must be defined *before* +including any of its header. Here is a list of available macros: + +- ``XTENSOR_ENABLE_ASSERT``: enables assertions in xtensor, such as bound check. +- ``XTENSOR_ENABLE_CHECK_DIMENSION``: enables the dimensions check in *xtensor*. Note that this option should not be turned + on if you expect ``operator()`` to perform broadcasting. +- ``XTENSOR_USE_XSIMD``: enables SIMD acceleration in *xtensor*. This requires that you have xsimd_ installed + on your system. +- ``XTENSOR_USE_TBB``: enables parallel assignment loop. This requires that you have you have tbb_ installed + on your system. +- ``XTENSOR_USE_OPENMP``: enables parallel assignment loop using OpenMP. This requires that OpenMP is available on your system. +- ``XTENSOR_DEFAULT_DATA_CONTAINER(T, A)``: defines the type used as the default data container for tensors and arrays. ``T`` + is the ``value_type`` of the container and ``A`` its ``allocator_type``. +- ``XTENSOR_DEFAULT_SHAPE_CONTAINER(T, EA, SA)``: defines the type used as the default shape container for tensors and arrays. + ``T`` is the ``value_type`` of the data container, ``EA`` its ``allocator_type``, and ``SA`` is the ``allocator_type`` + of the shape container. +- ``XTENSOR_DEFAULT_LAYOUT``: defines the default layout (row_major, column_major, dynamic) for tensors and arrays. We *strongly* + discourage using this macro, which is provided for testing purpose. Prefer defining alias types on tensor and array + containers instead. +- ``XTENSOR_DEFAULT_TRAVERSAL``: defines the default traversal order (row_major, column_major) for algorithms and iterators on tensors + and arrays. We *strongly* discourage using this macro, which is provided for testing purpose. + +Build the documentation +----------------------- + +First install the tools required to build the documentation: + +.. code:: + + conda install breathe doxygen sphinx_rtd_theme -c conda-forge + +You can then build the documentation: + +.. code:: + + cd docs + make html + +Type ``make help`` to see the list of available documentation targets. + +.. _xsimd: https://github.com/xtensor-stack/xsimd +.. _tbb: https://github.com/uxlfoundation/oneTBB diff --git a/docs/source/developer/assign_xexpression.svg b/docs/source/developer/assign_xexpression.svg index 25319cbeb..0617796c0 100644 --- a/docs/source/developer/assign_xexpression.svg +++ b/docs/source/developer/assign_xexpression.svg @@ -1,2 +1,2 @@ -
assign_xexpression(lhs, rhs)
assign_xexpression(lhs, rhs)
resize(lhs, rhs)
resize(lhs, rhs)
1
1
assign_data(lhs, rhs, trivial)
assign_data(lhs, rhs, trivial)
2
2
trivial?
trivial?
xsimd?
xsimd?
vectorized index-based loop
vectorized index-based loop
stepper-based loop
stepper-based loop
iterator-based loop
iterator-based loop
yes
yes
yes
yes
no
no
no
no
\ No newline at end of file +
assign_xexpression(lhs, rhs)
assign_xexpression(lhs, rhs)
resize(lhs, rhs)
resize(lhs, rhs)
1
1
assign_data(lhs, rhs, trivial)
assign_data(lhs, rhs, trivial)
2
2
trivial?
trivial?
xsimd?
xsimd?
vectorized index-based loop
vectorized index-based loop
stepper-based loop
stepper-based loop
iterator-based loop
iterator-based loop
yes
yes
yes
yes
no
no
no
no
diff --git a/docs/source/developer/assignment.rst b/docs/source/developer/assignment.rst index 3b17aead6..2d51d7e3e 100644 --- a/docs/source/developer/assignment.rst +++ b/docs/source/developer/assignment.rst @@ -9,14 +9,14 @@ Assignment ========== -In this section, we consider the class ``xarray`` and its semantic bases (``xcontainer_semantic`` and -``xsemantic_base``) to illustrate how the assignment works. `xtensor` provides different mechanics of +In this section, we consider the class :cpp:type:`xt::xarray` and its semantic bases (``xcontainer_semantic`` and +``xsemantic_base``) to illustrate how the assignment works. *xtensor* provides different mechanics of assignment depending on the type of expression. Extended copy semantic ~~~~~~~~~~~~~~~~~~~~~~ -``xarray`` provides an extended copy constructor and an extended assignment operator: +:cpp:type:`xt::xarray` provides an extended copy constructor and an extended assignment operator: .. code:: @@ -37,8 +37,8 @@ The assignment operator forwards to ``xsemantic_base::operator=`` whose implemen return this->derived_cast().assign_temporary(std::move(tmp)); } -Here ``temporary_type`` is ``xarray``, the assignment operator computes the result of the expression in -a temporary variable and then assigns it to the ``xarray`` instance. This temporary variable avoids aliasing +Here ``temporary_type`` is :cpp:type:`xt::xarray`, the assignment operator computes the result of the expression in +a temporary variable and then assigns it to the :cpp:type:`xt::xarray` instance. This temporary variable avoids aliasing when the array is involved in the rhs expression where broadcasting happens: .. code:: @@ -132,7 +132,7 @@ The three main functions for assigning expressions (``assign_xexpression``, ``co tag: .. code:: - + template inline void assign_xexpression(xexpression& e1, const xexpression& e2) { @@ -159,7 +159,7 @@ tag: // ... }; -`xtensor` provides specializations for ``xtensor_expression_tag`` and ``xoptional_expression_tag``. +*xtensor* provides specializations for ``xtensor_expression_tag`` and ``xoptional_expression_tag``. When implementing a new function type whose API is unrelated to the one of ``xfunction_base``, the ``xexpression_assigner`` should be specialized so that the assignment relies on this specific API. @@ -172,10 +172,10 @@ during the resize phase, is the nature of the assignment: trivial or not. The as trivial when the memory layout of the lhs and rhs are such that assignment can be done by iterating over a 1-D sequence on both sides. In that case, two options are possible: -- if ``xtensor`` is compiled with the optional ``xsimd`` dependency, and if the layout and the +- if *xtensor* is compiled with the optional *xsimd* dependency, and if the layout and the ``value_type`` of each expression allows it, the assignment is a vectorized index-based loop - operating on the expression buffers. -- if the ``xsimd`` assignment is not possible (for any reason), an iterator-based loop operating + operating on the expression buffers. +- if the *xsimd* assignment is not possible (for any reason), an iterator-based loop operating on the expresion buffers is used instead. These methods are implemented in specializations of the ``trivial_assigner`` class. @@ -213,4 +213,3 @@ operation on each value: std::transform(d.cbegin(), d.cend(), d.begin(), [e2, &f](const auto& v) { return f(v, e2); }); } - diff --git a/docs/source/developer/computed_assign.svg b/docs/source/developer/computed_assign.svg index 4a31ff162..518784652 100644 --- a/docs/source/developer/computed_assign.svg +++ b/docs/source/developer/computed_assign.svg @@ -1,2 +1,2 @@ -
computed_assign(lhs, rhs)
computed_assign(lhs, rhs)
resize(lhs, rhs)
resize(lhs, rhs)
1
1
assign_data(lhs, rhs, trivial)
assign_data(lhs, rhs, trivial)
2
2
broadcasting?
broadcasting?
no
no
assign_data(tmp, rhs, trivial)
assign_data(tmp, rhs, trivial)
lhs.assign_temporary(tmp)
lhs.assign_temporary(tmp)
yes
yes
1
1
2
2
\ No newline at end of file +
computed_assign(lhs, rhs)
computed_assign(lhs, rhs)
resize(lhs, rhs)
resize(lhs, rhs)
1
1
assign_data(lhs, rhs, trivial)
assign_data(lhs, rhs, trivial)
2
2
broadcasting?
broadcasting?
no
no
assign_data(tmp, rhs, trivial)
assign_data(tmp, rhs, trivial)
lhs.assign_temporary(tmp)
lhs.assign_temporary(tmp)
yes
yes
1
1
2
2
diff --git a/docs/source/developer/concepts.rst b/docs/source/developer/concepts.rst index 3ea368db3..06de0ffd2 100644 --- a/docs/source/developer/concepts.rst +++ b/docs/source/developer/concepts.rst @@ -9,22 +9,24 @@ Concepts ======== -`xtensor`'s core is built upon key concepts captured in interfaces that are put together in -derived classes through CRTP and multiple inheritance. Interfaces and classes that model -expressions implement *value semantic*. CRTP and value semantic achieve static polymorphism and -avoids performance overhead of virtual methods and dynamic dispatching. +*xtensor*'s core is built upon key concepts captured in interfaces that are put together in derived +classes through CRTP (`Curiously Recurring Template Pattern +`_) and multiple inheritance. +Interfaces and classes that model expressions implement *value semantic*. CRTP and value semantic +achieve static polymorphism and avoid performance overhead of virtual methods and dynamic +dispatching. xexpression ~~~~~~~~~~~ -``xexpression`` is the base class for all expression classes. It is a CRTP base whose template +:cpp:type:`xt::xexpression` is the base class for all expression classes. It is a CRTP base whose template parameter must be the most derived class in the hierarchy. For instance, if ``A`` inherits -from ``B`` which in turn inherits from ``xexpression``, then ``B`` should be a template -class whose template parameter is ``A`` and should forward this parameter to ``xexpression``: +from ``B`` which in turn inherits from :cpp:type:`xt::xexpression`, then ``B`` should be a template +class whose template parameter is ``A`` and should forward this parameter to :cpp:type:`xt::xexpression`: .. code:: - #include "xtensor/xexpression.hpp" + #include template class B : public xexpression @@ -37,14 +39,14 @@ class whose template parameter is ``A`` and should forward this parameter to ``x // ... }; -``xexpression`` only provides three overloads of a same function, that cast an ``xexpression`` -object to the most inheriting type, depending on the nature of the object (lvalue, -const lvalue or rvalue): +:cpp:type:`xt::xexpression` only provides three overloads of a same function, that cast an :cpp:type:`xt::xexpression` +object to the most inheriting type, depending on the nature of the object (*lvalue*, +*const lvalue* or *rvalue*): .. code:: derived_type& derived_cast() & noexcept; - const derived_type& derived_cast() & noexcept; + const derived_type& derived_cast() const & noexcept; derived_type derived_cast() && noexcept; .. _xiterable-concept-label: @@ -53,12 +55,18 @@ xiterable ~~~~~~~~~ The iterable concept is modeled by two classes, ``xconst_iterable`` and ``xiterable``, defined -in ``xtensor/xiterable.hpp``. ``xconst_iterable`` provides types and methods for iterating on +in ``xtensor/core/xiterable.hpp``. ``xconst_iterable`` provides types and methods for iterating on constant expressions, similar to the ones provided by the STL containers. Unlike the STL, the methods of ``xconst_iterable`` and ``xiterable`` are templated by a layout parameter that allows you to iterate over a N-dimensional expression in row-major order or column-major order. -Row-major layout means that elements that only differ by their last index are contiguous in memory. -Column-major layout means that elements that only differ by their first index are contiguous in memory. + +.. note:: + + Row-major layout means that elements that only differ by their last index are contiguous in + memory. Column-major layout means that elements that only differ by their first index are + contiguous in memory. + + .. image:: iteration.svg .. code:: @@ -80,20 +88,18 @@ Column-major layout means that elements that only differ by their first index ar template const_reverse_iterator crend() const noexcept; -.. image:: iteration.svg - -This template parameter is defaulted to ``XTENSOR_DEFAULT_LAYOUT`` (see :ref:`configuration-label`), so -that `xtensor` expressions can be used in generic code such as: +This template parameter is defaulted to ``XTENSOR_DEFAULT_TRAVERSAL`` (see :ref:`configuration-label`), so +that *xtensor* expressions can be used in generic code such as: .. code:: std::copy(a.cbegin(), a.cend(), b.begin()); -where ``a`` and ``b`` can be arbitrary types (from `xtensor`, the STL or any external library) +where ``a`` and ``b`` can be arbitrary types (from *xtensor*, the STL or any external library) supporting standard iteration. ``xiterable`` inherits from ``xconst_iterable`` and provides non-const counterpart of methods -defined in ``xconst_iterable``. Like ``xexpression``, both are CRTP classes whose template +defined in ``xconst_iterable``. Like :cpp:type:`xt::xexpression`, both are CRTP classes whose template parameter must be the most derived type. Besides traditional methods for iterating, ``xconst_iterable`` and ``xiterable`` provide overloads @@ -105,7 +111,7 @@ given shape: #include #include #include - #include "xtensor/xarray.hpp" + #include int main(int argc, char* argv[]) { @@ -140,8 +146,8 @@ The first overload is meant for computed assignment involving a scalar; it allow .. code:: - #include "xtensor/xarray.hpp" - #include "xio.hpp" + #include + #include int main(int argc, char* argv) { @@ -154,7 +160,7 @@ The first overload is meant for computed assignment involving a scalar; it allow We rely on SFINAE to remove this overload from the overload resolution set when the parameter that we want to assign is not a scalar, avoiding ambiguity. -Operator-based method taking a general ``xexpression`` parameter don't perform a direct assignment. Instead, +Operator-based methods taking a general :cpp:type:`xt::xexpression` parameter don't perform a direct assignment. Instead, the result is assigned to a temporary variable first, in order to prevent issues with aliasing. Thus, if ``a`` and ``b`` are expressions, the following @@ -185,9 +191,9 @@ Temporaries can be avoided with the assign-based methods: derived_type& modulus_assign(const xexpression&); ``xsemantic_base`` is a CRTP class whose parameter must be the most derived type in the hierarchy. It inherits -from ``xexpression`` and forwards its template parameter to this latter one. +from :cpp:type:`xt::xexpression` and forwards its template parameter to this latter one. -``xsemantic_base`` also provides a assignment operator that takes an ``xexpression`` in its protected section: +``xsemantic_base`` also provides a assignment operator that takes an :cpp:type:`xt::xexpression` in its protected section: .. code:: @@ -241,7 +247,7 @@ methods: disable_integral_t operator[](const S& index) const; template - const_reference operator[](std::initialize_list index) const; + const_reference operator[](std::initializer_list index) const; template const_reference element(It first, It last) const; @@ -257,9 +263,6 @@ methods: template bool broadcast_shape(const S& shape) const; - template - bool is_trivial_broadcast(const S& strides) const; - Lower-level methods are also provided, meant for optimized assignment and BLAS bindings. They are covered in the :ref:`xtensor-assign-label` section. @@ -267,8 +270,8 @@ If you read the entire code of ``xcontainer``, you'll notice that two types are strides and backstrides: ``shape_type`` and ``inner_shape_type``, ``strides_type`` and ``inner_strides_type``, and ``backstrides_type`` and ``inner_backstrides_type``. The distinction between ``inner_shape_type`` and ``shape_type`` was motivated by the xtensor-python wrapper around -numpy data structures, where the inner shape type is a proxy on the shape section of the numpy -arrayobject. It cannot have a value semantics on its own as it is bound to the entire numpy array. +NumPy data structures, where the inner shape type is a proxy on the shape section of the NumPy +arrayobject. It cannot have a value semantics on its own as it is bound to the entire NumPy array. ``xstrided_container`` inherits from ``xcontainer``; it represents a container that holds its shape and strides. It provides methods for reshaping the container: diff --git a/docs/source/developer/expression_tree.rst b/docs/source/developer/expression_tree.rst index a5e6c2eb9..b33907e05 100644 --- a/docs/source/developer/expression_tree.rst +++ b/docs/source/developer/expression_tree.rst @@ -7,14 +7,14 @@ Expression tree =============== -Most of the expressions in `xtensor` are lazy-evaluated, they do not hold any value, the values are computed upon -access or when the expression is assigned to a container. This means that `xtensor` needs somehow to keep track of +Most of the expressions in *xtensor* are lazy-evaluated, they do not hold any value, the values are computed upon +access or when the expression is assigned to a container. This means that *xtensor* needs somehow to keep track of the expression tree. xfunction ~~~~~~~~~ -A node in the expression tree may be represented by different classes in `xtensor`; here we focus on basic arithmetic +A node in the expression tree may be represented by different classes in *xtensor*; here we focus on basic arithmetic operations and mathematical functions, which are represented by an instance of ``xfunction``. This is a template class whose parameters are: @@ -105,7 +105,7 @@ This latter is responsible for setting the remaining template parameters of ``xf } The first line computes the ``expression_tag`` of the expression. This tag is used for selecting the right class -class modeling a function. In `xtensor`, two tags are provided, with the following mapping: +class modeling a function. In *xtensor*, two tags are provided, with the following mapping: - ``xtensor_expression_tag`` -> ``xfunction`` - ``xoptional_expression_tag`` -> ``xfunction`` @@ -114,7 +114,7 @@ In the case of ``xfunction``, the tag is also used to select a mixin base class Any expression may define a tag as its ``expression_tag`` inner type. If not, ``xtensor_expression_tag`` is used by default. Tags have different priorities so that a resulting tag can be computed for expressions involving different tag types. As we -will see in the next section, this system of tags and mapping make it easy to plug new functions types in `xtensor` and have +will see in the next section, this system of tags and mapping make it easy to plug new functions types in *xtensor* and have them working with all the mathematical functions already implemented. The function class mapped to the expression tag is retrieved in the third line of ``make_xfunction``, that is: @@ -135,7 +135,7 @@ Once all the types are known, ``make_xfunction`` can instantiate the right funct Plugging new function types ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -As mentioned in the section above, one can define a new function class and have it used by `xtensor`'s expression system. Let's +As mentioned in the section above, one can define a new function class and have it used by *xtensor*'s expression system. Let's illustrate this with an hypothetical ``xmapped_function`` class, which provides additional mapping access operators. The first thing to do is to define a new tag: @@ -170,7 +170,7 @@ This is done by specializing the ``expression_tag_and`` metafunction available i The second specialization simply forwards to the first one so we don't duplicate code. Note that when plugging your own function class, these specializations can be skipped if the new function class (and its corresponding tag) is not compatible, -and thus not supposed to be mixed, with the function classes provided by `xtensor`. +and thus not supposed to be mixed, with the function classes provided by *xtensor*. The last requirement is to specialize the ``select_xfunction_expression`` metafunction, as it is shown below: @@ -191,4 +191,3 @@ The last requirement is to specialize the ``select_xfunction_expression`` metafu In this example, ``xmapped_function`` may provide the same API as ``xfunction`` and define some additional methods unrelated to the assignment mechanics. However it is possible to define a function class with an API totally different from the one of ``xfunction``. In that case, the assignment mechanics need to be customized too, this is detailed in :ref:`xtensor-assign-label`. - diff --git a/docs/source/developer/extended_copy_semantic.svg b/docs/source/developer/extended_copy_semantic.svg index f2cfc6503..25360df81 100644 --- a/docs/source/developer/extended_copy_semantic.svg +++ b/docs/source/developer/extended_copy_semantic.svg @@ -1,2 +1,2 @@ -
xarray::operator=
[Not supported by viewer]
xcontainer_semantic::operator=
[Not supported by viewer]
xsemantic_base::operator=
[Not supported by viewer]
xarray::xarray
[Not supported by viewer]
xsemantic_base::assign
xsemantic_base::assign
xcontainer_semantic::assign_xexpression
xcontainer_semantic::assign_xexpression
xcontainer_semantic::assign_temporary
xcontainer_semantic::assign_temporary
1
1
2
2
xt::assign_xexpression
xt::assign_xexpression
\ No newline at end of file +
xarray::operator=
[Not supported by viewer]
xcontainer_semantic::operator=
[Not supported by viewer]
xsemantic_base::operator=
[Not supported by viewer]
xarray::xarray
[Not supported by viewer]
xsemantic_base::assign
xsemantic_base::assign
xcontainer_semantic::assign_xexpression
xcontainer_semantic::assign_xexpression
xcontainer_semantic::assign_temporary
xcontainer_semantic::assign_temporary
1
1
2
2
xt::assign_xexpression
xt::assign_xexpression
diff --git a/docs/source/developer/implementation_classes.rst b/docs/source/developer/implementation_classes.rst index 152390a1d..d8ead757d 100644 --- a/docs/source/developer/implementation_classes.rst +++ b/docs/source/developer/implementation_classes.rst @@ -10,9 +10,9 @@ Implementation classes Requirements ~~~~~~~~~~~~ -An implementation class in `xtensor` is a final class that models a specific +An implementation class in *xtensor* is a final class that models a specific kind of expression. It must inherit (either directly or indirectly) from -``xexpression`` and define (or inherit from classes that define) the following +:cpp:type:`xt::xexpression` and define (or inherit from classes that define) the following types: **container types** @@ -46,10 +46,10 @@ types: template const_reverse_broadcast_iterator; - storage_iterator; - const_storage_iterator; - reverse_storage_iterator; - const_reverse_storage_iterator; + linear_iterator; + const_linear_iterator; + reverse_linear_iterator; + const_reverse_linear_iterator; **layout data** @@ -77,9 +77,6 @@ totally: template bool broadcast_shape(const S& shape) const; - template - bool is_trivial_broadcast(const S& strides) const; - **data access methods** .. code:: @@ -97,7 +94,7 @@ totally: disable_integral_t operator[](const S& index) const; template - const_reference operator[](std::initialize_list index) const; + const_reference operator[](std::initializer_list index) const; template const_reference element(It first, It last) const; @@ -115,7 +112,7 @@ methods, and inherits from a semantic class to provide assignment operators. List of available expression classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -`xtensor` provides the following expression classes: +*xtensor* provides the following expression classes: **Containers** @@ -132,8 +129,8 @@ inheriting classes only provide constructors and assignment operators for the va The container classes are generally used through type aliases which set many of the template arguments: -- ``xarray`` -- ``xtensor`` +- :cpp:type:`xt::xarray` +- :cpp:type:`xt::xtensor` - ``xfixed_tensor`` The classes for adaptors can be instantiated through the many overloads of ``xt::adapt`` function, @@ -141,7 +138,7 @@ so that their templates parameters are deduced. **Scalar** -`xtensor` provides the ``xscalar`` class to adapt scalar values and give them the required API. +*xtensor* provides the ``xscalar`` class to adapt scalar values and give them the required API. **Optional containers** @@ -152,7 +149,7 @@ Most of the mehtods of these classes are defined in their base class ``xoptional **Views** -- ``xview``: N-dimensional view with static number of slices, supporting all kind of slices +- :cpp:type:`xt::xview`: N-dimensional view with static number of slices, supporting all kind of slices - ``xstrided_view``: N-dimensional view with dynamic number of slices, supporting strided slices only (see below) - ``xdynamic_view``: N-dimensional view with dynamic number of slices, supporting all kind of slices - ``xfunctor_view``: N-dimensional view applying a functor to its underlying elements (e.g. ``imag``, ``real``) @@ -160,7 +157,7 @@ Most of the mehtods of these classes are defined in their base class ``xoptional - ``xmasked_view`` : View on optional expression hiding values depending on a mask When the index of an element in the underlying expression of a view can be computed thanks to a strided scheme, -the slice used in this view is said to be a strided slice. `xtensor` provides the following strided slices: +the slice used in this view is said to be a strided slice. *xtensor* provides the following strided slices: - ``xrange`` - ``xstepped_range`` @@ -184,16 +181,16 @@ Contrary to containers and views, the functional expressions are immutable. xarray and xtensor ~~~~~~~~~~~~~~~~~~ -Although they represent different concepts, ``xarray`` and ``xtensor`` have really similar -implementations so only ``xarray`` will be covered. +Although they represent different concepts, :cpp:type:`xt::xarray` and :cpp:type:`xt::xtensor` have really similar +implementations so only :cpp:type:`xt::xarray` will be covered. -``xarray`` is a strided array expression that can be assigned to. Everything ``xarray`` needs -is already defined in classes modeling :ref:`concepts-label`, so ``xarray`` only has to inherit +:cpp:type:`xt::xarray` is a strided array expression that can be assigned to. Everything :cpp:type:`xt::xarray` needs +is already defined in classes modeling :ref:`concepts-label`, so :cpp:type:`xt::xarray` only has to inherit from these classes and define constructors and assignment operators: .. image:: xarray_uml.svg -Besides implementing the methods that define value semantic, ``xarray`` and ``xtensor`` hold +Besides implementing the methods that define value semantic, :cpp:type:`xt::xarray` and :cpp:type:`xt::xtensor` hold the data container. Since the ``xcontainer`` base class implements all the logic for accessing the data, it must me able to access the data container. This is achieved by requiring that every class inheriting from ``xcontainer`` provides the following methods: @@ -204,7 +201,7 @@ every class inheriting from ``xcontainer`` provides the following methods: const storage_type& storage_impl() const noexcept; These are the implementation methods of the ``storage()`` interface methods defined in ``xcontainer``, -and thus are defined in the private section of ``xarray`` and ``xtensor``. In order to grant access +and thus are defined in the private section of :cpp:type:`xt::xarray` and :cpp:type:`xt::xtensor`. In order to grant access to ``xcontainer``, this last one is declared as ``friend``: .. code:: @@ -236,8 +233,8 @@ Although the base classes use the types defined in the Requirement section, they define them; first because different base classes may need the same types and we want to avoid duplication of type definitions. The second reason is that most of the types may rely on other types specific to the implementation classes. For instance, -``value_type``, ``reference``, etc, of ``xarray`` are simply the types defined in the -container type hold by ``xarray``: +``value_type``, ``reference``, etc, of :cpp:type:`xt::xarray` are simply the types defined in the +container type hold by :cpp:type:`xt::xarray`: .. code:: diff --git a/docs/source/developer/iterating_expression.rst b/docs/source/developer/iterating_expression.rst index afd81c1f1..706a50c0c 100644 --- a/docs/source/developer/iterating_expression.rst +++ b/docs/source/developer/iterating_expression.rst @@ -12,7 +12,7 @@ Iterating over expressions xiterable and inner types ~~~~~~~~~~~~~~~~~~~~~~~~~ -`xtensor` provides two base classes for making expressions iterable: ``xconst_iterable`` and ``xiterable``. They define +*xtensor* provides two base classes for making expressions iterable: ``xconst_iterable`` and ``xiterable``. They define the API for iterating as described in :ref:`concepts-label`. For an expression to be iterable, it must inherit directly or indirectly from one of these classes. For instance, the ``xbroadcast`` class is defined as following: @@ -108,7 +108,7 @@ amount in a given dimension, dereferencing the stepper, and moving it to the beg .. code:: reference operator*() const; - + void step(size_type dim, size_type n = 1); void step_back(size_type dim, size_type n = 1); void reset(size_type dim); @@ -123,7 +123,7 @@ expression, etc...) in the expression, and can then be used to browse the expres .. image:: stepper_basic.svg -In this diagram, the data is stored in row-major order, and we step in the second dimension (dimension index starts at 0). +In this diagram, the data is stored in row-major order, and we step in the first dimension (dimension index starts at 0). The positions of the stepper are represented by the red dots. The ``to_end`` method takes a layout parameter, because the ending positions of a stepper depend on the layout used to iterate. @@ -137,7 +137,7 @@ in row-major order. Thus, if we assume that ``p`` is a pointer to the last eleme of the stepper are ``p + 1`` in row-major, and ``p + 3`` in column-major order. A stepper is specific to an expression type, therefore implementing a new kind of expression usually requires to implement a new -kind of stepper. However `xtensor` provides a generic ``xindexed_stepper`` class, that can be used with any kind of expressions. +kind of stepper. However *xtensor* provides a generic ``xindexed_stepper`` class, that can be used with any kind of expressions. Even though it is generally not optimal, authors of new expression types can make use of the generic index stepper in a first implementation. @@ -155,7 +155,7 @@ method would be: m_it += n * p_c->strides()[dim]; } -where ``m_it`` is an itrator on the underlying buffer, and ``p_c`` a pointer to the container_based expression. +where ``m_it`` is an iterator on the underlying buffer, and ``p_c`` a pointer to the container-based expression. However, this implementation fails when broadcasting is involved. Consider the following expression: @@ -187,7 +187,7 @@ avoid that, a broadcasting offset is added to the stepper: } This implementation takes into account that the broadcasting is done on the last dimension and dimensions are stored in ascending -order; here dimension 1 of ``a`` correpsonds to dimension 0 of ``b``. +order; here dimension 1 of ``a`` corresponds to dimension 0 of ``b``. This implementation ensures that a step in dimension 0 of the function updates the stepper of ``a`` while the stepper of ``b`` remains unchanged; on the other hand, stepping in dimension 1 will update both steppers, as illustrated below: @@ -200,11 +200,11 @@ with different dimension arguments. Iterators ~~~~~~~~~ -`xtensor` iterator is implemented in the ``xiterator`` class. This latter provides a STL compliant iterator interface, and is built +*xtensor* iterator is implemented in the ``xiterator`` class. This latter provides a STL compliant iterator interface, and is built upon the steppers. Whereas the steppers are tied to the expression they refer to, ``xiterator`` is generic enough to work with any kind of stepper. -An iterator holds a stepper an multi-dimensional index. A call to ``operator++`` increases the index and calls the ``step`` method +An iterator holds a stepper and a multi-dimensional index. A call to ``operator++`` increases the index and calls the ``step`` method of the stepper accordingly. The way the index is increased depends on the layout used for iterating. For a row-major order iteration over a container with shape ``{3, 4}``, the index iterating sequence is: @@ -224,7 +224,7 @@ over a container with shape ``{3, 4}``, the index iterating sequence is: {2, 3} When a member of an index reaches its maximum value, it is reset to 0 and the member in the next dimension is increased. This translates -in the calls of two methods of the stepper, first ``reset`` and then ``step``. This is illustrated by the following picture: +into the calls of two methods of the stepper, first ``reset`` and then ``step``. This is illustrated by the following picture: .. image:: stepper_iterating.svg @@ -234,4 +234,3 @@ from ``{0, 3}`` to ``{1, 0}``: first the stepper is reset to ``{0, 0}``, then `` ``xiterator`` implements a random access iterator, providing ``operator--`` and ``operator[]`` methods. The implementation of these methods is similar to the one of ``operator++``. - diff --git a/docs/source/developer/iteration.svg b/docs/source/developer/iteration.svg index efb1d2973..b0db64d8b 100644 --- a/docs/source/developer/iteration.svg +++ b/docs/source/developer/iteration.svg @@ -1,2 +1,2 @@ -
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
1
1
2
2
row major iteration 
[Not supported by viewer]
column major iteration
[Not supported by viewer]
\ No newline at end of file +
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
1
1
2
2
row major iteration 
[Not supported by viewer]
column major iteration
[Not supported by viewer]
diff --git a/docs/source/developer/stepper_basic.svg b/docs/source/developer/stepper_basic.svg index a2eec3803..69860f25e 100644 --- a/docs/source/developer/stepper_basic.svg +++ b/docs/source/developer/stepper_basic.svg @@ -1,2 +1,2 @@ -
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
step(0, 2) 
step(0, 2)&nbsp;
\ No newline at end of file +
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
step(0, 2) 
step(0, 2)&nbsp;
diff --git a/docs/source/developer/stepper_broadcasting.svg b/docs/source/developer/stepper_broadcasting.svg index f32982f50..5da35695e 100644 --- a/docs/source/developer/stepper_broadcasting.svg +++ b/docs/source/developer/stepper_broadcasting.svg @@ -1,2 +1,2 @@ -
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
0
0
1
1
2
2
3
3
+
[Not supported by viewer]
step(1, 2)
step(1, 2)
step(0, 2)
[Not supported by viewer]
step(1, 2)
step(1, 2)
step(0, 2)
[Not supported by viewer]
step(1, 2)
step(1, 2)
step(0, 2)
[Not supported by viewer]
\ No newline at end of file +
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
0
0
1
1
2
2
3
3
+
[Not supported by viewer]
step(1, 2)
step(1, 2)
step(0, 2)
[Not supported by viewer]
step(1, 2)
step(1, 2)
step(0, 2)
[Not supported by viewer]
step(1, 2)
step(1, 2)
step(0, 2)
[Not supported by viewer]
diff --git a/docs/source/developer/stepper_iterating.svg b/docs/source/developer/stepper_iterating.svg index 92a7d8d4c..027d6739f 100644 --- a/docs/source/developer/stepper_iterating.svg +++ b/docs/source/developer/stepper_iterating.svg @@ -1,2 +1,2 @@ -
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
step(1, 1)
step(1, 1)
reset(1)
reset(1)
step(0, 1)
step(0, 1)
{0, 3} to {1, 0}
{0, 3} to {1, 0}
{0, 0} to {0, 3}
[Not supported by viewer]
\ No newline at end of file +
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
step(1, 1)
step(1, 1)
reset(1)
reset(1)
step(0, 1)
step(0, 1)
{0, 3} to {1, 0}
{0, 3} to {1, 0}
{0, 0} to {0, 3}
[Not supported by viewer]
diff --git a/docs/source/developer/stepper_to_end.svg b/docs/source/developer/stepper_to_end.svg index ce24546a2..588899cf9 100644 --- a/docs/source/developer/stepper_to_end.svg +++ b/docs/source/developer/stepper_to_end.svg @@ -1,2 +1,2 @@ -
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
step_back(1, 1)
step_back(1, 1)
step_back(0, 1)
step_back(0, 1)
\ No newline at end of file +
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
step_back(1, 1)
step_back(1, 1)
step_back(0, 1)
step_back(0, 1)
diff --git a/docs/source/developer/xarray_uml.svg b/docs/source/developer/xarray_uml.svg index 2cc84c29c..958d142ea 100644 --- a/docs/source/developer/xarray_uml.svg +++ b/docs/source/developer/xarray_uml.svg @@ -1,3 +1,3 @@ -
xexpression
xexpression
xarray
xarray
xsemantic_base
xsemantic_base
xarray
xarray
xcontainer_semantic
xcontainer_semantic
xarray
xarray
xconst_iterable
xconst_iterable
xarray
xarray
xiterable
xiterable
xarray
xarray
xcontainer
xcontainer
xarray
xarray
xstrided_container
xstrided_container
xarray
xarray
xarray
xarray
xcontiguous_iterable
xcontiguous_iterable
xarray
xarray
\ No newline at end of file +
xexpression
xexpression
xarray
xarray
xsemantic_base
xsemantic_base
xarray
xarray
xcontainer_semantic
xcontainer_semantic
xarray
xarray
xconst_iterable
xconst_iterable
xarray
xarray
xiterable
xiterable
xarray
xarray
xcontainer
xcontainer
xarray
xarray
xstrided_container
xstrided_container
xarray
xarray
xarray
xarray
xcontiguous_iterable
xcontiguous_iterable
xarray
xarray
diff --git a/docs/source/developer/xcontainer_classes.svg b/docs/source/developer/xcontainer_classes.svg index 3d5a55320..ecfa32f63 100644 --- a/docs/source/developer/xcontainer_classes.svg +++ b/docs/source/developer/xcontainer_classes.svg @@ -1,2 +1,2 @@ -
xconst_iterable
xconst_iterable
D
D
xiterable
xiterable
D
D
xcontainer
xcontainer
D
D
xstrided_container
xstrided_container
D
D
xcontiguous_iterable
xcontiguous_iterable
D
D
\ No newline at end of file +
xconst_iterable
xconst_iterable
D
D
xiterable
xiterable
D
D
xcontainer
xcontainer
D
D
xstrided_container
xstrided_container
D
D
xcontiguous_iterable
xcontiguous_iterable
D
D
diff --git a/docs/source/developer/xfunction_tree.svg b/docs/source/developer/xfunction_tree.svg index a0b551d8a..791a9cd06 100644 --- a/docs/source/developer/xfunction_tree.svg +++ b/docs/source/developer/xfunction_tree.svg @@ -1,2 +1,2 @@ -
+
+
xfunction<plus, ...>
xfunction&lt;plus, ...<span>&gt;</span>
const xarray<double>&
const xarray&lt;double&gt;&amp;
const xarray<double>&
const xarray&lt;double&gt;&amp;
a
[Not supported by viewer]
b
[Not supported by viewer]
\ No newline at end of file +
+
+
xfunction<plus, ...>
xfunction&lt;plus, ...<span>&gt;</span>
const xarray<double>&
const xarray&lt;double&gt;&amp;
const xarray<double>&
const xarray&lt;double&gt;&amp;
a
[Not supported by viewer]
b
[Not supported by viewer]
diff --git a/docs/source/developer/xsemantic_classes.svg b/docs/source/developer/xsemantic_classes.svg index 861d145ae..95c501844 100644 --- a/docs/source/developer/xsemantic_classes.svg +++ b/docs/source/developer/xsemantic_classes.svg @@ -1,2 +1,2 @@ -
xexpression
xexpression
D
D
xsemantic_base
xsemantic_base
D
D
xcontainer_semantic
xcontainer_semantic
D
D
xview_semantic
xview_semantic
D
D
\ No newline at end of file +
xexpression
xexpression
D
D
xsemantic_base
xsemantic_base
D
D
xcontainer_semantic
xcontainer_semantic
D
D
xview_semantic
xview_semantic
D
D
diff --git a/docs/source/developer/xtensor_internals.rst b/docs/source/developer/xtensor_internals.rst index f03c844e0..ff1e897dd 100644 --- a/docs/source/developer/xtensor_internals.rst +++ b/docs/source/developer/xtensor_internals.rst @@ -7,8 +7,8 @@ Internals of xtensor ==================== -This section provides information about `xtensor`'s internals and its architecture. It is intended for developers -who want to contribute to `xtensor` or simply understand how it works under the hood. `xtensor` makes heavy use +This section provides information about *xtensor*'s internals and its architecture. It is intended for developers +who want to contribute to *xtensor* or simply understand how it works under the hood. *xtensor* makes heavy use of the CRTP pattern, template meta-programming, universal references and perfect forwarding. One should be familiar with these notions before going any further. diff --git a/docs/source/expression.rst b/docs/source/expression.rst index 4910e5280..8aa5d7324 100644 --- a/docs/source/expression.rst +++ b/docs/source/expression.rst @@ -10,16 +10,16 @@ Expressions and lazy evaluation =============================== -`xtensor` is more than an N-dimensional array library: it is an expression engine that allows numerical computation on any object implementing the expression interface. -These objects can be in-memory containers such as ``xarray`` and ``xtensor``, but can also be backed by a database or a representation on the file system. This -also enables creating adaptors as expressions for other data structures. +*xtensor* is more than an N-dimensional array library: it is an expression engine that allows numerical computation on any object implementing the expression interface. +These objects can be in-memory containers such as :cpp:type:`xt::xarray\` and :cpp:type:`xt::xtensor\`, but can also be backed by a database or a representation on the file system. +This also enables creating adaptors as expressions for other data structures. Expressions ----------- Assume ``x``, ``y`` and ``z`` are arrays of *compatible shapes* (we'll come back to that later), the return type of an expression such as ``x + y * sin(z)`` is **not an array**. -The result is an ``xexpression`` which offers the same interface as an N-dimensional array but does not hold any value. Such expressions can be plugged into others to build -more complex expressions: +The result is an :cpp:type:`xt::xexpression` which offers the same interface as an N-dimensional array but does not hold any value. +Such expressions can be plugged into others to build more complex expressions: .. code:: @@ -27,12 +27,12 @@ more complex expressions: auto f2 = w + 2 * cos(f); The expression engine avoids the evaluation of intermediate results and their storage in temporary arrays, so you can achieve the same performance as if you had written -a simple loop. Assuming ``x``, ``y`` and ``z`` are one-dimensional arrays of length ``n``, +a simple loop. Assuming ``x``, ``y`` and ``z`` are one-dimensional arrays of length ``n``, .. code:: xt::xarray res = x + y * sin(z) - + will produce quite the same assembly as the following loop: .. code:: @@ -71,8 +71,10 @@ and the size of the data, it might be convenient to store the result of the expr Forcing evaluation ------------------ -If you have to force the evaluation of an xexpression for some reason (for example, you want to have all results in memory to perform a sort or use external BLAS functions) then you can use ``xt::eval`` on an xexpression. -Evaluating will either return an rvalue to a newly allocated container in the case of a xexpression, or a reference to a container in case you are evaluating a ``xarray`` or ``xtensor``. Note that, in order to avoid copies, you should use an universal reference on the lefthand side (``auto&&``). For example: +If you have to force the evaluation of an xexpression for some reason (for example, you want to have all results in memory to perform a sort or use external BLAS functions) then you can use :cpp:func:`xt::eval` on an xexpression. +Evaluating will either return a *rvalue* to a newly allocated container in the case of an xexpression, or a reference to a container in case you are evaluating a :cpp:type:`xt::xarray` or :cpp:type:`xt::xtensor`. +Note that, in order to avoid copies, you should use a universal reference on the lefthand side (``auto&&``). +For example: .. code:: @@ -86,23 +88,23 @@ Evaluating will either return an rvalue to a newly allocated container in the ca Broadcasting ------------ -The number of dimensions of an ``xexpression`` and the sizes of these dimensions are provided by the ``shape()`` method, which returns a sequence of unsigned integers -specifying the size of each dimension. We can operate on expressions of different shapes of dimensions in an elementwise fashion. Broadcasting rules of `xtensor` are -similar to those of Numpy_ and libdynd_. +The number of dimensions of an :cpp:type:`xt::xexpression` and the sizes of these dimensions are provided by the :cpp:func:`~xt::xexpression::shape` method, which returns a sequence of unsigned integers +specifying the size of each dimension. We can operate on expressions of different shapes of dimensions in an elementwise fashion. +Broadcasting rules of *xtensor* are similar to those of NumPy_ and libdynd_. In an operation involving two arrays of different dimensions, the array with the lesser dimensions is broadcast across the leading dimensions of the other. -For example, if ``A`` has shape ``(2, 3)``, and ``B`` has shape ``(4, 2, 3)``, the result of a broadcasted operation with ``A`` and ``B`` has shape ``(4, 2, 3)``. +For example, if ``A`` has shape ``(2, 3)``, and ``B`` has shape ``(4, 2, 3)``, the result of a broadcast operation with ``A`` and ``B`` has shape ``(4, 2, 3)``. -.. code:: +.. code:: none (2, 3) # A (4, 2, 3) # B --------- (4, 2, 3) # Result -The same rule holds for scalars, which are handled as 0-D expressions. If `A` is a scalar, the equation becomes: +The same rule holds for scalars, which are handled as 0-D expressions. If ``A`` is a scalar, the equation becomes: -.. code:: +.. code:: none () # A (4, 2, 3) # B @@ -112,28 +114,62 @@ The same rule holds for scalars, which are handled as 0-D expressions. If `A` is If matched up dimensions of two input arrays are different, and one of them has size ``1``, it is broadcast to match the size of the other. Let's say B has the shape ``(4, 2, 1)`` in the previous example, so the broadcasting happens as follows: -.. code:: +.. code:: none (2, 3) # A (4, 2, 1) # B --------- (4, 2, 3) # Result +Accessing elements +------------------ + +You can access the elements of any :cpp:type:`xt::xexpression` with :cpp:func:`~xt::xexpression::operator()()`: + +.. code:: + + #include + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + auto f = 2 * a; + + double d1 = a(0, 2); + double d2 = f(1, 2); + +It is possible to call :cpp:func:`~xt::xexpression::operator()()` with fewer or more arguments than the number of dimensions +of the expression: + +- if :cpp:func:`~xt::xexpression::operator()()` is called with too many arguments, we drop the most left ones +- if :cpp:func:`~xt::xexpression::operator()()` is called with too few arguments, we prepend them with ``0`` values until + we match the number of dimensions + +.. code:: + + #include + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + + double d1 = a(2); // equivalent to a(0, 2) + double d2 = a(1, 1, 2) // equivalent to a(1, 2) + +The reason for this is that it is the one rule that ensures ``(a + b)(i0, ..., in) = a(i0, ..., in) + b(i0, ..., in)``, +i.e. commutativity of element access and broadcasting. + Expression interface -------------------- -All ``xexpression`` s in `xtensor` provide at least the following interface: +All :cpp:type:`xt::xexpression` s in :cpp:type:`xt::xtensor` provide at least the following interface: Shape ~~~~~ -- ``dimension()`` returns the number of dimension of the expression. -- ``shape()`` returns the shape of the expression. +- :cpp:func:`~xt::xexpression::dimension`: returns the number of dimensions of the expression. +- :cpp:func:`~xt::xexpression::shape`: returns the shape of the expression. .. code:: #include - #include "xtensor/xarray.hpp" + #include using array_type = xt::xarray; using shape_type = array_type::shape_type; @@ -147,15 +183,23 @@ Shape Element access ~~~~~~~~~~~~~~ -- ``operator()`` is an access operator which can take multiple integral arguments or none. -- ``at()`` is similar to ``operator()`` but checks that its number of arguments does not exceed the number of dimensions, and performs bounds checking. This should not be used where you expect ``operator()`` to perform broadcasting. -- ``operator[]`` has two overloads: one that takes a single integral argument and is equivalent to the call of ``operator()`` with one argument, and one with a single multi-index argument, which can be of a size determined at runtime. This operator also supports braced initializer arguments. -- ``element()`` is an access operator which takes a pair of iterators on a container of indices. +- :cpp:func:`~xt::xexpression::operator()()` is an access operator that can take multiple integral arguments or none. +- :cpp:func:`~xt::xexpression::at` is similar to :cpp:func:`~xt::xexpression::operator()()` but checks that its number + of arguments does not exceed the number of dimensions, and performs bounds checking. + This should not be used where you expect :cpp:func:`~xt::xexpression::operator()()` to perform broadcasting. +- :cpp:func:`~xt::xexpression::operator[]` has two overloads: one that takes a single integral argument and is + equivalent to the call of :cpp:func:`~xt::xexpression::operator()()` with one argument, and one with a single + multi-index argument, which can be of a size determined at runtime. + This operator also supports braced initializer arguments. +- :cpp:func:`~xt::xexpression::element` is an access operator which takes a pair of iterators on a container of indices. +- :cpp:func:`~xt::xexpression::periodic` is the equivalent of :cpp:func:`~xt::xexpression::operator()()` that can deal + with periodic indices (for example ``-1`` for the last item along an axis). +- :cpp:func:`~xt::xexpression::in_bounds` returns a ``bool`` that is ``true`` only if indices are valid for the array. .. code:: #include - #inclde "xtensor/xarray.hpp" + #inclde "xtensor/containers/xarray.hpp" // xt::xarray a = ... std::vector index = {1, 1, 1}; @@ -167,12 +211,26 @@ Element access Iterators ~~~~~~~~~ -- ``begin()`` and ``end()`` return instances of ``xiterator`` which can be used to iterate over all the elements of the expression. The layout of the iteration can be specified - through the ``layout_type`` template parameter, accepted values are ``layout_type::row_major`` and ``layout_type::column_major``. If not specified, ``XTENSOR_DEFAULT_LAYOUT`` is used. - This iterator pair permits to use algorithms of the STL with ``xexpression`` as if they were simple containers. -- ``begin(shape)`` and ``end(shape)`` are similar but take a *broadcasting shape* as an argument. Elements are iterated upon in ``XTENSOR_DEFAULT_LAYOUT`` if no ``layout_type`` template parameter is specified. Certain dimensions are repeated to match the provided shape as per the rules described above. -- ``rbegin()`` and ``rend()`` return instances of ``xiterator`` which can be used to iterate over all the elements of the reversed expression. As ``begin()`` and ``end()``, the layout of the iteration can be specified through the ``layout_type`` parameter. -- ``rbegin(shape)`` and ``rend(shape)`` are the reversed counterpart of ``begin(shape)`` and ``end(shape)``. - -.. _NumPy: http://www.numpy.org +- :cpp:func:`~xt::xexpression::begin` and :cpp:func:`~xt::xexpression::end` return instances of :cpp:type:`xt::xiterator` + which can be used to iterate over all the elements of the expression. + The layout of the iteration can be specified through the :cpp:enum:`xt::layout_type` template parameter, accepted values + are :cpp:enumerator:`xt::layout_type::row_major` and :cpp:enumerator:`xt::layout_type::column_major`. + If not specified, :c:macro:`XTENSOR_DEFAULT_TRAVERSAL` is used. + This iterator pair permits to use algorithms of the STL with :cpp:type:`xt::xexpression` as if they were simple containers. +- :cpp:func:`begin(shape) ` and + :cpp:func:`end(shape) ` are similar but take a *broadcasting shape* + as an argument. + Elements are iterated upon in :c:macro:`XTENSOR_DEFAULT_TRAVERSAL` if no :cpp:enum:`xt::layout_type` template parameter + is specified. + Certain dimensions are repeated to match the provided shape as per the rules described above. +- :cpp:func:`~xt::xexpression::rbegin` and :cpp:func:`~xt::xexpression::rend` return instances of :cpp:type:`xt::xiterator` + which can be used to iterate over all the elements of the reversed expression. + As :cpp:func:`~xt::xexpression::begin` and :cpp:func:`~xt::xexpression::end`, the layout of the iteration can be + specified through the :cpp:enum:`xt::layout_type` parameter. +- :cpp:func:`rbegin(shape) ` and + :cpp:func:`rend(shape) ` are the reversed counterpart of + :cpp:func:`begin(shape) ` and + :cpp:func:`end(shape) `. + +.. _NumPy: https://numpy.org/ .. _libdynd: http://libdynd.org diff --git a/docs/source/external-structures.rst b/docs/source/external-structures.rst index 4b74ad404..4d82738f2 100644 --- a/docs/source/external-structures.rst +++ b/docs/source/external-structures.rst @@ -7,14 +7,14 @@ Extending xtensor ================= -``xtensor`` provides means to plug external data structures into its expression engine without +*xtensor* provides means to plug external data structures into its expression engine without copying any data. Adapting one-dimensional containers ----------------------------------- You may want to use your own one-dimensional container as a backend for tensor data containers -and even for the shape or the strides. This is the simplest structure to plug into ``xtensor``. +and even for the shape or the strides. This is the simplest structure to plug into *xtensor*. In the following example, we define new container and adaptor types for user-specified storage and shape types. .. code:: @@ -27,7 +27,7 @@ In the following example, we define new container and adaptor types for user-spe using my_tensor_type = xt::xtensor_container; using my_adaptor_type = xt::xtensor_adaptor; -These new types will have all the features of the core ``xt::xtensor`` and ``xt::xarray`` types. +These new types will have all the features of the core :cpp:type:`xt::xtensor` and :cpp:type:`xt::xarray` types. ``xt::xarray_container`` and ``xt::xtensor_container`` embed the data container, while ``xt::xarray_adaptor`` and ``xt::xtensor_adaptor`` hold a reference on an already initialized container. @@ -39,15 +39,43 @@ A requirement for the user-specified containers is to provide a minimal ``std::v - iterator methods (``begin``, ``end``, ``cbegin``, ``cend``) - ``size`` and ``reshape``, ``resize`` methods -``xtensor`` does not require that the container has a contiguous memory layout, only that it +*xtensor* does not require that the container has a contiguous memory layout, only that it provides the aforementioned interface. In fact, the container could even be backed by a file on the disk, a database or a binary message. +Adapting a pointer +------------------ + +Suppose that you want to use the *xtensor* machinery on a small contiguous subset of a large tensor. +You can, of course, use :ref:`view-description`, but for efficiency you can also use pointers to the right bit of memory. +Consider an example of an ``[M, 2, 2]`` tensor ``A``, +for which you want to operate on ``A[i, :, :]`` for different ``i``. +In this case the most efficient *xtensor* has to offer is: + +.. code-block:: cpp + + int main() + { + size_t M = 3; + size_t nd = 2; + size_t size = nd * nd; + xt::xarray A = xt::arange(M * size).reshape({M, nd, nd}); + auto b = xt::adapt(&A.flat(0), std::array{nd, nd}); + + for (size_t i = 0; i < M; ++i) { + b.reset_buffer(&A.flat(i * size), size); + } + return 0; + } + +where ``xt::adapt`` first creates an ``xt::xtensor_adaptor`` on the memory of ``A[0, :, :]``. +Then, inside the loop, we only replace the pointer to the relevant ``A[i, 0, 0]``. + Structures that embed shape and strides --------------------------------------- Some structures may gather data container, shape and strides, making them impossible to plug -into ``xtensor`` with the method above. This section illustrates how to adapt such structures +into *xtensor* with the method above. This section illustrates how to adapt such structures with the following simple example: .. code:: @@ -71,7 +99,7 @@ with the following simple example: Define inner types ~~~~~~~~~~~~~~~~~~ -The following tells ``xtensor`` which types must be used for getting shape, strides, and data: +The following tells *xtensor* which types must be used for getting shape, strides, and data: .. code:: @@ -117,13 +145,13 @@ Next step is to inherit from the ``xcontainer`` and the ``xcontainer_semantic`` }; Thanks to definition of the previous structures, inheriting from ``xcontainer`` brings almost all the container -API available in the other entities of ``xtensor``, while inheriting from ``xtensor_semantic`` brings the support +API available in the other entities of *xtensor*, while inheriting from ``xtensor_semantic`` brings the support for mathematical operations. Define semantic ~~~~~~~~~~~~~~~ -``xtensor`` classes have full value semantic, so you may define the constructors specific to your structures, +*xtensor* classes have full value semantic, so you may define the constructors specific to your structures, and use the default copy and move constructors and assign operators. Note these last ones *must* be declared as they are declared as ``protected`` in the base class. @@ -133,7 +161,7 @@ they are declared as ``protected`` in the base class. class raw_tensor_adaptor : public xcontainer>, public xcontainer_semantic> { - + public: using self_type = raw_tensor_adaptor; @@ -161,7 +189,7 @@ they are declared as ``protected`` in the base class. return semantic_base::operator=(e); } }; - + The last two methods are extended copy constructor and assign operator. They allow writing things like .. code:: @@ -169,17 +197,17 @@ The last two methods are extended copy constructor and assign operator. They all using tensor_type = raw_tensor_adaptor; tensor_type a, b, c; // .... init a, b and c - tnesor_type d = a + b - c; + tensor_type d = a + b - c; Implement the resize methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The next methods to define are the overloads of ``resize``. ``xtensor`` provides utility functions to compute +The next methods to define are the overloads of ``resize``. *xtensor* provides utility functions to compute strides based on the shape and the layout, so the implementation of the ``resize`` overloads is straightforward: .. code:: - #include "xtensor/xstrides.hpp" // for utility functions + #include // for utility functions template void resize(const shape_type& shape) @@ -271,7 +299,7 @@ The following definitions are required: .. code:: template - struct xcontainer_inner_type> + struct xcontainer_inner_types> { using temporary_type = xarray; }; @@ -299,7 +327,8 @@ and to define a bunch of typedefs. public: - using self_type = table; + using self_type = table_adaptor; + using semantic_base = xcontainer_semantic; using value_type = T; using reference = T&; @@ -314,7 +343,7 @@ and to define a bunch of typedefs. using shape_type = inner_shape_type; using strides_type = inner_strides_type; - using iterable_base = xexpression_iterable; + using iterable_base = xiterable; using stepper = typename iterable_base::stepper; using const_stepper = typename iterable_base::const_stepper; }; @@ -353,7 +382,6 @@ constructor and assign operator. template table_adaptor(const xexpression& e) - : base_type() { semantic_base::assign(e); } @@ -364,11 +392,11 @@ constructor and assign operator. return semantic_base::operator=(e); } }; - + Implement access operators ~~~~~~~~~~~~~~~~~~~~~~~~~~ -``xtensor`` requires that the following access operators are defined +*xtensor* requires that the following access operators are defined .. code:: @@ -436,16 +464,10 @@ This part is relatively straightforward: template bool broadcast_shape(const S& s) const { - // Available in "xtensor/xtrides.hpp" + // Available in "xtensor/core/xstrides.hpp" return xt::broadcast_shape(shape(), s); } - template - bool is_trivial_broadcast(const S& str) const noexcept - { - return false; - } - Implement resize overloads ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -488,4 +510,3 @@ iterators. size_type offset = s.size() - dimension(); return const_stepper(this, offset, true); } - diff --git a/docs/source/file_loading.rst b/docs/source/file_loading.rst index 800c09218..348b12e40 100644 --- a/docs/source/file_loading.rst +++ b/docs/source/file_loading.rst @@ -7,19 +7,19 @@ File input and output ===================== -``xtensor`` has some builtin mechanisms to make loading and saving data easy. -The base xtensor package allows to save and load data in the ``.csv``, ``.json`` and ``.npy`` +*xtensor* has some built-in mechanisms to make loading and saving data easy. +The base *xtensor* package allows to save and load data in the ``.csv``, ``.json`` and ``.npy`` format. Please note that many more input and output formats are available in the `xtensor-io -`_ package. -``xtensor-io`` offers functions to load and store from image files (``jpg``, ``gif``, ``png``...), -sound files (``wav``, ``ogg``...), and compressed numpy format ``npz``. +`_ package. +`xtensor-io` offers functions to load and store from image files (``jpg``, ``gif``, ``png``...), +sound files (``wav``, ``ogg``...), HDF5 files (``h5``, ``hdf5``, ...), and compressed NumPy format (``npz``). Loading CSV data into xtensor ----------------------------- -The following example code demonstrates how to use ``load_csv`` and ``dump_csv`` to load and +The following example code demonstrates how to use :cpp:func:`xt::load_csv` and :cpp:func:`xt::dump_csv` to load and save data in the Comma-separated value format. The reference documentation is :doc:`api/xcsv`. .. code:: @@ -28,18 +28,18 @@ save data in the Comma-separated value format. The reference documentation is :d #include #include - #include "xtensor/xarray.hpp" - #include "xtensor/xcsv.hpp" + #include + #include int main() { - ifstream in_file; + std::ifstream in_file; in_file.open("in.csv"); auto data = xt::load_csv(in_file); - ofstream out_file; + std::ofstream out_file; out_file("out.csv"); - + xt::xarray a = {{1,2,3,4}, {5,6,7,8}}; xt::dump_csv(out_file, a); @@ -49,8 +49,8 @@ save data in the Comma-separated value format. The reference documentation is :d Loading NPY data into xtensor ----------------------------- -The following example demonstrates how to load and store xtensor data in the ``npy`` "NumPy" format, -using the ``load_npy`` and ``dump_npy`` functions. +The following example demonstrates how to load and store xtensor data in the ``npy`` "NumPy" format, +using the :cpp:func:`xt::load_npy` and :cpp:func:`xt::dump_npy` functions. Reference documentation for the functions used is found here :doc:`api/xnpy`. .. code:: @@ -59,8 +59,8 @@ Reference documentation for the functions used is found here :doc:`api/xnpy`. #include #include - #include "xtensor/xarray.hpp" - #include "xtensor/xnpy.hpp" + #include + #include int main() { @@ -77,20 +77,20 @@ Reference documentation for the functions used is found here :doc:`api/xnpy`. Loading JSON data into xtensor ------------------------------ -It's possible to load and dump data to json, using the json library written by -``nlohmann`` (https://nlohmann.github.io/json/) which offers a convenient way -to handle json data in C++. Note that the library needs to be seperately installed. +It's possible to load and dump data to json, using the json library written by +`nlohmann` (https://nlohmann.github.io/json/) which offers a convenient way +to handle json data in C++. Note that the library needs to be separately installed. The reference documentation is found :doc:`api/xjson`. .. code:: - #include "xtensor/xjson.hpp" - #include "xtensor/xarray.hpp" + #include + #include int main() { - + xt::xarray t = {{{1, 2}, {3, 4}}, {{1, 2}, @@ -102,5 +102,5 @@ The reference documentation is found :doc:`api/xjson`. xt::xarray res; auto j = "[[10.0,10.0],[10.0,10.0]]"_json; - from_json(j, res); + xt::from_json(j, res); } diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index bce4ba786..45f315f8a 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -7,7 +7,7 @@ Getting started =============== -This short guide explains how to get started with `xtensor` once you haveve installed it with one of +This short guide explains how to get started with *xtensor* once you have installed it with one of the methods described in the installation section. First example @@ -16,9 +16,9 @@ First example .. code:: #include - #include "xtensor/xarray.hpp" - #include "xtensor/xio.hpp" - #include "xtensor/xview.hpp" + #include + #include + #include int main(int argc, char* argv[]) { @@ -32,7 +32,7 @@ First example xt::xarray res = xt::view(arr1, 1) + arr2; - std::cout << res; + std::cout << res << std::endl; return 0; } @@ -43,15 +43,18 @@ array. Compiling the first example --------------------------- -`xtensor` is a header-only library, so there is no library to link with. The only constraint -is that the compiler must be able to find the headers of `xtensor`, this is usually done -by having the diretory containing the headers in the include path. With GCC, use the ``-I`` option +*xtensor* is a header-only library, so there is no library to link with. The only constraint +is that the compiler must be able to find the headers of *xtensor* (and *xtl*), this is usually done +by having the directory containing the headers in the include path. With G++, use the ``-I`` option to achieve this. Assuming the first example code is located in ``example.cpp``, the compilation command is: .. code:: bash - gcc -I /path/to/xtensor/ example.cpp -o example + g++ -I /path/to/xtensor/ -I /path/to/xtl/ example.cpp -o example + +Note that if you installed *xtensor* and *xtl* with *Cmake*, their headers will be located in the same +directory, so you will need to provide only one path with the ``-I`` option. When you run the program, it produces the following output: @@ -62,7 +65,7 @@ When you run the program, it produces the following output: Building with cmake ------------------- -A better alternative for building programs using `xtensor` is to use `cmake`, especially if you are +A better alternative for building programs using *xtensor* is to use *Cmake*, especially if you are developing for several platforms. Assuming the following folder structure: .. code:: bash @@ -81,9 +84,37 @@ The following minimal ``CMakeLists.txt`` is enough to build the first example: find_package(xtl REQUIRED) find_package(xtensor REQUIRED) - + add_executable(first_example src/example.cpp) - target_link_libraries(first_example xtensor) + + if(MSVC) + set(CMAKE_EXE_LINKER_FLAGS /MANIFEST:NO) + endif() + + target_link_libraries(first_example xtensor xtensor::optimize xtensor::use_xsimd) + +.. note:: + + .. code:: cmake + + target_link_libraries(... xtensor::optimize) + + set the following compiler flags, if supported by the target compiler: + + * Unix: ``-march=native``; + * Windows: ``/EHsc /MP /bigobj``. + + This may speed-up your code, but renders it hardware dependent. + +.. note:: + + .. code:: cmake + + target_link_libraries(... xtensor::use_xsimd) + + enables `xsimd `_: an optional dependency of xtensor that enables simd acceleration, + i.e. executing a same operation on a batch of data in a single CPU instruction. + This is well-suited to improve performance when operating on tensors, but renders it hardware dependent. `cmake` has to know where to find the headers, this is done through the ``CMAKE_INSTALL_PREFIX`` variable. Note that ``CMAKE_INSTALL_PREFIX`` is usually the path to a folder containing the following @@ -101,6 +132,8 @@ the first example with cmake and then runs the program: make ./first_program +See :ref:`build-configuration` for more details about the build options. + Second example: reshape ----------------------- @@ -109,8 +142,8 @@ This second example initializes a 1-dimensional array and reshapes it in-place: .. code:: #include - #include "xtensor/xarray.hpp" - #include "xtensor/xio.hpp" + #include + #include int main(int argc, char* argv[]) { @@ -131,14 +164,29 @@ When compiled and run, this produces the following output: {4, 5, 6}, {7, 8, 9}} +.. tip:: + + To print the shape to the standard output you can use either: + + .. code-block:: cpp + + const auto& s = arr.shape(); + std::copy(s.cbegin(), s.cend(), std::ostream_iterator(std::cout, " ")); + + Or: + + .. code-block:: cpp + + std::cout << xt::adapt(arr.shape()); // with: #include + Third example: index access --------------------------- .. code:: #include - #include "xtensor/xarray.hpp" - #include "xtensor/xio.hpp" + #include + #include int main(int argc, char* argv[]) { @@ -146,7 +194,7 @@ Third example: index access {{1.0, 2.0, 3.0}, {2.0, 5.0, 7.0}, {2.0, 5.0, 7.0}}; - + std::cout << arr1(0, 0) << std::endl; xt::xarray arr2 @@ -162,18 +210,18 @@ Outputs: 1.0 1 - + Fourth example: broadcasting ---------------------------- -This last example shows how to broadcast the ``xt::pow`` universal function: +This last example shows how to broadcast the :cpp:func:`xt::pow` universal function: .. code:: #include - #include "xtensor/xarray.hpp" - #include "xtensor/xmath.hpp" - #include "xtensor/xio.hpp" + #include + #include + #include int main(int argc, char* argv[]) { @@ -199,4 +247,3 @@ Outputs: {1, 32, 243}, {1, 64, 729}, {1, 128, 2187}} - diff --git a/docs/source/histogram.rst b/docs/source/histogram.rst index 42cdf9db1..f1e37c94c 100644 --- a/docs/source/histogram.rst +++ b/docs/source/histogram.rst @@ -4,35 +4,35 @@ The full license is in the file LICENSE, distributed with this software. +.. _histogram: + Histogram ========= Basic usage ----------- -.. note:: - - .. code-block:: cpp - - xt::histogram(a, bins[, weights][, density]) - xt::histogram_bin_edges(a, bins[, weights][, left, right][, bins][, mode]) +* :cpp:func:`xt::histogram(a, bins[, weights][, density]) ` +* :cpp:func:`xt::histogram_bin_edges(a[, weights][, left, right][, bins][, mode]) ` +.. note:: Any of the options ``[...]`` can be omitted (though the order must be preserved). The defaults are: - * ``weights = xt::ones(data.shape())`` - * ``density = false`` - * ``left = xt::amin(data)(0)`` - * ``right = xt::amax(data)(0)`` - * ``bins = 10`` - * ``mode = xt::histogram::automatic`` + * ``weights`` = :cpp:func:`xt::ones(data.shape()) ` + * ``density`` = ``false`` + * ``left`` = :cpp:func:`xt::amin(data)(0) ` + * ``right`` = :cpp:func:`Xt::amax(data)(0) ` + * ``bins`` = ``10`` + * ``mode`` = :cpp:enumerator:`xt::histogram::automatic` -The behavior, in-, and output of ``histogram`` is similar to that of `numpy.histogram `_ with that difference that the bin-edges are obtained by a separate function call: +The behavior, in-, and output of :cpp:func:`xt::histogram` is similar to that of :any:`numpy.histogram` +with that difference that the bin-edges are obtained by a separate function call: .. code-block:: cpp - #include - #include - #include + #include + #include + #include int main() { @@ -48,13 +48,14 @@ The behavior, in-, and output of ``histogram`` is similar to that of `numpy.hist Bin-edges algorithm ------------------- -To customize the algorithm to be used to construct the histogram, one needs to make use of the latter ``histogram_bin_edges``. For example: +To customize the algorithm to be used to construct the histogram, one needs to make use of the latter +:cpp:func:`xt::histogram_bin_edges`. For example: .. code-block:: cpp - #include - #include - #include + #include + #include + #include int main() { @@ -70,12 +71,10 @@ To customize the algorithm to be used to construct the histogram, one needs to m return 0; } -The following algorithms are available: - -* ``automatic``: equivalent to ``linspace``. - -* ``linspace``: linearly spaced bin-edges. - -* ``logspace``: bins that logarithmically increase in size. +The following :cpp:enum:`xt::histogram_algorithm` are available: -* ``uniform``: bin-edges such that the number of data-points is the same in all bins (as much as possible). +* :cpp:enumerator:`~xt::histogram_algorithm::automatic`: equivalent to :cpp:enumerator:`~xt::histogram_algorithm::linspace`. +* :cpp:enumerator:`~xt::histogram_algorithm::linspace`: linearly spaced bin-edges. +* :cpp:enumerator:`~xt::histogram_algorithm::logspace`: bins that logarithmically increase in size. +* :cpp:enumerator:`~xt::histogram_algorithm::uniform`: bin-edges such that the number of data points is + the same in all bins (as much as possible). diff --git a/docs/source/index.rst b/docs/source/index.rst index 922a00886..d28e135ea 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -12,25 +12,25 @@ Multi-dimensional arrays with broadcasting and lazy computing. Introduction ------------ -`xtensor` is a C++ library meant for numerical analysis with multi-dimensional +*xtensor* is a C++ library meant for numerical analysis with multi-dimensional array expressions. -`xtensor` provides +*xtensor* provides - an extensible expression system enabling **lazy broadcasting**. - an API following the idioms of the **C++ standard library**. -- tools to manipulate array expressions and build upon `xtensor`. +- tools to manipulate array expressions and build upon *xtensor*. -Containers of `xtensor` are inspired by `NumPy`_, the Python array programming +Containers of *xtensor* are inspired by `NumPy`_, the Python array programming library. **Adaptors** for existing data structures to be plugged into the expression system can easily be written. -In fact, `xtensor` can be used to **process numpy data structures in-place** -using Python's `buffer protocol`_. For more details on the numpy bindings, +In fact, *xtensor* can be used to **process NumPy data structures in-place** +using Python's `buffer protocol`_. For more details on the NumPy bindings, check out the xtensor-python_ project. Language bindings for R and Julia are also available. -`xtensor` requires a modern C++ compiler supporting C++14. The following C++ +*xtensor* requires a modern C++ compiler supporting C++14. The following C++ compilers are supported: - On Windows platforms, Visual C++ 2015 Update 2, or more recent @@ -63,11 +63,30 @@ for details. scalar adaptor operator - histogram view + indices builder missing + histogram + random + rank file_loading + build-options + pitfall + +.. toctree:: + :caption: QUICK REFERENCE + :maxdepth: 2 + + quickref/basic + quickref/builder + quickref/operator + quickref/math + quickref/reducer + view + quickref/iterator + quickref/manipulation + quickref/chunked_arrays .. toctree:: :caption: API REFERENCE @@ -75,16 +94,18 @@ for details. api/expression_index api/container_index + api/iterator_index api/function_index api/io_index api/xmath + api/shape .. toctree:: :caption: DEVELOPER ZONE :maxdepth: 2 compilers - build-options + dev-build-options developer/xtensor_internals external-structures releasing @@ -96,8 +117,9 @@ for details. numpy-differences closure-semantics related + bindings -.. _NumPy: http://www.numpy.org +.. _NumPy: https://numpy.org/ .. _Buffer Protocol: https://docs.python.org/3/c-api/buffer.html .. _libdynd: http://libdynd.org -.. _xtensor-python: https://github.com/QuantStack/xtensor-python +.. _xtensor-python: https://github.com/xtensor-stack/xtensor-python diff --git a/docs/source/indices.rst b/docs/source/indices.rst new file mode 100644 index 000000000..e32fce8c7 --- /dev/null +++ b/docs/source/indices.rst @@ -0,0 +1,289 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Indices +======= + +Definition +---------- + +There are two types of indices: *array indices* and *flat indices*. Consider this example (stored in row-major): + +.. code-block:: cpp + + #include + #include + #include + + int main() + { + xt::xarray a = xt::arange(3 * 4); + + a.reshape({3,4}); + + std::cout << a << std::endl; + } + +Which prints + +.. code-block:: none + + {{ 0, 1, 2, 3}, + { 4, 5, 6, 7}, + { 8, 9, 10, 11}} + +The *array index* ``{1, 2}`` corresponds to the *flat index* ``6``. + +Operators: array index +------------------------ + +An *array index* can be specified to an operators by a sequence of numbers. +To this end the following operators are at your disposal: + +:cpp:func:`operator()(args...) ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Example: ``a(1, 2) == 6``. +* See also: :cpp:func:`xt::xcontainer::operator()`. + +Returns a (constant) reference to the element, +specified by an *array index* given by a number of unsigned integers. + +* If the number of indices is less that the dimension of the array, + the indices are pre-padded with zeros until the dimension is matched + (example: ``a(2) == a(0, 2) == 2``). + +* If the number of indices is greater than the dimension of the array, + the first ``#indices - dimension`` indices are ignored. + +* To post-pad an arbitrary number of zeros use ``xt::missing`` + (example ``a(2, xt::missing) == a(2, 0) == 8``. + +:cpp:func:`at(args...) ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Example: ``a.at(1, 2) == 6``. +* See also: :cpp:func:`xt::xcontainer::at`. + +Same as :cpp:func:`~xt::xcontainer::operator()`: +Returns a (constant) reference to the element, +specified by an *array index* given by a number of unsigned integers. + +:cpp:func:`unchecked(args...) ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Example: ``a.unchecked(1, 2) == 6``. +* See also: :cpp:func:`xt::xcontainer::unchecked`. + +Returns a (constant) reference to the element, +specified by an *array index* given by a number of unsigned integers. +Different than :cpp:func:`~xt::xcontainer::operator()` there are no bounds checks (even when assertions) +are turned on, and the number of indices is assumed to match the dimension of the array. +:cpp:func:`~xt::xcontainer::unchecked` is thus aimed at performance. + +.. note:: + + If you assume responsibility for bounds-checking, this operator can be used to virtually + post-pad zeros if you specify less indices than the rank of the array. + Example: ``a.unchecked(1) == a(1, 0)``. + +:cpp:func:`periodic(args...) ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Example: ``a.periodic(-1, -2) == 7``. +* See also: :cpp:func:`xt::xcontainer::periodic`. + +Returns a (constant) reference to the element, +specified by an *array index* given by a number of signed integers. +Negative and 'overflowing' indices are changed by assuming periodicity along that axis. +For example, for the first axis: ``-1 -> a.shape(0) - 1 = 2``, +likewise for example ``3 -> 3 - a.shape(0) = 0``. +Of course this comes as the cost of some extra complexity. + +:cpp:func:`in_bounds(args...) ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Example: ``a.in_bounds(1, 2) == true``. +* See also: :cpp:func:`xt::xcontainer::in_bounds`. + +Check if the *array index* is 'in bounds', return ``false`` otherwise. + +:cpp:func:`operator[]({...}) ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Example: ``a[{1, 2}] == 6``. +* See also: :cpp:func:`xt::xcontainer::operator[]`. + +Returns a (constant) reference to the element, +specified by an *array index* given by a list of unsigned integers. + +Operators: flat index +--------------------- + +:cpp:func:`flat(i) ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Example: ``a.flat(6) == 6``. +* See also: :cpp:func:`xt::xcontainer::flat`. + +Returns a (constant) reference to the element specified by a *flat index*, +given an unsigned integer. + +.. note:: + + If the layout would not have been the default *row major*, + but *column major*, then ``a.flat(6) == 2``. + +.. note:: + + In many cases ``a.flat(i) == a.data()[i]``. + +Array indices +------------- + +Functions like :cpp:func:`xt::argwhere(a \< 5) ` return a ``std::vector`` of *array indices*. +Using the same matrix as above, we can do + +.. code-block:: cpp + + int main() + { + xt::xarray a = xt::arange(3 * 4); + + a.reshape({3,4}); + + auto idx = xt::from_indices(xt::argwhere(a >= 6)); + + std::cout << idx << std::endl; + } + +which prints + +.. code-block:: none + + {{1, 2}, + {1, 3}, + {2, 0}, + {2, 1}, + {2, 2}, + {2, 3}} + +To print the ``std::vector``, it is converted to a :cpp:type:`xt::xtensor\ ` +array, which is done using :cpp:func:`xt::from_indices`. + +From array indices to flat indices +---------------------------------- + +To convert the array indices to a :cpp:type:`xt::xtensor\ ` of flat indices, +:cpp:func:`xt::ravel_indices` can be used. +For the same example: + +.. code-block:: cpp + + #include + #include + #include + + int main() + { + xt::xarray a = xt::arange(3 * 4); + + a.reshape({3,4}); + + auto idx = xt::ravel_indices(xt::argwhere(a >= 6), a.shape()); + + std::cout << idx << std::endl; + } + +which prints + +.. code-block:: none + + { 6, 7, 8, 9, 10, 11} + +.. note:: + + To convert to a ``std::vector`` use + + .. code-block:: cpp + + auto idx = xt::ravel_indices(xt::argwhere(a >= 6), a.shape()); + +1-D arrays: array indices == flat indices +----------------------------------------- + +For 1-D arrays the array indices and flat indices coincide. +One can use the generic functions :cpp:func:`xt::flatten_indices` to get a +:cpp:type:`xt::xtensor\ ` of (array/flat) indices. +For example: + +.. code-block:: cpp + + #include + #include + #include + + int main() + { + xt::xtensor a = xt::arange(16); + + auto idx = xt::flatten_indices(xt::argwhere(a >= 6)); + + std::cout << idx << std::endl; + + std::cout << xt::view(a, xt::keep(idx)) << std::endl; + } + +which prints the indices and the selection (which are in this case identical): + +.. code-block:: none + + { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + +From flat indices to array indices +---------------------------------- + +To convert *flat indices* to *array_indices* the function :cpp:func:`xt::unravel_indices` can be used. +For example + +.. code-block:: cpp + + #include + #include + #include + #include + + int main() + { + xt::xarray a = xt::arange(3 * 4); + + a.reshape({3,4}); + + auto flat_indices = xt::ravel_indices(xt::argwhere(a >= 6), a.shape()); + + auto array_indices = xt::from_indices(xt::unravel_indices(flat_indices, a.shape())); + + std::cout << "flat_indices = " << std::endl << flat_indices << std::endl; + std::cout << "array_indices = " << std::endl << array_indices << std::endl; + } + +which prints + +.. code-block:: none + + flat_indices = + { 6, 7, 8, 9, 10, 11} + array_indices = + {{1, 2}, + {1, 3}, + {2, 0}, + {2, 1}, + {2, 2}, + {2, 3}} + +Notice that once again the function :cpp:func:`xt::from_indices` has been used to convert a +``std::vector`` of indices to a :cpp:type:`xt::xtensor` array for printing. diff --git a/docs/source/installation.rst b/docs/source/installation.rst index c149ca28d..bc0bdb7ca 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -21,7 +21,7 @@ Installation ============ -Although ``xtensor`` is a header-only library, we provide standardized means to +Although *xtensor* is a header-only library, we provide standardized means to install it, with package managers or with cmake. Besides the xtensor headers, all these methods place the ``cmake`` project @@ -30,14 +30,14 @@ cmake's ``find_package`` to locate xtensor headers. .. image:: conda.svg -Using the conda package ------------------------ +Using the conda-forge package +----------------------------- -A package for xtensor is available on the conda package manager. +A package for xtensor is available on the mamba (or conda) package manager. .. code:: - conda install -c conda-forge xtensor + mamba install -c conda-forge xtensor .. image:: debian.svg @@ -67,7 +67,7 @@ A package for xtensor is available on the Spack package manager. From source with cmake ---------------------- -You can also install ``xtensor`` from source with cmake. This requires that you +You can also install *xtensor* from source with cmake. This requires that you have the xtl_ library installed on your system. On Unix platforms, from the source directory: @@ -89,16 +89,26 @@ On Windows platforms, from the source directory: nmake install ``path_to_prefix`` is the absolute path to the folder where cmake searches for -dependencies and installs libraries. ``xtensor`` installation from cmake assumes +dependencies and installs libraries. *xtensor* installation from cmake assumes this folder contains ``include`` and ``lib`` subfolders. See the :doc:`build-options` section for more details about cmake options. +Although not officially supported, *xtensor* can be installed with MinGW: + +.. code:: + + mkdir build + cd build + cmake -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=path_to_prefix .. + mingw32-make + mingw32-make install + Including xtensor in your project --------------------------------- -The different packages of ``xtensor`` are built with cmake, so whatever the -installation mode you choose, you can add ``xtensor`` to your project using cmake: +The different packages of *xtensor* are built with cmake, so whatever the +installation mode you choose, you can add *xtensor* to your project using cmake: .. code:: @@ -106,4 +116,4 @@ installation mode you choose, you can add ``xtensor`` to your project using cmak target_include_directories(your_target PUBLIC ${xtensor_INCLUDE_DIRS}) target_link_libraries(your_target PUBLIC xtensor) -.. _xtl: https://github.com/QuantStack/xtl +.. _xtl: https://github.com/xtensor-stack/xtl diff --git a/docs/source/missing.rst b/docs/source/missing.rst index ffb15ab0a..80cba080c 100644 --- a/docs/source/missing.rst +++ b/docs/source/missing.rst @@ -7,17 +7,18 @@ Missing values ============== -``xtensor`` handles missing values and comprises specialized container types for an optimized support of missing values. +*xtensor* handles missing values and provides specialized container types for an optimized support of missing values. Optional expressions -------------------- -Support of missing values in xtensor is primarily provided through the ``xoptional`` value type and the ``xtensor_optional`` and -``xarray_optional`` containers. In the following example, we instantiate a 2-D tensor with a missing value: +Support of missing values in xtensor is primarily provided through the :cpp:type:`xtl::xoptional` +value type and the :cpp:type:`xt::xtensor_optional` and :cpp:type:`xt::xarray_optional` containers. +In the following example, we instantiate a 2-D tensor with a missing value: .. code:: cpp - xtensor_optional m + xt::xtensor_optional m {{ 1.0 , 2.0 }, { 3.0 , missing() }}; @@ -25,16 +26,19 @@ This code is semantically equivalent to .. code:: cpp - xtensor, 2> m + xt::xtensor, 2> m {{ 1.0 , 2.0 }, { 3.0 , missing() }}; -The ``xtensor_optional`` container is optimized to handle missing values. Internally, instead of holding a single container -of optional values, it holds an array of ``double`` and a boolean container where each value occupies a single bit instead of ``sizeof(bool)`` -bytes. +The :cpp:type:`xt::xtensor_optional` container is optimized to handle missing values. +Internally, instead of holding a single container of optional values, it holds an array of ``double`` +and a boolean container where each value occupies a single bit instead of ``sizeof(bool)`` bytes. -The ``xtensor_optional::reference`` typedef, which is the return type of ``operator()`` is a reference proxy which can be used as an -lvalue for assigning new values in the array. It happens to be an instance of ``xoptional`` where ``T`` and ``B`` are actually the reference types of the underlying storage for values and boolean flags. +The :cpp:type:`xt::xtensor_optional::reference` typedef, which is the return type of +:cpp:func:`~xt::xexpression::operator()` is a reference proxy which can be used as an +lvalue for assigning new values in the array. +It happens to be an instance of :cpp:type:`xtl::xoptional\ ` where ``T`` and +``B`` are actually the reference types of the underlying storage for values and boolean flags. This technique enables performance improvements in mathematical operations over boolean arrays including SIMD optimizations, and reduces the memory footprint of optional arrays. It should be transparent to the user. @@ -47,14 +51,14 @@ same way as regular scalars. .. code:: cpp - xtensor_optional a + xt::xtensor_optional a {{ 1.0 , 2.0 }, { 3.0 , missing() }}; - xtensor b + xt::xtensor b { 1.0, 2.0 }; - // `b` is broadcasted to match the shape of `a` + // ``b`` is broadcasted to match the shape of ``a`` std::cout << a + b << std::endl; outputs: @@ -67,24 +71,25 @@ outputs: Optional assemblies ------------------- -The classes ``xoptional_assembly`` and ``xoptional_assembly_adaptor`` provide containers and adaptors holding missing values that are optimized -for element-wise operations. -Contrary to ``xtensor_optional`` and ``xarray_optional``, the optional assemblies hold two expressions, one holding the values, the other holding -the mask for the missing values. The difference between ``xoptional_assembly`` and ``xoptional_assembly_adaptor`` is that the first one is the owner -of the two expressions while the last one holds a reference on at least one of the two expressions. +The classes :cpp:type:`xt::xoptional_assembly` and :cpp:type:`xt::xoptional_assembly_adaptor` provide +containers and adaptors holding missing values that are optimized for element-wise operations. +Contrary to :cpp:type:`xt::xtensor_optional` and :cpp:type:`xt::xarray_optional`, the optional +assemblies hold two expressions, one holding the values, the other holding the mask for the missing values. +The difference between :cpp:type:`xt::xoptional_assembly` and :cpp:type:`xt::xoptional_assembly_adaptor` +is that the first one is the owner of the two expressions while the last one holds a reference on at least +one of the two expressions. .. code:: cpp - xarray v + xt::xarray v {{ 1.0, 2.0 }, { 3.0, 4.0 }}; - xarray hv + xt::xarray hv {{ true, true }, { true, false }}; - xoptional_assembly, xarray> - assembly(v, vh); + xt::xoptional_assembly, xt::xarray> assembly(v, hv); std::cout << assembly << std::endl; outputs: @@ -97,16 +102,19 @@ outputs: Handling expressions with missing values ---------------------------------------- -Functions ``has_value(E&& e)`` and ``value(E&& e)`` return expressions corresponding to the underlying value and flag of optional elements. When ``e`` is an lvalue, ``value(E&& e)`` and ``has_value(E&& e)`` are lvalues too. +Functions :cpp:func:`xt::has_value(E&& e) ` and :cpp:func:`xt::value(E&& e) ` +return expressions corresponding to the underlying value and flag of optional elements. +When ``e`` is an lvalue, :cpp:func:`xt::has_value(E&& e) ` and +:cpp:func:`xt::value(E&& e) ` are lvalues too. .. code:: cpp - xtensor_optional a + xt::xtensor_optional a {{ 1.0 , 2.0 }, { 3.0 , missing() }}; - xtensor b = has_value(a); + xt::xtensor b = xt::has_value(a); std::cout << b << std::endl; diff --git a/docs/source/numpy-differences.rst b/docs/source/numpy-differences.rst index 12371ffda..03968685e 100644 --- a/docs/source/numpy-differences.rst +++ b/docs/source/numpy-differences.rst @@ -12,25 +12,42 @@ Notable differences with numpy :align: right xtensor and numpy are very different libraries in their internal semantics. While xtensor -is a lazy expression system, Numpy manipulates in-memory containers, however, similarities in +is a lazy expression system, numpy manipulates in-memory containers, however, similarities in APIs are obvious. See e.g. the numpy to xtensor cheat sheet. -And this page tracks the subtle differences of behavior between numpy and xtensor. +And this page tracks the subtle differences of behavior between NumPy and xtensor. Zero-dimensional arrays ----------------------- -With numpy, 0-D arrays are nearly indistinguishable from scalars. This led to some issues w.r.t. +With NumPy, 0-D arrays are nearly indistinguishable from scalars. This led to some issues w.r.t. universal functions returning scalars with 0-D array inputs instead of actual arrays... -In xtensor, 0-D expressions are not implicitely convertible to scalar values. Values held by 0-D +In xtensor, 0-D expressions are not implicitly convertible to scalar values. Values held by 0-D expressions can be accessed in the same way as values of higher dimensional arrays, that is with ``operator[]``, ``operator()`` and ``element``. +Accumulators (``cumsum``, ``cumprod``) throw an exception if an axis argument is passed and the +array argument is a 0-D argument: + +.. code:: + + #include + #include + + xt::xarray x = 1; + std::cout << xt::cumsum(x, 0) << std::endl; + // Outputs: + // Standard Exception: Axis larger than expression dimension in accumulator. + + std::cout << xt::cumsum(x) << std::endl; + //Outputs: + // 1 + Meshgrid -------- -Numpy's version of meshgrid supports two modes: the 'xy' indexing and the 'ij' indexing. +:any:`numpy.meshgrid` supports two modes: the 'xy' indexing and the 'ij' indexing. The following code @@ -47,7 +64,7 @@ The following code print 'xy:', [m.shape for m in xy] -would return +would return .. code-block:: python @@ -70,7 +87,7 @@ be assigned to a container such as xarray or xtensor. Missing values -------------- -Support of missing values in numpy can be emulated with the masked array module, +Support of missing values in NumPy can be emulated with the masked array module, which provides a means to handle arrays that have missing or invalid data. Support of missing values in xtensor is done through a notion of optional values, implemented in ``xoptional``, which serves both as a value type for container and as a reference proxy for optimized storage types. See the section of the documentation on :doc:`missing`. @@ -78,5 +95,24 @@ Support of missing values in xtensor is done through a notion of optional values Strides ------- -Strided containers of xtensor and numpy having the same exact memory layout may have different strides when accessing them through the ``strides`` attribute. +Strided containers of xtensor and NumPy having the same exact memory layout may have different strides when accessing them through the ``strides`` attribute. The reason is an optimization in xtensor, which is to set the strides to ``0`` in dimensions of length ``1``, which simplifies the implementation of broadcasting of universal functions. + +.. tip:: + + Use the free function ``xt::strides`` to switch between representations. + + .. code-block:: cpp + + xt::strides(a); // strides of ``a`` corresponding to storage + xt::strides(a, xt::stride_type::normal); // same + + xt::strides(a, xt::stride_type::internal); // ``== a.strides()`` + + xt::strides(a, xt::stride_type::bytes) // strides in bytes, as in NumPy + + +Array indices +------------- + +Array indices are in xtensor stored as a ``std::vector`` of array indices, whereby each entry corresponds to the array indices of one item. This results in a slightly different usage of ``xt::ravel_indices`` than of :any:`numpy.ravel_multi_index`. diff --git a/docs/source/numpy.rst b/docs/source/numpy.rst index e4f5d21fb..814f3ec6d 100644 --- a/docs/source/numpy.rst +++ b/docs/source/numpy.rst @@ -4,7 +4,7 @@ The full license is in the file LICENSE, distributed with this software. -From numpy to xtensor +From NumPy to xtensor ===================== .. image:: numpy.svg @@ -51,6 +51,10 @@ From numpy to xtensor border-left: none; } + .rst-content table.docutils td > p { + overflow: auto; + } + .rst-content table.docutils tr:hover { background-color: #d0e0e0; } @@ -79,19 +83,22 @@ From numpy to xtensor Containers ---------- -Two container types are provided. ``xarray`` (dynamic number of dimensions) and ``xtensor`` -(static number of dimensions). +Two container types are provided. :cpp:type:`xt::xarray` (dynamic number of dimensions) +and :cpp:type:`xt::xtensor` (static number of dimensions). + +.. table:: + :widths: 50 50 -+------------------------------------------------+------------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+================================================+================================================+ -| ``np.array([[3, 4], [5, 6]])`` | | ``xt::xarray({{3, 4}, {5, 6}})`` | -| | | ``xt::xtensor({{3, 4}, {5, 6}})`` | -+------------------------------------------------+------------------------------------------------+ -| ``arr.reshape([3, 4])`` | ``arr.reshape({3, 4})`` | -+------------------------------------------------+------------------------------------------------+ -| ``arr.astype(np.float64)`` | ``xt::cast(arr)`` | -+------------------------------------------------+------------------------------------------------+ + +------------------------------------------------------+------------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +======================================================+========================================================================+ + | :any:`np.array([[3, 4], [5, 6]]) ` || :cpp:type:`xt::xarray\({{3, 4}, {5, 6}}) ` | + | || :cpp:type:`xt::xtensor\({{3, 4}, {5, 6}}) ` | + +------------------------------------------------------+------------------------------------------------------------------------+ + | :any:`arr.reshape([3, 4]) ` | :cpp:func:`arr.reshape({3, 4}) ` | + +------------------------------------------------------+------------------------------------------------------------------------+ + | :any:`arr.astype(np.float64) ` | :cpp:func:`xt::cast\(arr) ` | + +------------------------------------------------------+------------------------------------------------------------------------+ Initializers ------------ @@ -100,27 +107,60 @@ Lazy helper functions return tensor expressions. Return types don't hold any val evaluated upon access or assignment. They can be assigned to a container or directly used in expressions. -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.linspace(1.0, 10.0, 100)`` | ``xt::linspace(1.0, 10.0, 100)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.logspace(2.0, 3.0, 4)`` | ``xt::logspace(2.0, 3.0, 4)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.arange(3, 7)`` | ``xt::arange(3, 7)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.eye(4)`` | ``xt::eye(4)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.zeros([3, 4])`` | ``xt::zeros({3, 4})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.ones([3, 4])`` | ``xt::ones({3, 4})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.empty([3, 4])`` | ``xt::empty({3, 4})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.meshgrid(x0, x1, x2, indexing='ij')`` | ``xt::meshgrid(x0, x1, x2)`` | -+-----------------------------------------------+-----------------------------------------------+ - -xtensor's ``meshgrid`` implementation corresponds to numpy's ``'ij'`` indexing order. +.. table:: + :widths: 50 50 + + +----------------------------------------------------------------+-------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +================================================================+===================================================================+ + | :any:`np.linspace(1.0, 10.0, 100) ` | :cpp:func:`xt::linspace\(1.0, 10.0, 100) ` | + +----------------------------------------------------------------+-------------------------------------------------------------------+ + | :any:`np.logspace(2.0, 3.0, 4) ` | :cpp:func:`xt::logspace\(2.0, 3.0, 4) ` | + +----------------------------------------------------------------+-------------------------------------------------------------------+ + | :any:`np.arange(3, 7) ` | :cpp:func:`xt::arange(3, 7) ` | + +----------------------------------------------------------------+-------------------------------------------------------------------+ + | :any:`np.eye(4) ` | :cpp:func:`xt::eye(4) ` | + +----------------------------------------------------------------+-------------------------------------------------------------------+ + | :any:`np.zeros([3, 4]) ` | :cpp:func:`xt::zeros\({3, 4}) ` | + +----------------------------------------------------------------+-------------------------------------------------------------------+ + | :any:`np.ones([3, 4]) ` | :cpp:func:`xt::ones\({3, 4}) ` | + +----------------------------------------------------------------+-------------------------------------------------------------------+ + | :any:`np.empty([3, 4]) ` | :cpp:func:`xt::empty\({3, 4}) ` | + +----------------------------------------------------------------+-------------------------------------------------------------------+ + | :any:`np.meshgrid(x0, x1, x2, indexing='ij') ` | :cpp:func:`xt::meshgrid(x0, x1, x2) ` | + +----------------------------------------------------------------+-------------------------------------------------------------------+ + +xtensor's :cpp:func:`meshgrid ` implementation corresponds to numpy's ``'ij'`` indexing order. + +Slicing and indexing +-------------------- + +See :any:`numpy indexing ` page. + +.. table:: + :widths: 50 50 + + +-----------------------------------------+---------------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +=========================================+===========================================================================+ + | ``a[3, 2]`` | :cpp:func:`a(3, 2) ` | + +-----------------------------------------+---------------------------------------------------------------------------+ + | :any:`a.flat[4] ` | :cpp:func:`a.flat(4) ` | + +-----------------------------------------+---------------------------------------------------------------------------+ + | ``a[3]`` || :cpp:func:`xt::view(a, 3, xt::all()) ` | + | || :cpp:func:`xt::row(a, 3) ` | + +-----------------------------------------+---------------------------------------------------------------------------+ + | ``a[:, 2]`` || :cpp:func:`xt::view(a, xt::all(), 2) ` | + | || :cpp:func:`xt::col(a, 2) ` | + +-----------------------------------------+---------------------------------------------------------------------------+ + | ``a[:5, 1:]`` | :cpp:func:`xt::view(a, xt::range(_, 5), xt::range(1, _)) ` | + +-----------------------------------------+---------------------------------------------------------------------------+ + | ``a[5:1:-1, :]`` | :cpp:func:`xt::view(a, xt::range(5, 1, -1), xt::all()) ` | + +-----------------------------------------+---------------------------------------------------------------------------+ + | ``a[..., 3]`` | :cpp:func:`xt::strided_view(a, {xt::ellipsis(), 3}) ` | + +-----------------------------------------+---------------------------------------------------------------------------+ + | :any:`a[:, np.newaxis] ` | :cpp:func:`xt::view(a, xt::all(), xt::newaxis()) ` | + +-----------------------------------------+---------------------------------------------------------------------------+ Broadcasting ------------ @@ -128,45 +168,47 @@ Broadcasting xtensor offers lazy numpy-style broadcasting, and universal functions. Unlike numpy, no copy or temporary variables are created. -+-----------------------------------------------------+-----------------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+=====================================================+=====================================================+ -| | ``a[:, np.newaxis]`` | | ``xt::view(a, xt::all(), xt::newaxis())`` | -| | ``a[:5, 1:]`` | | ``xt::view(a, xt::range(_, 5), xt::range(1, _))`` | -| | ``a[5:1:-1, :]`` | | ``xt::view(a, xt::range(5, 1, -1), xt::all())`` | -| | ``a[..., 3]`` | | ``xt::strided_view(a, {xt::ellipsis, 3})`` | -+-----------------------------------------------------+-----------------------------------------------------+ -| ``np.broadcast(a, [4, 5, 7])`` | ``xt::broadcast(a, {4, 5, 7})`` | -+-----------------------------------------------------+-----------------------------------------------------+ -| ``np.vectorize(f)`` | ``xt::vectorize(f)`` | -+-----------------------------------------------------+-----------------------------------------------------+ -| ``a[a > 5]`` | ``xt::filter(a, a > 5)`` | -+-----------------------------------------------------+-----------------------------------------------------+ -| ``a[[0, 1], [0, 0]]`` | ``xt::index_view(a, {{0, 0}, {1, 0}})`` | -+-----------------------------------------------------+-----------------------------------------------------+ +.. table:: + :widths: 50 50 + + +-----------------------------------------------------+------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +=====================================================+==================================================================+ + | :any:`np.broadcast(a, [4, 5, 7]) ` | :cpp:func:`xt::broadcast(a, {4, 5, 7}) ` | + +-----------------------------------------------------+------------------------------------------------------------------+ + | :any:`np.vectorize(f) ` | :cpp:func:`xt::vectorize(f) ` | + +-----------------------------------------------------+------------------------------------------------------------------+ + | ``a[a > 5]`` | :cpp:func:`xt::filter(a, a > 5) ` | + +-----------------------------------------------------+------------------------------------------------------------------+ + | ``a[[0, 1], [0, 0]]`` | :cpp:func:`xt::index_view(a, {{0, 0}, {1, 0}}) ` | + +-----------------------------------------------------+------------------------------------------------------------------+ Random ------ The random module provides simple ways to create random tensor expressions, lazily. - -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.random.seed(0)`` | ``xt::random::seed(0)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.random.randn(10, 10)`` | ``xt::random::randn({10, 10})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.random.randint(10, 10)`` | ``xt::random::randint({10, 10})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.random.rand(3, 4)`` | ``xt::random::rand({3, 4})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.random.choice(arr, 5)`` | ``xt::random::choice(arr, 5)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.random.shuffle(arr)`` | ``xt::random::shuffle(arr)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.random.permutation(30)`` | ``xt::random::permutation(30)`` | -+-----------------------------------------------+-----------------------------------------------+ +See :any:`numpy.random` and :ref:`xtensor random ` page. + +.. table:: + :widths: 50 50 + + +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +=======================================================================+===================================================================================+ + | :any:`np.random.seed(0) ` | :cpp:func:`xt::random::seed(0) ` | + +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+ + | :any:`np.random.randn(10, 10) ` | :cpp:func:`xt::random::randn\({10, 10}) ` | + +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+ + | :any:`np.random.randint(10, 10) ` | :cpp:func:`xt::random::randint\({10, 10}) ` | + +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+ + | :any:`np.random.rand(3, 4) ` | :cpp:func:`xt::random::rand\({3, 4}) ` | + +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+ + | :any:`np.random.choice(arr, 5[, replace][, p]) ` | :cpp:func:`xt::random::choice(arr, 5[, weights][, replace]) ` | + +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+ + | :any:`np.random.shuffle(arr) ` | :cpp:func:`xt::random::shuffle(arr) ` | + +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+ + | :any:`np.random.permutation(30) ` | :cpp:func:`xt::random::permutation(30) ` | + +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+ Concatenation, splitting, squeezing ----------------------------------- @@ -174,21 +216,38 @@ Concatenation, splitting, squeezing Concatenating expressions does not allocate memory, it returns a tensor or view expression holding closures on the specified arguments. -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.stack([a, b, c], axis=1)`` | ``xt::stack(xtuple(a, b, c), 1)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.concatenate([a, b, c], axis=1)`` | ``xt::concatenate(xtuple(a, b, c), 1)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.squeeze(a)`` | ``xt::squeeze(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.expand_dims(a, 1)`` | ``xt::expand_dims(a ,1)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.atleast_3d(a)`` | ``xt::atleast_3d(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.split(a, 4, axis=0)`` | ``xt::split(a, 4, 0)`` | -+-----------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +=============================================================================+============================================================================+ + | :any:`np.stack([a, b, c], axis=1) ` | :cpp:func:`xt::stack(xtuple(a, b, c), 1) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.hstack([a, b, c]) ` | :cpp:func:`xt::hstack(xtuple(a, b, c)) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.vstack([a, b, c]) ` | :cpp:func:`xt::vstack(xtuple(a, b, c)) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.concatenate([a, b, c], axis=1) ` | :cpp:func:`xt::concatenate(xtuple(a, b, c), 1) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.tile(a, reps) ` | :cpp:func:`xt::tile(a, reps) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.squeeze(a) ` | :cpp:func:`xt::squeeze(a) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.expand_dims(a, 1) ` | :cpp:func:`xt::expand_dims(a ,1) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.atleast_3d(a) ` | :cpp:func:`xt::atleast_3d(a) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.split(a, 4, axis=0) ` | :cpp:func:`xt::split(a, 4, 0) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.hsplit(a, 4) ` | :cpp:func:`xt::hsplit(a, 4) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.vsplit(a, 4) ` | :cpp:func:`xt::vsplit(a, 4) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.trim_zeros(a, trim='fb') ` | :cpp:func:`xt::trim_zeros(a, "fb") ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ + | :any:`np.pad(a, pad_width, mode='constant', constant_values=0) ` | :cpp:func:`xt::pad(a, pad_width[, xt::pad_mode::constant][, 0]) ` | + +-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ Rearrange elements ------------------ @@ -196,29 +255,42 @@ Rearrange elements In the same spirit as concatenation, the following operations do not allocate any memory and do not modify the underlying xexpression. -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.diag(a)`` | ``xt::diag(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.diagonal(a)`` | ``xt::diagonal(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.triu(a)`` | ``xt::triu(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.tril(a, k=1)`` | ``xt::tril(a, 1)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.flip(a, axis=3)`` | ``xt::flip(a, 3)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.flipud(a)`` | ``xt::flip(a, 0)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.fliplr(a)`` | ``xt::flip(a, 1)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.transpose(a, (1, 0, 2))`` | ``xt::transpose(a, {1, 0, 2})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.rot90(a)`` | ``xt::rot90(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.rot90(a, 2, (1, 2))`` | ``xt::rot90<2>(a, {1, 2})`` | -+-----------------------------------------------+-----------------------------------------------+ +.. list-table:: + :widths: 50 50 + :header-rows: 1 + + * - Python3 - NumPy + - C++14 - xtensor + * - :any:`np.nan_to_num(a) ` + - :cpp:func:`xt::nan_to_num(a) ` + * - :any:`np.diag(a) ` + - :cpp:func:`xt::diag(a) ` + * - :any:`np.diagonal(a) ` + - :cpp:func:`xt::diagonal(a) ` + * - :any:`np.triu(a) ` + - :cpp:func:`xt::triu(a) ` + * - :any:`np.tril(a, k=1) ` + - :cpp:func:`xt::tril(a, 1) ` + * - :any:`np.flip(a, axis=3) ` + - :cpp:func:`xt::flip(a, 3) ` + * - :any:`np.flipud(a) ` + - :cpp:func:`xt::flip(a, 0) ` + * - :any:`np.fliplr(a) ` + - :cpp:func:`xt::flip(a, 1) ` + * - :any:`np.transpose(a, (1, 0, 2)) ` + - :cpp:func:`xt::transpose(a, {1, 0, 2}) ` + * - :any:`np.swapaxes(a, 0, -1) ` + - :cpp:func:`xt::swapaxes(a, 0, -1) ` + * - :any:`np.moveaxis(a, 0, -1) ` + - :cpp:func:`xt::moveaxis(a, 0, -1) ` + * - :any:`np.ravel(a, order='F') ` + - :cpp:func:`xt::ravel\(a) ` + * - :any:`np.rot90(a) ` + - :cpp:func:`xt::rot90(a) ` + * - :any:`np.rot90(a, 2, (1, 2)) ` + - :cpp:func:`xt::rot90\<2\>(a, {1, 2}) ` + * - :any:`np.roll(a, 2, axis=1) ` + - :cpp:func:`xt::roll(a, 2, 1) ` Iteration --------- @@ -226,158 +298,275 @@ Iteration xtensor follows the idioms of the C++ STL providing iterator pairs to iterate on arrays in different fashions. -+----------------------------------------------------------------+----------------------------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+================================================================+================================================================+ -| | ``for x in np.nditer(a):`` | | ``for(auto it=a.begin(); it!=a.end(); ++it)`` | -+----------------------------------------------------------------+----------------------------------------------------------------+ -| Iterating over ``a`` with a prescribed broadcasting shape | | ``a.begin({3, 4})`` | -| | | ``a.end({3, 4})`` | -+----------------------------------------------------------------+----------------------------------------------------------------+ -| Iterating over ``a`` in a row-major fashion | | ``a.begin()`` | -| | | ``a.begin()`` | -+----------------------------------------------------------------+----------------------------------------------------------------+ -| Iterating over ``a`` in a column-major fashion | | ``a.begin()`` | -| | | ``a.end()`` | -+----------------------------------------------------------------+----------------------------------------------------------------+ +.. table:: + :widths: 50 50 + + +-----------------------------------------------------------+------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +===========================================================+================================================+ + | :any:`for x in np.nditer(a): ` | ``for(auto it=a.begin(); it!=a.end(); ++it)`` | + +-----------------------------------------------------------+------------------------------------------------+ + | Iterating over ``a`` with a prescribed broadcasting shape | | ``a.begin({3, 4})`` | + | | | ``a.end({3, 4})`` | + +-----------------------------------------------------------+------------------------------------------------+ + | Iterating over ``a`` in a row-major fashion | | ``a.begin()`` | + | | | ``a.begin()`` | + +-----------------------------------------------------------+------------------------------------------------+ + | Iterating over ``a`` in a column-major fashion | | ``a.begin()`` | + | | | ``a.end()`` | + +-----------------------------------------------------------+------------------------------------------------+ Logical ------- -Logical universal functions are truly lazy. ``xt::where(condition, a, b)`` does not evaluate ``a`` -where ``condition`` is falsy, and it does not evaluate ``b`` where ``condition`` is truthy. - -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.where(a > 5, a, b)`` | ``xt::where(a > 5, a, b)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.where(a > 5)`` | ``xt::where(a > 5)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.argwhere(a > 5)`` | ``xt::argwhere(a > 5)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.any(a)`` | ``xt::any(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.all(a)`` | ``xt::all(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.logical_and(a, b)`` | ``a && b`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.logical_or(a, b)`` | ``a || b`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.isclose(a, b)`` | ``xt::isclose(a, b)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.allclose(a, b)`` | ``xt::allclose(a, b)`` | -+-----------------------------------------------+-----------------------------------------------+ +Logical universal functions are truly lazy. +:cpp:func:`xt::where(condition, a, b) ` does not evaluate ``a`` where ``condition`` +is falsy, and it does not evaluate ``b`` where ``condition`` is truthy. + +.. table:: + :widths: 50 50 + + +-------------------------------------------------+------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +=================================================+================================================+ + | :any:`np.where(a > 5, a, b) ` | :cpp:func:`xt::where(a > 5, a, b) ` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`np.where(a > 5) ` | :cpp:func:`xt::where(a > 5) ` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`np.argwhere(a > 5) ` | :cpp:func:`xt::argwhere(a > 5) ` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`np.any(a) ` | :cpp:func:`xt::any(a) ` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`np.all(a) ` | :cpp:func:`xt::all(a) ` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`np.isin(a, b) ` | :cpp:func:`xt::isin(a, b) ` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`np.in1d(a, b) ` | :cpp:func:`xt::in1d(a, b) ` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`np.logical_and(a, b) ` | ``a && b`` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`np.logical_or(a, b) ` | ``a || b`` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`np.isclose(a, b) ` | :cpp:func:`xt::isclose(a, b) ` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`np.allclose(a, b) ` | :cpp:func:`xt::allclose(a, b) ` | + +-------------------------------------------------+------------------------------------------------+ + | :any:`a = ~b ` | ``a = !b`` | + +-------------------------------------------------+------------------------------------------------+ + +Indices +------- + +.. table:: + :widths: 50 50 + + +-------------------------------------------------------------------------+-----------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +=========================================================================+=======================================================================+ + | :any:`np.ravel_multi_index(indices, a.shape) ` | :cpp:func:`xt::ravel_indices(indices, a.shape()) ` | + +-------------------------------------------------------------------------+-----------------------------------------------------------------------+ Comparisons ----------- -+--------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+============================================+===============================================+ -| ``np.equal(a, b)`` | ``xt::equal(a, b)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.not_equal(a)`` | ``xt::not_equal(a)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.nonzero(a)`` | ``xt::nonzero(a)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.flatnonzero(a)`` | ``xt::flatnonzero(a)`` | -+--------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +-----------------------------------------------------+----------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +=====================================================+==========================================================+ + | :any:`np.equal(a, b) ` | :cpp:func:`xt::equal(a, b) ` | + +-----------------------------------------------------+----------------------------------------------------------+ + | :any:`np.not_equal(a, b) ` | :cpp:func:`xt::not_equal(a, b) ` | + +-----------------------------------------------------+----------------------------------------------------------+ + | :any:`np.less(a, b) ` || :cpp:func:`xt::less(a, b) ` | + | || ``a < b`` | + +-----------------------------------------------------+----------------------------------------------------------+ + | :any:`np.less_equal(a, b) ` || :cpp:func:`xt::less_equal(a, b) ` | + | || ``a <= b`` | + +-----------------------------------------------------+----------------------------------------------------------+ + | :any:`np.greater(a, b) ` || :cpp:func:`xt::greater(a, b) ` | + | || ``a > b`` | + +-----------------------------------------------------+----------------------------------------------------------+ + | :any:`np.greater_equal(a, b) ` || :cpp:func:`xt::greater_equal(a, b) ` | + | || ``a >= b`` | + +-----------------------------------------------------+----------------------------------------------------------+ + | :any:`np.nonzero(a) ` | :cpp:func:`xt::nonzero(a) ` | + +-----------------------------------------------------+----------------------------------------------------------+ + | :any:`np.flatnonzero(a) ` | :cpp:func:`xt::flatnonzero(a) ` | + +-----------------------------------------------------+----------------------------------------------------------+ Minimum, Maximum, Sorting ------------------------- -+--------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+============================================+===============================================+ -| ``np.amin(a)`` | ``xt::amin(a)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.amax(a)`` | ``xt::amax(a)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.argmin(a)`` | ``xt::argmin(a)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.argmax(a, axis=1)`` | ``xt::argmax(a, 1)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.sort(a, axis=1)`` | ``xt::sort(a, 1)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.argsort(a, axis=1)`` | ``xt::argsort(a, 1)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.unique(a)`` | ``xt::unique(a)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.setdiff1d(ar1, ar2)`` | ``xt::setdiff1d(ar1, ar2)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.diff(a[, n, axis])`` | ``xt::diff(a[, n, axis])`` | -+--------------------------------------------+-----------------------------------------------+ +.. list-table:: + :widths: 50 50 + :header-rows: 1 + + * - Python3 - NumPy + - C++14 - xtensor + * - :any:`np.amin(a) ` + - :cpp:func:`xt::amin(a) ` + * - :any:`np.amax(a) ` + - :cpp:func:`xt::amax(a) ` + * - :any:`np.argmin(a) ` + - :cpp:func:`xt::argmin(a) ` + * - :any:`np.argmax(a, axis=1) ` + - :cpp:func:`xt::argmax(a, 1) ` + * - :any:`np.sort(a, axis=1) ` + - :cpp:func:`xt::sort(a, 1) ` + * - :any:`np.argsort(a, axis=1) ` + - :cpp:func:`xt::argsort(a, 1) ` + * - :any:`np.unique(a) ` + - :cpp:func:`xt::unique(a) ` + * - :any:`np.setdiff1d(ar1, ar2) ` + - :cpp:func:`xt::setdiff1d(ar1, ar2) ` + * - :any:`np.partition(a, kth) ` + - :cpp:func:`xt::partition(a, kth) ` + * - :any:`np.argpartition(a, kth) ` + - :cpp:func:`xt::argpartition(a, kth) ` + * - :any:`np.quantile(a, [.1 .3], method="linear") ` + - :cpp:func:`xt::quantile(a, {.1, .3}, xt::quantile_method::linear) ` + * - :any:`np.quantile(a, [.1, .3], axis=1 method="linear") ` + - :cpp:func:`xt::quantile(a, {.1, .3}, 1, xt::quantile_method::linear) ` + * - + - :cpp:func:`xt::quantile(a, {.1, .3}, 1, 1.0, 1.0) ` + * - :any:`np.median(a, axis=1) ` + - :cpp:func:`xt::median(a, 1) ` Complex numbers --------------- -Functions ``xt::real`` and ``xt::imag`` respectively return views on the real and imaginary part -of a complex expression. The returned value is an expression holding a closure on the passed -argument. - -+--------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+============================================+===============================================+ -| ``np.real(a)`` | ``xt::real(a)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.imag(a)`` | ``xt::imag(a)`` | -+--------------------------------------------+-----------------------------------------------+ -| ``np.conj(a)`` | ``xt::conj(a)`` | -+--------------------------------------------+-----------------------------------------------+ - -- The constness and value category (rvalue / lvalue) of ``real(a)`` is the same as that of ``a``. - Hence, if ``a`` is a non-const lvalue, ``real(a)`` is an non-const lvalue reference, to which +Functions :cpp:func:`xt::real` and :cpp:func:`xt::imag` respectively return views on the real and imaginary part +of a complex expression. +The returned value is an expression holding a closure on the passed argument. + +.. table:: + :widths: 50 50 + + +--------------------------------+------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +================================+====================================+ + | :any:`np.real(a) ` | :cpp:func:`xt::real(a) ` | + +--------------------------------+------------------------------------+ + | :any:`np.imag(a) ` | :cpp:func:`xt::imag(a) ` | + +--------------------------------+------------------------------------+ + | :any:`np.conj(a) ` | :cpp:func:`xt::conj(a) ` | + +--------------------------------+------------------------------------+ + +- The constness and value category (rvalue / lvalue) of :cpp:func:`xt::real(a) ` is the same as that of ``a``. + Hence, if ``a`` is a non-const lvalue, :cpp:func:`real(a) ` is an non-const lvalue reference, to which one can assign a real expression. -- If ``a`` has complex values, the same holds for ``imag(a)``. The constness and value category of - ``imag(a)`` is the same as that of ``a``. -- If ``a`` has real values, ``imag(a)`` returns ``zeros(a.shape())``. +- If ``a`` has complex values, the same holds for :cpp:func:`xt::imag(a) `. The constness and value category of + :cpp:func:`xt::imag(a) ` is the same as that of ``a``. +- If ``a`` has real values, :cpp:func:`xt::imag(a) ` returns :cpp:func:`xt::zeros(a.shape()) `. Reducers -------- Reducers accumulate values of tensor expressions along specified axes. When no axis is specified, -values are accumulated along all axes. Reducers are lazy, meaning that returned expressons don't -hold any values and are computed upon access or assigmnent. - -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.sum(a, axis=[0, 1])`` | ``xt::sum(a, {0, 1})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.sum(a, axis=1)`` | ``xt::sum(a, 1)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.sum(a)`` | ``xt::sum(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.prod(a, axis=[0, 1])`` | ``xt::prod(a, {0, 1})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.prod(a, axis=1)`` | ``xt::prod(a, 1)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.prod(a)`` | ``xt::prod(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.mean(a, axis=[0, 1])`` | ``xt::mean(a, {0, 1})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.mean(a, axis=1)`` | ``xt::mean(a, 1)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.mean(a)`` | ``xt::mean(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.std(a, [axis])`` | ``xt::stddev(a, [axis])`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.var(a, [axis])`` | ``xt::variance(a, [axis])`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.trapz(a, dx=2.0, axis=-1)`` | ``xt::trapz(a, 2.0, -1)`` | -| ``np.trapz(a, x=b, axis=-1)`` | ``xt::trapz(a, b, -1)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.count_nonzero(a, axis=[0, 1])`` | ``xt::count_nonzero(a, {0, 1})`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.count_nonzero(a, axis=1)`` | ``xt::count_nonzero(a, 1)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.count_nonzero(a)`` | ``xt::count_nonzero(a)`` | -+-----------------------------------------------+-----------------------------------------------+ - -More generally, one can use the ``xt::reduce(function, input, axes)`` which allows the specification -of an arbitrary binary function for the reduction. The binary function must be cummutative and -associative up to rounding errors. +values are accumulated along all axes. Reducers are lazy, meaning that returned expressions don't +hold any values and are computed upon access or assignment. + +.. table:: + :widths: 50 50 + + +---------------------------------------------------------------+--------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +===============================================================+==============================================================+ + | :any:`np.sum(a, axis=(0, 1)) ` | :cpp:func:`xt::sum(a, {0, 1}) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.sum(a, axis=1) ` | :cpp:func:`xt::sum(a, 1) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.sum(a) ` | :cpp:func:`xt::sum(a) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.prod(a, axis=(0, 1)) ` | :cpp:func:`xt::prod(a, {0, 1}) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.prod(a, axis=1) ` | :cpp:func:`xt::prod(a, 1) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.prod(a) ` | :cpp:func:`xt::prod(a) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.mean(a, axis=(0, 1)) ` | :cpp:func:`xt::mean(a, {0, 1}) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.mean(a, axis=1) ` | :cpp:func:`xt::mean(a, 1) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.mean(a) ` | :cpp:func:`xt::mean(a) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.std(a, [axis]) ` | :cpp:func:`xt::stddev(a, [axis]) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.var(a, [axis]) ` | :cpp:func:`xt::variance(a, [axis]) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.diff(a[, n, axis]) ` | :cpp:func:`xt::diff(a[, n, axis]) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.trapz(a, dx=2.0, axis=-1) ` | :cpp:func:`xt::trapz(a, 2.0, -1) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.trapz(a, x=b, axis=-1) ` | :cpp:func:`xt::trapz(a, b, -1) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.count_nonzero(a, axis=(0, 1)) ` | :cpp:func:`xt::count_nonzero(a, {0, 1}) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.count_nonzero(a, axis=1) ` | :cpp:func:`xt::count_nonzero(a, 1) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + | :any:`np.count_nonzero(a) ` | :cpp:func:`xt::count_nonzero(a) ` | + +---------------------------------------------------------------+--------------------------------------------------------------+ + +More generally, one can use the :cpp:func:`xt::reduce(function, input, axes) ` which allows the specification +of an arbitrary binary function for the reduction. +The binary function must be commutative and associative up to rounding errors. + +NaN functions +------------- + +NaN functions allow disregarding NaNs during computation, changing the effective number of elements +considered in reductions. + +.. list-table:: + :widths: 50 50 + :header-rows: 1 + + * - Python3 - NumPy + - C++14 - xtensor + * - :any:`np.nan_to_num(a) ` + - :cpp:func:`xt::nan_to_num(a) ` + * - :any:`np.nanmin(a) ` + - :cpp:func:`xt::nanmin(a) ` + * - :any:`np.nanmin(a, axis=(0, 1)) ` + - :cpp:func:`xt::nanmin(a, {0, 1}) ` + * - :any:`np.nanmax(a) ` + - :cpp:func:`xt::nanmax(a) ` + * - :any:`np.nanmax(a, axis=(0, 1)) ` + - :cpp:func:`xt::nanmax(a, {0, 1}) ` + * - :any:`np.nansum(a) ` + - :cpp:func:`xt::nansum(a) ` + * - :any:`np.nansum(a, axis=0) ` + - :cpp:func:`xt::nansum(a, 0) ` + * - :any:`np.nansum(a, axis=(0, 1)) ` + - :cpp:func:`xt::nansum(a, {0, 1}) ` + * - :any:`np.nanprod(a) ` + - :cpp:func:`xt::nanprod(a) ` + * - :any:`np.nanprod(a, axis=0) ` + - :cpp:func:`xt::nanprod(a, 0) ` + * - :any:`np.nanprod(a, axis=(0, 1)) ` + - :cpp:func:`xt::nanprod(a, {0, 1}) ` + * - :any:`np.nancumsum(a) ` + - :cpp:func:`xt::nancumsum(a) ` + * - :any:`np.nancumsum(a, axis=0) ` + - :cpp:func:`xt::nancumsum(a, 0) ` + * - :any:`np.nancumprod(a) ` + - :cpp:func:`xt::nancumsum(a) ` + * - :any:`np.nancumprod(a, axis=0) ` + - :cpp:func:`xt::nancumsum(a, 0) ` + * - :any:`np.nanmean(a) ` + - :cpp:func:`xt::nanmean(a) ` + * - :any:`np.nanmean(a, axis=(0, 1)) ` + - :cpp:func:`xt::nanmean(a, {0, 1}) ` + * - :any:`np.nanvar(a) ` + - :cpp:func:`xt::nanvar(a) ` + * - :any:`np.nanvar(a, axis=(0, 1)) ` + - :cpp:func:`xt::nanvar(a, {0, 1}) ` + * - :any:`np.nanstd(a) ` + - :cpp:func:`xt::nanstd(a) ` + * - :any:`np.nanstd(a, axis=(0, 1)) ` + - :cpp:func:`xt::nanstd(a, {0, 1}) ` I/O --- @@ -386,31 +575,37 @@ I/O These options determine the way floating point numbers, tensors and other xtensor expressions are displayed. -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.set_printoptions(precision=4)`` | ``xt::print_options::set_precision(4)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.set_printoptions(threshold=5)`` | ``xt::print_options::set_threshold(5)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.set_printoptions(edgeitems=3)`` | ``xt::print_options::set_edgeitems(3)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.set_printoptions(linewidth=100)`` | ``xt::print_options::set_line_width(100)`` | -+-----------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +--------------------------------------------------------------------+----------------------------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +====================================================================+========================================================================================+ + | :any:`np.set_printoptions(precision=4) ` | :cpp:func:`xt::print_options::set_precision(4) ` | + +--------------------------------------------------------------------+----------------------------------------------------------------------------------------+ + | :any:`np.set_printoptions(threshold=5) ` | :cpp:func:`xt::print_options::set_threshold(5) ` | + +--------------------------------------------------------------------+----------------------------------------------------------------------------------------+ + | :any:`np.set_printoptions(edgeitems=3) ` | :cpp:func:`xt::print_options::set_edgeitems(3) ` | + +--------------------------------------------------------------------+----------------------------------------------------------------------------------------+ + | :any:`np.set_printoptions(linewidth=100) ` | :cpp:func:`xt::print_options::set_line_width(100) ` | + +--------------------------------------------------------------------+----------------------------------------------------------------------------------------+ **Reading npy, csv file formats** -Functions ``load_csv`` and ``dump_csv`` respectively take input and output streams as arguments. +Functions :cpp:func:`xt::load_csv` and :cpp:func:`xt::dump_csv` respectively take input and output streams as arguments. -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.load(filename)`` | ``xt::load_npy(filename)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.save(filename, arr)`` | ``xt::dump_npy(filename, arr)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.load_txt(filename, delimiter=',')`` | ``xt::load_csv(stream)`` | -+-----------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +------------------------------------------------------------+-------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +============================================================+=============================================================+ + | :any:`np.load(filename) ` | :cpp:func:`xt::load_npy\(filename) ` | + +------------------------------------------------------------+-------------------------------------------------------------+ + | :any:`np.save(filename, arr) ` | :cpp:func:`xt::dump_npy(filename, arr) ` | + +------------------------------------------------------------+-------------------------------------------------------------+ + | :any:`np.loadtxt(filename, delimiter=',') ` | :cpp:func:`xt::load_csv\(stream) ` | + +------------------------------------------------------------+-------------------------------------------------------------+ Mathematical functions ---------------------- @@ -419,198 +614,268 @@ xtensor universal functions are provided for a large set number of mathematical **Basic functions:** -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.absolute(a)`` | ``xt::abs(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.sign(a)`` | ``xt::sign(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.remainder(a, b)`` | ``xt::remainder(a, b)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.clip(a, min, max)`` | ``xt::clip(a, min, max)`` | -+-----------------------------------------------+-----------------------------------------------+ -| | ``xt::fma(a, b, c)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.interp(x, xp, fp, [,left, right])`` | ``xt::interp(x, xp, fp, [,left, right])`` | -+-----------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +------------------------------------------------------------+----------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +============================================================+================================================================+ + | :any:`np.absolute(a) ` | :cpp:func:`xt::abs(a) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.sign(a) ` | :cpp:func:`xt::sign(a) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.remainder(a, b) ` | :cpp:func:`xt::remainder(a, b) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.minimum(a, b) ` | :cpp:func:`xt::minimum(a, b) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.maximum(a, b) ` | :cpp:func:`xt::maximum(a, b) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.clip(a, min, max) ` | :cpp:func:`xt::clip(a, min, max) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | | :cpp:func:`xt::fma(a, b, c) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.interp(x, xp, fp, [,left, right]) ` | :cpp:func:`xt::interp(x, xp, fp, [,left, right]) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.rad2deg(a) ` | :cpp:func:`xt::rad2deg(a) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.degrees(a) ` | :cpp:func:`xt::degrees(a) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.deg2rad(a) ` | :cpp:func:`xt::deg2rad(a) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.radians(a) ` | :cpp:func:`xt::radians(a) ` | + +------------------------------------------------------------+----------------------------------------------------------------+ **Exponential functions:** -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.exp(a)`` | ``xt::exp(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.expm1(a)`` | ``xt::expm1(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.log(a)`` | ``xt::log(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.log1p(a)`` | ``xt::log1p(a)`` | -+-----------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +----------------------------------+--------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +==================================+======================================+ + | :any:`np.exp(a) ` | :cpp:func:`xt::exp(a) ` | + +----------------------------------+--------------------------------------+ + | :any:`np.expm1(a) ` | :cpp:func:`xt::expm1(a) ` | + +----------------------------------+--------------------------------------+ + | :any:`np.log(a) ` | :cpp:func:`xt::log(a) ` | + +----------------------------------+--------------------------------------+ + | :any:`np.log1p(a) ` | :cpp:func:`xt::log1p(a) ` | + +----------------------------------+--------------------------------------+ **Power functions:** -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.power(a, p)`` | ``xt::pow(a, b)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.sqrt(a)`` | ``xt::sqrt(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.square(a)`` | ``xt::square(a)`` | -| | ``xt::cube(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.cbrt(a)`` | ``xt::cbrt(a)`` | -+-----------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +-------------------------------------+----------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +=====================================+========================================+ + | :any:`np.power(a, p) ` | :cpp:func:`xt::pow(a, b) ` | + +-------------------------------------+----------------------------------------+ + | :any:`np.sqrt(a) ` | :cpp:func:`xt::sqrt(a) ` | + +-------------------------------------+----------------------------------------+ + | :any:`np.square(a) ` | :cpp:func:`xt::square(a) ` | + | | :cpp:func:`xt::cube(a) ` | + +-------------------------------------+----------------------------------------+ + | :any:`np.cbrt(a) ` | :cpp:func:`xt::cbrt(a) ` | + +-------------------------------------+----------------------------------------+ **Trigonometric functions:** -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.sin(a)`` | ``xt::sin(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.cos(a)`` | ``xt::cos(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.tan(a)`` | ``xt::tan(a)`` | -+-----------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +------------------------------+----------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +==============================+==================================+ + | :any:`np.sin(a) ` | :cpp:func:`xt::sin(a) ` | + +------------------------------+----------------------------------+ + | :any:`np.cos(a) ` | :cpp:func:`xt::cos(a) ` | + +------------------------------+----------------------------------+ + | :any:`np.tan(a) ` | :cpp:func:`xt::tan(a) ` | + +------------------------------+----------------------------------+ **Hyperbolic functions:** -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.sinh(a)`` | ``xt::sinh(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.cosh(a)`` | ``xt::cosh(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.tanh(a)`` | ``xt::tanh(a)`` | -+-----------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +--------------------------------+------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +================================+====================================+ + | :any:`np.sinh(a) ` | :cpp:func:`xt::sinh(a) ` | + +--------------------------------+------------------------------------+ + | :any:`np.cosh(a) ` | :cpp:func:`xt::cosh(a) ` | + +--------------------------------+------------------------------------+ + | :any:`np.tanh(a) ` | :cpp:func:`xt::tanh(a) ` | + +--------------------------------+------------------------------------+ **Error and gamma functions:** -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``scipy.special.erf(a)`` | ``xt::erf(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``scipy.special.gamma(a)`` | ``xt::tgamma(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``scipy.special.gammaln(a)`` | ``xt::lgamma(a)`` | -+-----------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +---------------------------------------------------------+----------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +=========================================================+========================================+ + | :any:`scipy.special.erf(a) ` | :cpp:func:`xt::erf(a) ` | + +---------------------------------------------------------+----------------------------------------+ + | :any:`scipy.special.gamma(a) ` | :cpp:func:`xt::tgamma(a) ` | + +---------------------------------------------------------+----------------------------------------+ + | :any:`scipy.special.gammaln(a) ` | :cpp:func:`xt::lgamma(a) ` | + +---------------------------------------------------------+----------------------------------------+ **Classification functions:** -+-----------------------------------------------+-----------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================+===============================================+ -| ``np.isnan(a)`` | ``xt::isnan(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.isinf(a)`` | ``xt::isinf(a)`` | -+-----------------------------------------------+-----------------------------------------------+ -| ``np.isfinite(a)`` | ``xt::isfinite(a)`` | -+-----------------------------------------------+-----------------------------------------------+ +.. table:: + :widths: 50 50 + + +-----------------------------------------------------------+----------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +===========================================================+================================================================+ + | :any:`np.isnan(a) ` | :cpp:func:`xt::isnan(a) ` | + +-----------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.isinf(a) ` | :cpp:func:`xt::isinf(a) ` | + +-----------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.isfinite(a) ` | :cpp:func:`xt::isfinite(a) ` | + +-----------------------------------------------------------+----------------------------------------------------------------+ + | :any:`np.searchsorted(a, v[, side]) ` | :cpp:func:`xt::searchsorted(a, v[, right]) ` | + +-----------------------------------------------------------+----------------------------------------------------------------+ **Histogram:** -+-------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+===============================================================================+================================================================================+ -| ``np.histogram(a, bins[, weights][, density])`` | ``xt::histogram(a, bins[, weights][, density])`` | -+-------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ -| ``np.histogram_bin_edges(a, bins[, weights][, left, right][, bins][, mode])`` | ``xt::histogram_bin_edges(a, bins[, weights][, left, right][, bins][, mode])`` | -+-------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ -| ``np.bincount(arr)`` | ``xt::bincount(arr)`` | -+-------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ +.. table:: + :widths: 50 50 + + +--------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +==============================================================================================================+==================================================================================================================+ + | :any:`np.histogram(a, bins[, weights][, density]) ` | :cpp:func:`xt::histogram(a, bins[, weights][, density]) ` | + +--------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ + | :any:`np.histogram_bin_edges(a, bins[, weights][, left, right][, bins][, mode]) ` | :cpp:func:`xt::histogram_bin_edges(a, bins[, weights][, left, right][, bins][, mode]) ` | + +--------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ + | :any:`np.bincount(arr) ` | :cpp:func:`xt::bincount(arr) ` | + +--------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ + | :any:`np.digitize(data, bin_edges[, right]) ` | :cpp:func:`xt::digitize(data, bin_edges[, right][, assume_sorted]) ` | + +--------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ + +See :ref:`histogram`. + +**Numerical constants:** + +.. table:: + :widths: 50 50 + + +------------------+----------------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +==================+============================================================================+ + | :any:`numpy.pi` | :cpp:var:`xt::numeric_constants\::PI ` | + +------------------+----------------------------------------------------------------------------+ Linear algebra -------------- -Many functions found in the ``numpy.linalg`` module are implemented in `xtensor-blas`_, a seperate package offering BLAS and LAPACK bindings, as well as a convenient interface replicating the ``linalg`` module. +Many functions found in the :any:`numpy.linalg` module are implemented in `xtensor-blas`_, a separate package offering BLAS and LAPACK bindings, +as well as a convenient interface replicating the ``linalg`` module. Please note, however, that while we're trying to be as close to NumPy as possible, some features are not -implemented yet. Most prominently that is broadcasting for all functions except for ``dot``. +implemented yet. Most prominently that is broadcasting for all functions except for :cpp:func:`xt::linalg::dot`. **Matrix, vector and tensor products** -+---------------------------------------------+---------------------------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+=============================================+===================================================+ -| ``np.dot(a, b)`` | ``xt::linalg::dot(a, b)`` | -+---------------------------------------------+---------------------------------------------------+ -| ``np.vdot(a, b)`` | ``xt::linalg::vdot(a, b)`` | -+---------------------------------------------+---------------------------------------------------+ -| ``np.outer(a, b)`` | ``xt::linalg::outer(a, b)`` | -+---------------------------------------------+---------------------------------------------------+ -| ``np.matrix_power(a, 123)`` | ``xt::linalg::matrix_power(a, 123)`` | -+---------------------------------------------+---------------------------------------------------+ -| ``np.kron(a, b)`` | ``xt::linalg::kron(a, b)`` | -+---------------------------------------------+---------------------------------------------------+ -| | ``np.tensordot(a, b, axes=3)`` | | ``xt::linalg::tensordot(a, b, 3)`` | -| | ``np.tensordot(a, b, axes=((0,2),(1,3))`` | | ``xt::linalg::tensordot(a, b, {0, 2}, {1, 3})`` | -+-------------------------------------------------------------------------------------------------+ +.. table:: + :widths: 50 50 + + +-------------------------------------------------------------------+---------------------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +===================================================================+=================================================================================+ + | :any:`np.dot(a, b) ` | :cpp:func:`xt::linalg::dot(a, b) ` | + +-------------------------------------------------------------------+---------------------------------------------------------------------------------+ + | :any:`np.vdot(a, b) ` | :cpp:func:`xt::linalg::vdot(a, b) ` | + +-------------------------------------------------------------------+---------------------------------------------------------------------------------+ + | :any:`np.outer(a, b) ` | :cpp:func:`xt::linalg::outer(a, b) ` | + +-------------------------------------------------------------------+---------------------------------------------------------------------------------+ + | :any:`np.linalg.matrix_power(a, 123) ` | :cpp:func:`xt::linalg::matrix_power(a, 123) ` | + +-------------------------------------------------------------------+---------------------------------------------------------------------------------+ + | :any:`np.kron(a, b) ` | :cpp:func:`xt::linalg::kron(a, b) ` | + +-------------------------------------------------------------------+---------------------------------------------------------------------------------+ + | :any:`np.tensordot(a, b, axes=3) ` | :cpp:func:`xt::linalg::tensordot(a, b, 3) ` | + +-------------------------------------------------------------------+---------------------------------------------------------------------------------+ + | :any:`np.tensordot(a, b, axes=((0,2),(1,3)) ` | :cpp:func:`xt::linalg::tensordot(a, b, {0, 2}, {1, 3}) ` | + +-------------------------------------------------------------------+---------------------------------------------------------------------------------+ **Decompositions** -+-----------------------------+-----------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+=============================+=============================+ -| ``np.linalg.cholesky(a)`` | ``xt::linalg::cholesky(a)`` | -+-----------------------------+-----------------------------+ -| ``np.linalg.qr(a)`` | ``xt::linalg::qr(a)`` | -+-----------------------------+-----------------------------+ -| ``np.linalg.svd(a)`` | ``xt::linalg::svd(a)`` | -+-----------------------------+-----------------------------+ +.. table:: + :widths: 50 50 + + +------------------------------------------------------+------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +======================================================+============================================================+ + | :any:`np.linalg.cholesky(a) ` | :cpp:func:`xt::linalg::cholesky(a) ` | + +------------------------------------------------------+------------------------------------------------------------+ + | :any:`np.linalg.qr(a) ` | :cpp:func:`xt::linalg::qr(a) ` | + +------------------------------------------------------+------------------------------------------------------------+ + | :any:`np.linalg.svd(a) ` | :cpp:func:`xt::linalg::svd(a) ` | + +------------------------------------------------------+------------------------------------------------------------+ **Matrix eigenvalues** -+-----------------------------+-----------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+=============================+=============================+ -| ``np.linalg.eig(a)`` | ``xt::linalg::eig(a)`` | -+-----------------------------+-----------------------------+ -| ``np.linalg.eigvals(a)`` | ``xt::linalg::eigvals(a)`` | -+-----------------------------+-----------------------------+ -| ``np.linalg.eigh(a)`` | ``xt::linalg::eigh(a)`` | -+-----------------------------+-----------------------------+ -| ``np.linalg.eigvalsh(a)`` | ``xt::linalg::eigvalsh(a)`` | -+-----------------------------+-----------------------------+ +.. table:: + :widths: 50 50 + + +------------------------------------------------------+------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +======================================================+============================================================+ + | :any:`np.linalg.eig(a) ` | :cpp:func:`xt::linalg::eig(a) ` | + +------------------------------------------------------+------------------------------------------------------------+ + | :any:`np.linalg.eigvals(a) ` | :cpp:func:`xt::linalg::eigvals(a) ` | + +------------------------------------------------------+------------------------------------------------------------+ + | :any:`np.linalg.eigh(a) ` | :cpp:func:`xt::linalg::eigh(a) ` | + +------------------------------------------------------+------------------------------------------------------------+ + | :any:`np.linalg.eigvalsh(a) ` | :cpp:func:`xt::linalg::eigvalsh(a) ` | + +------------------------------------------------------+------------------------------------------------------------+ **Norms and other numbers** -+--------------------------------+--------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+================================+================================+ -| ``np.linalg.norm(a, order=2)`` | ``xt::linalg::norm(a, 2)`` | -+--------------------------------+--------------------------------+ -| ``np.linalg.cond(a)`` | ``xt::linalg::cond(a)`` | -+--------------------------------+--------------------------------+ -| ``np.linalg.det(a)`` | ``xt::linalg::det(a)`` | -+--------------------------------+--------------------------------+ -| ``np.linalg.matrix_rank(a)`` | ``xt::linalg::matrix_rank(a)`` | -+--------------------------------+--------------------------------+ -| ``np.linalg.slogdet(a)`` | ``xt::linalg::slogdet(a)`` | -+--------------------------------+--------------------------------+ -| ``np.trace(a)`` | ``xt::linalg::trace(a)`` | -+--------------------------------+--------------------------------+ +.. table:: + :widths: 50 50 + + +------------------------------------------------------------+------------------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +============================================================+==================================================================+ + | :any:`np.linalg.norm(a, order=2) ` | :cpp:func:`xt::linalg::norm(a, 2) ` | + +------------------------------------------------------------+------------------------------------------------------------------+ + | :any:`np.linalg.cond(a) ` | :cpp:func:`xt::linalg::cond(a) ` | + +------------------------------------------------------------+------------------------------------------------------------------+ + | :any:`np.linalg.det(a) ` | :cpp:func:`xt::linalg::det(a) ` | + +------------------------------------------------------------+------------------------------------------------------------------+ + | :any:`np.linalg.matrix_rank(a) ` | :cpp:func:`xt::linalg::matrix_rank(a) ` | + +------------------------------------------------------------+------------------------------------------------------------------+ + | :any:`np.linalg.slogdet(a) ` | :cpp:func:`xt::linalg::slogdet(a) ` | + +------------------------------------------------------------+------------------------------------------------------------------+ + | :any:`np.trace(a) ` | :cpp:func:`xt::linalg::trace(a) ` | + +------------------------------------------------------------+------------------------------------------------------------------+ **Solving equations and inverting matrices** -+--------------------------------+--------------------------------+ -| Python 3 - numpy | C++ 14 - xtensor | -+================================+================================+ -| ``np.linalg.inv(a)`` | ``xt::linalg::inv(a)`` | -+--------------------------------+--------------------------------+ -| ``np.linalg.pinv(a)`` | ``xt::linalg::pinv(a)`` | -+--------------------------------+--------------------------------+ -| ``np.linalg.solve(A, b)`` | ``xt::linalg::solve(A, b)`` | -+--------------------------------+--------------------------------+ -| ``np.linalg.lstsq(A, b)`` | ``xt::linalg::lstsq(A, b)`` | -+--------------------------------+--------------------------------+ +.. table:: + :widths: 50 50 + + +---------------------------------------------------+---------------------------------------------------------+ + | Python 3 - NumPy | C++ 14 - xtensor | + +===================================================+=========================================================+ + | :any:`np.linalg.inv(a) ` | :cpp:func:`xt::linalg::inv(a) ` | + +---------------------------------------------------+---------------------------------------------------------+ + | :any:`np.linalg.pinv(a) ` | :cpp:func:`xt::linalg::pinv(a) ` | + +---------------------------------------------------+---------------------------------------------------------+ + | :any:`np.linalg.solve(A, b) ` | :cpp:func:`xt::linalg::solve(A, b) ` | + +---------------------------------------------------+---------------------------------------------------------+ + | :any:`np.linalg.lstsq(A, b) ` | :cpp:func:`xt::linalg::lstsq(A, b) ` | + +---------------------------------------------------+---------------------------------------------------------+ -.. _`xtensor-blas`: https://github.com/QuantStack/xtensor-blas +.. _`xtensor-blas`: https://github.com/xtensor-stack/xtensor-blas diff --git a/docs/source/numpy.svg b/docs/source/numpy.svg index 1ea8979f4..63b3ccf6b 100644 --- a/docs/source/numpy.svg +++ b/docs/source/numpy.svg @@ -4953,7 +4953,7 @@ inkscape:connector-curvature="0" style="fill:#6272c3" /> \ No newline at end of file + ]]> diff --git a/docs/source/operator.rst b/docs/source/operator.rst index 982dc8ae0..7323ed5a3 100644 --- a/docs/source/operator.rst +++ b/docs/source/operator.rst @@ -10,23 +10,23 @@ Operators and functions Arithmetic operators -------------------- -`xtensor` provides overloads of traditional arithmetic operators for -``xexpression`` objects: +*xtensor* provides overloads of traditional arithmetic operators for +:cpp:type:`xt::xexpression` objects: -- unary ``operator+`` -- unary ``operator-`` -- ``operator+`` -- ``operator-`` -- ``operator*`` -- ``operator/`` -- ``operator%`` +- unary :cpp:func:`~xt::xexpression::operator+` +- unary :cpp:func:`~xt::xexpression::operator-` +- :cpp:func:`~xt::xexpression::operator+` +- :cpp:func:`~xt::xexpression::operator-` +- :cpp:func:`~xt::xexpression::operator*` +- :cpp:func:`~xt::xexpression::operator/` +- :cpp:func:`~xt::xexpression::operator%` All these operators are element-wise operators and apply the lazy broadcasting rules explained in a previous section. .. code:: - #incude "xtensor/xarray.hpp" + #incude "xtensor/containers/xarray.hpp" xt::xarray a = {{1, 2}, {3, 4}}; xt::xarray b = {1, 2}; @@ -37,28 +37,28 @@ rules explained in a previous section. Logical operators ----------------- -`xtensor` also provides overloads of the logical operators: +*xtensor* also provides overloads of the logical operators: -- ``operator!`` -- ``operator||`` -- ``operator&&`` +- :cpp:func:`~xt::xexpression::operator!` +- :cpp:func:`~xt::xexpression::operator||` +- :cpp:func:`~xt::xexpression::operator&&` Like arithmetic operators, these logical operators are element-wise operators and apply the lazy broadcasting rules. In addition to these element-wise -logical operators, `xtensor` provides two reducing boolean functions: +logical operators, *xtensor* provides two reducing boolean functions: -- ``any(E&& e)`` returns ``true`` if any of ``e`` elements is truthy, ``false`` otherwise. -- ``all(E&& e)`` returns ``true`` if all alements of ``e`` are truthy, ``false`` otherwise. +- :cpp:func:`xt::any(E&& e) ` returns ``true`` if any of ``e`` elements is truthy, ``false`` otherwise. +- :cpp:func:`xt::all(E&& e) ` returns ``true`` if all elements of ``e`` are truthy, ``false`` otherwise. and an element-wise ternary function (similar to the ``: ?`` ternary operator): -- ``where(E&& b, E1&& e&, E2&& e2)`` returns an ``xexpression`` whose elements - are those of ``e1`` when corresponding elements of ``b`` are thruthy, and +- :cpp:func:`xt::where(E&& b, E1&& e1, E2&& e2) ` returns an :cpp:type:`xt::xexpression` whose elements + are those of ``e1`` when corresponding elements of ``b`` are truthy, and those of ``e2`` otherwise. .. code:: - #include "xtensor/xarray.hpp" + #include xt::xarray b = { false, true, true, false }; xt::xarray a1 = { 1, 2, 3, 4 }; @@ -67,26 +67,26 @@ and an element-wise ternary function (similar to the ``: ?`` ternary operator): xt::xarray res = xt::where(b, a1, a2); // => res = { 11, 2, 3, 14 } -Unlike in ``numpy.where``, ``xt::where`` takes full advantage of the lazyness -of `xtensor`. +Unlike in :any:`numpy.where`, :cpp:func:`xt::where` takes full advantage of the lazyness +of *xtensor*. Comparison operators -------------------- -`xtensor` provides overloads of the inequality operators: +*xtensor* provides overloads of the inequality operators: -- ``operator<`` -- ``operator<=`` -- ``operator>`` -- ``operator>=`` +- :cpp:func:`~xt::xexpression::operator\<` +- :cpp:func:`~xt::xexpression::operator\<=` +- :cpp:func:`~xt::xexpression::operator\>` +- :cpp:func:`~xt::xexpression::operator\>=` These overloads of inequality operators are quite different from the standard C++ inequality operators: they are element-wise operators returning boolean -``xexpression``: +:cpp:type:`xexpression`: .. code:: - #include "xtensor/xarray.hpp" + #include xt::xarray a1 = { 1, 12, 3, 14 }; xt::xarray a2 = { 11, 2, 13, 4 }; @@ -95,15 +95,17 @@ C++ inequality operators: they are element-wise operators returning boolean However, equality operators are similar to the traditional ones in C++: -- ``operator==(const E1& e1, const E2& e2)`` returns ``true`` if ``e1`` and ``e2`` hold the same elements. -- ``operator!=(const E1& e1, const E2& e2)`` returns ``true`` if ``e1`` and ``e2`` don't hold the same elements. +- :cpp:func:`operator==(const E1& e1, const E2& e2) ` returns ``true`` if ``e1`` + and ``e2`` hold the same elements. +- :cpp:func:`operator!=(const E1& e1, const E2& e2) ` returns ``true`` if ``e1`` + and ``e2`` don't hold the same elements. -Element-wise equality comparison can be achieved through the ``xt::equal`` +Element-wise equality comparison can be achieved through the :cpp:func:`xt::equal` function. .. code:: - #include "xtensor/xarray.hpp" + #include xt::xarray a1 = { 1, 2, 3, 4}; xt::xarray a2 = { 11, 12, 3, 4}; @@ -117,26 +119,26 @@ function. Bitwise operators ----------------- -`xtensor` also contains the following bitwise operators: +*xtensor* also contains the following bitwise operators: -- Bitwise and: ``operator&`` -- Bitwise or: ``operator|`` -- Bitwise xor: ``operator^`` -- Bitwise not: ``operator~`` -- Bitwise left/right shift: ``left_shift``, ``right_shift`` +- Bitwise and: :cpp:func:`~xt::xexpression::operator&` +- Bitwise or: :cpp:func:`~xt::xexpression::operator|` +- Bitwise xor: :cpp:func:`~xt::xexpression::operator^` +- Bitwise not: :cpp:func:`~xt::xexpression::operator~` +- Bitwise left/right shift: :cpp:func:`~xt::xexpression::left_shift`, :cpp:func:`~xt::xexpression::right_shift` Mathematical functions ---------------------- -`xtensor` provides overloads for many of the standard mathematical functions: +*xtensor* provides overloads for many of the standard mathematical functions: -- basic functions: ``abs``, ``remainder``, ``fma``, ... -- exponential functions: ``exp``, ``expm1``, ``log``, ``log1p``, ... -- power functions: ``pow``, ``sqrt``, ``cbrt``, ... -- trigonometric functions: ``sin``, ``cos``, ``tan``, ... -- hyperbolic functions: ``sinh``, ``cosh``, ``tanh``, ... -- Error and gamma functions: ``erf``, ``erfc``, ``tgamma``, ``lgamma``, .... -- Nearest integer floating point operations: ``ceil``, ``floor``, ``trunc``, ... +- basic functions: :cpp:func:`xt::abs`, :cpp:func:`xt::remainder`, :cpp:func:`xt::fma`, ... +- exponential functions: :cpp:func:`xt::exp`, :cpp:func:`xt::expm1`, :cpp:func:`xt::log`, :cpp:func:`xt::log1p`, ... +- power functions: :cpp:func:`xt::pow`, :cpp:func:`xt::sqrt`, :cpp:func:`xt::cbrt`, ... +- trigonometric functions: :cpp:func:`xt::sin`, :cpp:func:`xt::cos`, :cpp:func:`xt::tan`, ... +- hyperbolic functions: :cpp:func:`xt::sinh`, :cpp:func:`xt::cosh`, :cpp:func:`xt::tanh`, ... +- Error and gamma functions: :cpp:func:`xt::erf`, :cpp:func:`xt::erfc`, :cpp:func:`xt::tgamma`, :cpp:func:`xt::lgamma`, .... +- Nearest integer floating point operations: :cpp:func:`xt::ceil`, :cpp:func:`xt::floor`, :cpp:func:`xt::trunc`, ... See the API reference for a comprehensive list of available functions. Like operators, the mathematical functions are element-wise functions and apply the @@ -145,13 +147,13 @@ lazy broadcasting rules. Casting ------- -`xtensor` will implicitly promote and/or cast tensor expression elements as +*xtensor* will implicitly promote and/or cast tensor expression elements as needed, which suffices for most use-cases. But explicit casting can be -performed via ``cast``, which performs an element-wise ``static_cast``. +performed via :cpp:func:`xt::cast`, which performs an element-wise ``static_cast``. .. code:: - #include "xtensor/xarray.hpp" + #include xt::xarray a = { 3, 5, 7 }; @@ -164,46 +166,106 @@ performed via ``cast``, which performs an element-wise ``static_cast``. Reducers -------- -`xtensor` provides reducers, that is, means for accumulating values of tensor +*xtensor* provides reducers, that is, means for accumulating values of tensor expressions over prescribed axes. The return value of a reducer is an -``xexpression`` with the same shape as the input expression, with the specified +:cpp:type:`xt::xexpression` with the same shape as the input expression, with the specified axes removed. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xmath.hpp" + #include + #include xt::xarray a = xt::ones({3, 2, 4, 6, 5}); xt::xarray res = xt::sum(a, {1, 3}); // => res.shape() = { 3, 4, 5 }; // => res(0, 0, 0) = 12 -You can also call the ``reduce`` generator with your own reducing function: +You can also call the :cpp:func:`xt::reduce` generator with your own reducing function: .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xreducer.hpp" + #include + #include xt::xarray arr = some_init_function({3, 2, 4, 6, 5}); xt::xarray res = xt::reduce([](double a, double b) { return a*a + b*b; }, arr, {1, 3}); +The reduce generator also accepts a :cpp:type:`xt::xreducer_functors` object, a tuple of three functions +(one for reducing, one for initialization and one for merging). +A generator is provided to build the :cpp:type:`xt::xreducer_functors` object, the last function can be omitted: + +.. code:: + + #include + #include + + xt::xarray arr = some_init_function({3, 2, 4, 6, 5}); + xt::xarray res = xt::reduce(xt::make_xreducer_functor([](double a, double b) { return a*a + b*b; }, + [](double a) { return a * 2; }) + arr, + {1, 3}); + +If no axes are provided, the reduction is performed over all the axes, and the result is a 0-D expression. +Since *xtensor*'s expressions are lazy evaluated, you need to explicitely call the access operator to trigger +the evaluation and get the result: + +.. code:: + + #include + #include + + xt::xarray arr = some_init_function({3, 2, 4, 6, 5}); + double res = xt::reduce([](double a, double b) { return a*a + b*b; }, arr)(); + +The ``value_type`` of a reducer is the traditional result type of the reducing operation. +For instance, the ``value_type`` of the reducer for the sum is: + +- ``int`` if the underlying expression holds ``int`` values +- ``int`` if the underlying expression holds ``short`` values, because ``short + short`` = ``int`` + +You can pass a template argument to the reducer functions to specify the type of the initial value of +the reduction. This allows you to "promote" the value type of the reducer and limit overflows in +computation: + +.. code:: + + #include + #include + + xt::xarray arr = some_init_function({3, 2, 4, 6, 5}); + auto s1 = xt::sum(arr); // No effect, short + int = int + auto s2 = xt::sum(arr); // The value_type of s2 is long int + +When you write generic code and you want to limit overflows, you can use :cpp:any:`xt::big_promote_value_type_t` +as shown below: + +.. code:: + + #include + #include + + template + void my_computation(E&& e) + { + auto s = xt::sum>(e); + } + Accumulators ------------ -Similar to reducers, `xtensor` provides accumulators which are used to -implement cumulative functions such as ``cumsum`` or ``cumprod``. Accumulators +Similar to reducers, *xtensor* provides accumulators which are used to +implement cumulative functions such as :cpp:func:`xt::cumsum` or :cpp:func:`xt::cumprod`. Accumulators can currently only work on a single axis. Additionally, the accumulators are -not lazy and do not return an xexpression, but rather an evaluated ``xarray`` -or ``xtensor``. +not lazy and do not return an xexpression, but rather an evaluated :cpp:type:`xt::xarray` +or :cpp:type:`xt::xtensor`. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xmath.hpp" + #include + #include xt::xarray a = xt::ones({5, 8, 3}); xt::xarray res = xt::cumsum(a, 1); @@ -211,23 +273,38 @@ or ``xtensor``. // => res(0, 0, 0) = 1 // => res(0, 7, 0) = 8 -You can also call the ``accumumulate`` generator with your own accumulating +You can also call the :cpp:func:`xt::accumulate` generator with your own accumulating function. For example, the implementation of cumsum is as follows: .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xaccumulator.hpp" + #include + #include xt::xarray arr = some_init_function({5, 5, 5}); xt::xarray res = xt::accumulate([](double a, double b) { return a + b; }, arr, 1); +Like reducers, accumulators accept a template parameter to specify the ``value_type`` +of the initial value of the accumulation. The ``value_type`` of the result is computed +with the same rules as those for reducers: + +.. code:: + + #include + #include + + xt::xarray arr = some_init_function({5, 5, 5}); + auto r1 = xt::cumsum(a, 1); + // r1 holds int values + auto r2 = xt::cumsum(a, 1); + // r2 hols long int values + Evaluation strategy ------------------- -Generally, `xtensor` implements a :ref:`lazy execution model `, +Generally, *xtensor* implements a :ref:`lazy execution model `, but under certain circumstances, a *greedy* execution model with immediate execution can be favorable. For example, reusing (and recomputing) the same values of a reducer over and over again if you use them in a loop can cost a @@ -235,9 +312,10 @@ lot of CPU cycles. Additionally, *greedy* execution can benefit from SIMD acceleration over reduction axes and is faster when the entire result needs to be computed. -Therefore, xtensor allows to select an ``evaluation_strategy``. Currently, two -evaluation strategies are implemented: ``evaluation_strategy::immediate`` and -``evaluation_strategy::lazy``. When ``immediate`` evaluation is selected, the +Therefore, xtensor allows to select an :cpp:enum:`xt::evaluation_strategy`. Currently, two +evaluation strategies are implemented: :cpp:enumerator:`xt::evaluation_strategy::immediate` and +:cpp:enumerator:`xt::evaluation_strategy::lazy`. +When :cpp:enumerator:`~xt::evaluation_strategy::immediate` evaluation is selected, the return value is not an xexpression, but an in-memory datastructure such as a xarray or xtensor (depending on the input values). @@ -245,36 +323,36 @@ Choosing an evaluation_strategy is straightforward. For reducers: .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xreducer.hpp" + #include + #include xt::xarray a = xt::ones({3, 2, 4, 6, 5}); - auto res = xt::sum(a, {1, 3}, xt::evaluation_strategy::immediate()); + auto res = xt::sum(a, {1, 3}, xt::evaluation_strategy::immediate); // or select the default: - // auto res = xt::sum(a, {1, 3}, xt::evaluation_strategy::lazy()); + // auto res = xt::sum(a, {1, 3}, xt::evaluation_strategy::lazy); -Note: for accumulators, only the ``immediate`` evaluation strategy is currently -implemented. +Note: for accumulators, only the :cpp:enumerator:`~xt::evaluation_strategy::immediate` evaluation +strategy is currently implemented. Universal functions and vectorization ------------------------------------- -`xtensor` provides utilities to **vectorize any scalar function** (taking +*xtensor* provides utilities to **vectorize any scalar function** (taking multiple scalar arguments) into a function that will perform on -``xexpression`` s, applying the lazy broadcasting rules which we described in a -previous section. These functions are called ``xfunction`` s. They are -`xtensor`'s counterpart to numpy's universal functions. +:cpp:type:`xt::xexpression` s, applying the lazy broadcasting rules which we described in a +previous section. These functions are called :cpp:type:`xt::xfunction` s. +They are *xtensor*'s counterpart to numpy's universal functions. Actually, all arithmetic and logical operators, inequality operator and -mathematical functions we described before are ``xfunction`` s. +mathematical functions we described before are :cpp:type:`xt::xfunction` s. The following snippet shows how to vectorize a scalar function taking two arguments: .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xvectorize.hpp" + #include + #include int f(int a, int b) { diff --git a/docs/source/pitfall.rst b/docs/source/pitfall.rst new file mode 100644 index 000000000..b9e40a2a3 --- /dev/null +++ b/docs/source/pitfall.rst @@ -0,0 +1,214 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Common pitfalls +=============== + +xarray initialization +--------------------- + +.. code:: + + xt::xarray a({1, 3, 4, 2}); + +does not initialize a 4D-array, but a 1D-array containing the values ``1``, ``3``, +``4``, and ``2``. +It is strictly equivalent to + +.. code:: + + xt::xarray a = {1, 3, 4, 2}; + +To initialize a 4D-array with the given shape, use the :cpp:func:`xt::xarray::from_shape` static method: + +.. code:: + + auto a = xt::xarray::from_shape({1, 3, 4, 2}); + +The confusion often comes from the way :cpp:type:`xt::xtensor` can be initialized: + +.. code:: + + xt::xtensor a = {1, 3, 4, 2}; + +In this case, a 4D-tensor with shape ``(1, 3, 4, 2)`` is initialized. + +Intermediate result +------------------- + +Consider the following function: + +.. code:: + + template + auto func(const C& c) + { + return (1 - func_tmp(c)) / (1 + func_tmp(c)); + } + +where ``func_tmp`` is another unary function accepting an xtensor expression. You may +be tempted to simplify it a bit: + +.. code:: + + template + auto func(const C& c) + { + auto tmp = func_tmp(c); + return (1 - tmp) / (1 + tmp); + } + +Unfortunately, you introduced a bug; indeed, expressions in *xtensor* are not evaluated +immediately, they capture their arguments by reference or copy depending on their nature, +for future evaluation. Since ``tmp`` is an lvalue, it is captured by reference in the last +statement; when the function returns, ``tmp`` is destroyed, leading to a dangling reference +in the returned expression. + +Replacing ``auto tmp`` with ``xt::xarray tmp`` does not change anything, ``tmp`` +is still an lvalue and thus captured by reference. + +.. warning:: + + This issue is particularly subtle with reducer functions like :cpp:func:`xt::amax`, + :cpp:func:`xt::sum`, etc. Consider the following function: + + .. code:: + + template + xt::xtensor logSoftmax(const xt::xtensor &matrix) + { + xt::xtensor maxVals = xt::amax(matrix, {1}, xt::keep_dims); + auto shifted = matrix - maxVals; + auto expVals = xt::exp(shifted); + auto sumExp = xt::sum(expVals, {1}, xt::keep_dims); + return shifted - xt::log(sumExp); + } + + This function may produce incorrect results or crash, especially in optimized builds. + The issue is that ``shifted``, ``expVals``, and ``sumExp`` are all lazy expressions + that hold references to local variables. When the function returns, these local + variables are destroyed, and the returned expression contains dangling references. + + The fix is to evaluate reducer results and the returned expression explicitly. + Element-wise lazy expressions (like ``shifted`` and ``expVals``) are safe to + leave as ``auto``, but reducer results (like ``sumExp``) must be materialized + before being used in a subsequent element-wise expression: + + .. code:: + + template + xt::xtensor logSoftmax(const xt::xtensor &matrix) + { + xt::xtensor maxVals = xt::amax(matrix, {1}, xt::keep_dims); + auto shifted = matrix - maxVals; + auto expVals = xt::exp(shifted); + xt::xtensor sumExp = xt::sum(expVals, {1}, xt::keep_dims); + return xt::xtensor(shifted - xt::log(sumExp)); + } + +Random numbers not consistent +----------------------------- + +Using a random number function from xtensor actually returns a lazy +generator. That means, accessing the same element of a random number +generator does not give the same random number if called twice. + +.. code:: + + auto gen = xt::random::rand({10, 10}); + auto a0 = gen(0, 0); + auto a1 = gen(0, 0); + + // a0 != a1 !!! + +You need to explicitly assign or eval a random number generator, like so: + +.. code:: + + xt::xarray xr = xt::random::rand({10, 10}); + auto xr2 = xt::eval(xt::random::rand({10, 10})); + + // now xr(0, 0) == xr(0, 0) is true. + +variance arguments +------------------ + +When :cpp:func:`xt::variance` is passed an expression and an integer parameter, this latter +is not the axis along which the variance must be computed, but the degree of freedom: + +.. code:: + + xt::xtensor a = {{1., 2., 3.}, {4., 5., 6.}}; + std::cout << xt::variance(a, 1) << std::endl; + // Outputs 3.5 + +If you want to specify an axis, you need to pass an initializer list: + +.. code:: + + xt::xtensor a = {{1., 2., 3.}, {4., 5., 6.}}; + std::cout << xt::variance(a, {1}) << std::endl; + .. Outputs { 0.666667, 0.666667 } + +fixed_shape on Windows +---------------------- + +Builder functions such as :cpp:func:`xt::empty` or :cpp:func:`xt::ones` accept an initializer list +as argument. If the elements of this list do not have the same type, a +curious compilation error may occur on Windows: + +.. code:: + + size_t N = 10ull; + xt::xarray ages = xt::empty({N, 4ul}); + + // error: cannot convert argument 1 from 'initializer list' + // to 'const xt::fixed_shape<> &' + +To avoid this compiler bug (for which we don't have a workaround), ensure +all the elements in the initializer list have the same type. + +Alignment of fixed-size members +------------------------------- + +.. note:: + + If you are using ``C++ >= 17`` you should not have to worry about this. + +When building with *xsimd* (see :ref:`external-dependencies`), if you define a structure +having members of fixed-size xtensor types, you must ensure that the buffers properly +aligned. For this you can use the macro ``XTENSOR_FIXED_ALIGN`` available in +``xtensor/core/xtensor_config.hpp``. +Consider the following example: + +.. code-block:: cpp + + template + class alignas(XTENSOR_FIXED_ALIGN) Foo + { + public: + + using allocator_type = std::conditional_t, + std::allocator>; + + Foo(T fac) : m_fac(fac) + { + m_bar.fill(fac); + } + + auto get() const + { + return m_bar; + } + + private: + + xt::xtensor_fixed> m_bar; + T m_fac; + }; + +Whereby it is important to store the fixed-sized xtensor type (in this case ``xt::xtensor_fixed>``) as first member. diff --git a/docs/source/quantstack-white.svg b/docs/source/quantstack-white.svg index d527db199..1f03ebb42 100644 --- a/docs/source/quantstack-white.svg +++ b/docs/source/quantstack-white.svg @@ -49,4 +49,4 @@ d="m 85.3,16 c 1.2,0.6 2.4,1.3 3.4,2.2 l 0,22.2 c 0,9.2 -1.8,19.7 -14.2,19.7 l -1.9,0 C 60.1,60.1 58.4,49.6 58.4,40.4 l 0,-22.2 c 1,-0.9 2.2,-1.6 3.4,-2.2 l 0,23.4 c 0,10.4 1.5,17.7 11.4,17.7 l 0.9,0 c 9.8,0 11.4,-7.3 11.4,-17.7 L 85.5,16 Z M 133,38.1 c 0,15 -5.1,22.1 -18.1,22.1 -0.1,0 -0.6,0 -0.7,0 -11,0 -14.2,-5.1 -14.2,-12.4 0,-10.2 9.7,-12.6 29.5,-13.4 -0.6,-9.3 -3.7,-15.2 -14.6,-15.2 -3,0 -5.8,0.5 -8.6,1.8 l -1.5,-2.9 c 3.3,-1.7 6.7,-2.1 10.1,-2.1 13,0 18.1,7 18.1,22.1 z m -3.4,-0.7 c -16.6,0.8 -26.1,2.2 -26.1,10.5 0,2.8 0.5,4.9 1.9,6.4 0.4,0.5 1,0.9 1.7,1.2 2.6,1.1 5.2,1.5 7.9,1.5 12.2,0 14.7,-7.4 14.7,-18.9 -0.1,-0.3 -0.1,-0.5 -0.1,-0.7 z m 201.7,0.7 c 0,15 -5.1,22.1 -18.1,22.1 -0.1,0 -0.6,0 -0.7,0 -11,0 -14.2,-5.1 -14.2,-12.4 0,-10.2 9.7,-12.6 29.5,-13.4 -0.6,-9.3 -3.7,-15.2 -14.6,-15.2 -3,0 -5.8,0.5 -8.6,1.8 l -1.5,-2.9 c 3.3,-1.7 6.7,-2.1 10.1,-2.1 13,0 18.1,7 18.1,22.1 z m -3.4,-0.7 c -16.6,0.8 -26.1,2.2 -26.1,10.5 0,2.8 0.5,4.9 1.9,6.4 0.4,0.5 1,0.9 1.7,1.2 2.6,1.1 5.2,1.5 7.9,1.5 12.2,0 14.7,-7.4 14.7,-18.9 -0.1,-0.3 -0.1,-0.5 -0.1,-0.7 z M 57.2,82.2 c -0.9,0.9 -1.8,1.7 -2.9,2.3 C 45,79.7 38.3,71.4 34.9,60.6 31.7,62.2 27.8,63 23.1,63 6.5,63 0,53.3 0,32.3 0,11.4 6.5,1.6 23.1,1.6 c 16.6,0 23.1,9.7 23.1,30.7 0,13 -2.5,21.6 -8.4,26.4 3.2,10.9 10,19 19.4,23.5 z M 42.7,32.3 C 42.7,15.9 39.4,4.8 23,4.8 6.6,4.8 3.3,15.8 3.3,32.3 c 0,16.4 3.3,27.5 19.7,27.5 16.4,0 19.7,-11 19.7,-27.5 z m 366,-10.4 C 408,21 407.2,20.2 406.3,19.5 l -18.3,18.2 0,-22 -0.4,0 c -1.1,0.2 -2,0.5 -3,0.8 l 0,42.6 c 1.1,0.4 2.2,0.6 3.4,0.9 l 0,-21.3 17.8,17.8 c 0.9,-0.7 1.7,-1.4 2.5,-2.3 l -16,-16 16.4,-16.3 z M 360.6,57 c -12.2,0 -14.7,-7.4 -14.7,-18.9 0,-11.5 2.5,-18.9 14.7,-18.9 3.1,0 6,0.5 8.8,1.9 l 1.5,-2.9 c -3.4,-1.7 -6.9,-2.1 -10.2,-2.1 -13,0 -18.1,7 -18.1,22.1 0,15 5.1,22.1 18.1,22.1 3.4,0 6.9,-0.4 10.3,-2.1 l -1.5,-2.9 c -3,1.2 -5.9,1.7 -8.9,1.7 z m -198,-41.1 -1.9,0 c -12.5,0 -14.2,10.5 -14.2,19.7 l 0,22.2 c 1,0.9 2.2,1.6 3.4,2.2 l 0,-23.3 c 0,-10.4 1.5,-17.7 11.4,-17.7 l 0.9,0 c 9.8,0 11.4,7.3 11.4,17.7 l 0,23.4 c 1.2,-0.6 2.4,-1.3 3.4,-2.2 l 0,-22.2 c -0.2,-9.3 -2,-19.8 -14.4,-19.8 z m 127.7,4.3 -1.6,-3.1 -10.4,0 0,-10.9 -3.3,0 0,10.8 -10.5,0 -1.6,3.1 12.1,0 c 0,0 0,22.4 0,23.7 l 0,0 c -0.1,2.6 0.3,5.1 1.2,7.3 0,0.1 1,2.2 2.6,4.1 0.8,0.9 2.4,2.3 4.6,3.8 l 1.5,-3.1 c -1.7,-1.2 -2.9,-2.2 -3.5,-2.9 -1.3,-1.5 -2,-3.2 -2,-3.2 -0.7,-1.6 -1,-3.3 -1,-5 0,-1.2 0,-24.7 0,-24.7 l 11.9,0 z M 197.8,6 l -3.3,0 0,10.8 -12,0 1.6,3.1 10.4,0 c 0,0 0,12.2 0,13.5 l 0,0 c -0.1,2.6 0.3,5.1 1.2,7.3 0,0.1 1,2.2 2.6,4.1 0.8,0.9 2.3,2.2 4.4,3.7 l 1.6,-3.1 c -1.7,-1.2 -2.9,-2.2 -3.4,-2.9 -1.3,-1.5 -2,-3.2 -2,-3.2 -0.7,-1.6 -1,-3.3 -1,-5 0,-1.2 0,-14.5 0,-14.5 l 10.4,0 1.6,-3.1 -12.1,0 0,-10.7 z m 40.3,22.2 c -1.9,-0.7 -3.6,-1.3 -5.3,-2.1 l 0,0 c -5.1,-2.1 -8.7,-4.8 -8.7,-10.8 0,-9.2 6.4,-12.1 14.5,-12.1 3.8,0 7.5,0.4 11.2,1.7 L 251.3,2 c -4,-1.5 -8.3,-2 -12.8,-2 -9.4,0 -17.7,4.1 -17.7,15.4 0,6.7 3.4,10.4 8.6,12.9 l 0,0 c 0.8,0.3 1.4,0.6 2.1,0.9 0,0 0,0 0,0 l 0,0 c 1.9,0.8 3.3,1.4 5.1,2 8.4,3 12.3,3.5 15.1,6.6 0.2,0.2 4.1,4.8 3.1,10.4 -0.5,2.9 -2.2,5.5 -4.9,7.8 -6.2,5.1 -15.9,4 -25.2,0.9 l -1.6,3.1 c 5.1,1.8 10.4,3 15.4,3 5.1,0 9.7,-1.2 13.5,-4.3 4.2,-3.5 5.7,-7.2 6.1,-9.8 1.3,-7.1 -3.3,-12.6 -3.8,-13.2 -2.7,-2.9 -7.6,-4.4 -16.2,-7.5 z" id="path3" inkscape:connector-curvature="0" - style="fill:#ffffff" /> \ No newline at end of file + style="fill:#ffffff" /> diff --git a/docs/source/quickref/basic.rst b/docs/source/quickref/basic.rst new file mode 100644 index 000000000..2cd4b0d2b --- /dev/null +++ b/docs/source/quickref/basic.rst @@ -0,0 +1,247 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Basics +====== + +Tensor types +------------ + +- ``xarray``: tensor that can be reshaped to any number of dimensions. +- ``xtensor``: tensor with a number of dimensions set to ``N`` at compile time. +- ``xtensor_fixed``: tensor whose shape is fixed at compile time. +- ``xchunked_array``: chunked array using the ``CS`` chunk storage. + +.. note:: + + Except if mentioned otherwise, the methods described below are available for the + three kinds of containers, even if the examples show :cpp:type:`xt::xarray` usage only. + +Initialization +-------------- + +Tensor with dynamic shape: + +.. code:: + + #include + + xt::xarray::shape_type shape = {2, 3}; + xt::xarray a0(shape); + xt::xarray a1(shape, 2.5); + xt::xarray a2 = {{1., 2., 3.}, {4., 5., 6.}}; + auto a3 = xt::xarray::from_shape(shape); + +Tensor with static number of dimensions: + +.. code:: + + #include + + xt::xtensor::shape_type shape = {2, 3}; + xt::xtensor a0(shape); + xt::xtensor a1(shape, 2.5); + xt::xtensor a2 = {{1., 2., 3.}, {4., 5., 6.}}; + auto a3 = xt::xtensor::from_shape(shape); + +Tensor with fixed shape: + +.. code:: + + #include + + xt::xtensor_fixed> = {{1., 2., 3.}, {4., 5., 6.}}; + +In-memory chunked tensor with dynamic shape: + +.. code:: + + #include + + std::vector shape = {10, 10, 10}; + std::vector chunk_shape = {2, 3, 4}; + auto a = xt::chunked_array(shape, chunk_shape); + +Output +------ + +.. code:: + + #include + #include + #include + #include + + xt::xarray a = {{1., 2.}, {3., 4.}}; + std::cout << a << std::endl; + + xt::xtensor b = {{1., 2.}, {3., 4.}}; + std::cout << b << std::endl; + + xt::xtensor_fixed> c = {{1., 2.}, {3., 4.}}; + std::cout << c << std::endl; + +Shape - dimension - size +------------------------ + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + auto size = a.size(); // size = 6 + auto dim = a.dimension(); // dim = 2 + auto shape = a.shape(); // shape = {2, 3} + auto sh1 = a.shape(1); // sh1 = 3 + +Print the shape +--------------- + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + auto shape = a.shape(); + std::cout << xt::adapt(shape) << std::endl; + +Reshape +------- + +The number of elements of an :cpp:type:`xt::xarray` must remain the same: + +.. code:: + + xt::xarray a0 = {1., 2., 3., 4., 5., 6.}; + a0.reshape({2, 3}); + std::cout << a0 << std::endl; + // outputs {{1., 2., 3.}, {4., 5., 6. }} + +For :cpp:type:`xt::xtensor` the number of elements and the number of dimensions +must remain the same: + +.. code:: + + xt::xtensor a1 = {{1., 2.}, {3., 4.}, {5., 6.}}; + a1.reshape({2, 3}); + std::cout << a1 << std::endl; + // outputs {{1., 2., 3.}, {4., 5., 6. }} + +One value in the shape can be -1. In this case, the value is inferred from the +length of the underlying buffer and remaining dimensions: + +.. code:: + + xt::xarray a0 = {1., 2., 3., 4., 5., 6.}; + a0.reshape({2, -1}); + std::cout << a0 << std::endl; + // outputs {{1., 2., 3.}, {4., 5., 6. }} + + xt::xtensor a1 = {{1., 2.}, {3., 4.}, {5., 6.}}; + a1.reshape({-1, 3}); + std::cout << a1 << std::endl; + // outputs {{1., 2., 3.}, {4., 5., 6. }} + +``reshape`` is not defined for ``xtensor_fixed``. + +Resize +------ + +.. code:: + + xt::xarray a0 = {1., 2., 3, 4.}; + a0.resize({2, 3}); + +When resizing an :cpp:type:`xt::xtensor` object, the number of dimensions must remain +the same: + +.. code:: + + xt::xtensor a1 = {{1., 2.}, {3., 4.}}; + a1.resize({2, 3}); + +``resize`` is not defined for ``xtensor_fixed``. + +.. warning:: + + Contrary to STL containers like std::vector, resize do NOT + preserve elements. + +Element access +-------------- + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + double d0 = a(0, 2); // d0 is 3. + double d1 = a(2); // d1 is a(0, 2) + double d2 = a[{0, 2}]; // d2 is a(0, 2) + +The same operators are used for writing values: + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + a(0, 2) = 8.; + a(2) = 8.; + a[{0, 2}] = 8.; + +The ``at`` method is an access operator with bound checking: + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + double d0 = a.at(0, 3); // throws + double d1 = a.at(3); // throws + +The ``periodic`` method is an access operator that applies periodicity +to its arguments: + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + double d0 = a.periodic(2, -1); // d0 is 3 + +Fill +---- + +.. code:: + + auto a = xt::xarray::from_shape({2, 3}); + a.fill(2.); + std::cout << a << std::endl; + // Outputs {{2., 2., 2.}, {2., 2., 2.}} + +Iterators +--------- + +*xtensor* containers provide iterators compatible with algorithms from the STL: + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + xt::xarray b(a.shape()); + std::transform(a.cbegin(), a.cend(), b.begin(), [](auto&& v) { return v + 1; }); + std::cout << b << std::endl; + // Outputs {{2., 3., 4.}, {5., 6., 7.}} + +Reverse iterators are also available: + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + xt::xarray b(a.shape()); + std::copy(a.crbegin(), a.crend(), b.begin()); + std::cout << b << std::endl; + // Outputs {{6., 5., 4.}, {3., 2., 1.}} + +Data buffer +----------- + +The underlying 1D data buffer can be accessed with the ``data`` method: + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + a.data()[4] = 8.; + std::cout << a << std::endl; + // Outputs {{1., 2., 3.}, {8., 5., 6.}} diff --git a/docs/source/quickref/builder.rst b/docs/source/quickref/builder.rst new file mode 100644 index 000000000..573233074 --- /dev/null +++ b/docs/source/quickref/builder.rst @@ -0,0 +1,246 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Builders +======== + +Most of *xtensor* builders return unevaluated expressions (see :ref:`lazy-evaluation` +for more details) that can be assigned to any kind of *xtensor* container. + +Ones +---- + +.. code:: + + // Lazy version + auto e = xt::ones({2, 3}); + std::cout << e < std::endl; + // Outputs {{1., 1., 1.}, {1., 1., 1.}} + + // Evaluated versions + using fixed_tensor = xt::xtensor_fixed>; + xt::xarray a0 = xt::ones({2, 3}); + xt::xtensor a1 = xt::ones({2, 3}); + fixed_tensor a2 = xt::ones({2, 3}); + +Zeros +----- + +.. code:: + + // Lazy version + auto e = xt::zeros({2, 3}); + std::cout << e << std::endl; + // Outputs {{0., 0., 0.}, {0., 0., 0.}} + + // Evaluated versions + using fixed_tensor = xt::xtensor_fixed>; + xt::xarray a0 = xt::zeros({2, 3}); + xt::xtensor a1 = xt::zeros({2, 3}); + fixed_tensor a2 = xt::zeros({2, 3}); + +Empty +----- + +``xt::empty`` creates a container of uninitialized values. It selects the best container +match from the supplied shape: + +.. code:: + + xt::xarray::shape_type sh0 = {2, 3}; + auto a0 = xt::empty(sh0); + // a0 is xt::xarray + + xt::xtensor::shape_type sh1 = {2, 3}; + auto a1 = xt::empty(sh1); + // a1 is xt::xtensor + + xt::xshape<2, 3> sh2; + auto a2 = xt::empty(sh2); + // a2 is xt::xtensor_fixed> + +Full like +--------- + +``xt::full_like`` returns a container with the same shape as the input expression, and +filled with the specified value: + +.. code:: + + xt::xarray a0 = {{1., 2., 3.}, {4., 5., 6.}}; + auto b0 = xt::full_like(a0, 3.); + std::cout << b0 << std::endl; + // Outputs {{3., 3., 3.}, {3., 3., 3.}} + // b0 is an xt::xarray + + xt::xtensor a1 = {{1., 2., 3.}, {4., 5., 6.}}; + auto b1 = xt::full_like(a1, 3.); + std::cout << b1 << std::endl; + // Outputs {{3., 3., 3.}, {3., 3., 3.}} + // b1 is an xt::xtensor + + xt::xtensor_fixed> a2 = {{1., 2., 3.}, {4., 5., 6.}}; + auto b2 = xt::full_like(a2, 3.); + std::cout << b2 << std::endl; + // Outputs {{3., 3., 3.}, {3., 3., 3.}} + // b2 is an xt::xtensor_fixed> + +Ones like +--------- + +``ones_like(e)`` is equivalent to ``full_like(e, 1.)``. + +Zeros like +---------- + +``zeros_like(e)`` is equivalent to ``full_like(e, 0.)``. + +Eye +--- + +Generates an array with ones on the specified diagonal: + +.. code:: + + auto a = xt::eye({2, 3}, 1); + std::cout << a << std::endl; + // Outputs {{O, 1, 0}, {0, 0, 1}} + + auto b = xt::eye({3, 2}, -1); + std::cout << b << std::endl; + // Outputs {{0, 0}, {1, 0}, {0, 1}} + + aut c = xt::eye(3, 1); + std::cout << c << std::endl; + // Outputs {{O, 1, 0}, {0, 0, 1}, {0, 0, 0}} + +Arange +------ + +Generates evenly spaced numbers: + +.. code:: + + auto e = xt::arange(0., 10., 2); + std::cout << e << std::endl; + // Outputs {0., 2., 4., 6., 8.} + +A common pattern is to use ``arange`` followed by reshape to initialize +a tensor with an arbitrary number of dimensions: + +.. code:: + + xt::xarray a = xt::arange(0., 6.).reshape({2, 3}); + std::cout << a << std::endl; + // Outputs {{0., 1., 2.}, {3., 4., 5.}} + +Linspace +-------- + +.. code:: + + auto a = xt::linspace(0., 10., 5); + std::cout << a << std::endl; + // Outputs {0., 2.5, 5., 7.5, 10.} + +Logspace +-------- + +Similar to ``linspace`` but numbers are evenly space on a log scale. + +Concatenate +----------- + +.. code:: + + xt::xarray a = {{1, 2, 3}}; + xt::xarray b = {{2, 3, 4}}; + + auto c0 = xt::concatenate(xt::xtuple(a, b)); + std::cout << c0 << std::endl; + // Outputs {{1, 2, 3}, {2, 3, 4}} + + auto c1 = xt::concatenate(xt::xtuple(a, b), 1); + std::cout << c1 << std::endl; + // Outputs {1, 2, 3, 2, 3, 4} + +Stack +----- + +``stack`` always creates a new dimension along which elements are stacked: + +.. code:: + + xt::xarray a = {1, 2, 3}; + xt::xarray b = {5, 6, 7}; + + auto s0 = xt::stack(xt::xtuple(a, b)); + std::cout << s0 << std::endl; + // Outputs {{1, 2, 3}, {5, 6, 7}} + + auto s1 = xt::stack(xt::xtuple(a, b), 1); + std::cout << s1 << std::endl; + // Outputs {{1, 5}, {2, 6}, {3, 7}} + +HStack +------ + +.. code:: + + xt::xarray a0 = {{1, 2, 3}, {4, 5, 6}}; + xt::xarray b0 = {{7, 8}, {9, 10}}; + auto c0 = xt::hstack(xt::xtuple(a0, b0)); + std::cout << c0 << std:endl; + // Outputs {{1, 2, 3, 7, 8}, {4, 5, 6, 0, 10}} + + xt::xarray a1 = {1, 2, 3}; + xt::xarray b1 = {2, 3 ,4}; + auto c1 = xt::hstack(xt::xtuple(a1, b1)); + std::cout << c1 << std::endl; + // Outputs {1, 2, 3, 2, 3, 4} + +VStack +------ + +.. code:: + + xt::xarray a0 = {1, 2, 3}; + xt::xarray b0 = {2, 3, 4}; + auto c0 = xt::vstack(xt::xtuple(a0, b0)); + std::cout << c0 << std::endl; + // Outputs {{1, 2, 3}, {2, 3 ,4}} + + xt::xarray a1 = {{1, 2, 3}, {4, 5 ,6}, {7, 8, 9}}; + xt::xarray b1 = {{10, 11, 12}}; + auto c1 = xt::vstack(xt::xtuple(a1, b1)); + std::cout << c1 << std::endl; + // Outputs {{1, 2, 3}, {4, 5 ,6}, {7, 8, 9}, {10, 11, 12}} + +Diag +---- + +Returns a 2D-expression using the input value as its diagonal: + +.. code:: + + xt::xarray a = {1, 5, 7}; + auto b = xt::diag(a); + std::cout << b << std::endl; + // Outputs {{1, 0, 0} {0, 5, 0}, {0, 0, 7}} + +Diagonal +-------- + +Returns the elements on the diagonal of the expression + +.. code:: + + xt::xarray a = {{1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}}; + auto d = xt::diagonal(a); + std::cout << d << std::endl; + // Outputs {1, 5, 9} diff --git a/docs/source/quickref/chunked_arrays.rst b/docs/source/quickref/chunked_arrays.rst new file mode 100644 index 000000000..e645cea73 --- /dev/null +++ b/docs/source/quickref/chunked_arrays.rst @@ -0,0 +1,69 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Chunked arrays +============== + +Motivation +---------- + +Arrays can be very large and may not fit in memory. In this case, you may not be +able to use an in-memory array such as an :cpp:type:`xt::xarray`. A solution to this problem +is to cut up the large array into many small arrays, called chunks. Not only do +the chunks fit comfortably in memory, but this also allows to process them in +parallel, including in a distributed environment (although this is not supported +yet). + +Formats for the storage of arrays such as `Zarr `_ +specifically target chunked arrays. Such formats are becoming increasingly +popular in the field of big data, since the chunks can be stored in the cloud. + +In-memory chunked arrays +------------------------ + +This may not look very useful at first sight, since each chunk (and thus the +whole array) is held in memory. It means that it cannot work with very large +arrays, but it may be used to parallelize an algorithm, by processing several +chunks at the same time. + +An in-memory chunked array has the following type: + +.. code:: + + #include + + using data_type = double; + // don't use this code: + using inmemory_chunked_array = xt::xchunked_array>>; + +But you should not directly use this type to create a chunked array. Instead, +use the ``chunked_array`` factory function: + +.. code:: + + #include + + std::vector shape = {10, 10, 10}; + std::vector chunk_shape = {2, 3, 4}; + auto a = xt::chunked_array(shape, chunk_shape); + // a is an in-memory chunked array + // each chunk is an xarray, and chunks are hold in an xarray + // thus a is an xarray of xarray elements + a(3, 9, 2) = 1.; // this will address the chunk of index (1, 3, 0) + // and in this chunk, the element of index (1, 0, 2) + +Chunked arrays implement the full semantic of :cpp:type:`xt::xarray`, including lazy +evaluation. + +Stored chunked arrays +--------------------- + +These are arrays whose chunks are stored on a file system, allowing for +persistence of data. In particular, they are used as a building block for the +`xtensor-zarr `_ library. + +For further details, please refer to the documentation +of `xtensor-io `_. diff --git a/docs/source/quickref/iterator.rst b/docs/source/quickref/iterator.rst new file mode 100644 index 000000000..6937aa371 --- /dev/null +++ b/docs/source/quickref/iterator.rst @@ -0,0 +1,257 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Iterators +========= + +Default iteration +----------------- + +.. code:: + + #include + #include + #include + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}}; + std::copy(a.begin(), a.end(), std::ostream_iterator(std::cout, ", ")); + // Prints 1, 2, 3, 4, 5, 6, + +Specified traversal order +------------------------- + +.. code:: + + #include + #include + #include + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}}; + std::copy(a.begin(), + a.end(), + std::ostream_iterator(std::cout, ", ")); + // Prints 1, 2, 3, 4, 5, 6, + + std::copy(a.begin(), + a.end::column_major>(), + std::ostream_iterator(std::cout, ", ")); + // Prints 1, 4, 2, 5, 3, 6, + +Broacasting iteration +--------------------- + +.. code:: + + #include + #include + #include + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}}; + using shape_type = xt::dynamic_shape; + shape_type s = {2, 2, 3}; + + std::copy(a.begin(s), a.end(s), std::ostream_iterator(std::cout, ", ")); + // Prints 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, + + std::copy(a.begin(s), + a.end(s), + std::ostream_iterator(std::cout, ", ")); + // Prints 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, + + std::copy(a.begin(s), + a.end::column_major>(s), + std::ostream_iterator(std::cout, ", ")); + // Prints 1, 4, 2, 5, 3, 6, 1, 4, 2, 5, 3, 6, + +1-D slice iteration +------------------- + +Iterating over axis 0: + +.. code:: + + #include + #include + #include + + xarray a = {{{1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}}, + {{13, 14, 15, 16}, + {17, 18, 19, 20}, + {21, 22, 23, 24}}}; + + auto iter = axis_slice_begin(a, 0); + auto end = axis_slice_end(a, 0); + while(iter != end) + { + std::cout << *iter++ << std::endl; + } + // Prints: + // { 1, 13 } + // { 2, 14 } + // { 3, 15 } + // { 4, 16 } + // { 5, 17 } + // { 6, 18 } + // { 7, 19 } + // { 8, 20 } + // { 9, 21 } + // { 10, 22 } + // { 11, 23 } + // { 12, 24 } + +Iterating over axis 1: + +.. code:: + + #include + #include + #include + + xarray a = {{{1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}}, + {{13, 14, 15, 16}, + {17, 18, 19, 20}, + {21, 22, 23, 24}}}; + + auto iter = axis_slice_begin(a, 1u); + auto end = axis_slice_end(a, 1u); + while(iter != end) + { + std::cout << *iter++ << std::endl; + } + // Prints: + // { 1, 5, 9 } + // { 2, 6, 10 } + // { 3, 7, 11 } + // { 4, 8, 12 } + // { 13, 17, 21 } + // { 14, 18, 22 } + // { 15, 19, 23 } + // { 16, 20, 24 } + +Iterating over axis 2: + +.. code:: + + #include + #include + #include + + xarray a = {{{1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}}, + {{13, 14, 15, 16}, + {17, 18, 19, 20}, + {21, 22, 23, 24}}}; + + auto iter = axis_slice_begin(a, 2u); + auto end = axis_slice_end(a, 2u); + while(iter != end) + { + std::cout << *iter++ << std::endl; + } + // Prints: + // { 1, 2, 3, 4 } + // { 5, 6, 7, 8 } + // { 9, 10, 11, 12 } + // { 13, 14, 15, 16 } + // { 17, 18, 19, 20 } + // { 21, 22, 23, 24 } + +(N-1)-dimensional iteration +--------------------------- + +Iterating over axis 0: + +.. code:: + + #include + #include + #include + + xarray a = {{{1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}}, + {{13, 14, 15, 16}, + {17, 18, 19, 20}, + {21, 22, 23, 24}}}; + + auto iter = axis_begin(a, 0); + auto end = axis_end(a, 0); + while(iter != end) + { + std::cout << *iter++ << std::endl; + } + // Prints: + // {{ 1, 2, 3, 4 }, + // { 5, 6, 7, 9 }, + // { 9, 10, 11, 12 }} + // {{ 13, 14, 15, 16 }, + // { 17, 18, 19, 20 }, + // { 21, 22, 23, 24 }} + +Iterating over axis 1: + +.. code:: + + #include + #include + #include + + xarray a = {{{1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}}, + {{13, 14, 15, 16}, + {17, 18, 19, 20}, + {21, 22, 23, 24}}}; + + auto iter = axis_begin(a, 1u); + auto end = axis_end(a, 1u); + while(iter != end) + { + std::cout << *iter++ << std::endl; + } + // Prints: + // {{ 1, 2, 3, 4 }, + // { 13, 14, 15, 16 }} + // {{ 5, 6, 7, 8 }, + // { 17, 18, 19, 20 }} + // {{ 9, 10, 11, 12 }, + // { 21, 22, 23, 24 }} + +Iterating over axis 2: + +.. code:: + + #include + #include + #include + + xarray a = {{{1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}}, + {{13, 14, 15, 16}, + {17, 18, 19, 20}, + {21, 22, 23, 24}}}; + + auto iter = axis_begin(a, 2u); + auto end = axis_end(a, 2u); + while(iter != end) + { + std::cout << *iter++ << std::endl; + } + // Prints: + // {{ 1, 5, 9 } + // { 13, 17, 21 }} + // {{ 2, 6, 10 }, + // { 14, 18, 22 }} + // {{ 3, 7, 11 }, + // { 15, 19, 23 }} + // {{ 4, 8, 12 }, + // { 16, 20, 24 }} diff --git a/docs/source/quickref/manipulation.rst b/docs/source/quickref/manipulation.rst new file mode 100644 index 000000000..d020d1fac --- /dev/null +++ b/docs/source/quickref/manipulation.rst @@ -0,0 +1,136 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Manipulation +============ + +atleast_Nd +---------- + +.. code:: + + #include + + xt::xarray a0 = 123; + auto r1 = xt::atleast_1d(a0); + + xt::xarray a1 = { 1, 2, 3 }; + auto r2 = xt::atleast_2d(a1); + auto r3 = xt::atleast_3d(a1); + auto r4 = xt::atleast_Nd<4>(a1); + +expand_dims +----------- + +.. code:: + + #include + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + auto r0 = xt::expand_dims(a, 0); + auto r1 = xt::expand_dims(a, 1); + auto r2 = xt::expand_dims(a, 2); + +flip +---- + +.. code:: + + #include + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + auto f0 = xt::flip(a, 0); + auto f1 = xt::flip(a, 1); + +repeat +------ + +.. code:: + + #include + + xt::xarray a = {{1, 2}, {3, 4}}; + auto r0 = xt::repeat(a, 3, 1); + auto r1 = xt::repeat(a, {1, 2}, 0); + +roll +---- + +.. code:: + + #include + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + auto t0 = xt::roll(a, 2); + auto t1 = xt::roll(a, 2, 1); + +rot90 +----- + +.. code:: + + #include + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + auto r0 = xt::rot90<1>(a); + auto r1 = xt::rot90<-2>(a); + auto r2 = xt::rot90(a); + auto r4 = xt::rot90(a, {-2, -1}); + +split +----- + +.. code:: + + #include + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + auto s0 = xt::split(a, 3); + auto s1 = xt::split(a, 3, 1); + +hsplit +------ + +.. code:: + + #include + + xt::xarray a = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}; + auto res = xt::hsplit(a, 2); + +vsplit +------ + +.. code:: + + #include + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; + auto res = xt::vsplit(a, 2); + +squeeze +------- + +.. code:: + + #include + + auto b = xt::xarray::from_shape({3, 3, 1, 1, 2, 1, 3}); + auto sq0 = xt::xqueeze(b); + auto sq1 = squeeze(b, {2, 3}, check_policy::full()); + auto sq2 = squeeze(b, 2); + +trim_zeros +---------- + +.. code:: + + #include + + xt::xarray a = {0, 0, 0, 1, 3, 0}; + auto t0 = xt::trim_zeros(a); + auto t1 = xt::trim_zeros(a, "b"); + auto t2 = xt::trim_zeros(a, "f"); diff --git a/docs/source/quickref/math.rst b/docs/source/quickref/math.rst new file mode 100644 index 000000000..0b5d5f61a --- /dev/null +++ b/docs/source/quickref/math.rst @@ -0,0 +1,119 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Mathematical functions +====================== + +Operations and functions of *xtensor* are not evaluated until they are assigned. +In the following, ``e1``, ``e2`` and ``e3`` can be arbitrary tensor expressions. +The results of operations and functions are assigned to :cpp:type:`xt::xarray` in the examples, +but that could be any other container (or even views). To keep an unevaluated +operator / function, assign to an ``auto`` variable: + +.. code:: + + auto res = e1 + e2; + +See :ref:`lazy-evaluation` for more details on unevaluated expressions. + +Basic functions +--------------- + +.. code:: + + xt::xarray res0 = xt::abs(e1); + xt::xarray res1 = xt::fabs(e1); + xt::xarray res2 = xt::fmod(e1, e2); + xt::xarray res3 = xt::remainder(e1, e2); + xt::xarray res4 = xt::fma(e1, e2, e3); + xt::xarray res5 = xt::maximum(e1, e2); + xt::xarray res6 = xt::minimum(e2, e2); + xt::xarray res7 = xt::fmax(e1, e2); + xt::xarray res8 = xt::fmin(e1, e2); + xt::xarray res9 = xt::fdim(e1, e2); + xt::xarray res10 = xt::clip(e1, e2, e3); + xt::xarray res11 = xt::sign(e1); + +Exponential functions +--------------------- + +.. code:: + + xt::xarray res0 = xt::exp(e1); + xt::xarray res2 = xt::exp2(e1); + xt::xarray res3 = xt::expm1(e1); + xt::xarray res4 = xt::log(e1); + xt::xarray res5 = xt::log2(e1); + xt::xarray res6 = xt::log10(e1); + xt::xarray res7 = xt::log1p(e1); + +Power functions +--------------- + +.. code:: + + xt::xarray res0 = xt::pow(e1, e2); + xt::xarray res1 = xt::sqrt(e1); + xt::xarray res2 = xt::cbrt(e1); + xt::xarray res3 = xt::hypot(e1, e2); + +Trigonometric functions +----------------------- + +.. code:: + + xt::xarray res0 = xt::cos(e1); + xt::xarray res1 = xt::sin(e1); + xt::xarray res2 = xt::tan(e1); + xt::xarray res3 = xt::acos(e2); + xt::xarray res4 = xt::asin(e2); + xt::xarray res5 = xt::atan(e2); + xt::xarray res6 = xt::atan2(e2, e3); + +Hyperbolic functions +-------------------- + +.. code:: + + xt::xarray res0 = xt::cosh(e1); + xt::xarray res1 = xt::sinh(e1); + xt::xarray res2 = xt::tanh(e1); + xt::xarray res3 = xt::acosh(e2); + xt::xarray res4 = xt::asinh(e2); + xt::xarray res5 = xt::atanh(e2); + +Error and gamma functions +------------------------- + +.. code:: + + xt::xarray res0 = xt::erf(e1); + xt::xarray res1 = xt::erfc(e1); + xt::xarray res2 = xt::tgamma(e1); + xt::xarray res3 = xt::lgamma(e1); + +Nearest integer operations +-------------------------- + +.. code:: + + xt::xarray res0 = xt::ceil(e1); + xt::xarray res1 = xt::floor(e1); + xt::xarray res2 = xt::trunc(e1); + xt::xarray res3 = xt::round(e1); + xt::xarray res4 = xt::nearbyint(e1); + xt::xarray res5 = xt::rint(e1); + +Classification functions +------------------------ + +.. code:: + + xt::xarray res0 = xt::isfinite(e1); + xt::xarray res1 = xt::isinf(e1); + xt::xarray res2 = xt::isnan(e1); + xt::xarray res3 = xt::isclose(e1, e2); + bool res4 = xt::allclose(e1, e2); diff --git a/docs/source/quickref/operator.rst b/docs/source/quickref/operator.rst new file mode 100644 index 000000000..3690ce088 --- /dev/null +++ b/docs/source/quickref/operator.rst @@ -0,0 +1,86 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Operators +========= + +Operations and functions of *xtensor* are not evaluated until they are assigned. +In the following, ``e1``, ``e2`` and ``e3`` can be arbitrary tensor expressions. +The results of operations and functions are assigned to :cpp:type:`xt::xarray` in the examples, +but that could be any other container (or even views). To keep an unevaluated +operator / function, assign to an ``auto`` variable: + +.. code:: + + auto res = e1 + e2; + +See :ref:`lazy-evaluation` for more details on unevaluated expressions. + +Arithmetic operators +-------------------- + +.. code:: + + xt::xarray res0 = -e1; + xt::xarray res1 = e1 + e2; + xt::xarray res2 = e1 - e2; + xt::xarray res3 = e1 * e2; + xt::xarray res4 = e1 / e2; + xt::xarray res5 = e1 % e2; + + res1 += e2; + res2 -= e2; + res3 *= e2; + res4 /= e2; + res5 %= e2; + +Bitwise operators +----------------- + +.. code:: + + xt::xarray res0 = e1 & e2; + xt::xarray res1 = e1 | e2; + xt::xarray res2 = e1 ^ e2; + xt::xarray res3 = ~e1; + + res0 &= e2; + res1 |= e2; + +Logical operators +----------------- + +.. code:: + + xt::xarray res0 = e1 && e2; + xt::xarray res1 = e1 || e2; + xt::xarray res2 = !e1; + bool res3 = any(e1); + bool res4 = all(e1); + xt::xarray res5 = where(e1, e2, e3); + +Comparison operators +-------------------- + +Comparison operators return expressions performing element-wise +comparison: + +.. code:: + + xt::xarray res0 = e1 < e2; + xt::xarray res1 = e1 > e2; + xt::xarray res2 = e1 <= e2; + xt::xarray res3 = e1 >= e2; + xt::xarray res4 = xt::equal(e1, e2); + xt::xarray res5 = xt::not_equal(e1, e2); + +Except for equality and inequality operators which performs traditional +comparison and return a boolean: + +.. code:: + + bool res0 = e1 == e2; // true if all elements in e1 equal those in e2 + bool res1 = e1 != e2; diff --git a/docs/source/quickref/reducer.rst b/docs/source/quickref/reducer.rst new file mode 100644 index 000000000..064bb0261 --- /dev/null +++ b/docs/source/quickref/reducer.rst @@ -0,0 +1,146 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +Reductions +========== + +Sum +--- + +.. code:: + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}}; + xt::xarray r0 = xt::sum(a, {1}); + std::cout << r0 << std::endl; + // Outputs {6, 15} + + xt::xarray r1 = xt::sum(a); + std::cout << r1 << std::endl; + // Outputs {21}, i.e. r1 is a 0D-tensor + + int r2 = xt::sum(a)(); + std::cout << r2 << std::endl; + // Outputs 21 + + auto r3 = xt::sum(a, {1}); + std::cout << r3 << std::endl; + // Outputs {6, 15}, but r3 is an unevaluated expression + // the values are computed upon each access + + auto r4 = xt::sum(a, {1}); + // r4 holds long int values + + auto r5 = xt::sum(a, {1}); + // r5 holds int values + + auto r6 = xt::sum>(a, {1}); + // r6 holds long long int values + +Prod +---- + +.. code:: + + xt::xarray a = {{1, 2}, {3, 4}}; + xt::xarray r0 = xt::prod(a, {1}); + xt::xarray r1 = xt::prod(a); + int r2 = xt::prod(a)(); + auto r3 = xt::prod(a, {0}); + auro r4 = xt::prod(a, {0}); + auto r5 = xt::prod>(a, {1}); + +Mean +---- + +.. code:: + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}}; + xt::xarray r0 = xt::mean(a, {1}); + xt::xarray r1 = xt::mean(a); + int r2 = xt::mean(a)(); + auto r3 = xt::mean(a, {0}); + +Variance +-------- + +.. code:: + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}}; + xt::xarray r0 = xt::variance(a, {1}); + xt::xarray r1 = xt::variance(a); + int r2 = xt::variance(a)(); + auto r3 = xt::variance(a, {0}); + +Standard deviation +------------------ + +.. code:: + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}}; + xt::xarray r0 = xt::stddev(a, {1}); + xt::xarray r1 = xt::stddev(a); + int r2 = xt::stddev(a)(); + auto r3 = xt::stddev(a, {0}); + +Diff +---- + +.. code:: + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}}; + xt::xarray r0 = xt::diff(a, 1, {0}); + std::cout << r0 << std::endl; + // Outputs {{1, 1}, {1, 1}} + +Amax +---- + +.. code:: + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}}; + xt::xarray r0 = xt::amax(a, {1}); + std::cout << r0 << std::endl; + // Outputs {3, 6} + +Amin +---- + +.. code:: + + xt::xarray a = {{1, 2, 3}, {4, 5, 6}}; + xt::xarray r0 = xt::amin(a, {0}); + std::cout << r0 << std::endl; + // Outputs {1, 2, 3} + +Norms +----- + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + xt::xarray b0 = xt::norm_l0(a, {1}); + xt::xarray b1 = xt::norm_l1(a, {1}); + xt::xarray b2 = xt::norm_sq(a, {1}); + xt::xarray b3 = xt::norm_l2(a, {1}); + xt::xarray b4 = xt::norm_linf(a, {1}); + xt::xarray b5 = xt::norm_lp_to_p(a, {1}); + xt::xarray b6 = xt::norm_lp(a, {1}); + xt::xarray b7 = xt::norm_induced_l1(a, {1}); + xt::xarray b8 = xt::norm_induced_linf(a, {1}); + +Accumulating functions +---------------------- + +.. code:: + + xt::xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + xt::xarray b0 = xt::cumsum(a, {1}); + std::cout << b0 << std::endl; + // Outputs {{1., 3., 6.}, {4., 9., 15.}} + + xt::xarray b1 = xt::cumprod(a, {1}); + std::cout << b1 << std::endl; + // Outputs {{1., 2., 6.}, {4., 20., 120.}} diff --git a/docs/source/random.rst b/docs/source/random.rst new file mode 100644 index 000000000..c0f555664 --- /dev/null +++ b/docs/source/random.rst @@ -0,0 +1,128 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +.. _random: + +****** +Random +****** + +:cpp:func:`xt::random::seed` +============================ + +Set seed for random number generator. A common practice to get a 'real' random number is to use: + +.. code-block:: cpp + + #include + + ... + + xt::random::seed(time(NULL)); + +:cpp:func:`xt::random::rand` +============================ + +:cpp:func:`xt::random::randint` +=============================== + +:cpp:func:`xt::random::randn` +============================= + +:cpp:func:`xt::random::binomial` +================================ + +:cpp:func:`xt::random::geometric` +================================= + +:cpp:func:`xt::random::negative_binomial` +========================================= + +:cpp:func:`xt::random::poisson` +=============================== + +:cpp:func:`xt::random::exponential` +=================================== + +:cpp:func:`xt::random::gamma` +============================= + +Produces (an array of) random positive floating-point values, +distributed according to the probability density: + +.. math:: + + P(x) = x^{\alpha-1} \frac{e^{-x / \beta}}{\beta^\alpha \; \Gamma(\alpha)} + +where :math:`\alpha` is the shape (also known as :math:`k`) and :math:`\beta` the scale +(also known as :math:`\theta`), and :math:`\Gamma` is the Gamma function. + +.. note:: + + Different from NumPy, the first argument is the shape of the output array. + +.. seealso:: + + * :any:`numpy.random.gamma` + * `std::gamma_distribution `_ + * `Weisstein, Eric W. "Gamma Distribution." From MathWorld – A Wolfram Web Resource. `_ + * `Wikipedia, "Gamma distribution". `_ + +:cpp:func:`xt::random::weibull` +=============================== + +Produces (an array of) random positive floating-point values, +distributed according to the probability density: + +.. math:: + + P(x) = \frac{a}{b} \left( \frac{x}{b} \right)^{a - 1} e^{-(x / b)^a} + +where :math:`a > 0` is the shape parameter and :math:`b > 0` the scale parameter. +In particular, a random variable is produced as + +.. math:: + + X = b (- \ln (U))^{1/a} + +where :math:`U` is drawn from the uniform distribution (0, 1]. + +By default both the shape :math:`a = 1` and the scale :math:`b = 1`. +Note that you can specify only :math:`a` while choosing the default for :math:`b`. + +.. note:: + + Different from NumPy, the first argument is the shape of the output array. + +.. seealso:: + + * :any:`numpy.random.weibull` + * `std::weibull_distribution `_ + * `Wikipedia, "Weibull distribution". `_ + +:cpp:func:`xt::random::extreme_value` +===================================== + +:cpp:func:`xt::random::lognormal` +================================= + +:cpp:func:`xt::random::cauchy` +============================== + +:cpp:func:`xt::random::fisher_f` +================================ + +:cpp:func:`xt::random::student_t` +================================= + +:cpp:func:`xt::random::choice` +============================== + +:cpp:func:`xt::random::shuffle` +=============================== + +:cpp:func:`xt::random::permutation` +=================================== diff --git a/docs/source/rank.rst b/docs/source/rank.rst new file mode 100644 index 000000000..8456dc1e4 --- /dev/null +++ b/docs/source/rank.rst @@ -0,0 +1,116 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + + Distributed under the terms of the BSD 3-Clause License. + + The full license is in the file LICENSE, distributed with this software. + +.. _rank: + +Tensor Rank +=========== + +Rank overload +------------- + +All *xtensor*'s classes have a member ``rank`` that can be used +to overload based on rank using *SFINAE*. +Consider the following example: + +.. code-block:: cpp + + template ::value, int> = 0> + inline E foo(E&& a) + { + ... // act on object of flexible rank, or fixed rank != 2 + } + + template ::value, int> = 0> + inline E foo(E&& a) + { + ... // act on object of fixed rank == 2 + } + + int main() + { + xt::xarray a = {{9, 9}, {9, 9}}; + xt::xtensor b = {9, 9}; + xt::xtensor c = {{9, 9}, {9, 9}}; + + foo(a); // flexible rank -> first overload + foo(b); // fixed rank == 2 -> first overload + foo(c); // fixed rank == 2 -> second overload + + return 0; + } + +.. note:: + + If one wants to test for more than a single value for ``rank``, + one can use the default value ``SIZE_MAX`` used for flexible rank objects. + For example, one could have the following overloads: + + .. code-block:: cpp + + // flexible rank + template ::value, int> = 0> + inline E foo(E&& a); + + // fixed rank == 1 + template ::value, int> = 0> + inline E foo(E&& a); + + // fixed rank == 2 + template ::value, int> = 0> + inline E foo(E&& a); + + Note that fixed ranks other than 1 and 2 will raise a compiler error. + + Of course, if one wants a more limited scope, one could also do the following: + + .. code-block:: cpp + + // flexible rank + inline void foo(xt::xarray& a); + + // fixed rank == 1 + inline void foo(xt::xtensor& a); + + // fixed rank == 2 + inline void foo(xt::xtensor& a); + +Rank as member +-------------- + +If you want to use the rank as a member of your own class you can use +:cpp:type:`xt::get_rank\ `. +Consider the following example: + +.. code-block:: cpp + + template + struct Foo + { + static const size_t rank = xt::get_rank::value; + + static size_t value() + { + return rank; + } + }; + + int main() + { + xt::xtensor A = xt::zeros({2}); + xt::xtensor B = xt::zeros({2, 2}); + xt::xarray C = xt::zeros({2, 2}); + + assert(Foo::value() == 1); + assert(Foo::value() == 2); + assert(Foo::value() == SIZE_MAX); + + return 0; + } + +``xt::get_rank`` 'returns' the rank of the *xtensor* object if its rank is fixed. +In all other cases it 'returns' ``SIZE_MAX``. +Indeed ``xt::get_rank>::value`` is equal to ``SIZE_MAX``, but equally so is ``xt::get_rank::value``. diff --git a/docs/source/related.rst b/docs/source/related.rst index ad2cbb8c5..60c640272 100644 --- a/docs/source/related.rst +++ b/docs/source/related.rst @@ -12,6 +12,8 @@ } +.. _related-projects: + Related projects ================ @@ -22,11 +24,11 @@ xtensor-python :alt: xtensor-python The xtensor-python_ project provides the implementation of container types -compatible with ``xtensor``'s expression system, ``pyarray`` and ``pytensor`` -which effectively wrap numpy arrays, allowing operating on numpy arrays +compatible with *xtensor*'s expression system, ``pyarray`` and ``pytensor`` +which effectively wrap NumPy arrays, allowing operating on NumPy arrays in-place. -Example 1: Use an algorithm of the C++ library on a numpy array in-place +Example 1: Use an algorithm of the C++ library on a NumPy array in-place ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **C++ code** @@ -34,10 +36,10 @@ Example 1: Use an algorithm of the C++ library on a numpy array in-place .. code:: #include // Standard library import for std::accumulate - #include "pybind11/pybind11.h" // Pybind11 import to define Python bindings - #include "xtensor/xmath.hpp" // xtensor import for the C++ universal functions - #define FORCE_IMPORT_ARRAY // numpy C api loading - #include "xtensor-python/pyarray.hpp" // Numpy bindings + #include // Pybind11 import to define Python bindings + #include // xtensor import for the C++ universal functions + #define FORCE_IMPORT_ARRAY // NumPy C api loading + #include // NumPy bindings double sum_of_sines(xt::pyarray &m) { @@ -61,8 +63,6 @@ Example 1: Use an algorithm of the C++ library on a numpy array in-place .. code:: - Python Code - import numpy as np import xtensor_python_test as xt @@ -84,9 +84,9 @@ Example 2: Create a universal function from a C++ scalar function .. code:: - #include "pybind11/pybind11.h" + #include #define FORCE_IMPORT_ARRAY - #include "xtensor-python/pyvectorize.hpp" + #include #include #include @@ -135,7 +135,7 @@ xtensor-python-cookiecutter :width: 50% The xtensor-python-cookiecutter_ project helps extension authors create Python -extension modules making use of `xtensor`. +extension modules making use of *xtensor*. It takes care of the initial work of generating a project skeleton with @@ -144,7 +144,7 @@ It takes care of the initial work of generating a project skeleton with A few examples included in the resulting project including - A universal function defined from C++ -- A function making use of an algorithm from the STL on a numpy array +- A function making use of an algorithm from the STL on a NumPy array - Unit tests - The generation of the HTML documentation with sphinx @@ -155,7 +155,7 @@ xtensor-julia :alt: xtensor-julia The xtensor-julia_ project provides the implementation of container types -compatible with ``xtensor``'s expression system, ``jlarray`` and ``jltensor`` +compatible with *xtensor*'s expression system, ``jlarray`` and ``jltensor`` which effectively wrap Julia arrays, allowing operating on Julia arrays in-place. @@ -168,8 +168,8 @@ Example 1: Use an algorithm of the C++ library with a Julia array #include // Standard library import for std::accumulate #include // CxxWrap import to define Julia bindings - #include "xtensor-julia/jltensor.hpp" // Import the jltensor container definition - #include "xtensor/xmath.hpp" // xtensor import for the C++ universal functions + #include // Import the jltensor container definition + #include // xtensor import for the C++ universal functions double sum_of_sines(xt::jltensor m) { @@ -200,7 +200,7 @@ Example 1: Use an algorithm of the C++ library with a Julia array 1.2853996391883833 -Example 2: Create a numpy-style universal function from a C++ scalar function +Example 2: Create a NumPy-style universal function from a C++ scalar function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **C++ code** @@ -208,7 +208,7 @@ Example 2: Create a numpy-style universal function from a C++ scalar function .. code:: #include - #include "xtensor-julia/jlvectorize.hpp" + #include double scalar_func(double i, double j) { @@ -249,7 +249,7 @@ xtensor-julia-cookiecutter :width: 50% The xtensor-julia-cookiecutter_ project helps extension authors create Julia -extension modules making use of `xtensor`. +extension modules making use of *xtensor*. It takes care of the initial work of generating a project skeleton with @@ -257,8 +257,8 @@ It takes care of the initial work of generating a project skeleton with A few examples included in the resulting project including -- A numpy-style universal function defined from C++ -- A function making use of an algorithm from the STL on a numpy array +- A NumPy-style universal function defined from C++ +- A function making use of an algorithm from the STL on a NumPy array - Unit tests - The generation of the HTML documentation with sphinx @@ -269,7 +269,7 @@ xtensor-r :alt: xtensor-r The xtensor-r_ project provides the implementation of container types -compatible with ``xtensor``'s expression system, ``rarray`` and ``rtensor`` +compatible with *xtensor*'s expression system, ``rarray`` and ``rtensor`` which effectively wrap R arrays, allowing operating on R arrays in-place. Example 1: Use an algorithm of the C++ library on a R array in-place @@ -280,8 +280,8 @@ Example 1: Use an algorithm of the C++ library on a R array in-place .. code:: #include // Standard library import for std::accumulate - #include "xtensor/xmath.hpp" // xtensor import for the C++ universal functions - #include "xtensor-r/rarray.hpp" // R bindings + #include // xtensor import for the C++ universal functions + #include // R bindings #include using namespace Rcpp; @@ -318,7 +318,7 @@ xtensor-blas The xtensor-blas_ project is an extension to the xtensor library, offering bindings to BLAS and LAPACK libraries through cxxblas and cxxlapack from the FLENS project. ``xtensor-blas`` powers the ``xt::linalg`` functionalities, -which are the counterpart to numpy's ``linalg`` module. +which are the counterpart to NumPy's ``linalg`` module. xtensor-fftw ------------ @@ -328,7 +328,7 @@ xtensor-fftw The xtensor-fftw_ project is an extension to the xtensor library, offering bindings to the fftw library. ``xtensor-fftw`` powers the ``xt::fftw`` -functionalities, which are the counterpart to numpy's ``fft`` module. +functionalities, which are the counterpart to NumPy's ``fft`` module. Example 1: Calculate a derivative in Fourier space ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -339,13 +339,13 @@ Calculate the derivative of a (discretized) field in Fourier space, e.g. a sine .. code:: - #include // rfft, irfft - #include // rfftscale - #include - #include // xt::arange - #include // xt::sin, cos + #include // rfft, irfft + #include // rfftscale + #include + #include // xt::arange + #include // xt::sin, cos #include - #include + #include // generate a sinusoid field double dx = M_PI / 100; @@ -406,7 +406,7 @@ The xsimd_ project provides a unified API for making use of the SIMD features of modern preprocessors for C++ library authors. It also provides accelerated implementation of common mathematical functions operating on batches. -xsimd_ is an optional dependency to ``xtensor`` which enable SIMD vectorization +xsimd_ is an optional dependency to *xtensor* which enable SIMD vectorization of xtensor operations. This feature is enabled with the ``XTENSOR_USE_XSIMD`` compilation flag, which is set to ``false`` by default. @@ -416,18 +416,49 @@ xtl .. image:: xtl.svg :alt: xtl -The xtl_ project, the only dependency of ``xtensor`` is a C++ template library -holding the implementation of basic tools used accross the libraries in the -QuantStack ecosystem. - -.. _xtensor-python: https://github.com/QuantStack/xtensor-python -.. _xtensor-python-cookiecutter: https://github.com/QuantStack/xtensor-python-cookiecutter -.. _xtensor-julia: https://github.com/QuantStack/xtensor-julia -.. _xtensor-julia-cookiecutter: https://github.com/QuantStack/xtensor-julia-cookiecutter -.. _xtensor-r: https://github.com/QuantStack/xtensor-r -.. _xtensor-blas: https://github.com/QuantStack/xtensor-blas -.. _xtensor-io: https://github.com/QuantStack/xtensor-io -.. _xtensor-fftw: https://github.com/egpbos/xtensor-fftw -.. _xtensor-ros: https://github.com/wolfv/xtensor_ros -.. _xsimd: https://github.com/QuantStack/xsimd -.. _xtl: https://github.com/QuantStack/xtl +The xtl_ project, the only dependency of *xtensor* is a C++ template library +holding the implementation of basic tools used across the libraries in the ecosystem. + +xframe +------ + +.. image:: xframe.svg + :alt: xframe + +The xframe_ project provides multi-dimensional labeled arrays and a data frame for C++, +based on *xtensor* and *xtl*. + +`xframe` provides + +- an extensible expression system enabling lazy broadcasting. +- an API following the idioms of the C++ standard library. +- tools to manipulate n-dimensional labeled tensor expressions. + +The API of xframe is inspired by xarray_, a Python package implementing labelled multi-dimensional arrays and datasets. + +z5 +-- + +The z5_ project implements the zarr_ and n5_ storage specifications in C++. +Both specifications describe chunked nd-array storage similar to HDF5, but +use the filesystem to store chunks. This design allows for parallel write access +and efficient cloud based storage, crucial requirements in modern big data applications. +The project uses *xtensor* to represent arrays in memory +and also provides a python wrapper based on ``xtensor-python``. + +.. _xtensor-python: https://github.com/xtensor-stack/xtensor-python +.. _xtensor-python-cookiecutter: https://github.com/xtensor-stack/xtensor-python-cookiecutter +.. _xtensor-julia: https://github.com/xtensor-stack/xtensor-julia +.. _xtensor-julia-cookiecutter: https://github.com/xtensor-stack/xtensor-julia-cookiecutter +.. _xtensor-r: https://github.com/xtensor-stack/xtensor-r +.. _xtensor-blas: https://github.com/xtensor-stack/xtensor-blas +.. _xtensor-io: https://github.com/xtensor-stack/xtensor-io +.. _xtensor-fftw: https://github.com/xtensor-stack/xtensor-fftw +.. _xtensor-ros: https://github.com/RoboStack/xtensor-ros +.. _xsimd: https://github.com/xtensor-stack/xsimd +.. _xtl: https://github.com/xtensor-stack/xtl +.. _xframe: https://github.com/xtensor-stack/xframe +.. _z5: https://github.com/constantinpape/z5 +.. _zarr: https://github.com/zarr-developers/zarr-python +.. _n5: https://github.com/saalfeldlab/n5 +.. _xarray: https://docs.xarray.dev/en/stable/ diff --git a/docs/source/releasing.rst b/docs/source/releasing.rst index c56bddaa9..b7fd4c608 100644 --- a/docs/source/releasing.rst +++ b/docs/source/releasing.rst @@ -13,7 +13,7 @@ Releasing a new version From the master branch of xtensor - Make sure that you are in sync with the master branch of the upstream remote. -- Update the `changelog `_. +- Update the `changelog `_. - In file ``xtensor_config.hpp``, set the macros for ``XTENSOR_VERSION_MAJOR``, ``XTENSOR_VERSION_MINOR`` and ``XTENSOR_VERSION_PATCH`` to the desired values. - In file ``CMakeLists.txt``, update the version of the dependencies and the corresponding variables, e.g. ``xtl_REQUIRED_VERSION``. - In file ``environment.yml``, update the version of the dependencies including ``xtensor``. diff --git a/docs/source/scalar.rst b/docs/source/scalar.rst index c0b1bf436..8d74dc8a5 100644 --- a/docs/source/scalar.rst +++ b/docs/source/scalar.rst @@ -10,13 +10,13 @@ Scalars and 0-D expressions Assignment ---------- -In ``xtensor``, scalars are handled as if they were 0-dimensional expressions. This means that when assigning -a scalar value to an ``xarray``, this last one is **not filled** with that value, but resized to become a 0-D -array containing the scalar value: +In *xtensor*, scalars are handled as if they were 0-dimensional expressions. +This means that when assigning a scalar value to an :cpp:type:`xt::xarray`, the array is **not filled** with that value, +but resized to become a 0-D array containing the scalar value: .. code:: - #include "xtensor/xarray.hpp" + #include xt::xarray a = {{0., 1., 2.}, {3., 4., 5.}}; double s = 1.2; @@ -36,7 +36,7 @@ Assuming that the scalar assignment does not resize the array, we have the follo .. code:: - #include "xtensor/xarray.hpp" + #include xt::xarray a = {{0., 1., 2.}, {3., 4., 5.}}; double s = 1.2; @@ -48,18 +48,18 @@ This is not consistent with the behavior of the copy constructor from a scalar: .. code:: - #include "xtensor/xarray.hpp" + #include xt::xarray a(1.2); std::cout << a << std::endl; // prints 1.2 (a is a 0-D array) A way to fix this is to disable copy construction from scalar, and provide a constructor taking a shape and -a scalar: +a scalar: .. code:: - #include "xtensor/xarray.hpp" + #include xt::xarray a = {{0., 1., 2.}, {3., 4., 5.}}; a = 1.2; @@ -92,11 +92,12 @@ Then, somewhere in your program: // ... // later eval_mean(a, b); - // Now b is a 0-D container holding 21. + // Now b is a 0-D container holding 3.5. -After that, ``b`` is a 0-dimensional array containing the mean of the elements of ``a``. Indeed, ``sum(a) / e1.size()`` is a -0-D expression, thus when assigned to ``b``, this latter is resized. Later, you realize that you also need the sum of the elements -of ``a``. Since the ``eval_mean`` function already computes it, you decide to return it from that function: +After that, ``b`` is a 0-dimensional array containing the mean of the elements of ``a``. +Indeed, ``sum(a) / e1.size()`` is a 0-D expression, thus when assigned to ``b``, this latter is resized. +Later, you realize that you also need the sum of the elements of ``a``. +Since the ``eval_mean()`` function already computes it, you decide to return it from that function: .. code:: @@ -120,11 +121,11 @@ And then you change the client code: double s = eval_mean(a, b); // Now b is a 2-D container! -After that, ``b`` has become a 2-dimensional array! Indeed, since assigning a scalar to an expression does not resize it, the change in -``eval_mean`` implementation now assigns the mean of ``a`` to each elements of ``b``. +After that, ``b`` has become a 2-dimensional array! +Indeed, since assigning a scalar to an expression does not resize it, the change in ``eval_mean()`` +implementation now assigns the mean of ``a`` to each elements of ``b``. This simple example shows that without consistency between scalars and 0-D expressions, refactoring the code to cache the result of some 0-D computation actually *silently* changes the shape of the expressions that this result is assigned to. The only way to avoid that behavior and the bugs it leads to is to handle scalars as if they were 0-dimensional expressions. - diff --git a/docs/source/view.rst b/docs/source/view.rst index 4a8db5614..95b6365b8 100644 --- a/docs/source/view.rst +++ b/docs/source/view.rst @@ -4,34 +4,37 @@ The full license is in the file LICENSE, distributed with this software. +.. _view-description: + Views ===== -Views are used to adapt the shape of an ``xexpression`` without changing it, nor copying it. `xtensor` -provides many kinds of views. +Views are used to adapt the shape of an :cpp:type:`xt::xexpression` without changing it, nor copying it. Views are +convenient tools for assigning parts of an expression: since they do not copy the underlying expression, +assigning to the view actually assigns to the underlying expression. *xtensor* provides many kinds of views. Sliced views ------------ -Sliced views consist of the combination of the ``xexpression`` to adapt, and a list of ``slice`` that specify how -the shape must be adapted. Sliced views are implemented by the ``xview`` class. Objects of this type should not be -instantiated directly, but though the ``view`` helper function. +Sliced views consist of the combination of the :cpp:type:`xt::xexpression` to adapt, and a list of ``slice`` that specify how +the shape must be adapted. Sliced views are implemented by the :cpp:type:`xt::xview` class. Objects of this type should not be +instantiated directly, but though the :cpp:func:`xt::view` helper function. Slices can be specified in the following ways: - selection in a dimension by specifying an index (unsigned integer) -- ``range(min, max)``, a slice representing an interval -- ``range(min, max, step)``, a slice representing a stepped interval -- ``all()``, a slice representing all the elements of a dimension -- ``newaxis()``, a slice representing an additional dimension of length one -- ``keep(i0, i1, i2, ...)`` a slice selecting non-contiguous indices to keep on the underlying expression -- ``drop(i0, i1, i2, ...)`` a slice selecting non-contiguous indices to drop on the underlying expression +- :cpp:func:`xt::range(min, max) `, a slice representing the interval [min, max) +- :cpp:func:`xt::range(min, max, step) `, a slice representing the stepped interval [min, max) +- :cpp:func:`xt::all`, a slice representing all the elements of a dimension +- :cpp:func:`xt::newaxis`, a slice representing an additional dimension of length one +- :cpp:func:`xt::keep(i0, i1, i2, ...) ` a slice selecting non-contiguous indices to keep on the underlying expression +- :cpp:func:`xt::drop(i0, i1, i2, ...) ` a slice selecting non-contiguous indices to drop on the underlying expression .. code:: #include - #include "xtensor/xarray.hpp" - #include "xtensor/xview.hpp" + #include + #include std::vector shape = {3, 2, 4}; xt::xarray a(shape); @@ -59,28 +62,33 @@ Slices can be specified in the following ways: // => v4(0, 0, 0) = a(1, 0, 0) // => v4(1, 1, 1) = a(2, 1, 3) + // View built with negative index + auto v5 = xt::view(a, -2, xt::all(), xt::range(0, 4, 2)); + // => v5 == v2 + The range function supports the placeholder ``_`` syntax: .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xview.hpp" + #include + #include - using namespace xt::placeholders; // required for `_` to work + using namespace xt::placeholders; // required for ``_`` to work auto a = xt::xarray::from_shape({3, 2, 4}); auto v1 = xt::view(a, xt::range(_, 2), xt::all(), xt::range(1, _)); // The previous line is equivalent to auto v2 = xt::view(a, xt::range(0, 2), xt::all(), xt::range(1, 4)); -``xview`` does not perform a copy of the underlying expression. This means if you modify an element of the ``xview``, +:cpp:type:`xt::xview` does not perform a copy of the underlying expression. +This means if you modify an element of the :cpp:type:`xt::xview`, you are actually also altering the underlying expression. .. code:: #include - #include "xtensor/xarray.hpp" - #include "xtensor/xview.hpp" + #include + #include std::vector shape = {3, 2, 4}; xt::xarray a(shape, 0); @@ -89,19 +97,36 @@ you are actually also altering the underlying expression. v1(0, 0) = 1; // => a(1, 0, 1) = 1 +The convenient methods :cpp:func:`xt::row` and :cpp:func:`xt::col` are available for 2-D expressions: + +.. code:: + + #include + #include + #include + + xt::xtensor a = {{1, 2}, {3, 4}}; + auto r = xt::row(a, 0); + // => r = {1, 2} + auto c = xt::col(a, -1); + // => c = { 2, 4 } Strided views ------------- -While the ``xt::view`` is a compile-time static expression, xtensor also contains a dynamic strided view in ``xstrided_view.hpp``. -The strided view and the slice vector allow to dynamically push_back slices, so when the dimension is unknown at compile time, the slice -vector can be built dynamically at runtime. Note that the slice vector is actually a type-alias for a ``std::vector`` of a ``variant`` for -all the slice types. The strided view does not support the slices returned by the ``keep`` and ``drop`` functions. +While the :cpp:func:`xt::view` is a compile-time static expression, xtensor also contains a dynamic +strided view in ``xstrided_view.hpp``. +The strided view and the slice vector allow to dynamically push_back slices, so when the dimension +is unknown at compile time, the slice vector can be built dynamically at runtime. +Note that the slice vector is actually a type-alias for a ``std::vector`` of a ``variant`` for +all the slice types. +The strided view does not support the slices returned by the :cpp:func:`xt::keep` and +:cpp:func:`xt::drop` functions. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xstrided_view.hpp" + #include + #include auto a = xt::xarray::from_shape({3, 2, 3, 4, 5}); @@ -124,8 +149,8 @@ Since ``xtensor 0.16.3``, a new range syntax can be used with strided views: .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xstrided_view.hpp" + #include + #include using namespace xt::placeholders; @@ -134,18 +159,20 @@ Since ``xtensor 0.16.3``, a new range syntax can be used with strided views: // The previous line is equivalent to auto v2 = xt::strided_view(a, {xt::range(0, 1), 1, xt::range(_, 2), xt::range(_, _, -1)}); -The ``xstrided_view`` is very efficient on contigous memory (e.g. ``xtensor`` or ``xarray``) but less efficient on xexpressions. +The :cpp:type:`xt::xstrided_view` type is very efficient on contigous memory +(e.g. :cpp:type:`xt::xtensor` or :cpp:type:`xt::xarray`) but less efficient on +generic :cpp:type:`xt::xexpression` objects. Transposed views ---------------- -``xtensor`` provides a lazy transposed view on any expression, whose layout is either row major order or column major order. Trying to build -a transposed view on a expression with a dynamic layout throws an exception. +*xtensor* provides a lazy transposed view on any expression, whose layout is either row-major order or column major order. +Trying to build a transposed view on a expression with a dynamic layout throws an exception. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xstrided_view.hpp" + #include + #include xt::xarray a = { {0, 1, 2}, {3, 4, 5} }; auto tr = xt::transpose(a); @@ -155,19 +182,20 @@ a transposed view on a expression with a dynamic layout throws an exception. auto tr2 = xt::transpose(b); // => throw transpose_error -Like the strided view, the transposed view is built upon the ``xstrided_view``. +Like the strided view, the transposed view is built upon the :cpp:type:`xt::xstrided_view`. Flatten views ------------- -It is sometimes useful to have a one-dimensional view of all the elements of an expression. ``xtensor`` provides two functions -for that, ``ravel`` and ``flatten``. The former one let you specify the order used to read the elements while the latter one +It is sometimes useful to have a one-dimensional view of all the elements of an expression. +*xtensor* provides two functions for that, :cpp:func:`xt::ravel` and :cpp:func:`xt::flatten`. +The former one lets you specify the order used to read the elements while the latter one uses the layout of the expression. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xstrided_view.hpp" + #include + #include xt::xarray a = { {0, 1, 2}, {3, 4, 5} }; auto flc = xt::ravel(a); @@ -178,19 +206,19 @@ uses the layout of the expression. std::cout << fl << std::endl; // => prints { 0, 1, 2, 3, 4, 5 } -Like the strided view and the transposed view, the flatten view is built upon the ``xstrided_view``. +Like the strided view and the transposed view, the flatten view is built upon the :cpp:type:`xt::xstrided_view`. Reshape views ------------- The reshape view allows to handle an expression as if it was given a new shape, however no additional memory allocation occurs, the original expression keeps its shape. Like any view, the underlying expression is not copied, thus assigning a value through -the view modifies the underlying exression. +the view modifies the underlying expression. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xstrided_view.hpp" + #include + #include auto a = xt::xarray::from_shape({3, 2, 4}); auto v = xt::reshape_view(a, { 4, 2, 3 }); @@ -200,19 +228,20 @@ the view modifies the underlying exression. v(0, 2, 0) = 4; // a(0, 1, 2) == 4 -Like the strided view and the transposed view, the reshape view is built upon the ``xstrided_view``. +Like the strided view and the transposed view, the reshape view is built upon the :cpp:type:`xt::xstrided_view`. Dynamic views ------------- -The dynamic view is like the strided view, but with support of the slices returned by the ``keep`` and ``drop`` functions. -However, this support has a cost and the dynamic view is slower than the strided view, even when no keeping or dropping -slice is involved. +The dynamic view is like the strided view, but with support of the slices returned by the +:cpp:func:`xt::keep` and :cpp:func:`xt::drop` functions. +However, this support has a cost and the dynamic view is slower than the strided view, even when no +keeping or dropping of a slice is involved. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xdynamic_view.hpp + #include + #include auto a = xt::xarray::from_shape({3, 2, 3, 4, 5}); xt::xdynamic_slice_vector sv({xt::range(0, 1), xt::newaxis()}); @@ -230,14 +259,15 @@ slice is involved. Index views ----------- -Index views are one-dimensional views of an ``xexpression``, containing the elements whose positions are specified by a list -of indices. Like for sliced views, the elements of the underlying ``xexpression`` are not copied. Index views should be built -with the ``index_view`` helper function. +Index views are one-dimensional views of an :cpp:type:`xt::xexpression`, containing the elements +whose positions are specified by a list of indices. +Like for sliced views, the elements of the underlying :cpp:type:`xt::xexpression` are not copied. +Index views should be built with the :cpp:func:`xt::index_view` helper function. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xindex_view.hpp" + #include + #include xt::xarray a = {{1, 5, 3}, {4, 5, 6}}; auto b = xt::index_view(a, {{0,0}, {1, 0}, {0, 1}}); @@ -245,16 +275,33 @@ with the ``index_view`` helper function. b += 100; // => a = {{101, 5, 3}, {104, 105, 6}} +The type used for representing indices can be any 1-D container providing an ``std::vector``-like API. +The same stands for the type of the list of indices: + +.. code:: + + #include + #include + + xt::xarray a = {{1, 5, 3}, {4, 5, 6}}; + using index_type = std::array; + std::vector indices = {{0, 0}, {1, 0}, {0, 1}}; + auto b = xt::index_view(a, indices); + // => b = { 1, 4, 5 } + b += 100; + // => a = {{101, 5, 3}, {104, 105, 6}} + Filter views ------------ -Filters are one-dimensional views holding elements of an ``xexpression`` that verify a given condition. Like for other views, -the elements of the underlying ``xexpression`` are not copied. Filters should be built with the ``filter`` helper function. +Filters are one-dimensional views holding elements of an :cpp:type:`xt::xexpression` that verify a given condition. +Like for other views, the elements of the underlying :cpp:type:`xt::xexpression` are not copied. +Filters should be built with the :cpp:func:`xt::filter` helper function. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xindex_view.hpp" + #include + #include xt::xarray a = {{1, 5, 3}, {4, 5, 6}}; auto v = xt::filter(a, a >= 5); @@ -265,15 +312,16 @@ the elements of the underlying ``xexpression`` are not copied. Filters should be Filtration ---------- -Sometimes, the only thing you want to do with a filter is to assign it a scalar. Though this can be done as shown -in the previous section, this is not the *optimal* way to do it. `xtensor` provides a specially optimized mechanism -for that, called filtration. A filtration IS NOT an ``xexpression``, the only methods it provides are scalar and +Sometimes, the only thing you want to do with a filter is to assign it a scalar. +Though this can be done as shown in the previous section, this is not the *optimal* way to do it. +*xtensor* provides a specially optimized mechanism for that, called filtration. +A filtration IS NOT an :cpp:type:`xt::xexpression`, the only methods it provides are scalar and computed scalar assignments. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xindex_view.hpp" + #include + #include xt::xarray a = {{1, 5, 3}, {4, 5, 6}}; filtration(a, a >= 5) += 100; @@ -282,12 +330,12 @@ computed scalar assignments. Masked view ----------- -Masked views are multidimensional views that apply a mask on an ``xexpression``. +Masked views are multidimensional views that apply a mask on an :cpp:type:`xt::xexpression`. .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xmasked_view.hpp" + #include + #include xt::xarray a = {{1, 5, 3}, {4, 5, 6}}; xt::xarray mask = {{true, false, false}, {false, true, false}}; @@ -301,15 +349,16 @@ Masked views are multidimensional views that apply a mask on an ``xexpression``. Broadcasting views ------------------ -Another type of view provided by `xtensor` is *broadcasting view*. Such a view broadcast an expression to the specified -shape. As long as the view is not assigned to an array, no memory allocation or copy occurs. Broadcasting views should be -built with the ``broadcast`` helper function. +Another type of view provided by *xtensor* is *broadcasting view*. +Such a view broadcasts an expression to the specified shape. +As long as the view is not assigned to an array, no memory allocation or copy occurs. +Broadcasting views should be built with the :cpp:func:`xt::broadcast` helper function. .. code:: #include - #include "xtensor/xarray.hpp" - #include "xtensor/xbroadcast.hpp" + #include + #include std::vector s1 = { 2, 3 }; std::vector s2 = { 3, 2, 3 }; @@ -321,22 +370,28 @@ built with the ``broadcast`` helper function. Complex views ------------- -In the case of tensor containing complex numbers, `xtensor` provides views returning ``xexpression`` corresponding to the real -and imaginary parts of the complex numbers. Like for other views, the elements of the underlying ``xexpression`` are not copied. +In the case of a tensor containing complex numbers, *xtensor* provides views returning +:cpp:type:`xt::xexpression` corresponding to the real and imaginary parts of the complex numbers. +Like for other views, the elements of the underlying :cpp:type:`xt::xexpression` are not copied. -Functions ``xt::real`` and ``xt::imag`` respectively return views on the real and imaginary part of a complex expression. +Functions :cpp:func:`xt::real` and :cpp:func:`xt::imag` respectively return views on the real and +imaginary part of a complex expression. The returned value is an expression holding a closure on the passed argument. -- The constness and value category (rvalue / lvalue) of ``real(a)`` is the same as that of ``a``. Hence, if ``a`` is a non-const lvalue, - ``real(a)`` is an non-const lvalue reference, to which one can assign a real expression. -- If ``a`` has complex values, the same holds for ``imag(a)``. The constness and value category of ``imag(a)`` is the same as that of ``a``. -- If ``a`` has real values, ``imag(a)`` returns ``zeros(a.shape())``. +- The constness and value category (rvalue / lvalue) of :cpp:func:`xt::real(a) ` is the same + as that of ``a``. + Hence, if ``a`` is a non-const lvalue, :cpp:func:`xt::real(a) ` is an non-const lvalue + reference, to which one can assign a real expression. +- If ``a`` has complex values, the same holds for :cpp:func:`xt::imag(a) `. + The constness and value category of :cpp:func:`xt::imag(a) ` is the same as that of ``a``. +- If ``a`` has real values, :cpp:func:`xt::imag(a) ` returns + :cpp:func:`xt::zeros(a.shape()) `. .. code:: #include - #include "xtensor/xarray.hpp" - #include "xtensor/xcomplex.hpp" + #include + #include using namespace std::complex_literals; @@ -350,13 +405,14 @@ The returned value is an expression holding a closure on the passed argument. Assigning to a view ------------------- -When assigning an expression ``rhs`` to a container such as ``xarray``, this last one is resized so its shape is the same as the one -of ``RHS``. However, since views *cannot be resized*, when assigning an expression to a view, broadcasting rules are applied: +When assigning an expression ``rhs`` to a container such as :cpp:type:`xt::xarray`, the container +is resized so its shape is the same as the one of ``rhs``. +However, since views *cannot be resized*, when assigning an expression to a view, broadcasting rules are applied: .. code:: - #include "xtensor/xarray.hpp" - #include "xtensor/xview.hpp" + #include + #include xarray a = {{0., 1., 2.}, {3., 4., 5.}}; double b = 1.2; diff --git a/docs/source/xeus-cling-screenshot.png b/docs/source/xeus-cling-screenshot.png new file mode 100644 index 000000000..543a2447a Binary files /dev/null and b/docs/source/xeus-cling-screenshot.png differ diff --git a/docs/source/xfft.rst b/docs/source/xfft.rst new file mode 100644 index 000000000..20eed9619 --- /dev/null +++ b/docs/source/xfft.rst @@ -0,0 +1,17 @@ +.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht + Distributed under the terms of the BSD 3-Clause License. + The full license is in the file LICENSE, distributed with this software. +xfft +==== + +Defined in ``xtensor/misc/xfft.hpp`` + +.. doxygenclass:: xt::fft::convolve + :project: xtensor + :members: + +.. doxygentypedef:: xt::fft::fft + :project: xtensor + +.. doxygentypedef:: xt::fft::ifft + :project: xtensor diff --git a/docs/source/xframe.svg b/docs/source/xframe.svg new file mode 100644 index 000000000..4fa903af1 --- /dev/null +++ b/docs/source/xframe.svg @@ -0,0 +1,63 @@ + + + +image/svg+xml diff --git a/docs/source/xsimd-small.svg b/docs/source/xsimd-small.svg index 84d92be03..b191c15f9 100644 --- a/docs/source/xsimd-small.svg +++ b/docs/source/xsimd-small.svg @@ -45,8 +45,8 @@ inkscape:current-layer="Calque_1" /> - - - - - - + + + + + + + diff --git a/docs/source/xtensor-blas-small.svg b/docs/source/xtensor-blas-small.svg index b59fb3c20..bbd3defaf 100644 --- a/docs/source/xtensor-blas-small.svg +++ b/docs/source/xtensor-blas-small.svg @@ -1,53 +1,53 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/docs/source/xtensor-blas.svg b/docs/source/xtensor-blas.svg index 9ab9f9481..86714cb23 100644 --- a/docs/source/xtensor-blas.svg +++ b/docs/source/xtensor-blas.svg @@ -1,53 +1,53 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/docs/source/xtensor-cookiecutter.svg b/docs/source/xtensor-cookiecutter.svg index 118d91308..961833a5b 100644 --- a/docs/source/xtensor-cookiecutter.svg +++ b/docs/source/xtensor-cookiecutter.svg @@ -3767,4 +3767,4 @@ d="m 179.748,307.774 c -1.662,-0.26 -2.799,-2.016 -2.642,-3.604 l 0,0 c 0.209,-2.117 2.693,-3.665 4.506,-2.954 l 0,0 c 1.237,0.484 1.928,1.928 1.858,3.195 l 0,0 c -0.092,1.695 -1.566,3.395 -3.308,3.395 l 0,0 c -0.136,0 -0.275,-0.01 -0.414,-0.032" style="fill:url(#radialGradient3560);stroke:none" id="path3570" - inkscape:connector-curvature="0" /> \ No newline at end of file + inkscape:connector-curvature="0" /> diff --git a/docs/source/xtensor-fftw.svg b/docs/source/xtensor-fftw.svg index 681d8a053..d290fdc94 100644 --- a/docs/source/xtensor-fftw.svg +++ b/docs/source/xtensor-fftw.svg @@ -44,9 +44,9 @@ inkscape:current-layer="text4147" /> \ No newline at end of file + id="path13" /> diff --git a/docs/source/xtensor-julia-small.svg b/docs/source/xtensor-julia-small.svg index 4b31c814b..3fd141998 100644 --- a/docs/source/xtensor-julia-small.svg +++ b/docs/source/xtensor-julia-small.svg @@ -1,61 +1,61 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/docs/source/xtensor-julia.svg b/docs/source/xtensor-julia.svg index cba4c7fb1..9f80f2ff1 100644 --- a/docs/source/xtensor-julia.svg +++ b/docs/source/xtensor-julia.svg @@ -1,61 +1,61 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/docs/source/xtensor-python-small.svg b/docs/source/xtensor-python-small.svg index 08f6215d0..ad71c9ab9 100644 --- a/docs/source/xtensor-python-small.svg +++ b/docs/source/xtensor-python-small.svg @@ -1,60 +1,60 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/docs/source/xtensor-python.svg b/docs/source/xtensor-python.svg index 181465f92..7a29ffde8 100644 --- a/docs/source/xtensor-python.svg +++ b/docs/source/xtensor-python.svg @@ -1,60 +1,60 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/docs/source/xtensor-r-small.svg b/docs/source/xtensor-r-small.svg index 5e3a5cd99..ff7958a87 100644 --- a/docs/source/xtensor-r-small.svg +++ b/docs/source/xtensor-r-small.svg @@ -1,48 +1,48 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/docs/source/xtensor-r.svg b/docs/source/xtensor-r.svg index de03f1aed..c07afc656 100644 --- a/docs/source/xtensor-r.svg +++ b/docs/source/xtensor-r.svg @@ -1,48 +1,48 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/docs/source/xtensor-ros.svg b/docs/source/xtensor-ros.svg index cf86857ba..5f03871d1 100644 --- a/docs/source/xtensor-ros.svg +++ b/docs/source/xtensor-ros.svg @@ -45,9 +45,9 @@ inkscape:current-layer="text4147" /> \ No newline at end of file + id="path13" /> diff --git a/docs/source/xtensor.svg b/docs/source/xtensor.svg index df4cdb2fb..d86f6294f 100644 --- a/docs/source/xtensor.svg +++ b/docs/source/xtensor.svg @@ -1,35 +1,35 @@ - - - - - - - + + + + + + + diff --git a/docs/source/xtl.svg b/docs/source/xtl.svg index 52318e2eb..2e7eea7a0 100644 --- a/docs/source/xtl.svg +++ b/docs/source/xtl.svg @@ -48,8 +48,8 @@ inkscape:current-layer="Calque_1" /> +#include + +#include "../chunk/xchunked_assign.hpp" +#include "../containers/xarray.hpp" + +namespace xt +{ + /** + * @defgroup xt_xchunked_array Chunked array + * + * Chunked array container. + * Defined in ``xtensor/xchunked_array.hpp``. + */ + + /****************************** + * xchunked_array declaration * + ******************************/ + + template + class xchunked_array; + + template + struct xcontainer_inner_types> + { + using chunk_type = typename chunk_storage::value_type; + using const_reference = typename chunk_type::const_reference; + using reference = typename chunk_type::reference; + using size_type = std::size_t; + using storage_type = chunk_type; + using temporary_type = xchunked_array; + }; + + template + struct xiterable_inner_types> + { + using chunk_type = typename chunk_storage::value_type; + using inner_shape_type = typename chunk_type::shape_type; + using const_stepper = xindexed_stepper, true>; + using stepper = xindexed_stepper, false>; + }; + + template + class xchunked_array : public xaccessible>, + public xiterable>, + public xchunked_semantic> + { + public: + + using chunk_storage_type = chunk_storage; + using chunk_type = typename chunk_storage::value_type; + using grid_shape_type = typename chunk_storage::shape_type; + using const_reference = typename chunk_type::const_reference; + using reference = typename chunk_type::reference; + using self_type = xchunked_array; + using semantic_base = xchunked_semantic; + using iterable_base = xconst_iterable; + using const_stepper = typename iterable_base::const_stepper; + using stepper = typename iterable_base::stepper; + using inner_types = xcontainer_inner_types; + using size_type = typename inner_types::size_type; + using storage_type = typename inner_types::storage_type; + using value_type = typename storage_type::value_type; + using pointer = value_type*; + using const_pointer = const value_type*; + using difference_type = std::ptrdiff_t; + using shape_type = typename chunk_type::shape_type; + using temporary_type = typename inner_types::temporary_type; + using bool_load_type = xt::bool_load_type; + static constexpr layout_type static_layout = layout_type::dynamic; + static constexpr bool contiguous_layout = false; + using chunk_iterator = xchunk_iterator; + using const_chunk_iterator = xchunk_iterator; + + template + xchunked_array( + chunk_storage_type&& chunks, + S&& shape, + S&& chunk_shape, + layout_type chunk_memory_layout = XTENSOR_DEFAULT_LAYOUT + ); + ~xchunked_array() = default; + + xchunked_array(const xchunked_array&) = default; + xchunked_array& operator=(const xchunked_array&) = default; + + xchunked_array(xchunked_array&&) = default; + xchunked_array& operator=(xchunked_array&&) = default; + + template + xchunked_array( + const xexpression& e, + chunk_storage_type&& chunks, + layout_type chunk_memory_layout = XTENSOR_DEFAULT_LAYOUT + ); + + template + xchunked_array( + const xexpression& e, + chunk_storage_type&& chunks, + S&& chunk_shape, + layout_type chunk_memory_layout = XTENSOR_DEFAULT_LAYOUT + ); + + template + xchunked_array& operator=(const xexpression& e); + + size_type dimension() const noexcept; + const shape_type& shape() const noexcept; + layout_type layout() const noexcept; + bool is_contiguous() const noexcept; + + template + reference operator()(Idxs... idxs); + + template + const_reference operator()(Idxs... idxs) const; + + template + reference element(It first, It last); + + template + const_reference element(It first, It last) const; + + template + bool broadcast_shape(S& s, bool reuse_cache = false) const; + + template + bool has_linear_assign(const S& strides) const noexcept; + + template + stepper stepper_begin(const S& shape) noexcept; + template + stepper stepper_end(const S& shape, layout_type) noexcept; + + template + const_stepper stepper_begin(const S& shape) const noexcept; + template + const_stepper stepper_end(const S& shape, layout_type) const noexcept; + + const shape_type& chunk_shape() const noexcept; + size_type grid_size() const noexcept; + const grid_shape_type& grid_shape() const noexcept; + + chunk_storage_type& chunks(); + const chunk_storage_type& chunks() const; + + chunk_iterator chunk_begin(); + chunk_iterator chunk_end(); + + const_chunk_iterator chunk_begin() const; + const_chunk_iterator chunk_end() const; + const_chunk_iterator chunk_cbegin() const; + const_chunk_iterator chunk_cend() const; + + private: + + template + using indexes_type = std:: + pair, std::array>; + + template + using chunk_indexes_type = std::array, sizeof...(Idxs)>; + + template + using static_indexes_type = std::pair, std::array>; + + using dynamic_indexes_type = std::pair, std::vector>; + + template + void resize(S1&& shape, S2&& chunk_shape, layout_type chunk_memory_layout = XTENSOR_DEFAULT_LAYOUT); + + template + indexes_type get_indexes(Idxs... idxs) const; + + template + std::pair get_chunk_indexes_in_dimension(std::size_t dim, Idx idx) const; + + template + chunk_indexes_type get_chunk_indexes(std::index_sequence, Idxs... idxs) const; + + template + static_indexes_type unpack(const std::array& arr) const; + + template + dynamic_indexes_type get_indexes_dynamic(It first, It last) const; + + shape_type m_shape; + shape_type m_chunk_shape; + chunk_storage_type m_chunks; + }; + + template + constexpr bool is_chunked(const xexpression& e); + + template + constexpr bool is_chunked(); + + /** + * Creates an in-memory chunked array. + * + * This function returns an uninitialized ``xt::xchunked_array>``. + * + * @ingroup xt_xchunked_array + * + * @tparam T The type of the elements (e.g. double) + * @tparam L The layout_type of the array + * + * @param shape The shape of the array + * @param chunk_shape The shape of a chunk + * @param chunk_memory_layout The layout of each chunk (default: XTENSOR_DEFAULT_LAYOUT) + * + * @return returns a ``xt::xchunked_array>`` with the given shape, chunk shape and memory + * layout. + */ + template + xchunked_array>> + chunked_array(S&& shape, S&& chunk_shape, layout_type chunk_memory_layout = XTENSOR_DEFAULT_LAYOUT); + + template + xchunked_array>> chunked_array( + std::initializer_list shape, + std::initializer_list chunk_shape, + layout_type chunk_memory_layout = XTENSOR_DEFAULT_LAYOUT + ); + + /** + * Creates an in-memory chunked array. + * + * This function returns a ``xt::xchunked_array>`` initialized from an expression. + * + * @ingroup xt_xchunked_array + * + * @tparam L The layout_type of the array + * + * @param e The expression to initialize the chunked array from + * @param chunk_shape The shape of a chunk + * @param chunk_memory_layout The layout of each chunk (default: XTENSOR_DEFAULT_LAYOUT) + * + * @return returns a ``xt::xchunked_array>`` from the given expression, with the given chunk + * shape and memory layout. + */ + template + xchunked_array>> + chunked_array(const xexpression& e, S&& chunk_shape, layout_type chunk_memory_layout = XTENSOR_DEFAULT_LAYOUT); + + /** + * Creates an in-memory chunked array. + * + * This function returns a ``xt::xchunked_array>`` initialized from an expression. + * + * @ingroup xt_xchunked_array + * + * @tparam L The layout_type of the array + * + * @param e The expression to initialize the chunked array from + * @param chunk_memory_layout The layout of each chunk (default: XTENSOR_DEFAULT_LAYOUT) + * + * @return returns a ``xt::xchunked_array>`` from the given expression, with the + * expression's chunk shape and the given memory layout. + */ + template + xchunked_array>> + chunked_array(const xexpression& e, layout_type chunk_memory_layout = XTENSOR_DEFAULT_LAYOUT); + + /******************************* + * chunk_helper implementation * + *******************************/ + + namespace detail + { + // Workaround for VS2015 + template + using try_chunk_shape = decltype(std::declval().chunk_shape()); + + template class OP, class = void> + struct chunk_helper_impl + { + using is_chunked = std::false_type; + + static const auto& chunk_shape(const xexpression& e) + { + return e.derived_cast().shape(); + } + + template + static void + resize(E& chunks, const S1& container_shape, const S2& chunk_shape, layout_type chunk_memory_layout) + { + chunks.resize(container_shape); + for (auto& c : chunks) + { + c.resize(chunk_shape, chunk_memory_layout); + } + } + }; + + template class OP> + struct chunk_helper_impl>> + { + using is_chunked = std::true_type; + + static const auto& chunk_shape(const xexpression& e) + { + return e.derived_cast().chunk_shape(); + } + + template + static void + resize(E& chunks, const S1& container_shape, const S2& /*chunk_shape*/, layout_type /*chunk_memory_layout*/) + { + chunks.resize(container_shape); + } + }; + + template + using chunk_helper = chunk_helper_impl; + } + + template + constexpr bool is_chunked(const xexpression&) + { + return is_chunked(); + } + + template + constexpr bool is_chunked() + { + using return_type = typename detail::chunk_helper::is_chunked; + return return_type::value; + } + + template + inline xchunked_array>> + chunked_array(S&& shape, S&& chunk_shape, layout_type chunk_memory_layout) + { + using chunk_storage = xarray>; + return xchunked_array( + chunk_storage(), + std::forward(shape), + std::forward(chunk_shape), + chunk_memory_layout + ); + } + + template + xchunked_array>> + chunked_array(std::initializer_list shape, std::initializer_list chunk_shape, layout_type chunk_memory_layout) + { + using sh_type = std::vector; + auto sh = xtl::forward_sequence>(shape); + auto ch_sh = xtl::forward_sequence>(chunk_shape); + return chunked_array(std::move(sh), std::move(ch_sh), chunk_memory_layout); + } + + template + inline xchunked_array>> + chunked_array(const xexpression& e, S&& chunk_shape, layout_type chunk_memory_layout) + { + using chunk_storage = xarray>; + return xchunked_array(e, chunk_storage(), std::forward(chunk_shape), chunk_memory_layout); + } + + template + inline xchunked_array>> + chunked_array(const xexpression& e, layout_type chunk_memory_layout) + { + using chunk_storage = xarray>; + return xchunked_array(e, chunk_storage(), chunk_memory_layout); + } + + /********************************* + * xchunked_array implementation * + *********************************/ + + template + template + inline xchunked_array::xchunked_array(CS&& chunks, S&& shape, S&& chunk_shape, layout_type chunk_memory_layout) + : m_chunks(std::move(chunks)) + { + resize(std::forward(shape), std::forward(chunk_shape), chunk_memory_layout); + } + + template + template + inline xchunked_array::xchunked_array(const xexpression& e, CS&& chunks, layout_type chunk_memory_layout) + : xchunked_array(e, std::move(chunks), detail::chunk_helper::chunk_shape(e), chunk_memory_layout) + { + } + + template + template + inline xchunked_array::xchunked_array( + const xexpression& e, + CS&& chunks, + S&& chunk_shape, + layout_type chunk_memory_layout + ) + : m_chunks(std::move(chunks)) + { + resize(e.derived_cast().shape(), std::forward(chunk_shape), chunk_memory_layout); + semantic_base::assign_xexpression(e); + } + + template + template + inline auto xchunked_array::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + + template + inline auto xchunked_array::dimension() const noexcept -> size_type + { + return m_shape.size(); + } + + template + inline auto xchunked_array::shape() const noexcept -> const shape_type& + { + return m_shape; + } + + template + inline auto xchunked_array::layout() const noexcept -> layout_type + { + return static_layout; + } + + template + inline bool xchunked_array::is_contiguous() const noexcept + { + return false; + } + + template + template + inline auto xchunked_array::operator()(Idxs... idxs) -> reference + { + auto ii = get_indexes(idxs...); + auto& chunk = m_chunks.element(ii.first.cbegin(), ii.first.cend()); + return chunk.element(ii.second.cbegin(), ii.second.cend()); + } + + template + template + inline auto xchunked_array::operator()(Idxs... idxs) const -> const_reference + { + auto ii = get_indexes(idxs...); + auto& chunk = m_chunks.element(ii.first.cbegin(), ii.first.cend()); + return chunk.element(ii.second.cbegin(), ii.second.cend()); + } + + template + template + inline auto xchunked_array::element(It first, It last) -> reference + { + auto ii = get_indexes_dynamic(first, last); + auto& chunk = m_chunks.element(ii.first.begin(), ii.first.end()); + return chunk.element(ii.second.begin(), ii.second.end()); + } + + template + template + inline auto xchunked_array::element(It first, It last) const -> const_reference + { + auto ii = get_indexes_dynamic(first, last); + auto& chunk = m_chunks.element(ii.first.begin(), ii.first.end()); + return chunk.element(ii.second.begin(), ii.second.end()); + } + + template + template + inline bool xchunked_array::broadcast_shape(S& s, bool) const + { + return xt::broadcast_shape(shape(), s); + } + + template + template + inline bool xchunked_array::has_linear_assign(const S&) const noexcept + { + return false; + } + + template + template + inline auto xchunked_array::stepper_begin(const S& shape) noexcept -> stepper + { + size_type offset = shape.size() - this->dimension(); + return stepper(this, offset); + } + + template + template + inline auto xchunked_array::stepper_end(const S& shape, layout_type) noexcept -> stepper + { + size_type offset = shape.size() - this->dimension(); + return stepper(this, offset, true); + } + + template + template + inline auto xchunked_array::stepper_begin(const S& shape) const noexcept -> const_stepper + { + size_type offset = shape.size() - this->dimension(); + return const_stepper(this, offset); + } + + template + template + inline auto xchunked_array::stepper_end(const S& shape, layout_type) const noexcept -> const_stepper + { + size_type offset = shape.size() - this->dimension(); + return const_stepper(this, offset, true); + } + + template + inline auto xchunked_array::chunk_shape() const noexcept -> const shape_type& + { + return m_chunk_shape; + } + + template + inline auto xchunked_array::grid_size() const noexcept -> size_type + { + return m_chunks.size(); + } + + template + inline auto xchunked_array::grid_shape() const noexcept -> const grid_shape_type& + { + return m_chunks.shape(); + } + + template + inline auto xchunked_array::chunks() -> chunk_storage_type& + { + return m_chunks; + } + + template + inline auto xchunked_array::chunks() const -> const chunk_storage_type& + { + return m_chunks; + } + + template + inline auto xchunked_array::chunk_begin() -> chunk_iterator + { + shape_type chunk_index(m_shape.size(), size_type(0)); + return chunk_iterator(*this, std::move(chunk_index), 0u); + } + + template + inline auto xchunked_array::chunk_end() -> chunk_iterator + { + shape_type sh = xtl::forward_sequence(grid_shape()); + return chunk_iterator(*this, std::move(sh), grid_size()); + } + + template + inline auto xchunked_array::chunk_begin() const -> const_chunk_iterator + { + shape_type chunk_index(m_shape.size(), size_type(0)); + return const_chunk_iterator(*this, std::move(chunk_index), 0u); + } + + template + inline auto xchunked_array::chunk_end() const -> const_chunk_iterator + { + shape_type sh = xtl::forward_sequence(grid_shape()); + return const_chunk_iterator(*this, std::move(sh), grid_size()); + } + + template + inline auto xchunked_array::chunk_cbegin() const -> const_chunk_iterator + { + return chunk_begin(); + } + + template + inline auto xchunked_array::chunk_cend() const -> const_chunk_iterator + { + return chunk_end(); + } + + template + template + inline void xchunked_array::resize(S1&& shape, S2&& chunk_shape, layout_type chunk_memory_layout) + { + // compute chunk number in each dimension (shape_of_chunks) + std::vector shape_of_chunks(shape.size()); + std::transform( + shape.cbegin(), + shape.cend(), + chunk_shape.cbegin(), + shape_of_chunks.begin(), + [](auto s, auto cs) + { + std::size_t cn = s / cs; + if (s % cs > 0) + { + cn += std::size_t(1); // edge_chunk + } + return cn; + } + ); + + detail::chunk_helper::resize(m_chunks, shape_of_chunks, chunk_shape, chunk_memory_layout); + + m_shape = xtl::forward_sequence(shape); + m_chunk_shape = xtl::forward_sequence(chunk_shape); + } + + template + template + inline auto xchunked_array::get_indexes(Idxs... idxs) const -> indexes_type + { + auto chunk_indexes_packed = get_chunk_indexes(std::make_index_sequence(), idxs...); + return unpack(chunk_indexes_packed); + } + + template + template + inline std::pair + xchunked_array::get_chunk_indexes_in_dimension(std::size_t dim, Idx idx) const + { + std::size_t index_of_chunk = static_cast(idx) / m_chunk_shape[dim]; + std::size_t index_in_chunk = static_cast(idx) - index_of_chunk * m_chunk_shape[dim]; + return std::make_pair(index_of_chunk, index_in_chunk); + } + + template + template + inline auto xchunked_array::get_chunk_indexes(std::index_sequence, Idxs... idxs) const + -> chunk_indexes_type + { + chunk_indexes_type chunk_indexes = {{get_chunk_indexes_in_dimension(dims, idxs)...}}; + return chunk_indexes; + } + + template + template + inline auto xchunked_array::unpack(const std::array& arr) const -> static_indexes_type + { + std::array arr0; + std::array arr1; + for (std::size_t i = 0; i < N; ++i) + { + arr0[i] = std::get<0>(arr[i]); + arr1[i] = std::get<1>(arr[i]); + } + return std::make_pair(arr0, arr1); + } + + template + template + inline auto xchunked_array::get_indexes_dynamic(It first, It last) const -> dynamic_indexes_type + { + auto size = static_cast(std::distance(first, last)); + std::vector indexes_of_chunk(size); + std::vector indexes_in_chunk(size); + for (std::size_t dim = 0; dim < size; ++dim) + { + auto chunk_index = get_chunk_indexes_in_dimension(dim, *first++); + indexes_of_chunk[dim] = chunk_index.first; + indexes_in_chunk[dim] = chunk_index.second; + } + return std::make_pair(indexes_of_chunk, indexes_in_chunk); + } +} + +#endif diff --git a/include/xtensor/chunk/xchunked_assign.hpp b/include/xtensor/chunk/xchunked_assign.hpp new file mode 100644 index 000000000..334e824b9 --- /dev/null +++ b/include/xtensor/chunk/xchunked_assign.hpp @@ -0,0 +1,378 @@ +/*************************************************************************** + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#ifndef XTENSOR_CHUNKED_ASSIGN_HPP +#define XTENSOR_CHUNKED_ASSIGN_HPP + +#include "../core/xnoalias.hpp" +#include "../views/xstrided_view.hpp" + +namespace xt +{ + + /******************* + * xchunk_assigner * + *******************/ + + template + class xchunked_assigner + { + public: + + using temporary_type = T; + + template + void build_and_assign_temporary(const xexpression& e, DST& dst); + }; + + /********************************* + * xchunked_semantic declaration * + *********************************/ + + template + class xchunked_semantic : public xsemantic_base + { + public: + + using base_type = xsemantic_base; + using derived_type = D; + using temporary_type = typename base_type::temporary_type; + + template + derived_type& assign_xexpression(const xexpression& e); + + template + derived_type& computed_assign(const xexpression& e); + + template + derived_type& scalar_computed_assign(const E& e, F&& f); + + protected: + + xchunked_semantic() = default; + ~xchunked_semantic() = default; + + xchunked_semantic(const xchunked_semantic&) = default; + xchunked_semantic& operator=(const xchunked_semantic&) = default; + + xchunked_semantic(xchunked_semantic&&) = default; + xchunked_semantic& operator=(xchunked_semantic&&) = default; + + template + derived_type& operator=(const xexpression& e); + + private: + + template + xchunked_assigner get_assigner(const CS&) const; + }; + + /******************* + * xchunk_iterator * + *******************/ + + template + class xchunked_array; + + template + class xchunked_view; + + namespace detail + { + template + struct is_xchunked_array : std::false_type + { + }; + + template + struct is_xchunked_array> : std::true_type + { + }; + + template + struct is_xchunked_view : std::false_type + { + }; + + template + struct is_xchunked_view> : std::true_type + { + }; + + struct invalid_chunk_iterator + { + }; + + template + struct xchunk_iterator_array + { + using reference = decltype(*(std::declval().chunks().begin())); + + inline decltype(auto) get_chunk(A& arr, typename A::size_type i, const xstrided_slice_vector&) const + { + using difference_type = typename A::difference_type; + return *(arr.chunks().begin() + static_cast(i)); + } + }; + + template + struct xchunk_iterator_view + { + using reference = decltype(xt::strided_view( + std::declval().expression(), + std::declval() + )); + + inline auto get_chunk(V& view, typename V::size_type, const xstrided_slice_vector& sv) const + { + return xt::strided_view(view.expression(), sv); + } + }; + + template + struct xchunk_iterator_base + : std::conditional_t< + is_xchunked_array>::value, + xchunk_iterator_array, + std::conditional_t>::value, xchunk_iterator_view, invalid_chunk_iterator>> + { + }; + } + + template + class xchunk_iterator : private detail::xchunk_iterator_base + { + public: + + using base_type = detail::xchunk_iterator_base; + using self_type = xchunk_iterator; + using size_type = typename E::size_type; + using shape_type = typename E::shape_type; + using slice_vector = xstrided_slice_vector; + + using reference = typename base_type::reference; + using value_type = std::remove_reference_t; + using pointer = value_type*; + using difference_type = typename E::difference_type; + using iterator_category = std::forward_iterator_tag; + + + xchunk_iterator() = default; + xchunk_iterator(E& chunked_expression, shape_type&& chunk_index, size_type chunk_linear_index); + + self_type& operator++(); + self_type operator++(int); + decltype(auto) operator*() const; + + bool operator==(const self_type& rhs) const; + bool operator!=(const self_type& rhs) const; + + const shape_type& chunk_index() const; + + const slice_vector& get_slice_vector() const; + slice_vector get_chunk_slice_vector() const; + + private: + + void fill_slice_vector(size_type index); + + E* p_chunked_expression; + shape_type m_chunk_index; + size_type m_chunk_linear_index; + xstrided_slice_vector m_slice_vector; + }; + + /************************************ + * xchunked_semantic implementation * + ************************************/ + + template + template + inline void xchunked_assigner::build_and_assign_temporary(const xexpression& e, DST& dst) + { + temporary_type tmp(e, CS(), dst.chunk_shape()); + dst = std::move(tmp); + } + + template + template + inline auto xchunked_semantic::assign_xexpression(const xexpression& e) -> derived_type& + { + auto& d = this->derived_cast(); + const auto& chunk_shape = d.chunk_shape(); + size_t i = 0; + auto it_end = d.chunk_end(); + for (auto it = d.chunk_begin(); it != it_end; ++it, ++i) + { + auto rhs = strided_view(e.derived_cast(), it.get_slice_vector()); + if (rhs.shape() != chunk_shape) + { + noalias(strided_view(*it, it.get_chunk_slice_vector())) = rhs; + } + else + { + noalias(*it) = rhs; + } + } + + return this->derived_cast(); + } + + template + template + inline auto xchunked_semantic::computed_assign(const xexpression& e) -> derived_type& + { + D& d = this->derived_cast(); + if (e.derived_cast().dimension() > d.dimension() || e.derived_cast().shape() > d.shape()) + { + return operator=(e); + } + else + { + return assign_xexpression(e); + } + } + + template + template + inline auto xchunked_semantic::scalar_computed_assign(const E& e, F&& f) -> derived_type& + { + for (auto& c : this->derived_cast().chunks()) + { + c.scalar_computed_assign(e, f); + } + return this->derived_cast(); + } + + template + template + inline auto xchunked_semantic::operator=(const xexpression& e) -> derived_type& + { + D& d = this->derived_cast(); + get_assigner(d.chunks()).build_and_assign_temporary(e, d); + return d; + } + + template + template + inline auto xchunked_semantic::get_assigner(const CS&) const -> xchunked_assigner + { + return xchunked_assigner(); + } + + /********************************** + * xchunk_iterator implementation * + **********************************/ + + template + inline xchunk_iterator::xchunk_iterator(E& expression, shape_type&& chunk_index, size_type chunk_linear_index) + : p_chunked_expression(&expression) + , m_chunk_index(std::move(chunk_index)) + , m_chunk_linear_index(chunk_linear_index) + , m_slice_vector(m_chunk_index.size()) + { + for (size_type i = 0; i < m_chunk_index.size(); ++i) + { + fill_slice_vector(i); + } + } + + template + inline xchunk_iterator& xchunk_iterator::operator++() + { + if (m_chunk_linear_index + 1u != p_chunked_expression->grid_size()) + { + size_type i = p_chunked_expression->dimension(); + while (i != 0) + { + --i; + if (m_chunk_index[i] + 1u == p_chunked_expression->grid_shape()[i]) + { + m_chunk_index[i] = 0; + fill_slice_vector(i); + } + else + { + m_chunk_index[i] += 1; + fill_slice_vector(i); + break; + } + } + } + m_chunk_linear_index++; + return *this; + } + + template + inline xchunk_iterator xchunk_iterator::operator++(int) + { + xchunk_iterator it = *this; + ++(*this); + return it; + } + + template + inline decltype(auto) xchunk_iterator::operator*() const + { + return base_type::get_chunk(*p_chunked_expression, m_chunk_linear_index, m_slice_vector); + } + + template + inline bool xchunk_iterator::operator==(const xchunk_iterator& other) const + { + return m_chunk_linear_index == other.m_chunk_linear_index; + } + + template + inline bool xchunk_iterator::operator!=(const xchunk_iterator& other) const + { + return !(*this == other); + } + + template + inline auto xchunk_iterator::get_slice_vector() const -> const slice_vector& + { + return m_slice_vector; + } + + template + auto xchunk_iterator::chunk_index() const -> const shape_type& + { + return m_chunk_index; + } + + template + inline auto xchunk_iterator::get_chunk_slice_vector() const -> slice_vector + { + slice_vector slices(m_chunk_index.size()); + for (size_type i = 0; i < m_chunk_index.size(); ++i) + { + size_type chunk_shape = p_chunked_expression->chunk_shape()[i]; + size_type end = std::min( + chunk_shape, + p_chunked_expression->shape()[i] - m_chunk_index[i] * chunk_shape + ); + slices[i] = range(0u, end); + } + return slices; + } + + template + inline void xchunk_iterator::fill_slice_vector(size_type i) + { + size_type range_start = m_chunk_index[i] * p_chunked_expression->chunk_shape()[i]; + size_type range_end = std::min( + (m_chunk_index[i] + 1) * p_chunked_expression->chunk_shape()[i], + p_chunked_expression->shape()[i] + ); + m_slice_vector[i] = range(range_start, range_end); + } +} + +#endif diff --git a/include/xtensor/chunk/xchunked_view.hpp b/include/xtensor/chunk/xchunked_view.hpp new file mode 100644 index 000000000..6c9d0a3f2 --- /dev/null +++ b/include/xtensor/chunk/xchunked_view.hpp @@ -0,0 +1,295 @@ +/*************************************************************************** + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#ifndef XTENSOR_CHUNKED_VIEW_HPP +#define XTENSOR_CHUNKED_VIEW_HPP + +#include + +#include "../chunk/xchunked_array.hpp" +#include "../containers/xstorage.hpp" +#include "../core/xnoalias.hpp" +#include "../views/xstrided_view.hpp" + +namespace xt +{ + + template + struct is_chunked_t : detail::chunk_helper::is_chunked + { + }; + + /***************** + * xchunked_view * + *****************/ + + template + class xchunk_iterator; + + template + class xchunked_view + { + public: + + using self_type = xchunked_view; + using expression_type = std::decay_t; + using value_type = typename expression_type::value_type; + using reference = typename expression_type::reference; + using const_reference = typename expression_type::const_reference; + using pointer = typename expression_type::pointer; + using const_pointer = typename expression_type::const_pointer; + using size_type = typename expression_type::size_type; + using difference_type = typename expression_type::difference_type; + using shape_type = svector; + using chunk_iterator = xchunk_iterator; + using const_chunk_iterator = xchunk_iterator; + + template + xchunked_view(OE&& e, S&& chunk_shape); + + template + xchunked_view(OE&& e); + + void init(); + + template + typename std::enable_if_t::value, xchunked_view&> operator=(const OE& e); + + template + typename std::enable_if_t::value, xchunked_view&> operator=(const OE& e); + + size_type dimension() const noexcept; + const shape_type& shape() const noexcept; + const shape_type& chunk_shape() const noexcept; + size_type grid_size() const noexcept; + const shape_type& grid_shape() const noexcept; + + expression_type& expression() noexcept; + const expression_type& expression() const noexcept; + + chunk_iterator chunk_begin(); + chunk_iterator chunk_end(); + + const_chunk_iterator chunk_begin() const; + const_chunk_iterator chunk_end() const; + const_chunk_iterator chunk_cbegin() const; + const_chunk_iterator chunk_cend() const; + + private: + + E m_expression; + shape_type m_shape; + shape_type m_chunk_shape; + shape_type m_grid_shape; + size_type m_chunk_nb; + }; + + template + xchunked_view as_chunked(E&& e, S&& chunk_shape); + + /******************************** + * xchunked_view implementation * + ********************************/ + + template + template + inline xchunked_view::xchunked_view(OE&& e, S&& chunk_shape) + : m_expression(std::forward(e)) + , m_chunk_shape(xtl::forward_sequence(chunk_shape)) + { + m_shape.resize(e.dimension()); + const auto& s = e.shape(); + std::copy(s.cbegin(), s.cend(), m_shape.begin()); + init(); + } + + template + template + inline xchunked_view::xchunked_view(OE&& e) + : m_expression(std::forward(e)) + { + m_shape.resize(e.dimension()); + const auto& s = e.shape(); + std::copy(s.cbegin(), s.cend(), m_shape.begin()); + } + + template + void xchunked_view::init() + { + // compute chunk number in each dimension + m_grid_shape.resize(m_shape.size()); + std::transform( + m_shape.cbegin(), + m_shape.cend(), + m_chunk_shape.cbegin(), + m_grid_shape.begin(), + [](auto s, auto cs) + { + std::size_t cn = s / cs; + if (s % cs > 0) + { + cn++; // edge_chunk + } + return cn; + } + ); + m_chunk_nb = std::accumulate( + std::begin(m_grid_shape), + std::end(m_grid_shape), + std::size_t(1), + std::multiplies<>() + ); + } + + template + template + typename std::enable_if_t::value, xchunked_view&> + xchunked_view::operator=(const OE& e) + { + auto end = chunk_end(); + for (auto it = chunk_begin(); it != end; ++it) + { + auto el = *it; + noalias(el) = strided_view(e, it.get_slice_vector()); + } + return *this; + } + + template + template + typename std::enable_if_t::value, xchunked_view&> + xchunked_view::operator=(const OE& e) + { + m_chunk_shape.resize(e.dimension()); + const auto& cs = e.chunk_shape(); + std::copy(cs.cbegin(), cs.cend(), m_chunk_shape.begin()); + init(); + auto it2 = e.chunks().begin(); + auto end1 = chunk_end(); + for (auto it1 = chunk_begin(); it1 != end1; ++it1, ++it2) + { + auto el1 = *it1; + auto el2 = *it2; + auto lhs_shape = el1.shape(); + if (lhs_shape != el2.shape()) + { + xstrided_slice_vector esv(el2.dimension()); // element slice in edge chunk + std::transform( + lhs_shape.begin(), + lhs_shape.end(), + esv.begin(), + [](auto size) + { + return range(0, size); + } + ); + noalias(el1) = strided_view(el2, esv); + } + else + { + noalias(el1) = el2; + } + } + return *this; + } + + template + inline auto xchunked_view::dimension() const noexcept -> size_type + { + return m_shape.size(); + } + + template + inline auto xchunked_view::shape() const noexcept -> const shape_type& + { + return m_shape; + } + + template + inline auto xchunked_view::chunk_shape() const noexcept -> const shape_type& + { + return m_chunk_shape; + } + + template + inline auto xchunked_view::grid_size() const noexcept -> size_type + { + return m_chunk_nb; + } + + template + inline auto xchunked_view::grid_shape() const noexcept -> const shape_type& + { + return m_grid_shape; + } + + template + inline auto xchunked_view::expression() noexcept -> expression_type& + { + return m_expression; + } + + template + inline auto xchunked_view::expression() const noexcept -> const expression_type& + { + return m_expression; + } + + template + inline auto xchunked_view::chunk_begin() -> chunk_iterator + { + shape_type chunk_index(m_shape.size(), size_type(0)); + return chunk_iterator(*this, std::move(chunk_index), 0u); + } + + template + inline auto xchunked_view::chunk_end() -> chunk_iterator + { + return chunk_iterator(*this, shape_type(grid_shape()), grid_size()); + } + + template + inline auto xchunked_view::chunk_begin() const -> const_chunk_iterator + { + shape_type chunk_index(m_shape.size(), size_type(0)); + return const_chunk_iterator(*this, std::move(chunk_index), 0u); + } + + template + inline auto xchunked_view::chunk_end() const -> const_chunk_iterator + { + return const_chunk_iterator(*this, shape_type(grid_shape()), grid_size()); + } + + template + inline auto xchunked_view::chunk_cbegin() const -> const_chunk_iterator + { + return chunk_begin(); + } + + template + inline auto xchunked_view::chunk_cend() const -> const_chunk_iterator + { + return chunk_end(); + } + + template + inline xchunked_view as_chunked(E&& e, S&& chunk_shape) + { + return xchunked_view(std::forward(e), std::forward(chunk_shape)); + } + + template + inline xchunked_view as_chunked(E&& e) + { + return xchunked_view(std::forward(e)); + } +} + +#endif diff --git a/include/xtensor/containers/xadapt.hpp b/include/xtensor/containers/xadapt.hpp new file mode 100644 index 000000000..725a75d42 --- /dev/null +++ b/include/xtensor/containers/xadapt.hpp @@ -0,0 +1,921 @@ +/*************************************************************************** + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#ifndef XTENSOR_ADAPT_HPP +#define XTENSOR_ADAPT_HPP + +#include +#include +#include +#include + +#include + +#include "../containers/xarray.hpp" +#include "../containers/xbuffer_adaptor.hpp" +#include "../containers/xfixed.hpp" +#include "../containers/xtensor.hpp" + +namespace xt +{ + /** + * @defgroup xt_xadapt Adaptors of STL-like containers + */ + + namespace detail + { + template + struct array_size_impl; + + template + struct array_size_impl> + { + static constexpr std::size_t value = N; + }; + + template + using array_size = array_size_impl>; + + template + struct default_allocator_for_ptr + { + using type = std::allocator>>>; + }; + + template + using default_allocator_for_ptr_t = typename default_allocator_for_ptr

::type; + + template + using not_an_array = std::negation>; + + template + using not_a_pointer = std::negation>; + + template + using not_a_layout = std::negation>; + } + +#ifndef IN_DOXYGEN + + /************************** + * xarray_adaptor builder * + **************************/ + + /** + * Constructs an xarray_adaptor of the given stl-like container, + * with the specified shape and layout. + * + * @ingroup xt_xadapt + * @param container the container to adapt + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class C, + class SC, + XTL_REQUIRES(detail::not_an_array>, detail::not_a_pointer)> + inline xarray_adaptor, L, std::decay_t> + adapt(C&& container, const SC& shape, layout_type l = L) + { + static_assert(!xtl::is_integral::value, "shape cannot be a integer"); + using return_type = xarray_adaptor, L, std::decay_t>; + return return_type(std::forward(container), shape, l); + } + + /** + * Constructs an non-owning xarray_adaptor from a pointer with the specified shape and layout. + * + * @ingroup xt_xadapt + * @param pointer the container to adapt + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class C, + class SC, + XTL_REQUIRES(detail::not_an_array>, std::is_pointer>)> + inline auto adapt(C&& pointer, const SC& shape, layout_type l = L) + { + static_assert(!xtl::is_integral::value, "shape cannot be a integer"); + using buffer_type = xbuffer_adaptor>; + using return_type = xarray_adaptor>; + std::size_t size = compute_size(shape); + return return_type(buffer_type(pointer, size), shape, l); + } + + /** + * Constructs an xarray_adaptor of the given stl-like container, + * with the specified shape and strides. + * + * @ingroup xt_xadapt + * @param container the container to adapt + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template < + class C, + class SC, + class SS, + XTL_REQUIRES(detail::not_an_array>, detail::not_a_layout>)> + inline xarray_adaptor, layout_type::dynamic, std::decay_t> + adapt(C&& container, SC&& shape, SS&& strides) + { + static_assert(!xtl::is_integral>::value, "shape cannot be a integer"); + using return_type = xarray_adaptor, layout_type::dynamic, std::decay_t>; + return return_type( + std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides) + ); + } + + /** + * Constructs an xarray_adaptor of the given dynamically allocated C array, + * with the specified shape and layout. + * + * @ingroup xt_xadapt + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class P, + class O, + class SC, + class A = detail::default_allocator_for_ptr_t

, + XTL_REQUIRES(detail::not_an_array>)> + inline xarray_adaptor, O, A>, L, SC> adapt( + P&& pointer, + typename A::size_type size, + O ownership, + const SC& shape, + layout_type l = L, + const A& alloc = A() + ) + { + static_assert(!xtl::is_integral::value, "shape cannot be a integer"); + (void) ownership; + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), shape, l); + } + + /** + * Constructs an xarray_adaptor of the given dynamically allocated C array, + * with the specified shape and strides. + * + * @ingroup xt_xadapt + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template < + class P, + class O, + class SC, + class SS, + class A = detail::default_allocator_for_ptr_t

, + XTL_REQUIRES(detail::not_an_array>, detail::not_a_layout>)> + inline xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()) + { + static_assert(!xtl::is_integral>::value, "shape cannot be a integer"); + (void) ownership; + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor>; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type( + std::move(buf), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides) + ); + } + + /** + * Constructs an xarray_adaptor of the given C array allocated on the stack, with the + * specified shape and layout. + * + * @ingroup xt_xadapt + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class T, + std::size_t N, + class SC, + XTL_REQUIRES(detail::not_an_array>)> + inline auto adapt(T (&c_array)[N], const SC& shape, layout_type l = L) + { + return adapt(&c_array[0], N, xt::no_ownership(), shape, l); + } + + /** + * Constructs an xarray_adaptor of the given C array allocated on the stack, with the + * specified shape and stirdes. + * + * @ingroup xt_xadapt + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template < + class T, + std::size_t N, + class SC, + class SS, + XTL_REQUIRES(detail::not_an_array>, detail::not_a_layout>)> + inline auto adapt(T (&c_array)[N], SC&& shape, SS&& strides) + { + return adapt(&c_array[0], N, xt::no_ownership(), std::forward(shape), std::forward(strides)); + } + + /*************************** + * xtensor_adaptor builder * + ***************************/ + + /** + * Constructs a 1-D xtensor_adaptor of the given stl-like container, + * with the specified layout_type. + * + * @ingroup xt_xadapt + * @param container the container to adapt + * @param l the layout_type of the xtensor_adaptor + */ + template + inline xtensor_adaptor adapt(C&& container, layout_type l = L) + { + const std::array::size_type, 1> shape{container.size()}; + using return_type = xtensor_adaptor, 1, L>; + return return_type(std::forward(container), shape, l); + } + + /** + * Constructs an xtensor_adaptor of the given stl-like container, + * with the specified shape and layout_type. + * + * @ingroup xt_xadapt + * @param container the container to adapt + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class C, + class SC, + XTL_REQUIRES(detail::is_array>, detail::not_a_pointer)> + inline xtensor_adaptor::value, L> + adapt(C&& container, const SC& shape, layout_type l = L) + { + static_assert(!xtl::is_integral::value, "shape cannot be a integer"); + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor, N, L>; + return return_type(std::forward(container), shape, l); + } + + /** + * Constructs an non-owning xtensor_adaptor from a pointer with the specified shape and layout. + * + * @ingroup xt_xadapt + * @param pointer the pointer to adapt + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class C, + class SC, + XTL_REQUIRES(detail::is_array>, std::is_pointer>)> + inline auto adapt(C&& pointer, const SC& shape, layout_type l = L) + { + static_assert(!xtl::is_integral::value, "shape cannot be a integer"); + using buffer_type = xbuffer_adaptor>; + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor; + return return_type(buffer_type(pointer, compute_size(shape)), shape, l); + } + + /** + * Constructs an xtensor_adaptor of the given stl-like container, + * with the specified shape and strides. + * + * @ingroup xt_xadapt + * @param container the container to adapt + * @param shape the shape of the xtensor_adaptor + * @param strides the strides of the xtensor_adaptor + */ + template < + class C, + class SC, + class SS, + XTL_REQUIRES(detail::is_array>, detail::not_a_layout>)> + inline xtensor_adaptor::value, layout_type::dynamic> + adapt(C&& container, SC&& shape, SS&& strides) + { + static_assert(!xtl::is_integral>::value, "shape cannot be a integer"); + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor, N, layout_type::dynamic>; + return return_type( + std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides) + ); + } + + /** + * Constructs a 1-D xtensor_adaptor of the given dynamically allocated C array, + * with the specified layout. + * + * @ingroup xt_xadapt + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param l the layout_type of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template > + inline xtensor_adaptor, O, A>, 1, L> + adapt(P&& pointer, typename A::size_type size, O ownership, layout_type l = L, const A& alloc = A()) + { + (void) ownership; + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xtensor_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + const std::array shape{size}; + return return_type(std::move(buf), shape, l); + } + + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and layout. + * + * @ingroup xt_xadapt + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class P, + class O, + class SC, + class A = detail::default_allocator_for_ptr_t

, + XTL_REQUIRES(detail::is_array>)> + inline xtensor_adaptor, O, A>, detail::array_size::value, L> + adapt( + P&& pointer, + typename A::size_type size, + O ownership, + const SC& shape, + layout_type l = L, + const A& alloc = A() + ) + { + static_assert(!xtl::is_integral::value, "shape cannot be a integer"); + (void) ownership; + using buffer_type = xbuffer_adaptor, O, A>; + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), shape, l); + } + + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and strides. + * + * @ingroup xt_xadapt + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param strides the strides of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template < + class P, + class O, + class SC, + class SS, + class A = detail::default_allocator_for_ptr_t

, + XTL_REQUIRES(detail::is_array>, detail::not_a_layout>)> + inline xtensor_adaptor, O, A>, detail::array_size::value, layout_type::dynamic> + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()) + { + static_assert(!xtl::is_integral>::value, "shape cannot be a integer"); + (void) ownership; + using buffer_type = xbuffer_adaptor, O, A>; + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type( + std::move(buf), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides) + ); + } + + /** + * Constructs an xtensor_adaptor of the given C array allocated on the stack, with the + * specified shape and layout. + * + * @ingroup xt_xadapt + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class T, + std::size_t N, + class SC, + XTL_REQUIRES(detail::is_array>)> + inline auto adapt(T (&c_array)[N], const SC& shape, layout_type l = L) + { + return adapt(&c_array[0], N, xt::no_ownership(), shape, l); + } + + /** + * Constructs an xtensor_adaptor of the given C array allocated on the stack, with the + * specified shape and strides. + * + * @ingroup xt_xadapt + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template < + class T, + std::size_t N, + class SC, + class SS, + XTL_REQUIRES(detail::is_array>, detail::not_a_layout>)> + inline auto adapt(T (&c_array)[N], SC&& shape, SS&& strides) + { + return adapt(&c_array[0], N, xt::no_ownership(), std::forward(shape), std::forward(strides)); + } + + /** + * Constructs an non-owning xtensor_fixed_adaptor from a pointer with the + * specified shape and layout. + * + * @ingroup xt_xadapt + * @param pointer the pointer to adapt + * @param shape the shape of the xtensor_fixed_adaptor + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class C, + std::size_t... X, + XTL_REQUIRES(std::is_pointer>)> + inline auto adapt(C&& pointer, const fixed_shape& /*shape*/) + { + using buffer_type = xbuffer_adaptor>; + using return_type = xfixed_adaptor, L>; + return return_type(buffer_type(pointer, detail::fixed_compute_size>::value)); + } + + template + inline auto adapt(C&& ptr, const T (&shape)[N]) + { + using shape_type = std::array; + return adapt(std::forward(ptr), xtl::forward_sequence(shape)); + } + +#else // IN_DOXYGEN + + /** + * Constructs: + * - an xarray_adaptor if SC is not an array type + * - an xtensor_adaptor if SC is an array type + * + * from the given stl-like container or pointer, with the specified shape and layout. + * If the adaptor is built from a pointer, it does not take its ownership. + * + * @ingroup xt_xadapt + * @param container the container or pointer to adapt + * @param shape the shape of the adaptor + * @param l the layout_type of the adaptor + */ + template + inline auto adapt(C&& container, const SC& shape, layout_type l = L); + + /** + * Constructs: + * - an xarray_adaptor if SC is not an array type + * - an xtensor_adaptor if SC is an array type + * + * from the given stl-like container with the specified shape and strides. + * + * @ingroup xt_xadapt + * @param container the container to adapt + * @param shape the shape of the adaptor + * @param strides the strides of the adaptor + */ + template + inline auto adapt(C&& container, SC&& shape, SS&& strides); + + /** + * Constructs: + * - an xarray_adaptor if SC is not an array type + * - an xtensor_adaptor if SC is an array type + * + * of the given dynamically allocated C array, with the specified shape and layout. + * + * @ingroup xt_xadapt + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the adaptor + * @param l the layout_type of the adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template > + inline auto adapt( + P&& pointer, + typename A::size_type size, + O ownership, + const SC& shape, + layout_type l = L, + const A& alloc = A() + ); + + /** + * Constructs: + * - an xarray_adaptor if SC is not an array type + * - an xtensor_adaptor if SC is an array type + * + * of the given dynamically allocated C array, with the specified shape and strides. + * + * @ingroup xt_xadapt + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the adaptor + * @param strides the strides of the adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template > + inline auto + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); + + /** + * Constructs: + * - an xarray_adaptor if SC is not an array type + * - an xtensor_adaptor if SC is an array type + * + * of the given C array allocated on the stack, with the specified shape and layout. + * + * @ingroup xt_xadapt + * @param c_array the C array allocated on the stack + * @param shape the shape of the adaptor + * @param l the layout_type of the adaptor + */ + template + inline auto adapt(T (&c_array)[N], const SC& shape, layout_type l = L); + + /** + * Constructs: + * - an xarray_adaptor if SC is not an array type + * - an xtensor_adaptor if SC is an array type + * + * of the given C array allocated on the stack, with the + * specified shape and strides. + * + * @ingroup xt_xadapt + * @param c_array the C array allocated on the stack + * @param shape the shape of the adaptor + * @param strides the strides of the adaptor + */ + template + inline auto adapt(T (&c_array)[N], SC&& shape, SS&& strides); + + /** + * Constructs an non-owning xtensor_fixed_adaptor from a pointer with the + * specified shape and layout. + * + * @ingroup xt_xadapt + * @param pointer the pointer to adapt + * @param shape the shape of the xtensor_fixed_adaptor + */ + template + inline auto adapt(C&& pointer, const fixed_shape& /*shape*/); + + /** + * Constructs a 1-D xtensor_adaptor of the given stl-like container, + * with the specified layout_type. + * + * @ingroup xt_xadapt + * @param container the container to adapt + * @param l the layout_type of the xtensor_adaptor + */ + template + inline xtensor_adaptor adapt(C&& container, layout_type l = L); + + /** + * Constructs a 1-D xtensor_adaptor of the given dynamically allocated C array, + * with the specified layout. + * + * @ingroup xt_xadapt + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param l the layout_type of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template > + inline xtensor_adaptor, O, A>, 1, L> + adapt(P&& pointer, typename A::size_type size, O ownership, layout_type l = L, const A& alloc = A()); + +#endif // IN_DOXYGEN + + /***************************** + * smart_ptr adapter builder * + *****************************/ + + /** + * Adapt a smart pointer to a typed memory block (unique_ptr or shared_ptr) + * + * @code{.cpp} + * #include + * #include + * + * std::shared_ptr sptr(new double[8], std::default_delete()); + * sptr.get()[2] = 321.; + * std::vector shape = {4, 2}; + * auto xptr = adapt_smart_ptr(sptr, shape); + * xptr(1, 3) = 123.; + * std::cout << xptr; + * @endcode + * + * @ingroup xt_xadapt + * @param smart_ptr a smart pointer to a memory block of T[] + * @param shape The desired shape + * @param l The desired memory layout + * + * @return xarray_adaptor for memory + */ + template >)> + auto adapt_smart_ptr(P&& smart_ptr, const SC& shape, layout_type l = L) + { + using buffer_adaptor = xbuffer_adaptor>; + return xarray_adaptor>( + buffer_adaptor(smart_ptr.get(), compute_size(shape), std::forward

(smart_ptr)), + shape, + l + ); + } + + /** + * Adapt a smart pointer (shared_ptr or unique_ptr) + * + * This function allows to automatically adapt a shared or unique pointer to + * a given shape and operate naturally on it. Memory will be automatically + * handled by the smart pointer implementation. + * + * @code{.cpp} + * #include + * #include + * + * struct Buffer { + * Buffer(std::vector& buf) : m_buf(buf) {} + * ~Buffer() { std::cout << "deleted" << std::endl; } + * std::vector m_buf; + * }; + * + * auto data = std::vector{1,2,3,4,5,6,7,8}; + * auto shared_buf = std::make_shared(data); + * auto unique_buf = std::make_unique(data); + * + * std::cout << shared_buf.use_count() << std::endl; + * { + * std::vector shape = {2, 4}; + * auto obj = adapt_smart_ptr(shared_buf.get()->m_buf.data(), + * shape, shared_buf); + * // Use count increased to 2 + * std::cout << shared_buf.use_count() << std::endl; + * std::cout << obj << std::endl; + * } + * // Use count reset to 1 + * std::cout << shared_buf.use_count() << std::endl; + * + * { + * std::vector shape = {2, 4}; + * auto obj = adapt_smart_ptr(unique_buf.get()->m_buf.data(), + * shape, std::move(unique_buf)); + * std::cout << obj << std::endl; + * } + * @endcode + * + * @ingroup xt_xadapt + * @param data_ptr A pointer to a typed data block (e.g. double*) + * @param shape The desired shape + * @param smart_ptr A smart pointer to move or copy, in order to manage memory + * @param l The desired memory layout + * + * @return xarray_adaptor on the memory + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class P, + class SC, + class D, + XTL_REQUIRES(detail::not_an_array>, detail::not_a_layout>)> + auto adapt_smart_ptr(P&& data_ptr, const SC& shape, D&& smart_ptr, layout_type l = L) + { + using buffer_adaptor = xbuffer_adaptor>; + + return xarray_adaptor>( + buffer_adaptor(data_ptr, compute_size(shape), std::forward(smart_ptr)), + shape, + l + ); + } + + /** + * Adapt a smart pointer to a typed memory block (unique_ptr or shared_ptr) + * + * @code{.cpp} + * #include + * #include + * + * std::shared_ptr sptr(new double[8], std::default_delete()); + * sptr.get()[2] = 321.; + * auto xptr = adapt_smart_ptr(sptr, {4, 2}); + * xptr(1, 3) = 123.; + * std::cout << xptr; + * @endcode + * + * @ingroup xt_xadapt + * @param smart_ptr a smart pointer to a memory block of T[] + * @param shape The desired shape + * @param l The desired memory layout + * + * @return xtensor_adaptor for memory + */ + template + auto adapt_smart_ptr(P&& smart_ptr, const I (&shape)[N], layout_type l = L) + { + using buffer_adaptor = xbuffer_adaptor>; + std::array fshape = xtl::forward_sequence, decltype(shape)>( + shape + ); + return xtensor_adaptor( + buffer_adaptor(smart_ptr.get(), compute_size(fshape), std::forward

(smart_ptr)), + std::move(fshape), + l + ); + } + + /** + * Adapt a smart pointer (shared_ptr or unique_ptr) + * + * This function allows to automatically adapt a shared or unique pointer to + * a given shape and operate naturally on it. Memory will be automatically + * handled by the smart pointer implementation. + * + * @code{.cpp} + * #include + * #include + * + * struct Buffer { + * Buffer(std::vector& buf) : m_buf(buf) {} + * ~Buffer() { std::cout << "deleted" << std::endl; } + * std::vector m_buf; + * }; + * + * auto data = std::vector{1,2,3,4,5,6,7,8}; + * auto shared_buf = std::make_shared(data); + * auto unique_buf = std::make_unique(data); + * + * std::cout << shared_buf.use_count() << std::endl; + * { + * auto obj = adapt_smart_ptr(shared_buf.get()->m_buf.data(), + * {2, 4}, shared_buf); + * // Use count increased to 2 + * std::cout << shared_buf.use_count() << std::endl; + * std::cout << obj << std::endl; + * } + * // Use count reset to 1 + * std::cout << shared_buf.use_count() << std::endl; + * + * { + * auto obj = adapt_smart_ptr(unique_buf.get()->m_buf.data(), + * {2, 4}, std::move(unique_buf)); + * std::cout << obj << std::endl; + * } + * @endcode + * + * @ingroup xt_xadapt + * @param data_ptr A pointer to a typed data block (e.g. double*) + * @param shape The desired shape + * @param smart_ptr A smart pointer to move or copy, in order to manage memory + * @param l The desired memory layout + * + * @return xtensor_adaptor on the memory + */ + template < + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class P, + class I, + std::size_t N, + class D, + XTL_REQUIRES(detail::not_a_layout>)> + auto adapt_smart_ptr(P&& data_ptr, const I (&shape)[N], D&& smart_ptr, layout_type l = L) + { + using buffer_adaptor = xbuffer_adaptor>; + std::array fshape = xtl::forward_sequence, decltype(shape)>( + shape + ); + + return xtensor_adaptor( + buffer_adaptor(data_ptr, compute_size(fshape), std::forward(smart_ptr)), + std::move(fshape), + l + ); + } + + /** + * @brief xtensor adaptor for a pointer. + * + * Construct for example with: + * + * @code{.cpp} + * #include + * + * std::array shape = {2, 2}; + * std::vector data = {1, 2, 3, 4}; + * + * xt::xtensor_pointer a = xt::adapt(data.data(), 4, xt::no_ownership(), shape); + * @endcode + * + * @ingroup xt_xadapt + * @tparam T The data type (e.g. ``double``). + * @tparam N The number of dimensions. + * @tparam L The xt::layout_type() of the xtensor. + */ + template + using xtensor_pointer = xtensor_adaptor< + xbuffer_adaptor, xt::no_ownership, detail::default_allocator_for_ptr_t>, + N, + L>; + + /** + * @brief xarray adaptor for a pointer. + * + * Construct for example with: + * + * @code{.cpp} + * #include + * + * std::vector data(4, 0); + * xt::svector shape({2, 2}); + * + * xt::xarray_pointer a = xt::adapt(data.data(), data.size(), xt::no_ownership(), shape); + * @endcode + * + * @ingroup xt_xadapt + * @tparam T The data type (e.g. ``double``). + * @tparam L The xt::layout_type() of the xarray. + * @tparam SC The shape container type (e.g. ``xt::svector``). Default matches + * xt::adapt(P&&, typename A::size_type, O, const SC&, layout_type, const A& alloc) + */ + template < + class T, + layout_type L = XTENSOR_DEFAULT_LAYOUT, + class SC = XTENSOR_DEFAULT_SHAPE_CONTAINER(T, std::allocator, std::allocator)> + using xarray_pointer = xarray_adaptor< + xbuffer_adaptor, xt::no_ownership, detail::default_allocator_for_ptr_t>, + L, + SC>; +} + +#endif diff --git a/include/xtensor/xarray.hpp b/include/xtensor/containers/xarray.hpp similarity index 81% rename from include/xtensor/xarray.hpp rename to include/xtensor/containers/xarray.hpp index fb46d2d1a..7f27bd296 100644 --- a/include/xtensor/xarray.hpp +++ b/include/xtensor/containers/xarray.hpp @@ -1,23 +1,23 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #ifndef XTENSOR_ARRAY_HPP #define XTENSOR_ARRAY_HPP #include -#include #include #include -#include "xbuffer_adaptor.hpp" -#include "xcontainer.hpp" -#include "xsemantic.hpp" +#include "../containers/xbuffer_adaptor.hpp" +#include "../containers/xcontainer.hpp" +#include "../core/xsemantic.hpp" namespace xt { @@ -45,6 +45,9 @@ namespace xt struct xcontainer_inner_types> { using storage_type = EC; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; using shape_type = SC; using strides_type = get_strides_t; using backstrides_type = get_strides_t; @@ -72,7 +75,7 @@ namespace xt * @tparam L The layout_type of the container. * @tparam SC The type of the containers holding the shape and the strides. * @tparam Tag The expression tag. - * @sa xarray + * @sa xarray, xstrided_container, xcontainer */ template class xarray_container : public xstrided_container>, @@ -100,6 +103,7 @@ namespace xt using inner_backstrides_type = typename base_type::inner_backstrides_type; using temporary_type = typename semantic_base::temporary_type; using expression_tag = Tag; + static constexpr std::size_t rank = SIZE_MAX; xarray_container(); explicit xarray_container(const shape_type& shape, layout_type l = L); @@ -151,10 +155,28 @@ namespace xt * xarray_adaptor declaration * ******************************/ + namespace extension + { + template + struct xarray_adaptor_base; + + template + struct xarray_adaptor_base + { + using type = xtensor_empty_base; + }; + + template + using xarray_adaptor_base_t = typename xarray_adaptor_base::type; + } + template struct xcontainer_inner_types> { using storage_type = std::remove_reference_t; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; using shape_type = SC; using strides_type = get_strides_t; using backstrides_type = get_strides_t; @@ -185,10 +207,12 @@ namespace xt * @tparam L The layout_type of the adaptor. * @tparam SC The type of the containers holding the shape and the strides. * @tparam Tag The expression tag. + * @sa xstrided_container, xcontainer */ template class xarray_adaptor : public xstrided_container>, - public xcontainer_semantic> + public xcontainer_semantic>, + public extension::xarray_adaptor_base_t { public: @@ -197,6 +221,7 @@ namespace xt using self_type = xarray_adaptor; using base_type = xstrided_container; using semantic_base = xcontainer_semantic; + using extension_base = extension::xarray_adaptor_base_t; using storage_type = typename base_type::storage_type; using allocator_type = typename base_type::allocator_type; using shape_type = typename base_type::shape_type; @@ -204,6 +229,7 @@ namespace xt using backstrides_type = typename base_type::backstrides_type; using temporary_type = typename semantic_base::temporary_type; using expression_tag = Tag; + static constexpr std::size_t rank = SIZE_MAX; xarray_adaptor(storage_type&& storage); xarray_adaptor(const storage_type& storage); @@ -226,6 +252,9 @@ namespace xt template xarray_adaptor& operator=(const xexpression& e); + template + void reset_buffer(P&& pointer, S&& size); + private: container_closure_type m_storage; @@ -249,7 +278,8 @@ namespace xt */ template inline xarray_container::xarray_container() - : base_type(), m_storage(1, value_type()) + : base_type() + , m_storage(1, value_type()) { } @@ -274,7 +304,11 @@ namespace xt * @param l the layout_type of the xarray_container */ template - inline xarray_container::xarray_container(const shape_type& shape, const_reference value, layout_type l) + inline xarray_container::xarray_container( + const shape_type& shape, + const_reference value, + layout_type l + ) : base_type() { base_type::resize(shape, l); @@ -301,7 +335,11 @@ namespace xt * @param value the value of the elements */ template - inline xarray_container::xarray_container(const shape_type& shape, const strides_type& strides, const_reference value) + inline xarray_container::xarray_container( + const shape_type& shape, + const strides_type& strides, + const_reference value + ) : base_type() { base_type::resize(shape, strides); @@ -329,10 +367,16 @@ namespace xt * @param strides the strides of the xarray_container */ template - inline xarray_container::xarray_container(storage_type&& storage, inner_shape_type&& shape, inner_strides_type&& strides) - : base_type(std::move(shape), std::move(strides)), m_storage(std::move(storage)) + inline xarray_container::xarray_container( + storage_type&& storage, + inner_shape_type&& shape, + inner_strides_type&& strides + ) + : base_type(std::move(shape), std::move(strides)) + , m_storage(std::move(storage)) { } + //@} /** @@ -348,7 +392,8 @@ namespace xt : base_type() { base_type::resize(xt::shape(t)); - L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + constexpr auto tmp = layout_type::row_major; + L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } /** @@ -360,7 +405,8 @@ namespace xt : base_type() { base_type::resize(xt::shape(t)); - L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + constexpr auto tmp = layout_type::row_major; + L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } /** @@ -372,7 +418,8 @@ namespace xt : base_type() { base_type::resize(xt::shape(t)); - L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + constexpr auto tmp = layout_type::row_major; + L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } /** @@ -384,7 +431,8 @@ namespace xt : base_type() { base_type::resize(xt::shape(t)); - L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + constexpr auto tmp = layout_type::row_major; + L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } /** @@ -396,8 +444,10 @@ namespace xt : base_type() { base_type::resize(xt::shape(t)); - L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + constexpr auto tmp = layout_type::row_major; + L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } + //@} /** @@ -408,24 +458,27 @@ namespace xt template inline xarray_container xarray_container::from_shape(S&& s) { - shape_type shape = xtl::forward_sequence(s); + shape_type shape = xtl::forward_sequence(s); return self_type(shape); } template template inline xarray_container::xarray_container(xtensor_container&& rhs) - : base_type(inner_shape_type(rhs.shape().cbegin(), rhs.shape().cend()), - inner_strides_type(rhs.strides().cbegin(), rhs.strides().cend()), - inner_backstrides_type(rhs.backstrides().cbegin(), rhs.backstrides().cend()), - std::move(rhs.layout())), - m_storage(std::move(rhs.storage())) + : base_type( + inner_shape_type(rhs.shape().cbegin(), rhs.shape().cend()), + inner_strides_type(rhs.strides().cbegin(), rhs.strides().cend()), + inner_backstrides_type(rhs.backstrides().cbegin(), rhs.backstrides().cend()), + std::move(rhs.layout()) + ) + , m_storage(std::move(rhs.storage())) { } template template - inline xarray_container& xarray_container::operator=(xtensor_container&& rhs) + inline xarray_container& + xarray_container::operator=(xtensor_container&& rhs) { this->shape_impl().assign(rhs.shape().cbegin(), rhs.shape().cend()); this->strides_impl().assign(rhs.strides().cbegin(), rhs.strides().cend()); @@ -465,6 +518,7 @@ namespace xt { return semantic_base::operator=(e); } + //@} template @@ -493,7 +547,8 @@ namespace xt */ template inline xarray_adaptor::xarray_adaptor(storage_type&& storage) - : base_type(), m_storage(std::move(storage)) + : base_type() + , m_storage(std::move(storage)) { } @@ -503,7 +558,8 @@ namespace xt */ template inline xarray_adaptor::xarray_adaptor(const storage_type& storage) - : base_type(), m_storage(storage) + : base_type() + , m_storage(storage) { } @@ -517,7 +573,8 @@ namespace xt template template inline xarray_adaptor::xarray_adaptor(D&& storage, const shape_type& shape, layout_type l) - : base_type(), m_storage(std::forward(storage)) + : base_type() + , m_storage(std::forward(storage)) { base_type::resize(shape, l); } @@ -531,11 +588,17 @@ namespace xt */ template template - inline xarray_adaptor::xarray_adaptor(D&& storage, const shape_type& shape, const strides_type& strides) - : base_type(), m_storage(std::forward(storage)) + inline xarray_adaptor::xarray_adaptor( + D&& storage, + const shape_type& shape, + const strides_type& strides + ) + : base_type() + , m_storage(std::forward(storage)) { base_type::resize(shape, strides); } + //@} template @@ -577,6 +640,7 @@ namespace xt { return semantic_base::operator=(e); } + //@} template @@ -590,6 +654,13 @@ namespace xt { return m_storage; } + + template + template + inline void xarray_adaptor::reset_buffer(P&& pointer, S&& size) + { + return m_storage.reset_data(std::forward

(data)) + , m_size(size) + { + } + + template + inline auto xbuffer_storage::size() const noexcept -> size_type + { + return m_size; + } + + template + inline void xbuffer_storage::resize(size_type size) + { + if (size != m_size) + { + XTENSOR_THROW(std::runtime_error, "xbuffer_storage not resizable"); + } + } + + template + inline auto xbuffer_storage::data() noexcept -> pointer + { + return p_data; + } + + template + inline auto xbuffer_storage::data() const noexcept -> const_pointer + { + return p_data; + } + + template + inline void xbuffer_storage::swap(self_type& rhs) noexcept + { + using std::swap; + swap(p_data, rhs.p_data); + swap(m_size, rhs.m_size); + } + + template + template + inline void xbuffer_storage::reset_data(P&& data, size_type size) noexcept + { + p_data = std::forward

(data); + m_size = size; + } + } + + /**************************************** + * xbuffer_owner_storage implementation * + ****************************************/ + + namespace detail + { + template + template + inline xbuffer_owner_storage::xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc) + : m_data(std::forward

(data)) + , m_size(size) + , m_moved_from(false) + , m_allocator(alloc) + { + } + + template + inline xbuffer_owner_storage::~xbuffer_owner_storage() + { + if (!m_moved_from) + { + safe_destroy_deallocate(m_allocator, m_data.get(), m_size); + m_size = 0; + } + } + + template + inline auto xbuffer_owner_storage::operator=(const self_type& rhs) -> self_type& + { + using std::swap; + if (this != &rhs) + { + allocator_type al = std::allocator_traits::select_on_container_copy_construction( + rhs.get_allocator() + ); + pointer tmp = safe_init_allocate(al, rhs.m_size); + if (std::is_trivially_default_constructible::value) + { + std::uninitialized_copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp); + } + else + { + std::copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp); + } + swap(m_data.get(), tmp); + swap(m_allocator, al); + safe_destroy_deallocate(al, tmp, m_size); + m_size = rhs.m_size; + } + return *this; + } + + template + inline xbuffer_owner_storage::xbuffer_owner_storage(self_type&& rhs) + : m_data(std::move(rhs.m_data)) + , m_size(std::move(rhs.m_size)) + , m_moved_from(std::move(rhs.m_moved_from)) + , m_allocator(std::move(rhs.m_allocator)) + { + rhs.m_moved_from = true; + rhs.m_size = 0; + } + + template + inline auto xbuffer_owner_storage::operator=(self_type&& rhs) -> self_type& + { + swap(rhs); + return *this; + } + + template + inline auto xbuffer_owner_storage::size() const noexcept -> size_type + { + return m_size; + } + + template + void xbuffer_owner_storage::resize(size_type size) + { + using std::swap; + if (size != m_size) + { + pointer tmp = safe_init_allocate(m_allocator, size); + swap(m_data.get(), tmp); + swap(m_size, size); + safe_destroy_deallocate(m_allocator, tmp, size); + } + } + + template + inline auto xbuffer_owner_storage::data() noexcept -> pointer + { + return m_data.get(); + } + + template + inline auto xbuffer_owner_storage::data() const noexcept -> const_pointer + { + return m_data.get(); + } + + template + inline auto xbuffer_owner_storage::get_allocator() const noexcept -> allocator_type + { + return allocator_type(m_allocator); + } + + template + inline void xbuffer_owner_storage::swap(self_type& rhs) noexcept + { + using std::swap; + swap(m_data, rhs.m_data); + swap(m_size, rhs.m_size); + swap(m_allocator, rhs.m_allocator); + } + + template + template + inline void + xbuffer_owner_storage::reset_data(P&& data, size_type size, const allocator_type& alloc) noexcept + { + xbuffer_owner_storage tmp(std::forward

(data), size, alloc); + this->swap(tmp); + } + } + + /**************************************** + * xbuffer_smart_pointer implementation * + ****************************************/ + + namespace detail + { + template + template + xbuffer_smart_pointer::xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct) + : p_data(data_ptr) + , m_size(size) + , m_destruct(std::forward

(destruct)) + { + } + + template + auto xbuffer_smart_pointer::size() const noexcept -> size_type + { + return m_size; + } + + template + void xbuffer_smart_pointer::resize(size_type size) + { + if (m_size != size) + { + XTENSOR_THROW(std::runtime_error, "xbuffer_storage not resizeable"); + } + } + + template + auto xbuffer_smart_pointer::data() noexcept -> pointer + { + return p_data; + } + + template + auto xbuffer_smart_pointer::data() const noexcept -> const_pointer + { + return p_data; + } + + template + void xbuffer_smart_pointer::swap(self_type& rhs) noexcept + { + using std::swap; + swap(p_data, rhs.p_data); + swap(m_size, rhs.m_size); + swap(m_destruct, rhs.m_destruct); + } + + template + template + void xbuffer_smart_pointer::reset_data(P&& data, size_type size, DT&& destruct) noexcept + { + p_data = std::forward

(data); + m_size = size; + m_destruct = destruct; + } + } + + /*************************************** + * xbuffer_adaptor_base implementation * + ***************************************/ + + template + inline bool xbuffer_adaptor_base::empty() const noexcept + { + return derived_cast().size() == size_type(0); + } + + template + inline auto xbuffer_adaptor_base::operator[](size_type i) -> reference + { + return derived_cast().data()[static_cast(i)]; + } + + template + inline auto xbuffer_adaptor_base::operator[](size_type i) const -> const_reference + { + return derived_cast().data()[static_cast(i)]; + } + + template + inline auto xbuffer_adaptor_base::front() -> reference + { + return this->operator[](0); + } + + template + inline auto xbuffer_adaptor_base::front() const -> const_reference + { + return this->operator[](0); + } + + template + inline auto xbuffer_adaptor_base::back() -> reference + { + return this->operator[](derived_cast().size() - 1); + } + + template + inline auto xbuffer_adaptor_base::back() const -> const_reference + { + return this->operator[](derived_cast().size() - 1); + } + + template + inline auto xbuffer_adaptor_base::begin() noexcept -> iterator + { + return derived_cast().data(); + } + + template + inline auto xbuffer_adaptor_base::end() noexcept -> iterator + { + return derived_cast().data() + static_cast(derived_cast().size()); + } + + template + inline auto xbuffer_adaptor_base::begin() const noexcept -> const_iterator + { + return derived_cast().data(); + } + + template + inline auto xbuffer_adaptor_base::end() const noexcept -> const_iterator + { + return derived_cast().data() + static_cast(derived_cast().size()); + } + + template + inline auto xbuffer_adaptor_base::cbegin() const noexcept -> const_iterator + { + return begin(); + } + + template + inline auto xbuffer_adaptor_base::cend() const noexcept -> const_iterator + { + return end(); + } + + template + inline auto xbuffer_adaptor_base::rbegin() noexcept -> reverse_iterator + { + return reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor_base::rend() noexcept -> reverse_iterator + { + return reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor_base::rbegin() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor_base::rend() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor_base::crbegin() const noexcept -> const_reverse_iterator + { + return rbegin(); + } + + template + inline auto xbuffer_adaptor_base::crend() const noexcept -> const_reverse_iterator + { + return rend(); + } + + template + inline auto xbuffer_adaptor_base::derived_cast() noexcept -> derived_type& + { + return *static_cast(this); + } + + template + inline auto xbuffer_adaptor_base::derived_cast() const noexcept -> const derived_type& + { + return *static_cast(this); + } + + template + inline bool operator==(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) + { + return lhs.derived_cast().size() == rhs.derived_cast().size() + && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + template + inline bool operator!=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) + { + return !(lhs == rhs); + } + + template + inline bool operator<(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare( + lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end(), + std::less() + ); + } + + template + inline bool operator<=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare( + lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end(), + std::less_equal() + ); + } + + template + inline bool operator>(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare( + lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end(), + std::greater() + ); + } + + template + inline bool operator>=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare( + lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end(), + std::greater_equal() + ); + } + + /********************************** + * xbuffer_adaptor implementation * + **********************************/ + + template + inline auto xbuffer_adaptor::operator=(temporary_type&& tmp) -> self_type& + { + base_type::resize(tmp.size()); + std::copy(tmp.cbegin(), tmp.cend(), this->begin()); + return *this; + } + + template + inline void swap(xbuffer_adaptor& lhs, xbuffer_adaptor& rhs) noexcept + { + lhs.swap(rhs); + } + + /************************************ + * xiterator_adaptor implementation * + ************************************/ + + template + inline xiterator_adaptor::xiterator_adaptor(I it, CI cit, size_type size) + : m_it(it) + , m_cit(cit) + , m_size(size) + { + } + + template + inline auto xiterator_adaptor::operator=(const temporary_type& rhs) -> self_type& + { + resize(rhs.size()); + std::copy(rhs.cbegin(), rhs.cend(), m_it); + return *this; + } + + template + inline auto xiterator_adaptor::operator=(temporary_type&& rhs) -> self_type& + { + return (*this = rhs); + } + + template + inline auto xiterator_adaptor::size() const noexcept -> size_type + { + return m_size; + } + + template + inline void xiterator_adaptor::resize(size_type size) + { + if (m_size != size) + { + XTENSOR_THROW(std::runtime_error, "xiterator_adaptor not resizeable"); + } + } + + template + inline auto xiterator_adaptor::data() noexcept -> iterator + { + return m_it; + } + + template + inline auto xiterator_adaptor::data() const noexcept -> const_iterator + { + return m_cit; + } + + template + inline void xiterator_adaptor::swap(self_type& rhs) noexcept + { + using std::swap; + swap(m_it, rhs.m_it); + swap(m_cit, rhs.m_cit); + swap(m_size, rhs.m_size); + } + + template + inline void swap(xiterator_adaptor& lhs, xiterator_adaptor& rhs) noexcept + { + lhs.swap(rhs); + } + + /****************************************** + * xiterator_owner_adaptor implementation * + ******************************************/ + + template + inline xiterator_owner_adaptor::xiterator_owner_adaptor(C&& c) + : m_container(std::move(c)) + { + init_iterators(); + } + + template + inline xiterator_owner_adaptor::xiterator_owner_adaptor(const self_type& rhs) + : m_container(rhs.m_container) + { + init_iterators(); + } + + template + inline xiterator_owner_adaptor& xiterator_owner_adaptor::operator=(const self_type& rhs) + { + m_container = rhs.m_container; + init_iterators(); + } + + template + inline xiterator_owner_adaptor::xiterator_owner_adaptor(self_type&& rhs) + : m_container(std::move(rhs.m_container)) + { + init_iterators(); + } + + template + inline xiterator_owner_adaptor& xiterator_owner_adaptor::operator=(self_type&& rhs) + { + m_container = std::move(rhs.m_container); + init_iterators(); + } + + template + inline xiterator_owner_adaptor& xiterator_owner_adaptor::operator=(const temporary_type& rhs) + { + resize(rhs.size()); + std::copy(rhs.cbegin(), rhs.cend(), m_it); + return *this; + } + + template + inline xiterator_owner_adaptor& xiterator_owner_adaptor::operator=(temporary_type&& rhs) + { + return (*this = rhs); + } + + template + inline auto xiterator_owner_adaptor::size() const noexcept -> size_type + { + return m_size; + } + + template + inline void xiterator_owner_adaptor::resize(size_type size) + { + if (m_size != size) + { + XTENSOR_THROW(std::runtime_error, "xiterator_owner_adaptor not resizeable"); + } + } + + template + inline auto xiterator_owner_adaptor::data() noexcept -> iterator + { + return m_it; + } + + template + inline auto xiterator_owner_adaptor::data() const noexcept -> const_iterator + { + return m_cit; + } + + template + inline void xiterator_owner_adaptor::swap(self_type& rhs) noexcept + { + using std::swap; + swap(m_container, rhs.m_container); + init_iterators(); + rhs.init_iterators(); + } + + template + inline void xiterator_owner_adaptor::init_iterators() + { + m_it = IG::begin(m_container); + m_cit = IG::cbegin(m_container); + m_size = IG::size(m_container); + } + + template + inline void swap(xiterator_owner_adaptor& lhs, xiterator_owner_adaptor& rhs) noexcept + { + lhs.swap(rhs); + } + + /***************************************** + * make_xiterator_adaptor implementation * + *****************************************/ + + namespace detail + { + template ::value> + struct xiterator_adaptor_builder + { + using iterator = decltype(IG::begin(std::declval())); + using const_iterator = decltype(IG::cbegin(std::declval())); + using type = xiterator_adaptor; + + inline static type build(C& c) + { + return type(IG::begin(c), IG::cbegin(c), IG::size(c)); + } + }; + + template + struct xiterator_adaptor_builder + { + using type = xiterator_owner_adaptor; + + inline static type build(C&& c) + { + return type(std::move(c)); + } + }; + } + + template + inline auto make_xiterator_adaptor(C&& container, IG) + { + using builder_type = detail::xiterator_adaptor_builder; + return builder_type::build(std::forward(container)); + } +} + +#endif diff --git a/include/xtensor/xcontainer.hpp b/include/xtensor/containers/xcontainer.hpp similarity index 65% rename from include/xtensor/xcontainer.hpp rename to include/xtensor/containers/xcontainer.hpp index 91f3e51b8..7f17ffe01 100644 --- a/include/xtensor/xcontainer.hpp +++ b/include/xtensor/containers/xcontainer.hpp @@ -1,28 +1,30 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #ifndef XTENSOR_CONTAINER_HPP #define XTENSOR_CONTAINER_HPP #include -#include -#include +#include #include #include #include -#include "xiterable.hpp" -#include "xiterator.hpp" -#include "xmath.hpp" -#include "xoperation.hpp" -#include "xstrides.hpp" -#include "xtensor_forward.hpp" +#include "../core/xaccessible.hpp" +#include "../core/xiterable.hpp" +#include "../core/xiterator.hpp" +#include "../core/xmath.hpp" +#include "../core/xoperation.hpp" +#include "../core/xstrides.hpp" +#include "../core/xtensor_config.hpp" +#include "../core/xtensor_forward.hpp" namespace xt { @@ -30,7 +32,6 @@ namespace xt struct xcontainer_iterable_types { using inner_shape_type = typename xcontainer_inner_types::inner_shape_type; - using storage_type = typename xcontainer_inner_types::storage_type; using stepper = xstepper; using const_stepper = xstepper; }; @@ -53,7 +54,6 @@ namespace xt template using allocator_type_t = typename detail::allocator_type_impl::type; - /** * @class xcontainer * @brief Base class for dense multidimensional containers. @@ -66,7 +66,8 @@ namespace xt * provides the interface. */ template - class xcontainer : public xcontiguous_iterable + class xcontainer : public xcontiguous_iterable, + private xaccessible { public: @@ -76,15 +77,14 @@ namespace xt using storage_type = typename inner_types::storage_type; using allocator_type = allocator_type_t>; using value_type = typename storage_type::value_type; - using reference = std::conditional_t::value, - typename storage_type::const_reference, - typename storage_type::reference>; - using const_reference = typename storage_type::const_reference; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; using pointer = typename storage_type::pointer; using const_pointer = typename storage_type::const_pointer; - using size_type = typename storage_type::size_type; + using size_type = typename inner_types::size_type; using difference_type = typename storage_type::difference_type; - using simd_value_type = xsimd::simd_type; + using simd_value_type = xt_simd::simd_type; + using bool_load_type = xt::bool_load_type; using shape_type = typename inner_types::shape_type; using strides_type = typename inner_types::strides_type; @@ -98,25 +98,27 @@ namespace xt using stepper = typename iterable_base::stepper; using const_stepper = typename iterable_base::const_stepper; + using accessible_base = xaccessible; + static constexpr layout_type static_layout = inner_types::layout; static constexpr bool contiguous_layout = static_layout != layout_type::dynamic; - using data_alignment = xsimd::container_alignment_t; - using simd_type = xsimd::simd_type; + using data_alignment = xt_simd::container_alignment_t; + using simd_type = xt_simd::simd_type; - using storage_iterator = typename storage_type::iterator; - using const_storage_iterator = typename storage_type::const_iterator; - using reverse_storage_iterator = typename storage_type::reverse_iterator; - using const_reverse_storage_iterator = typename storage_type::const_reverse_iterator; + using linear_iterator = typename iterable_base::linear_iterator; + using const_linear_iterator = typename iterable_base::const_linear_iterator; + using reverse_linear_iterator = typename iterable_base::reverse_linear_iterator; + using const_reverse_linear_iterator = typename iterable_base::const_reverse_linear_iterator; static_assert(static_layout != layout_type::any, "Container layout can never be layout_type::any!"); size_type size() const noexcept; - XTENSOR_CONSTEXPR_RETURN size_type dimension() const noexcept; + constexpr size_type dimension() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides() const noexcept; + constexpr const inner_shape_type& shape() const noexcept; + constexpr const inner_strides_type& strides() const noexcept; + constexpr const inner_backstrides_type& backstrides() const noexcept; template void fill(const T& value); @@ -127,29 +129,19 @@ namespace xt template const_reference operator()(Args... args) const; - template - reference at(Args... args); - - template - const_reference at(Args... args) const; - template reference unchecked(Args... args); template const_reference unchecked(Args... args) const; - template - disable_integral_t operator[](const S& index); - template - reference operator[](std::initializer_list index); - reference operator[](size_type i); - - template - disable_integral_t operator[](const S& index) const; - template - const_reference operator[](std::initializer_list index) const; - const_reference operator[](size_type i) const; + using accessible_base::at; + using accessible_base::shape; + using accessible_base::operator[]; + using accessible_base::back; + using accessible_base::front; + using accessible_base::in_bounds; + using accessible_base::periodic; template reference element(It first, It last); @@ -159,8 +151,8 @@ namespace xt storage_type& storage() noexcept; const storage_type& storage() const noexcept; - value_type* data() noexcept; - const value_type* data() const noexcept; + pointer data() noexcept; + const_pointer data() const noexcept; const size_type data_offset() const noexcept; template @@ -169,7 +161,6 @@ namespace xt template bool has_linear_assign(const S& strides) const noexcept; template - stepper stepper_begin(const S& shape) noexcept; template stepper stepper_end(const S& shape, layout_type l) noexcept; @@ -182,33 +173,36 @@ namespace xt reference data_element(size_type i); const_reference data_element(size_type i) const; + reference flat(size_type i); + const_reference flat(size_type i) const; + template - using simd_return_type = xsimd::simd_return_type; + using simd_return_type = xt_simd::simd_return_type; template void store_simd(size_type i, const simd& e); - template ::size> - simd_return_type load_simd(size_type i) const; + template ::size> + container_simd_return_type_t + /*simd_return_type*/ load_simd(size_type i) const; - storage_iterator storage_begin() noexcept; - storage_iterator storage_end() noexcept; + linear_iterator linear_begin() noexcept; + linear_iterator linear_end() noexcept; - const_storage_iterator storage_begin() const noexcept; - const_storage_iterator storage_end() const noexcept; - const_storage_iterator storage_cbegin() const noexcept; - const_storage_iterator storage_cend() const noexcept; + const_linear_iterator linear_begin() const noexcept; + const_linear_iterator linear_end() const noexcept; + const_linear_iterator linear_cbegin() const noexcept; + const_linear_iterator linear_cend() const noexcept; - reverse_storage_iterator storage_rbegin() noexcept; - reverse_storage_iterator storage_rend() noexcept; + reverse_linear_iterator linear_rbegin() noexcept; + reverse_linear_iterator linear_rend() noexcept; - const_reverse_storage_iterator storage_rbegin() const noexcept; - const_reverse_storage_iterator storage_rend() const noexcept; - const_reverse_storage_iterator storage_crbegin() const noexcept; - const_reverse_storage_iterator storage_crend() const noexcept; + const_reverse_linear_iterator linear_rbegin() const noexcept; + const_reverse_linear_iterator linear_rend() const noexcept; + const_reverse_linear_iterator linear_crbegin() const noexcept; + const_reverse_linear_iterator linear_crend() const noexcept; - using container_iterator = storage_iterator; - using const_container_iterator = const_storage_iterator; + using container_iterator = linear_iterator; + using const_container_iterator = const_linear_iterator; protected: @@ -223,26 +217,29 @@ namespace xt container_iterator data_xbegin() noexcept; const_container_iterator data_xbegin() const noexcept; - container_iterator data_xend(layout_type l) noexcept; - const_container_iterator data_xend(layout_type l) const noexcept; + container_iterator data_xend(layout_type l, size_type offset) noexcept; + const_container_iterator data_xend(layout_type l, size_type offset) const noexcept; protected: derived_type& derived_cast() & noexcept; - const derived_type& derived_cast() const & noexcept; + const derived_type& derived_cast() const& noexcept; derived_type derived_cast() && noexcept; private: - template - friend class xstepper; - template - It data_xend_impl(It end, layout_type l) const noexcept; + It data_xend_impl(It begin, layout_type l, size_type offset) const noexcept; inner_shape_type& mutable_shape(); inner_strides_type& mutable_strides(); inner_backstrides_type& mutable_backstrides(); + + template + friend class xstepper; + + friend class xaccessible; + friend class xconst_accessible; }; /** @@ -284,9 +281,13 @@ namespace xt void resize(S&& shape, const strides_type& strides); template - void reshape(S&& shape, layout_type layout = base_type::static_layout); + auto& reshape(S&& shape, layout_type layout = base_type::static_layout) &; + + template + auto& reshape(std::initializer_list shape, layout_type layout = base_type::static_layout) &; layout_type layout() const noexcept; + bool is_contiguous() const noexcept; protected: @@ -316,10 +317,7 @@ namespace xt template void reshape_impl(S&& shape, std::false_type, layout_type layout = base_type::static_layout); - layout_type& mutable_layout() noexcept - { - return m_layout; - } + layout_type& mutable_layout() noexcept; private: @@ -335,9 +333,9 @@ namespace xt template template - inline It xcontainer::data_xend_impl(It end, layout_type l) const noexcept + inline It xcontainer::data_xend_impl(It begin, layout_type l, size_type offset) const noexcept { - return strided_data_end(*this, end, l); + return strided_data_end(*this, begin, l, offset); } template @@ -375,7 +373,7 @@ namespace xt * Returns the number of dimensions of the container. */ template - XTENSOR_CONSTEXPR_RETURN auto xcontainer::dimension() const noexcept -> size_type + constexpr auto xcontainer::dimension() const noexcept -> size_type { return shape().size(); } @@ -384,7 +382,7 @@ namespace xt * Returns the shape of the container. */ template - XTENSOR_CONSTEXPR_RETURN auto xcontainer::shape() const noexcept -> const inner_shape_type& + constexpr auto xcontainer::shape() const noexcept -> const inner_shape_type& { return derived_cast().shape_impl(); } @@ -393,7 +391,7 @@ namespace xt * Returns the strides of the container. */ template - XTENSOR_CONSTEXPR_RETURN auto xcontainer::strides() const noexcept -> const inner_strides_type& + constexpr auto xcontainer::strides() const noexcept -> const inner_strides_type& { return derived_cast().strides_impl(); } @@ -402,10 +400,11 @@ namespace xt * Returns the backstrides of the container. */ template - XTENSOR_CONSTEXPR_RETURN auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& + constexpr auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& { return derived_cast().backstrides_impl(); } + //@} /** @@ -421,7 +420,14 @@ namespace xt template inline void xcontainer::fill(const T& value) { - std::fill(storage_begin(), storage_end(), value); + if (contiguous_layout) + { + std::fill(this->linear_begin(), this->linear_end(), value); + } + else + { + std::fill(this->begin(), this->end(), value); + } } /** @@ -436,7 +442,7 @@ namespace xt { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); - size_type index = xt::data_offset(strides(), static_cast(args)...); + size_type index = xt::data_offset(strides(), args...); return storage()[index]; } @@ -452,44 +458,10 @@ namespace xt { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); - size_type index = xt::data_offset(strides(), static_cast(args)...); + size_type index = xt::data_offset(strides(), args...); return storage()[index]; } - /** - * Returns a reference to the element at the specified position in the container, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the container. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xcontainer::at(Args... args) -> reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - - /** - * Returns a constant reference to the element at the specified position in the container, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the container. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xcontainer::at(Args... args) const -> const_reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - /** * Returns a reference to the element at the specified position in the container. * @param args a list of indices specifying the position in the container. Indices @@ -498,22 +470,25 @@ namespace xt * * @warning This method is meant for performance, for expressions with a dynamic * number of dimensions (i.e. not known at compile time). Since it may have - * undefined behavior (see parameters), operator() should be prefered whenever + * undefined behavior (see parameters), operator() should be preferred whenever * it is possible. * @warning This method is NOT compatible with broadcasting, meaning the following * code has undefined behavior: - * \code{.cpp} + * @code{.cpp} * xt::xarray a = {{0, 1}, {2, 3}}; * xt::xarray b = {0, 1}; * auto fd = a + b; * double res = fd.uncheked(0, 1); - * \endcode + * @endcode */ template template inline auto xcontainer::unchecked(Args... args) -> reference { - size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + size_type index = xt::unchecked_data_offset( + strides(), + static_cast(args)... + ); return storage()[index]; } @@ -525,79 +500,28 @@ namespace xt * * @warning This method is meant for performance, for expressions with a dynamic * number of dimensions (i.e. not known at compile time). Since it may have - * undefined behavior (see parameters), operator() should be prefered whenever + * undefined behavior (see parameters), operator() should be preferred whenever * it is possible. * @warning This method is NOT compatible with broadcasting, meaning the following * code has undefined behavior: - * \code{.cpp} + * @code{.cpp} * xt::xarray a = {{0, 1}, {2, 3}}; * xt::xarray b = {0, 1}; * auto fd = a + b; * double res = fd.uncheked(0, 1); - * \endcode + * @endcode */ template template inline auto xcontainer::unchecked(Args... args) const -> const_reference { - size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + size_type index = xt::unchecked_data_offset( + strides(), + static_cast(args)... + ); return storage()[index]; } - /** - * Returns a reference to the element at the specified position in the container. - * @param index a sequence of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices in the list should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xcontainer::operator[](const S& index) - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xcontainer::operator[](std::initializer_list index) -> reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xcontainer::operator[](size_type i) -> reference - { - return operator()(i); - } - - /** - * Returns a constant reference to the element at the specified position in the container. - * @param index a sequence of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices in the list should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xcontainer::operator[](const S& index) const - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xcontainer::operator[](std::initializer_list index) const -> const_reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xcontainer::operator[](size_type i) const -> const_reference - { - return operator()(i); - } - /** * Returns a reference to the element at the specified position in the container. * @param first iterator starting the sequence of indices @@ -653,18 +577,18 @@ namespace xt * container is empty (data() is not is not dereferenceable in that case) */ template - inline auto xcontainer::data() noexcept -> value_type* + inline auto xcontainer::data() noexcept -> pointer { return storage().data(); } /** - * Returns a constant pointer to the underlying array serving as element storage. The pointer - * is such that range [data(); data() + size()] is always a valid range, even if the - * container is empty (data() is not is not dereferenceable in that case) - */ + * Returns a constant pointer to the underlying array serving as element storage. The pointer + * is such that range [data(); data() + size()] is always a valid range, even if the + * container is empty (data() is not is not dereferenceable in that case) + */ template - inline auto xcontainer::data() const noexcept -> const value_type* + inline auto xcontainer::data() const noexcept -> const_pointer { return storage().data(); } @@ -677,6 +601,7 @@ namespace xt { return size_type(0); } + //@} /** @@ -705,13 +630,13 @@ namespace xt template inline bool xcontainer::has_linear_assign(const S& str) const noexcept { - return str.size() == strides().size() && - std::equal(str.cbegin(), str.cend(), strides().begin()); + return str.size() == strides().size() && std::equal(str.cbegin(), str.cend(), strides().begin()); } + //@} template - inline auto xcontainer::derived_cast() const & noexcept -> const derived_type& + inline auto xcontainer::derived_cast() const& noexcept -> const derived_type& { return *static_cast(this); } @@ -734,6 +659,32 @@ namespace xt return storage()[i]; } + /** + * Returns a reference to the element at the specified position in the container + * storage (as if it was one dimensional). + * @param i index specifying the position in the storage. + * Must be smaller than the number of elements in the container. + */ + template + inline auto xcontainer::flat(size_type i) -> reference + { + XTENSOR_ASSERT(i < size()); + return storage()[i]; + } + + /** + * Returns a constant reference to the element at the specified position in the container + * storage (as if it was one dimensional). + * @param i index specifying the position in the storage. + * Must be smaller than the number of elements in the container. + */ + template + inline auto xcontainer::flat(size_type i) const -> const_reference + { + XTENSOR_ASSERT(i < size()); + return storage()[i]; + } + /*************** * stepper api * ***************/ @@ -751,7 +702,7 @@ namespace xt inline auto xcontainer::stepper_end(const S& shape, layout_type l) noexcept -> stepper { size_type offset = shape.size() - dimension(); - return stepper(static_cast(this), data_xend(l), offset); + return stepper(static_cast(this), data_xend(l, offset), offset); } template @@ -767,7 +718,7 @@ namespace xt inline auto xcontainer::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper { size_type offset = shape.size() - dimension(); - return const_stepper(static_cast(this), data_xend(l), offset); + return const_stepper(static_cast(this), data_xend(l, offset), offset); } template @@ -779,19 +730,20 @@ namespace xt template inline auto xcontainer::data_xbegin() const noexcept -> const_container_iterator { - return storage().begin(); + return storage().cbegin(); } template - inline auto xcontainer::data_xend(layout_type l) noexcept -> container_iterator + inline auto xcontainer::data_xend(layout_type l, size_type offset) noexcept -> container_iterator { - return data_xend_impl(storage().end(), l); + return data_xend_impl(storage().begin(), l, offset); } template - inline auto xcontainer::data_xend(layout_type l) const noexcept -> const_container_iterator + inline auto xcontainer::data_xend(layout_type l, size_type offset) const noexcept + -> const_container_iterator { - return data_xend_impl(storage().end(), l); + return data_xend_impl(storage().cbegin(), l, offset); } template @@ -799,86 +751,86 @@ namespace xt inline void xcontainer::store_simd(size_type i, const simd& e) { using align_mode = driven_align_mode_t; - xsimd::store_simd(&(storage()[i]), e, align_mode()); + xt_simd::store_as(std::addressof(storage()[i]), e, align_mode()); } template template inline auto xcontainer::load_simd(size_type i) const - -> simd_return_type + -> container_simd_return_type_t { using align_mode = driven_align_mode_t; - return xsimd::load_simd(&(storage()[i]), align_mode()); + return xt_simd::load_as(std::addressof(storage()[i]), align_mode()); } template - inline auto xcontainer::storage_begin() noexcept -> storage_iterator + inline auto xcontainer::linear_begin() noexcept -> linear_iterator { return storage().begin(); } template - inline auto xcontainer::storage_end() noexcept -> storage_iterator + inline auto xcontainer::linear_end() noexcept -> linear_iterator { return storage().end(); } template - inline auto xcontainer::storage_begin() const noexcept -> const_storage_iterator + inline auto xcontainer::linear_begin() const noexcept -> const_linear_iterator { return storage().begin(); } template - inline auto xcontainer::storage_end() const noexcept -> const_storage_iterator + inline auto xcontainer::linear_end() const noexcept -> const_linear_iterator { return storage().cend(); } template - inline auto xcontainer::storage_cbegin() const noexcept -> const_storage_iterator + inline auto xcontainer::linear_cbegin() const noexcept -> const_linear_iterator { return storage().cbegin(); } template - inline auto xcontainer::storage_cend() const noexcept -> const_storage_iterator + inline auto xcontainer::linear_cend() const noexcept -> const_linear_iterator { return storage().cend(); } template - inline auto xcontainer::storage_rbegin() noexcept -> reverse_storage_iterator + inline auto xcontainer::linear_rbegin() noexcept -> reverse_linear_iterator { return storage().rbegin(); } template - inline auto xcontainer::storage_rend() noexcept -> reverse_storage_iterator + inline auto xcontainer::linear_rend() noexcept -> reverse_linear_iterator { return storage().rend(); } template - inline auto xcontainer::storage_rbegin() const noexcept -> const_reverse_storage_iterator + inline auto xcontainer::linear_rbegin() const noexcept -> const_reverse_linear_iterator { return storage().rbegin(); } template - inline auto xcontainer::storage_rend() const noexcept -> const_reverse_storage_iterator + inline auto xcontainer::linear_rend() const noexcept -> const_reverse_linear_iterator { return storage().rend(); } template - inline auto xcontainer::storage_crbegin() const noexcept -> const_reverse_storage_iterator + inline auto xcontainer::linear_crbegin() const noexcept -> const_reverse_linear_iterator { return storage().crbegin(); } template - inline auto xcontainer::storage_crend() const noexcept -> const_reverse_storage_iterator + inline auto xcontainer::linear_crend() const noexcept -> const_reverse_linear_iterator { return storage().crend(); } @@ -904,15 +856,26 @@ namespace xt template inline xstrided_container::xstrided_container(inner_shape_type&& shape, inner_strides_type&& strides) noexcept - : base_type(), m_shape(std::move(shape)), m_strides(std::move(strides)) + : base_type() + , m_shape(std::move(shape)) + , m_strides(std::move(strides)) { m_backstrides = xtl::make_sequence(m_shape.size(), 0); adapt_strides(m_shape, m_strides, m_backstrides); } template - inline xstrided_container::xstrided_container(inner_shape_type&& shape, inner_strides_type&& strides, inner_backstrides_type&& backstrides, layout_type&& layout) noexcept - : base_type(), m_shape(std::move(shape)), m_strides(std::move(strides)), m_backstrides(std::move(backstrides)), m_layout(std::move(layout)) + inline xstrided_container::xstrided_container( + inner_shape_type&& shape, + inner_strides_type&& strides, + inner_backstrides_type&& backstrides, + layout_type&& layout + ) noexcept + : base_type() + , m_shape(std::move(shape)) + , m_strides(std::move(strides)) + , m_backstrides(std::move(backstrides)) + , m_layout(std::move(layout)) { } @@ -957,11 +920,43 @@ namespace xt * @return layout_type of the container */ template - layout_type xstrided_container::layout() const noexcept + inline layout_type xstrided_container::layout() const noexcept { return m_layout; } + template + inline bool xstrided_container::is_contiguous() const noexcept + { + using str_type = typename inner_strides_type::value_type; + auto is_zero = [](auto i) + { + return i == 0; + }; + if (!is_contiguous_container::value) + { + return false; + } + // We need to make sure the inner-most non-zero stride is one. + // Trailing zero strides are ignored because they indicate bradcasted dimensions. + if (m_layout == layout_type::row_major) + { + auto it = std::find_if_not(m_strides.rbegin(), m_strides.rend(), is_zero); + // If the array has strides of zero, it is a constant, and therefore contiguous. + return it == m_strides.rend() || *it == str_type(1); + } + else if (m_layout == layout_type::column_major) + { + auto it = std::find_if_not(m_strides.begin(), m_strides.end(), is_zero); + // If the array has strides of zero, it is a constant, and therefore contiguous. + return it == m_strides.end() || *it == str_type(1); + } + else + { + return m_strides.empty(); + } + } + namespace detail { template @@ -977,10 +972,24 @@ namespace xt (void) size; XTENSOR_ASSERT_MSG(c.size() == size, "Trying to resize const data container with wrong size."); } + + template + constexpr bool check_resize_dimension(const S&, const T&) + { + return true; + } + + template + constexpr bool check_resize_dimension(const std::array&, const S& s) + { + return N == s.size(); + } } /** - * resizes the container. + * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param force force reshaping, even if the shape stays the same (default: false) */ @@ -988,14 +997,20 @@ namespace xt template inline void xstrided_container::resize(S&& shape, bool force) { + XTENSOR_PRECONDITION( + detail::check_resize_dimension(m_shape, shape), + "cannot change the number of dimensions of xtensor" + ); std::size_t dim = shape.size(); - if (m_shape.size() != dim || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force) + if (m_shape.size() != dim || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) + || force) { if (D::static_layout == layout_type::dynamic && m_layout == layout_type::dynamic) { m_layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout } - m_shape = xtl::forward_sequence(shape); + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, dim); resize_container(m_backstrides, dim); size_type data_size = compute_strides(m_shape, m_layout, m_strides, m_backstrides); @@ -1004,7 +1019,9 @@ namespace xt } /** - * resizes the container. + * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param l the new layout_type */ @@ -1012,9 +1029,16 @@ namespace xt template inline void xstrided_container::resize(S&& shape, layout_type l) { + XTENSOR_ASSERT_MSG( + detail::check_resize_dimension(m_shape, shape), + "cannot change the number of dimensions of xtensor" + ) if (base_type::static_layout != layout_type::dynamic && l != base_type::static_layout) { - throw std::runtime_error("Cannot change layout_type if template parameter not layout_type::dynamic."); + XTENSOR_THROW( + std::runtime_error, + "Cannot change layout_type if template parameter not layout_type::dynamic." + ); } m_layout = l; resize(std::forward(shape), true); @@ -1022,6 +1046,8 @@ namespace xt /** * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param strides the new strides */ @@ -1029,11 +1055,18 @@ namespace xt template inline void xstrided_container::resize(S&& shape, const strides_type& strides) { + XTENSOR_ASSERT_MSG( + detail::check_resize_dimension(m_shape, shape), + "cannot change the number of dimensions of xtensor" + ) if (base_type::static_layout != layout_type::dynamic) { - throw std::runtime_error("Cannot resize with custom strides when layout() is != layout_type::dynamic."); + XTENSOR_THROW( + std::runtime_error, + "Cannot resize with custom strides when layout() is != layout_type::dynamic." + ); } - m_shape = xtl::forward_sequence(shape); + m_shape = xtl::forward_sequence(shape); m_strides = strides; resize_container(m_backstrides, m_strides.size()); adapt_strides(m_shape, m_strides, m_backstrides); @@ -1042,24 +1075,52 @@ namespace xt } /** - * Reshapes the container and keeps old elements + * Reshapes the container and keeps old elements. The `shape` argument can have one of its value + * equal to `-1`, in this case the value is inferred from the number of elements in the container + * and the remaining values in the `shape`. + * @code{.cpp} + * xt::xarray a = { 1, 2, 3, 4, 5, 6, 7, 8 }; + * a.reshape({-1, 4}); + * //a.shape() is {2, 4} + * @endcode * @param shape the new shape (has to have same number of elements as the original container) * @param layout the layout to compute the strides (defaults to static layout of the container, * or for a container with dynamic layout to XTENSOR_DEFAULT_LAYOUT) */ template template - inline void xstrided_container::reshape(S&& shape, layout_type layout){ - reshape_impl(std::forward(shape), std::is_signed::value_type>>(), std::forward(layout)); + inline auto& xstrided_container::reshape(S&& shape, layout_type layout) & + { + reshape_impl( + std::forward(shape), + xtl::is_signed::value_type>>(), + std::forward(layout) + ); + return this->derived_cast(); + } + + template + template + inline auto& xstrided_container::reshape(std::initializer_list shape, layout_type layout) & + { + using sh_type = rebind_container_t; + sh_type sh = xtl::make_sequence(shape.size()); + std::copy(shape.begin(), shape.end(), sh.begin()); + reshape_impl(std::move(sh), xtl::is_signed(), std::forward(layout)); + return this->derived_cast(); } template template - inline void xstrided_container::reshape_impl(S&& shape, std::false_type /* is unsigned */, layout_type layout) + inline void + xstrided_container::reshape_impl(S&& shape, std::false_type /* is unsigned */, layout_type layout) { if (compute_size(shape) != this->size()) { - throw std::runtime_error("Cannot reshape with incorrect number of elements. Do you mean to resize?"); + XTENSOR_THROW( + std::runtime_error, + "Cannot reshape with incorrect number of elements. Do you mean to resize?" + ); } if (D::static_layout == layout_type::dynamic && layout == layout_type::dynamic) { @@ -1067,47 +1128,63 @@ namespace xt } if (D::static_layout != layout_type::dynamic && layout != D::static_layout) { - throw std::runtime_error("Cannot reshape with different layout if static layout != dynamic."); + XTENSOR_THROW(std::runtime_error, "Cannot reshape with different layout if static layout != dynamic."); } m_layout = layout; - m_shape = xtl::forward_sequence(shape); + m_shape = xtl::forward_sequence(shape); resize_container(m_strides, m_shape.size()); resize_container(m_backstrides, m_shape.size()); compute_strides(m_shape, m_layout, m_strides, m_backstrides); } + template template - inline void xstrided_container::reshape_impl(S&& _shape, std::true_type /* is signed */, layout_type layout) + inline void + xstrided_container::reshape_impl(S&& _shape, std::true_type /* is signed */, layout_type layout) { - using value_type = typename std::decay_t::value_type; - if (this->size() % compute_size(_shape)) + using tmp_value_type = typename std::decay_t::value_type; + auto new_size = compute_size(_shape); + if (this->size() % new_size) { - throw std::runtime_error("Negative axis size cannot be inferred. Shape mismatch."); + XTENSOR_THROW(std::runtime_error, "Negative axis size cannot be inferred. Shape mismatch."); } - std::decay_t shape = _shape; - value_type accumulator = 1; + std::decay_t shape = _shape; + tmp_value_type accumulator = 1; std::size_t neg_idx = 0; std::size_t i = 0; - for(auto it = shape.begin(); it != shape.end(); ++it, i++) + for (auto it = shape.begin(); it != shape.end(); ++it, i++) { auto&& dim = *it; - if(dim < 0) + if (dim < 0) { XTENSOR_ASSERT(dim == -1 && !neg_idx); neg_idx = i; } accumulator *= dim; } - if(accumulator < 0) + if (accumulator < 0) + { + shape[neg_idx] = static_cast(this->size()) / std::abs(accumulator); + } + else if (this->size() != new_size) { - shape[neg_idx] = static_cast(this->size()) / std::abs(accumulator); + XTENSOR_THROW( + std::runtime_error, + "Cannot reshape with incorrect number of elements. Do you mean to resize?" + ); } m_layout = layout; - m_shape = xtl::forward_sequence(shape); + m_shape = xtl::forward_sequence(shape); resize_container(m_strides, m_shape.size()); resize_container(m_backstrides, m_shape.size()); compute_strides(m_shape, m_layout, m_strides, m_backstrides); } + + template + inline auto xstrided_container::mutable_layout() noexcept -> layout_type& + { + return m_layout; + } } #endif diff --git a/include/xtensor/xfixed.hpp b/include/xtensor/containers/xfixed.hpp similarity index 56% rename from include/xtensor/xfixed.hpp rename to include/xtensor/containers/xfixed.hpp index 89e5eed26..e1b02867d 100644 --- a/include/xtensor/xfixed.hpp +++ b/include/xtensor/containers/xfixed.hpp @@ -1,10 +1,11 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #ifndef XTENSOR_FIXED_HPP #define XTENSOR_FIXED_HPP @@ -13,12 +14,14 @@ #include #include #include -#include -#include "xcontainer.hpp" -#include "xstrides.hpp" -#include "xstorage.hpp" -#include "xsemantic.hpp" +#include + +#include "../containers/xcontainer.hpp" +#include "../containers/xstorage.hpp" +#include "../core/xsemantic.hpp" +#include "../core/xstrides.hpp" +#include "../core/xtensor_config.hpp" namespace xtl { @@ -46,13 +49,13 @@ namespace xt * xfixed declaration * **********************/ - template + template class xfixed_container; namespace detail { /************************************************************************************** - The following is something we can currently only dream about -- for when we drop + The following is something we can currently only dream about -- for when we drop support for a lot of the old compilers (e.g. GCC 4.9, MSVC 2017 ;) template @@ -95,39 +98,66 @@ namespace xt template struct calculate_stride { - constexpr static std::ptrdiff_t value = Y * calculate_stride::value; + static constexpr std::ptrdiff_t value = Y + * calculate_stride::value; }; template struct calculate_stride { - constexpr static std::ptrdiff_t value = 1; + static constexpr std::ptrdiff_t value = 1; }; template struct calculate_stride_row_major { - constexpr static std::ptrdiff_t value = at::value * calculate_stride_row_major::value; + static constexpr std::ptrdiff_t value = at::value + * calculate_stride_row_major::value; }; template struct calculate_stride_row_major<0, X...> { - constexpr static std::ptrdiff_t value = 1; + static constexpr std::ptrdiff_t value = 1; }; template struct calculate_stride { - constexpr static std::ptrdiff_t value = calculate_stride_row_major::value; + static constexpr std::ptrdiff_t value = calculate_stride_row_major::value; }; + namespace workaround + { + template + struct computed_strides; + + template + struct computed_strides> + { + static constexpr std::ptrdiff_t value = calculate_stride::value; + }; + + template + constexpr std::ptrdiff_t get_computed_strides(bool cond) + { + return cond ? 0 : computed_strides::value; + } + } + template constexpr R get_strides_impl(const xt::fixed_shape& shape, std::index_sequence) { - static_assert((L == layout_type::row_major) || (L == layout_type::column_major), - "Layout not supported for fixed array"); + static_assert( + (L == layout_type::row_major) || (L == layout_type::column_major), + "Layout not supported for fixed array" + ); +#if (_MSC_VER >= 1910) + using temp_type = std::index_sequence; + return R({workaround::get_computed_strides(shape[I] == 1)...}); +#else return R({shape[I] == 1 ? 0 : calculate_stride::value...}); +#endif } template @@ -142,20 +172,20 @@ namespace xt template struct fixed_compute_size_impl { - constexpr static std::size_t value = Y * fixed_compute_size_impl::value; + static constexpr std::size_t value = Y * fixed_compute_size_impl::value; }; template struct fixed_compute_size_impl { - constexpr static std::size_t value = X; + static constexpr std::size_t value = X; }; template <> struct fixed_compute_size_impl<> { // support for 0D xtensor fixed (empty shape = xshape<>) - constexpr static std::size_t value = 1; + static constexpr std::size_t value = 1; }; // TODO unify with constexpr compute_size when dropping MSVC 2015 @@ -165,7 +195,7 @@ namespace xt template struct fixed_compute_size> { - constexpr static std::size_t value = fixed_compute_size_impl::value; + static constexpr std::size_t value = fixed_compute_size_impl::value; }; template @@ -200,8 +230,7 @@ namespace xt template constexpr T get_backstrides(const S& shape, const T& strides) noexcept { - return detail::get_backstrides_impl(shape, strides, - std::make_index_sequence::value>{}); + return detail::get_backstrides_impl(shape, strides, std::make_index_sequence::value>{}); } template @@ -216,8 +245,8 @@ namespace xt template using get_init_type_t = typename get_init_type::type; - template - struct xcontainer_inner_types> + template + struct xcontainer_inner_types> { using shape_type = S; using inner_shape_type = typename S::cast_type; @@ -227,20 +256,18 @@ namespace xt using inner_backstrides_type = backstrides_type; // NOTE: 0D (S::size() == 0) results in storage for 1 element (scalar) - #if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(_WIN64) - // WORKAROUND FOR MSVC 2015 32 bit, fallback to unaligned container for 0D scalar case - using storage_type = std::array::value>; - #else using storage_type = aligned_array::value>; - #endif - using temporary_type = xfixed_container; + using reference = typename storage_type::reference; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; + using temporary_type = xfixed_container; static constexpr layout_type layout = L; }; - template - struct xiterable_inner_types> - : xcontainer_iterable_types> + template + struct xiterable_inner_types> + : xcontainer_iterable_types> { }; @@ -253,18 +280,19 @@ namespace xt * with tensor semantic and fixed dimension * * @tparam ET The type of the elements. - * @tparam S The xshape template paramter of the container. + * @tparam S The xshape template paramter of the container. * @tparam L The layout_type of the tensor. + * @tparam SH Wether the tensor can be used as a shared expression. * @tparam Tag The expression tag. * @sa xtensor_fixed */ - template - class xfixed_container : public xcontainer>, - public xcontainer_semantic> + template + class xfixed_container : public xcontainer>, + public xcontainer_semantic> { public: - using self_type = xfixed_container; + using self_type = xfixed_container; using base_type = xcontainer; using semantic_base = xcontainer_semantic; @@ -283,16 +311,17 @@ namespace xt using temporary_type = typename semantic_base::temporary_type; using expression_tag = Tag; - constexpr static std::size_t N = std::tuple_size::value; + static constexpr std::size_t N = std::tuple_size::value; + static constexpr std::size_t rank = N; xfixed_container() = default; xfixed_container(const value_type& v); explicit xfixed_container(const inner_shape_type& shape, layout_type l = L); explicit xfixed_container(const inner_shape_type& shape, value_type v, layout_type l = L); - // remove this enable_if when removing the other value_type constructor - template , class EN = std::enable_if_t> - xfixed_container(nested_initializer_list_t t); + template > + xfixed_container(nested_initializer_list_t t) + requires(IX::value != 0); ~xfixed_container() = default; @@ -319,12 +348,13 @@ namespace xt void resize(ST&& shape, const strides_type& strides) const; template > - void reshape(ST&& shape, layout_type layout = L) const; + const auto& reshape(ST&& shape, layout_type layout = L) const; template bool broadcast_shape(ST& s, bool reuse_cache = false) const; constexpr layout_type layout() const noexcept; + bool is_contiguous() const noexcept; private: @@ -332,54 +362,46 @@ namespace xt XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S(); XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides(S()); - XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type m_backstrides = get_backstrides(m_shape, m_strides); + XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type + m_backstrides = get_backstrides(m_shape, m_strides); storage_type& storage_impl() noexcept; const storage_type& storage_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept; + constexpr const inner_shape_type& shape_impl() const noexcept; + constexpr const inner_strides_type& strides_impl() const noexcept; + constexpr const inner_backstrides_type& backstrides_impl() const noexcept; - friend class xcontainer>; + friend class xcontainer>; }; -#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED - // Out of line definitions to prevent linker errors prior to C++17 - template - constexpr typename xfixed_container::inner_shape_type xfixed_container::m_shape; - - template - constexpr typename xfixed_container::inner_strides_type xfixed_container::m_strides; - - template - constexpr typename xfixed_container::inner_backstrides_type xfixed_container::m_backstrides; -#endif - /**************************************** * xfixed_container_adaptor declaration * ****************************************/ - template + template class xfixed_adaptor; - template - struct xcontainer_inner_types> + template + struct xcontainer_inner_types> { using storage_type = std::remove_reference_t; + using reference = typename storage_type::reference; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; using shape_type = S; using inner_shape_type = typename S::cast_type; using strides_type = get_strides_t; using backstrides_type = strides_type; using inner_strides_type = strides_type; using inner_backstrides_type = backstrides_type; - using temporary_type = xfixed_container; + using temporary_type = xfixed_container; static constexpr layout_type layout = L; }; - template - struct xiterable_inner_types> - : xcontainer_iterable_types> + template + struct xiterable_inner_types> + : xcontainer_iterable_types> { }; @@ -396,17 +418,18 @@ namespace xt * @tparam EC The closure for the container type to adapt. * @tparam S The xshape template parameter for the fixed shape of the adaptor * @tparam L The layout_type of the adaptor. + * @tparam SH Wether the adaptor can be used as a shared expression. * @tparam Tag The expression tag. */ - template - class xfixed_adaptor : public xcontainer>, - public xcontainer_semantic> + template + class xfixed_adaptor : public xcontainer>, + public xcontainer_semantic> { public: using container_closure_type = EC; - using self_type = xfixed_adaptor; + using self_type = xfixed_adaptor; using base_type = xcontainer; using semantic_base = xcontainer_semantic; using storage_type = typename base_type::storage_type; @@ -419,7 +442,7 @@ namespace xt using temporary_type = typename semantic_base::temporary_type; using expression_tag = Tag; - constexpr static std::size_t N = S::size(); + static constexpr std::size_t N = S::size(); xfixed_adaptor(storage_type&& data); xfixed_adaptor(const storage_type& data); @@ -447,12 +470,13 @@ namespace xt void resize(ST&& shape, const strides_type& strides) const; template > - void reshape(ST&& shape, layout_type layout = L) const; + const auto& reshape(ST&& shape, layout_type layout = L) const; template bool broadcast_shape(ST& s, bool reuse_cache = false) const; constexpr layout_type layout() const noexcept; + bool is_contiguous() const noexcept; private: @@ -460,30 +484,19 @@ namespace xt XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S(); XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides(S()); - XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type m_backstrides = get_backstrides(m_shape, m_strides); + XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type + m_backstrides = get_backstrides(m_shape, m_strides); storage_type& storage_impl() noexcept; const storage_type& storage_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept; + constexpr const inner_shape_type& shape_impl() const noexcept; + constexpr const inner_strides_type& strides_impl() const noexcept; + constexpr const inner_backstrides_type& backstrides_impl() const noexcept; - friend class xcontainer>; + friend class xcontainer>; }; -#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED - // Out of line definitions to prevent linker errors prior to C++17 - template - constexpr typename xfixed_adaptor::inner_shape_type xfixed_adaptor::m_shape; - - template - constexpr typename xfixed_adaptor::inner_strides_type xfixed_adaptor::m_strides; - - template - constexpr typename xfixed_adaptor::inner_backstrides_type xfixed_adaptor::m_backstrides; -#endif - /************************************ * xfixed_container implementation * ************************************/ @@ -495,45 +508,49 @@ namespace xt /** * Create an uninitialized xfixed_container. - * Note this function is only provided for homogenity, and the shape & layout argument is + * Note this function is only provided for homogeneity, and the shape & layout argument is * disregarded (the template shape is always used). * * @param shape the shape of the xfixed_container (unused!) * @param l the layout_type of the xfixed_container (unused!) */ - template - inline xfixed_container::xfixed_container(const inner_shape_type& shape, layout_type l) + template + inline xfixed_container::xfixed_container(const inner_shape_type& shape, layout_type l) { - (void)(shape); - (void)(l); + (void) (shape); + (void) (l); XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), m_shape.begin())); XTENSOR_ASSERT(L == l); } - template - inline xfixed_container::xfixed_container(const value_type& v) + template + inline xfixed_container::xfixed_container(const value_type& v) { if (this->size() != 1) { - throw std::runtime_error("wrong shape for scalar assignment (has to be xshape<>)."); + XTENSOR_THROW(std::runtime_error, "wrong shape for scalar assignment (has to be xshape<>)."); } m_storage[0] = v; } /** * Create an xfixed_container, and initialize with the value of v. - * Note, the shape argument to this function is only provided for homogenity, + * Note, the shape argument to this function is only provided for homogeneity, * and the shape argument is disregarded (the template shape is always used). * * @param shape the shape of the xfixed_container (unused!) * @param v the fill value * @param l the layout_type of the xfixed_container (unused!) */ - template - inline xfixed_container::xfixed_container(const inner_shape_type& shape, value_type v, layout_type l) - { - (void)(shape); - (void)(l); + template + inline xfixed_container::xfixed_container( + const inner_shape_type& shape, + value_type v, + layout_type l + ) + { + (void) (shape); + (void) (l); XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), m_shape.begin())); XTENSOR_ASSERT(L == l); std::fill(m_storage.begin(), m_storage.end(), v); @@ -568,9 +585,9 @@ namespace xt }; } - template + template template - inline xfixed_container xfixed_container::from_shape(ST&& shape) + inline xfixed_container xfixed_container::from_shape(ST&& shape) { (void) shape; self_type tmp; @@ -580,18 +597,24 @@ namespace xt /** * Allocates an xfixed_container with shape S with values from a C array. - * The type returned by get_init_type_t is raw C array ``value_type[X][Y][Z]`` for ``xt::xshape``. - * C arrays can be initialized with the initializer list syntax, but the size is checked at compile - * time to prevent errors. + * The type returned by get_init_type_t is raw C array ``value_type[X][Y][Z]`` for + * ``xt::xshape``. C arrays can be initialized with the initializer list syntax, + * but the size is checked at compile time to prevent errors. * Note: for clang < 3.8 this is an initializer_list and the size is not checked at compile-or runtime. */ - template - template - inline xfixed_container::xfixed_container(nested_initializer_list_t t) + template + template + inline xfixed_container::xfixed_container(nested_initializer_list_t t) + requires(IX::value != 0) { - XTENSOR_ASSERT_MSG(detail::check_initializer_list_shape::run(t, this->shape()) == true, "initializer list shape does not match fixed shape"); - L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + XTENSOR_ASSERT_MSG( + detail::check_initializer_list_shape::run(t, this->shape()) == true, + "initializer list shape does not match fixed shape" + ); + constexpr auto tmp = layout_type::row_major; + L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } + //@} /** @@ -601,9 +624,9 @@ namespace xt /** * The extended copy constructor. */ - template + template template - inline xfixed_container::xfixed_container(const xexpression& e) + inline xfixed_container::xfixed_container(const xexpression& e) { semantic_base::assign(e); } @@ -611,23 +634,24 @@ namespace xt /** * The extended assignment operator. */ - template + template template - inline auto xfixed_container::operator=(const xexpression& e) -> self_type& + inline auto xfixed_container::operator=(const xexpression& e) -> self_type& { return semantic_base::operator=(e); } + //@} /** * Note that the xfixed_container **cannot** be resized. Attempting to resize with a different * size throws an assert in debug mode. */ - template + template template - inline void xfixed_container::resize(ST&& shape, bool) const + inline void xfixed_container::resize(ST&& shape, bool) const { - (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined + (void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()); } @@ -635,81 +659,97 @@ namespace xt * Note that the xfixed_container **cannot** be resized. Attempting to resize with a different * size throws an assert in debug mode. */ - template + template template - inline void xfixed_container::resize(ST&& shape, layout_type l) const + inline void xfixed_container::resize(ST&& shape, layout_type l) const { - (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined - (void)(l); - XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && L == l); + (void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined + (void) (l); + XTENSOR_ASSERT( + std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && L == l + ); } /** * Note that the xfixed_container **cannot** be resized. Attempting to resize with a different * size throws an assert in debug mode. */ - template + template template - inline void xfixed_container::resize(ST&& shape, const strides_type& strides) const + inline void xfixed_container::resize(ST&& shape, const strides_type& strides) const { - (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined - (void)(strides); + (void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined + (void) (strides); XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()); - XTENSOR_ASSERT(std::equal(strides.begin(), strides.end(), m_strides.begin()) && strides.size() == m_strides.size()); + XTENSOR_ASSERT( + std::equal(strides.begin(), strides.end(), m_strides.begin()) && strides.size() == m_strides.size() + ); } /** * Note that the xfixed_container **cannot** be reshaped to a shape different from ``S``. */ - template + template template - inline void xfixed_container::reshape(ST&& shape, layout_type layout) const + inline const auto& xfixed_container::reshape(ST&& shape, layout_type layout) const { - if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && layout == L)) + if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() + && layout == L)) { - throw std::runtime_error("Trying to reshape xtensor_fixed with different shape or layout."); + XTENSOR_THROW(std::runtime_error, "Trying to reshape xtensor_fixed with different shape or layout."); } + return *this; } - template + template template - inline bool xfixed_container::broadcast_shape(ST& shape, bool) const + inline bool xfixed_container::broadcast_shape(ST& shape, bool) const { return xt::broadcast_shape(m_shape, shape); } - template - constexpr layout_type xfixed_container::layout() const noexcept + template + constexpr layout_type xfixed_container::layout() const noexcept { return base_type::static_layout; } - template - inline auto xfixed_container::storage_impl() noexcept -> storage_type& + template + inline bool xfixed_container::is_contiguous() const noexcept + { + using str_type = typename inner_strides_type::value_type; + return m_strides.empty() || (layout() == layout_type::row_major && m_strides.back() == str_type(1)) + || (layout() == layout_type::column_major && m_strides.front() == str_type(1)); + } + + template + inline auto xfixed_container::storage_impl() noexcept -> storage_type& { return m_storage; } - template - inline auto xfixed_container::storage_impl() const noexcept -> const storage_type& + template + inline auto xfixed_container::storage_impl() const noexcept -> const storage_type& { return m_storage; } - template - XTENSOR_CONSTEXPR_RETURN auto xfixed_container::shape_impl() const noexcept -> const inner_shape_type& + template + constexpr auto xfixed_container::shape_impl() const noexcept -> const inner_shape_type& { return m_shape; } - template - XTENSOR_CONSTEXPR_RETURN auto xfixed_container::strides_impl() const noexcept -> const inner_strides_type& + template + constexpr auto xfixed_container::strides_impl() const noexcept + -> const inner_strides_type& { return m_strides; } - template - XTENSOR_CONSTEXPR_RETURN auto xfixed_container::backstrides_impl() const noexcept -> const inner_backstrides_type& + template + constexpr auto xfixed_container::backstrides_impl() const noexcept + -> const inner_backstrides_type& { return m_backstrides; } @@ -726,9 +766,10 @@ namespace xt * Constructs an xfixed_adaptor of the given stl-like container. * @param data the container to adapt */ - template - inline xfixed_adaptor::xfixed_adaptor(storage_type&& data) - : base_type(), m_storage(std::move(data)) + template + inline xfixed_adaptor::xfixed_adaptor(storage_type&& data) + : base_type() + , m_storage(std::move(data)) { } @@ -736,9 +777,10 @@ namespace xt * Constructs an xfixed_adaptor of the given stl-like container. * @param data the container to adapt */ - template - inline xfixed_adaptor::xfixed_adaptor(const storage_type& data) - : base_type(), m_storage(data) + template + inline xfixed_adaptor::xfixed_adaptor(const storage_type& data) + : base_type() + , m_storage(data) { } @@ -747,34 +789,37 @@ namespace xt * with the specified shape and layout_type. * @param data the container to adapt */ - template + template template - inline xfixed_adaptor::xfixed_adaptor(D&& data) - : base_type(), m_storage(std::forward(data)) + inline xfixed_adaptor::xfixed_adaptor(D&& data) + : base_type() + , m_storage(std::forward(data)) { } + //@} - template - inline auto xfixed_adaptor::operator=(const xfixed_adaptor& rhs) -> self_type& + template + inline auto xfixed_adaptor::operator=(const xfixed_adaptor& rhs) -> self_type& { base_type::operator=(rhs); m_storage = rhs.m_storage; return *this; } - template - inline auto xfixed_adaptor::operator=(xfixed_adaptor&& rhs) -> self_type& + template + inline auto xfixed_adaptor::operator=(xfixed_adaptor&& rhs) -> self_type& { base_type::operator=(std::move(rhs)); m_storage = rhs.m_storage; return *this; } - template - inline auto xfixed_adaptor::operator=(temporary_type&& rhs) -> self_type& + template + inline auto xfixed_adaptor::operator=(temporary_type&& rhs) -> self_type& { - m_storage = xtl::forward_sequence(std::move(rhs.storage())); + m_storage.resize(rhs.storage().size()); + std::copy(rhs.storage().cbegin(), rhs.storage().cend(), m_storage.begin()); return *this; } @@ -785,23 +830,24 @@ namespace xt /** * The extended assignment operator. */ - template + template template - inline auto xfixed_adaptor::operator=(const xexpression& e) -> self_type& + inline auto xfixed_adaptor::operator=(const xexpression& e) -> self_type& { return semantic_base::operator=(e); } + //@} /** * Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different * size throws an assert in debug mode. */ - template + template template - inline void xfixed_adaptor::resize(ST&& shape, bool) const + inline void xfixed_adaptor::resize(ST&& shape, bool) const { - (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined + (void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()); } @@ -809,81 +855,97 @@ namespace xt * Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different * size throws an assert in debug mode. */ - template + template template - inline void xfixed_adaptor::resize(ST&& shape, layout_type l) const + inline void xfixed_adaptor::resize(ST&& shape, layout_type l) const { - (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined - (void)(l); - XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && L == l); + (void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined + (void) (l); + XTENSOR_ASSERT( + std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && L == l + ); } /** * Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different * size throws an assert in debug mode. */ - template + template template - inline void xfixed_adaptor::resize(ST&& shape, const strides_type& strides) const + inline void xfixed_adaptor::resize(ST&& shape, const strides_type& strides) const { - (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined - (void)(strides); + (void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined + (void) (strides); XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()); - XTENSOR_ASSERT(std::equal(strides.begin(), strides.end(), m_strides.begin()) && strides.size() == m_strides.size()); + XTENSOR_ASSERT( + std::equal(strides.begin(), strides.end(), m_strides.begin()) && strides.size() == m_strides.size() + ); } /** * Note that the xfixed_container **cannot** be reshaped to a shape different from ``S``. */ - template + template template - inline void xfixed_adaptor::reshape(ST&& shape, layout_type layout) const + inline const auto& xfixed_adaptor::reshape(ST&& shape, layout_type layout) const { - if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && layout == L)) + if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() + && layout == L)) { - throw std::runtime_error("Trying to reshape xtensor_fixed with different shape or layout."); + XTENSOR_THROW(std::runtime_error, "Trying to reshape xtensor_fixed with different shape or layout."); } + return *this; } - template + template template - inline bool xfixed_adaptor::broadcast_shape(ST& shape, bool) const + inline bool xfixed_adaptor::broadcast_shape(ST& shape, bool) const { return xt::broadcast_shape(m_shape, shape); } - template - inline auto xfixed_adaptor::storage_impl() noexcept -> storage_type& + template + inline auto xfixed_adaptor::storage_impl() noexcept -> storage_type& { return m_storage; } - template - inline auto xfixed_adaptor::storage_impl() const noexcept -> const storage_type& + template + inline auto xfixed_adaptor::storage_impl() const noexcept -> const storage_type& { return m_storage; } - template - constexpr layout_type xfixed_adaptor::layout() const noexcept + template + constexpr layout_type xfixed_adaptor::layout() const noexcept { return base_type::static_layout; } - template - XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::shape_impl() const noexcept -> const inner_shape_type& + template + inline bool xfixed_adaptor::is_contiguous() const noexcept + { + using str_type = typename inner_strides_type::value_type; + return m_strides.empty() || (layout() == layout_type::row_major && m_strides.back() == str_type(1)) + || (layout() == layout_type::column_major && m_strides.front() == str_type(1)); + } + + template + constexpr auto xfixed_adaptor::shape_impl() const noexcept -> const inner_shape_type& { return m_shape; } - template - XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::strides_impl() const noexcept -> const inner_strides_type& + template + constexpr auto xfixed_adaptor::strides_impl() const noexcept + -> const inner_strides_type& { return m_strides; } - template - XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::backstrides_impl() const noexcept -> const inner_backstrides_type& + template + constexpr auto xfixed_adaptor::backstrides_impl() const noexcept + -> const inner_backstrides_type& { return m_backstrides; } diff --git a/include/xtensor/xscalar.hpp b/include/xtensor/containers/xscalar.hpp similarity index 73% rename from include/xtensor/xscalar.hpp rename to include/xtensor/containers/xscalar.hpp index 6002b9a34..106a65923 100644 --- a/include/xtensor/xscalar.hpp +++ b/include/xtensor/containers/xscalar.hpp @@ -1,24 +1,25 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #ifndef XTENSOR_SCALAR_HPP #define XTENSOR_SCALAR_HPP #include #include -#include #include -#include "xexpression.hpp" -#include "xiterable.hpp" -#include "xlayout.hpp" -#include "xtensor_simd.hpp" +#include "../core/xaccessible.hpp" +#include "../core/xexpression.hpp" +#include "../core/xiterable.hpp" +#include "../core/xlayout.hpp" +#include "../utils/xtensor_simd.hpp" namespace xt { @@ -71,10 +72,19 @@ namespace xt using stepper = xscalar_stepper; }; -#define DL XTENSOR_DEFAULT_LAYOUT template - class xscalar : public xexpression>, + struct xcontainer_inner_types> + { + using value_type = std::decay_t; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + }; + + template + class xscalar : public xsharable_expression>, private xiterable>, + private xaccessible>, public extension::xscalar_base_t { public: @@ -82,16 +92,19 @@ namespace xt using self_type = xscalar; using xexpression_type = std::decay_t; using extension_base = extension::xscalar_base_t; + using accessible_base = xaccessible; using expression_tag = typename extension_base::expression_tag; + using inner_types = xcontainer_inner_types; - using value_type = std::decay_t; - using reference = value_type&; - using const_reference = const value_type&; + using value_type = typename inner_types::value_type; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; using pointer = value_type*; using const_pointer = const value_type*; - using size_type = std::size_t; + using size_type = typename inner_types::size_type; using difference_type = std::ptrdiff_t; - using simd_value_type = xsimd::simd_type; + using simd_value_type = xt_simd::simd_type; + using bool_load_type = xt::bool_load_type; using iterable_base = xiterable; using inner_shape_type = typename iterable_base::inner_shape_type; @@ -138,33 +151,29 @@ namespace xt operator const value_type&() const noexcept; size_type size() const noexcept; - size_type dimension() const noexcept; const shape_type& shape() const noexcept; + size_type shape(size_type i) const noexcept; layout_type layout() const noexcept; + bool is_contiguous() const noexcept; + using accessible_base::dimension; + using accessible_base::shape; template reference operator()(Args...) noexcept; template - reference at(Args...); - template reference unchecked(Args...) noexcept; - template - disable_integral_t operator[](const S&) noexcept; - template - reference operator[](std::initializer_list) noexcept; - reference operator[](size_type) noexcept; template const_reference operator()(Args...) const noexcept; template - const_reference at(Args...) const; - template const_reference unchecked(Args...) const noexcept; - template - disable_integral_t operator[](const S&) const noexcept; - template - const_reference operator[](std::initializer_list) const noexcept; - const_reference operator[](size_type) const noexcept; + + using accessible_base::at; + using accessible_base::operator[]; + using accessible_base::back; + using accessible_base::front; + using accessible_base::in_bounds; + using accessible_base::periodic; template reference element(It, It) noexcept; @@ -181,78 +190,78 @@ namespace xt template bool has_linear_assign(const S& strides) const noexcept; - template + template iterator begin() noexcept; - template + template iterator end() noexcept; - template + template const_iterator begin() const noexcept; - template + template const_iterator end() const noexcept; - template + template const_iterator cbegin() const noexcept; - template + template const_iterator cend() const noexcept; - template + template reverse_iterator rbegin() noexcept; - template + template reverse_iterator rend() noexcept; - template + template const_reverse_iterator rbegin() const noexcept; - template + template const_reverse_iterator rend() const noexcept; - template + template const_reverse_iterator crbegin() const noexcept; - template + template const_reverse_iterator crend() const noexcept; - template + template broadcast_iterator begin(const S& shape) noexcept; - template + template broadcast_iterator end(const S& shape) noexcept; - template + template const_broadcast_iterator begin(const S& shape) const noexcept; - template + template const_broadcast_iterator end(const S& shape) const noexcept; - template + template const_broadcast_iterator cbegin(const S& shape) const noexcept; - template + template const_broadcast_iterator cend(const S& shape) const noexcept; - template + template reverse_broadcast_iterator rbegin(const S& shape) noexcept; - template + template reverse_broadcast_iterator rend(const S& shape) noexcept; - template + template const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; - template + template const_reverse_broadcast_iterator rend(const S& shape) const noexcept; - template + template const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; - template + template const_reverse_broadcast_iterator crend(const S& shape) const noexcept; - iterator storage_begin() noexcept; - iterator storage_end() noexcept; + iterator linear_begin() noexcept; + iterator linear_end() noexcept; - const_iterator storage_begin() const noexcept; - const_iterator storage_end() const noexcept; - const_iterator storage_cbegin() const noexcept; - const_iterator storage_cend() const noexcept; + const_iterator linear_begin() const noexcept; + const_iterator linear_end() const noexcept; + const_iterator linear_cbegin() const noexcept; + const_iterator linear_cend() const noexcept; - reverse_iterator storage_rbegin() noexcept; - reverse_iterator storage_rend() noexcept; + reverse_iterator linear_rbegin() noexcept; + reverse_iterator linear_rend() noexcept; - const_reverse_iterator storage_rbegin() const noexcept; - const_reverse_iterator storage_rend() const noexcept; - const_reverse_iterator storage_crbegin() const noexcept; - const_reverse_iterator storage_crend() const noexcept; + const_reverse_iterator linear_rbegin() const noexcept; + const_reverse_iterator linear_rend() const noexcept; + const_reverse_iterator linear_crbegin() const noexcept; + const_reverse_iterator linear_crend() const noexcept; template stepper stepper_begin(const S& shape) noexcept; @@ -273,12 +282,13 @@ namespace xt reference data_element(size_type i) noexcept; const_reference data_element(size_type i) const noexcept; + reference flat(size_type i) noexcept; + const_reference flat(size_type i) const noexcept; + template void store_simd(size_type i, const simd& e); - template ::size> - xsimd::simd_return_type - load_simd(size_type i) const; + template ::size> + xt_simd::simd_return_type load_simd(size_type i) const; private: @@ -286,8 +296,9 @@ namespace xt friend class xconst_iterable; friend class xiterable; + friend class xaccessible; + friend class xconst_accessible; }; -#undef DL namespace detail { @@ -305,18 +316,21 @@ namespace xt template using is_xscalar = detail::is_xscalar_impl; + template + concept xscalar_concept = is_xscalar>::value; + namespace detail { template struct all_xscalar { - static constexpr bool value = xtl::conjunction>...>::value; + static constexpr bool value = std::conjunction>...>::value; }; } // Note: MSVC bug workaround. Cannot just define // template - // using all_xscalar = xtl::conjunction>...>; + // using all_xscalar = std::conjunction>...>; template using all_xscalar = detail::all_xscalar; @@ -341,19 +355,18 @@ namespace xt public: using self_type = xscalar_stepper; - using storage_type = std::conditional_t, - xscalar>; + using storage_type = std::conditional_t, xscalar>; using value_type = typename storage_type::value_type; - using reference = std::conditional_t; - using pointer = std::conditional_t; + using reference = std:: + conditional_t; + using pointer = std::conditional_t; using size_type = typename storage_type::size_type; using difference_type = typename storage_type::difference_type; + using shape_type = typename storage_type::shape_type; + + template + using simd_return_type = xt_simd::simd_return_type; xscalar_stepper(storage_type* c) noexcept; @@ -367,10 +380,10 @@ namespace xt void to_begin() noexcept; void to_end(layout_type l) noexcept; - template - R step_simd(); + template + simd_return_type step_simd(); - value_type step_leading(); + void step_leading(); private: @@ -384,30 +397,26 @@ namespace xt namespace detail { template - using dummy_reference_t = std::conditional_t::const_reference, - typename xscalar::reference>; + using dummy_reference_t = std:: + conditional_t::const_reference, typename xscalar::reference>; template - using dummy_pointer_t = std::conditional_t::const_pointer, - typename xscalar::pointer>; + using dummy_pointer_t = std:: + conditional_t::const_pointer, typename xscalar::pointer>; } template - class xdummy_iterator - : public xtl::xrandom_access_iterator_base, - typename xscalar::value_type, - typename xscalar::difference_type, - detail::dummy_pointer_t, - detail::dummy_reference_t> + class xdummy_iterator : public xtl::xrandom_access_iterator_base< + xdummy_iterator, + typename xscalar::value_type, + typename xscalar::difference_type, + detail::dummy_pointer_t, + detail::dummy_reference_t> { public: using self_type = xdummy_iterator; - using storage_type = std::conditional_t, - xscalar>; + using storage_type = std::conditional_t, xscalar>; using value_type = typename storage_type::value_type; using reference = detail::dummy_reference_t; @@ -436,20 +445,19 @@ namespace xt }; template - bool operator==(const xdummy_iterator& lhs, - const xdummy_iterator& rhs) noexcept; + bool + operator==(const xdummy_iterator& lhs, const xdummy_iterator& rhs) noexcept; template - bool operator<(const xdummy_iterator& lhs, - const xdummy_iterator& rhs) noexcept; + bool operator<(const xdummy_iterator& lhs, const xdummy_iterator& rhs) noexcept; template - struct is_xdummy_iterator : std::false_type + struct is_not_xdummy_iterator : std::true_type { }; template - struct is_xdummy_iterator> : std::true_type + struct is_not_xdummy_iterator> : std::false_type { }; @@ -457,31 +465,28 @@ namespace xt * linear_begin / linear_end * *****************************/ - namespace detail + template + constexpr auto linear_begin(xscalar& c) noexcept -> decltype(c.dummy_begin()) { - template - constexpr auto linear_begin(xscalar& c) noexcept -> decltype(c.dummy_begin()) - { - return c.dummy_begin(); - } + return c.dummy_begin(); + } - template - constexpr auto linear_end(xscalar& c) noexcept -> decltype(c.dummy_end()) - { - return c.dummy_end(); - } + template + constexpr auto linear_end(xscalar& c) noexcept -> decltype(c.dummy_end()) + { + return c.dummy_end(); + } - template - constexpr auto linear_begin(const xscalar& c) noexcept -> decltype(c.dummy_begin()) - { - return c.dummy_begin(); - } + template + constexpr auto linear_begin(const xscalar& c) noexcept -> decltype(c.dummy_begin()) + { + return c.dummy_begin(); + } - template - constexpr auto linear_end(const xscalar& c) noexcept -> decltype(c.dummy_end()) - { - return c.dummy_end(); - } + template + constexpr auto linear_end(const xscalar& c) noexcept -> decltype(c.dummy_end()) + { + return c.dummy_end(); } /************************** @@ -519,12 +524,6 @@ namespace xt return 1; } - template - inline auto xscalar::dimension() const noexcept -> size_type - { - return 0; - } - template inline auto xscalar::shape() const noexcept -> const shape_type& { @@ -533,52 +532,34 @@ namespace xt } template - inline layout_type xscalar::layout() const noexcept + inline auto xscalar::shape(size_type) const noexcept -> size_type { - return static_layout; + return 0; } template - template - inline auto xscalar::operator()(Args...) noexcept -> reference + inline layout_type xscalar::layout() const noexcept { - XTENSOR_CHECK_DIMENSION((std::array()), Args()...); - return m_value; + return static_layout; } template - template - inline auto xscalar::at(Args... args) -> reference + inline bool xscalar::is_contiguous() const noexcept { - check_dimension(shape(), args...); - return this->operator()(args...); + return true; } template template - inline auto xscalar::unchecked(Args...) noexcept -> reference - { - return m_value; - } - - template - template - inline auto xscalar::operator[](const S&) noexcept - -> disable_integral_t - { - return m_value; - } - - template - template - inline auto xscalar::operator[](std::initializer_list) noexcept - -> reference + inline auto xscalar::operator()(Args...) noexcept -> reference { + XTENSOR_CHECK_DIMENSION((std::array()), Args()...); return m_value; } template - inline auto xscalar::operator[](size_type) noexcept -> reference + template + inline auto xscalar::unchecked(Args...) noexcept -> reference { return m_value; } @@ -591,14 +572,6 @@ namespace xt return m_value; } - template - template - inline auto xscalar::at(Args... args) const -> const_reference - { - check_dimension(shape(), args...); - return this->operator()(args...); - } - template template inline auto xscalar::unchecked(Args...) const noexcept -> const_reference @@ -606,28 +579,6 @@ namespace xt return m_value; } - template - template - inline auto xscalar::operator[](const S&) const noexcept - -> disable_integral_t - { - return m_value; - } - - template - template - inline auto xscalar::operator[](std::initializer_list) const noexcept - -> const_reference - { - return m_value; - } - - template - inline auto xscalar::operator[](size_type) const noexcept -> const_reference - { - return m_value; - } - template template inline auto xscalar::element(It, It) noexcept -> reference @@ -714,14 +665,14 @@ namespace xt template inline auto xscalar::rbegin() noexcept -> reverse_iterator { - return reverse_storage_iterator(end()); + return reverse_iterator(end()); } template template inline auto xscalar::rend() noexcept -> reverse_iterator { - return reverse_storage_iterator(begin()); + return reverse_iterator(begin()); } template @@ -742,19 +693,19 @@ namespace xt template inline auto xscalar::crbegin() const noexcept -> const_reverse_iterator { - return const_reverse_storage_iterator(cend()); + return const_reverse_iterator(cend()); } template template inline auto xscalar::crend() const noexcept -> const_reverse_iterator { - return const_reverse_storage_iterator(cbegin()); + return const_reverse_iterator(cbegin()); } /***************************** - * Broadcasting iterator api * - *****************************/ + * Broadcasting iterator api * + *****************************/ template template @@ -841,73 +792,73 @@ namespace xt } template - inline auto xscalar::storage_begin() noexcept -> iterator + inline auto xscalar::linear_begin() noexcept -> iterator { return this->template begin(); } template - inline auto xscalar::storage_end() noexcept -> iterator + inline auto xscalar::linear_end() noexcept -> iterator { return this->template end(); } template - inline auto xscalar::storage_begin() const noexcept -> const_iterator + inline auto xscalar::linear_begin() const noexcept -> const_iterator { return this->template begin(); } template - inline auto xscalar::storage_end() const noexcept -> const_iterator + inline auto xscalar::linear_end() const noexcept -> const_iterator { return this->template end(); } template - inline auto xscalar::storage_cbegin() const noexcept -> const_iterator + inline auto xscalar::linear_cbegin() const noexcept -> const_iterator { return this->template cbegin(); } template - inline auto xscalar::storage_cend() const noexcept -> const_iterator + inline auto xscalar::linear_cend() const noexcept -> const_iterator { return this->template cend(); } template - inline auto xscalar::storage_rbegin() noexcept -> reverse_iterator + inline auto xscalar::linear_rbegin() noexcept -> reverse_iterator { return this->template rbegin(); } template - inline auto xscalar::storage_rend() noexcept -> reverse_iterator + inline auto xscalar::linear_rend() noexcept -> reverse_iterator { return this->template rend(); } template - inline auto xscalar::storage_rbegin() const noexcept -> const_reverse_iterator + inline auto xscalar::linear_rbegin() const noexcept -> const_reverse_iterator { return this->template rbegin(); } template - inline auto xscalar::storage_rend() const noexcept -> const_reverse_iterator + inline auto xscalar::linear_rend() const noexcept -> const_reverse_iterator { return this->template rend(); } template - inline auto xscalar::storage_crbegin() const noexcept -> const_reverse_iterator + inline auto xscalar::linear_crbegin() const noexcept -> const_reverse_iterator { return this->template crbegin(); } template - inline auto xscalar::storage_crend() const noexcept -> const_reverse_iterator + inline auto xscalar::linear_crend() const noexcept -> const_reverse_iterator { return this->template crend(); } @@ -976,6 +927,18 @@ namespace xt return m_value; } + template + inline auto xscalar::flat(size_type) noexcept -> reference + { + return m_value; + } + + template + inline auto xscalar::flat(size_type) const noexcept -> const_reference + { + return m_value; + } + template template inline void xscalar::store_simd(size_type, const simd& e) @@ -986,9 +949,9 @@ namespace xt template template inline auto xscalar::load_simd(size_type) const - -> xsimd::simd_return_type + -> xt_simd::simd_return_type { - return xsimd::set_simd(m_value); + return xt_simd::broadcast_as(m_value); } template @@ -1050,17 +1013,15 @@ namespace xt } template - template - inline R xscalar_stepper::step_simd() + template + inline auto xscalar_stepper::step_simd() -> simd_return_type { - return R(p_c->operator()()); + return simd_return_type(p_c->operator()()); } template - inline auto xscalar_stepper::step_leading() - -> value_type + inline void xscalar_stepper::step_leading() { - return p_c->operator()(); } /********************************** @@ -1122,15 +1083,15 @@ namespace xt } template - inline bool operator==(const xdummy_iterator& lhs, - const xdummy_iterator& rhs) noexcept + inline bool + operator==(const xdummy_iterator& lhs, const xdummy_iterator& rhs) noexcept { return lhs.equal(rhs); } template - inline bool operator<(const xdummy_iterator& lhs, - const xdummy_iterator& rhs) noexcept + inline bool + operator<(const xdummy_iterator& lhs, const xdummy_iterator& rhs) noexcept { return lhs.less_than(rhs); } diff --git a/include/xtensor/xstorage.hpp b/include/xtensor/containers/xstorage.hpp similarity index 72% rename from include/xtensor/xstorage.hpp rename to include/xtensor/containers/xstorage.hpp index 190e46c61..26d4a8ccd 100644 --- a/include/xtensor/xstorage.hpp +++ b/include/xtensor/containers/xstorage.hpp @@ -1,10 +1,11 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * -* * -* Distributed under the terms of the BSD 3-Clause License. * -* * -* The full license is in the file LICENSE, distributed with this software. * -****************************************************************************/ + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ #ifndef XTENSOR_STORAGE_HPP #define XTENSOR_STORAGE_HPP @@ -17,44 +18,33 @@ #include #include -#include "xexception.hpp" -#include "xtensor_simd.hpp" -#include "xutils.hpp" - -#ifndef XTENSOR_ALIGNMENT - #ifdef XTENSOR_USE_XSIMD - #include - #define XTENSOR_ALIGNMENT XSIMD_DEFAULT_ALIGNMENT - #else - #define XTENSOR_ALIGNMENT 0 - #endif -#endif +#include "../core/xtensor_config.hpp" +#include "../utils/xexception.hpp" +#include "../utils/xtensor_simd.hpp" +#include "../utils/xutils.hpp" namespace xt { - - namespace detail + template + struct is_contiguous_container : std::true_type { - template - using require_input_iter = typename std::enable_if::iterator_category, - std::input_iterator_tag>::value>::type; - } + }; - template > + template > class uvector { public: - using allocator_type = Allocator; + using allocator_type = A; - using value_type = typename allocator_type::value_type; - using reference = typename allocator_type::reference; - using const_reference = typename allocator_type::const_reference; - using pointer = typename allocator_type::pointer; - using const_pointer = typename allocator_type::const_pointer; + using value_type = typename std::allocator_traits::value_type; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; - using size_type = typename allocator_type::size_type; - using difference_type = typename allocator_type::difference_type; + using size_type = typename std::allocator_traits::size_type; + using difference_type = typename std::allocator_traits::difference_type; using iterator = pointer; using const_iterator = const_pointer; @@ -66,7 +56,7 @@ namespace xt explicit uvector(size_type count, const allocator_type& alloc = allocator_type()); uvector(size_type count, const_reference value, const allocator_type& alloc = allocator_type()); - template > + template uvector(InputIt first, InputIt last, const allocator_type& alloc = allocator_type()); uvector(std::initializer_list init, const allocator_type& alloc = allocator_type()); @@ -86,10 +76,18 @@ namespace xt bool empty() const noexcept; size_type size() const noexcept; void resize(size_type size); + size_type max_size() const noexcept; + void reserve(size_type new_cap); + size_type capacity() const noexcept; + void shrink_to_fit(); + void clear(); reference operator[](size_type i); const_reference operator[](size_type i) const; + reference at(size_type i); + const_reference at(size_type i) const; + reference front(); const_reference front() const; @@ -162,36 +160,43 @@ namespace xt namespace detail { template - inline typename A::pointer safe_init_allocate(A& alloc, typename A::size_type size) + inline typename std::allocator_traits::pointer + safe_init_allocate(A& alloc, typename std::allocator_traits::size_type size) { - using pointer = typename A::pointer; - using value_type = typename A::value_type; + using traits = std::allocator_traits; + using pointer = typename traits::pointer; + using value_type = typename traits::value_type; pointer res = alloc.allocate(size); - if (!xtrivially_default_constructible::value) + if (!std::is_trivially_default_constructible::value) { for (pointer p = res; p != res + size; ++p) { - alloc.construct(p, value_type()); + traits::construct(alloc, p, value_type()); } } return res; } template - inline void safe_destroy_deallocate(A& alloc, typename A::pointer ptr, typename A::size_type size) + inline void safe_destroy_deallocate( + A& alloc, + typename std::allocator_traits::pointer ptr, + typename std::allocator_traits::size_type size + ) { - using pointer = typename A::pointer; - using value_type = typename A::value_type; + using traits = std::allocator_traits; + using pointer = typename traits::pointer; + using value_type = typename traits::value_type; if (ptr != nullptr) { - if (!xtrivially_default_constructible::value) + if (!std::is_trivially_default_constructible::value) { for (pointer p = ptr; p != ptr + size; ++p) { - alloc.destroy(p); + traits::destroy(alloc, p); } } - alloc.deallocate(ptr, size); + traits::deallocate(alloc, ptr, size); } } } @@ -230,13 +235,17 @@ namespace xt template inline uvector::uvector(const allocator_type& alloc) noexcept - : m_allocator(alloc), p_begin(nullptr), p_end(nullptr) + : m_allocator(alloc) + , p_begin(nullptr) + , p_end(nullptr) { } template inline uvector::uvector(size_type count, const allocator_type& alloc) - : m_allocator(alloc), p_begin(nullptr), p_end(nullptr) + : m_allocator(alloc) + , p_begin(nullptr) + , p_end(nullptr) { if (count != 0) { @@ -247,7 +256,9 @@ namespace xt template inline uvector::uvector(size_type count, const_reference value, const allocator_type& alloc) - : m_allocator(alloc), p_begin(nullptr), p_end(nullptr) + : m_allocator(alloc) + , p_begin(nullptr) + , p_end(nullptr) { if (count != 0) { @@ -258,16 +269,20 @@ namespace xt } template - template + template inline uvector::uvector(InputIt first, InputIt last, const allocator_type& alloc) - : m_allocator(alloc), p_begin(nullptr), p_end(nullptr) + : m_allocator(alloc) + , p_begin(nullptr) + , p_end(nullptr) { init_data(first, last); } template inline uvector::uvector(std::initializer_list init, const allocator_type& alloc) - : m_allocator(alloc), p_begin(nullptr), p_end(nullptr) + : m_allocator(alloc) + , p_begin(nullptr) + , p_end(nullptr) { init_data(init.begin(), init.end()); } @@ -282,15 +297,20 @@ namespace xt template inline uvector::uvector(const uvector& rhs) - : m_allocator(std::allocator_traits::select_on_container_copy_construction(rhs.get_allocator())), - p_begin(nullptr), p_end(nullptr) + : m_allocator( + std::allocator_traits::select_on_container_copy_construction(rhs.get_allocator()) + ) + , p_begin(nullptr) + , p_end(nullptr) { init_data(rhs.p_begin, rhs.p_end); } template inline uvector::uvector(const uvector& rhs, const allocator_type& alloc) - : m_allocator(alloc), p_begin(nullptr), p_end(nullptr) + : m_allocator(alloc) + , p_begin(nullptr) + , p_end(nullptr) { init_data(rhs.p_begin, rhs.p_end); } @@ -301,9 +321,11 @@ namespace xt // No copy and swap idiom here due to performance issues if (this != &rhs) { - m_allocator = std::allocator_traits::select_on_container_copy_construction(rhs.get_allocator()); + m_allocator = std::allocator_traits::select_on_container_copy_construction( + rhs.get_allocator() + ); resize_impl(rhs.size()); - if (xtrivially_default_constructible::value) + if (std::is_trivially_default_constructible::value) { std::uninitialized_copy(rhs.p_begin, rhs.p_end, p_begin); } @@ -317,7 +339,9 @@ namespace xt template inline uvector::uvector(uvector&& rhs) noexcept - : m_allocator(std::move(rhs.m_allocator)), p_begin(rhs.p_begin), p_end(rhs.p_end) + : m_allocator(std::move(rhs.m_allocator)) + , p_begin(rhs.p_begin) + , p_end(rhs.p_end) { rhs.p_begin = nullptr; rhs.p_end = nullptr; @@ -325,7 +349,9 @@ namespace xt template inline uvector::uvector(uvector&& rhs, const allocator_type& alloc) noexcept - : m_allocator(alloc), p_begin(rhs.p_begin), p_end(rhs.p_end) + : m_allocator(alloc) + , p_begin(rhs.p_begin) + , p_end(rhs.p_end) { rhs.p_begin = nullptr; rhs.p_end = nullptr; @@ -365,6 +391,34 @@ namespace xt resize_impl(size); } + template + inline auto uvector::max_size() const noexcept -> size_type + { + return m_allocator.max_size(); + } + + template + inline void uvector::reserve(size_type /*new_cap*/) + { + } + + template + inline auto uvector::capacity() const noexcept -> size_type + { + return size(); + } + + template + inline void uvector::shrink_to_fit() + { + } + + template + inline void uvector::clear() + { + resize(size_type(0)); + } + template inline auto uvector::operator[](size_type i) -> reference { @@ -377,6 +431,26 @@ namespace xt return p_begin[i]; } + template + inline auto uvector::at(size_type i) -> reference + { + if (i >= size()) + { + XTENSOR_THROW(std::out_of_range, "Out of range in uvector access"); + } + return this->operator[](i); + } + + template + inline auto uvector::at(size_type i) const -> const_reference + { + if (i >= size()) + { + XTENSOR_THROW(std::out_of_range, "Out of range in uvector access"); + } + return this->operator[](i); + } + template inline auto uvector::front() -> reference { @@ -509,8 +583,7 @@ namespace xt template inline bool operator<(const uvector& lhs, const uvector& rhs) { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end()); + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template @@ -546,13 +619,13 @@ namespace xt template struct allocator_alignment { - constexpr static std::size_t value = 0; + static constexpr std::size_t value = 0; }; template - struct allocator_alignment> + struct allocator_alignment> { - constexpr static std::size_t value = A; + static constexpr std::size_t value = A; }; } @@ -563,25 +636,22 @@ namespace xt using self_type = svector; using allocator_type = A; - using size_type = typename A::size_type; - using value_type = typename A::value_type; - using pointer = typename A::pointer; - using const_pointer = typename A::const_pointer; - using reference = typename A::reference; - using const_reference = typename A::const_reference; - using difference_type = typename A::difference_type; + using size_type = typename std::allocator_traits::size_type; + using value_type = typename std::allocator_traits::value_type; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using difference_type = typename std::allocator_traits::difference_type; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - #if defined(_MSC_VER) && _MSC_VER < 1910 - constexpr static std::size_t alignment = detail::allocator_alignment::value; - #else - constexpr static std::size_t alignment = detail::allocator_alignment::value != 0 ? - detail::allocator_alignment::value : alignof(T); - #endif + static constexpr std::size_t alignment = detail::allocator_alignment::value != 0 + ? detail::allocator_alignment::value + : alignof(T); svector() noexcept; ~svector(); @@ -593,22 +663,24 @@ namespace xt svector(const std::vector& vec); - template > + template svector(IT begin, IT end, const allocator_type& alloc = allocator_type()); - template > - explicit svector(const svector& rhs); + template + explicit svector(const svector& rhs) + requires(N != N2); svector& operator=(const svector& rhs); - svector& operator=(svector&& rhs); + svector& operator=(svector&& rhs) noexcept(std::is_nothrow_move_assignable::value); svector& operator=(const std::vector& rhs); svector& operator=(std::initializer_list il); - template > - svector& operator=(const svector& rhs); + template + svector& operator=(const svector& rhs) + requires(N != N2); svector(const svector& other); - svector(svector&& other); + svector(svector&& other) noexcept(std::is_nothrow_move_constructible::value); void assign(size_type n, const value_type& v); @@ -621,14 +693,14 @@ namespace xt reference operator[](size_type idx); const_reference operator[](size_type idx) const; + reference at(size_type idx); + const_reference at(size_type idx) const; + pointer data(); const_pointer data() const; - void resize(size_type n); - - size_type capacity() const; void push_back(const T& elt); - + void push_back(T&& elt); void pop_back(); iterator begin(); @@ -645,9 +717,14 @@ namespace xt const_reverse_iterator rend() const; const_reverse_iterator crend() const; - size_type size() const; - bool empty() const; + size_type size() const; + void resize(size_type n); + size_type max_size() const noexcept; + size_type capacity() const; + void reserve(size_type n); + void shrink_to_fit(); + void clear(); reference front(); const_reference front() const; @@ -661,6 +738,11 @@ namespace xt iterator insert(const_iterator it, const T& elt); + template + iterator insert(const_iterator pos, It first, It last); + + iterator insert(const_iterator pos, std::initializer_list l); + template void swap(svector& rhs); @@ -717,7 +799,7 @@ namespace xt } template - template + template inline svector::svector(IT begin, IT end, const allocator_type& alloc) : m_allocator(alloc) { @@ -725,8 +807,9 @@ namespace xt } template - template + template inline svector::svector(const svector& rhs) + requires(N != N2) : m_allocator(rhs.get_allocator()) { assign(rhs.begin(), rhs.end()); @@ -760,7 +843,8 @@ namespace xt } template - inline svector& svector::operator=(svector&& rhs) + inline svector& svector::operator=(svector&& rhs + ) noexcept(std::is_nothrow_move_assignable::value) { assign(rhs.begin(), rhs.end()); return *this; @@ -769,7 +853,9 @@ namespace xt template inline svector& svector::operator=(const std::vector& rhs) { - m_allocator = std::allocator_traits::select_on_container_copy_construction(rhs.get_allocator()); + m_allocator = std::allocator_traits::select_on_container_copy_construction( + rhs.get_allocator() + ); assign(rhs.begin(), rhs.end()); return *this; } @@ -781,23 +867,29 @@ namespace xt } template - template + template inline svector& svector::operator=(const svector& rhs) + requires(N != N2) { - m_allocator = std::allocator_traits::select_on_container_copy_construction(rhs.get_allocator()); + m_allocator = std::allocator_traits::select_on_container_copy_construction( + rhs.get_allocator() + ); assign(rhs.begin(), rhs.end()); return *this; } template inline svector::svector(const svector& rhs) - : m_allocator(std::allocator_traits::select_on_container_copy_construction(rhs.get_allocator())) + : m_allocator( + std::allocator_traits::select_on_container_copy_construction(rhs.get_allocator()) + ) { assign(rhs.begin(), rhs.end()); } template - inline svector::svector(svector&& rhs) + inline svector::svector(svector&& rhs + ) noexcept(std::is_nothrow_move_constructible::value) { this->swap(rhs); } @@ -845,6 +937,26 @@ namespace xt return m_begin[idx]; } + template + inline auto svector::at(size_type idx) -> reference + { + if (idx >= size()) + { + XTENSOR_THROW(std::out_of_range, "Out of range in svector access"); + } + return this->operator[](idx); + } + + template + inline auto svector::at(size_type idx) const -> const_reference + { + if (idx >= size()) + { + XTENSOR_THROW(std::out_of_range, "Out of range in svector access"); + } + return this->operator[](idx); + } + template inline auto svector::data() -> pointer { @@ -864,19 +976,47 @@ namespace xt { grow(n); } + size_type old_size = size(); m_end = m_begin + n; - if (Init) + if (Init && old_size < size()) { - std::fill(begin(), end(), T()); + std::fill(begin() + old_size, end(), T()); } } + template + inline auto svector::max_size() const noexcept -> size_type + { + return m_allocator.max_size(); + } + template inline auto svector::capacity() const -> size_type { return static_cast(m_capacity - m_begin); } + template + inline void svector::reserve(size_type n) + { + if (n > N && n > capacity()) + { + grow(n); + } + } + + template + inline void svector::shrink_to_fit() + { + // No op for now + } + + template + inline void svector::clear() + { + resize(size_type(0)); + } + template void svector::push_back(const T& elt) { @@ -887,6 +1027,16 @@ namespace xt *(m_end++) = elt; } + template + void svector::push_back(T&& elt) + { + if (m_end >= m_capacity) + { + grow(); + } + *(m_end++) = std::move(elt); + } + template void svector::pop_back() { @@ -1066,18 +1216,46 @@ namespace xt // Update ref if element moved const T* elt_ptr = &elt; - if (it <= elt_ptr && elt_ptr < m_end) + bool cond = it <= elt_ptr && elt_ptr < m_end; + // More complicated than incrementing elt_ptr, but this avoids + // false positive array-bounds warning on GCC 10 + const T* src_ptr = cond ? it + (elt_ptr - it) + std::ptrdiff_t(1) : elt_ptr; + *it = *src_ptr; + return it; + } + + template + template + inline auto svector::insert(const_iterator pos, It first, It last) -> iterator + { + auto it = const_cast(pos); + difference_type n = std::distance(first, last); + if (n > 0) { - ++elt_ptr; + if (n > m_capacity - m_end) + { + std::ptrdiff_t elt_no = it - m_begin; + grow(static_cast((m_capacity - m_begin) + n)); + it = m_begin + elt_no; + } + + std::move_backward(it, m_end, m_end + n); + m_end += n; + std::copy(first, last, it); } - *it = *elt_ptr; return it; } + template + inline auto svector::insert(const_iterator pos, std::initializer_list l) -> iterator + { + return insert(pos, l.begin(), l.end()); + } + template inline void svector::destroy_range(T* begin, T* end) { - if (!xtrivially_default_constructible::value) + if (!std::is_trivially_default_constructible::value) { while (begin != end) { @@ -1091,6 +1269,7 @@ namespace xt template inline void svector::swap(svector& rhs) { + using std::swap; if (this == &rhs) { return; @@ -1099,45 +1278,43 @@ namespace xt // We can only avoid copying elements if neither vector is small. if (!this->on_stack() && !rhs.on_stack()) { - std::swap(this->m_begin, rhs.m_begin); - std::swap(this->m_end, rhs.m_end); - std::swap(this->m_capacity, rhs.m_capacity); + swap(this->m_begin, rhs.m_begin); + swap(this->m_end, rhs.m_end); + swap(this->m_capacity, rhs.m_capacity); return; } - if (rhs.size() > this->capacity()) + size_type rhs_old_size = rhs.size(); + size_type old_size = this->size(); + + if (rhs_old_size > old_size) { - this->resize(rhs.size()); + this->resize(rhs_old_size); } - if (this->size() > rhs.capacity()) + else if (old_size > rhs_old_size) { - rhs.resize(this->size()); + rhs.resize(old_size); } // Swap the shared elements. - std::size_t num_shared = (std::min)(this->size(), rhs.size()); - - for (size_type i = 0; i != num_shared; ++i) + size_type min_size = (std::min)(old_size, rhs_old_size); + for (size_type i = 0; i < min_size; ++i) { - std::swap((*this)[i], rhs[i]); + swap((*this)[i], rhs[i]); } // Copy over the extra elts. - if (this->size() > rhs.size()) + if (old_size > rhs_old_size) { - std::size_t elements_diff = this->size() - rhs.size(); - std::copy(this->begin() + num_shared, this->end(), rhs.end()); - rhs.m_end = rhs.end() + elements_diff; - this->destroy_range(this->begin() + num_shared, this->end()); - this->m_end = this->begin() + num_shared; + std::copy(this->begin() + min_size, this->end(), rhs.begin() + min_size); + this->destroy_range(this->begin() + min_size, this->end()); + this->m_end = this->begin() + min_size; } - else if (rhs.size() > this->size()) + else if (rhs_old_size > old_size) { - std::size_t elements_diff = rhs.size() - this->size(); - std::uninitialized_copy(rhs.begin() + num_shared, rhs.end(), this->end()); - this->m_end = this->end() + elements_diff; - this->destroy_range(rhs.begin() + num_shared, rhs.end()); - rhs.m_end = rhs.begin() + num_shared; + std::copy(rhs.begin() + min_size, rhs.end(), this->begin() + min_size); + this->destroy_range(rhs.begin() + min_size, rhs.end()); + rhs.m_end = rhs.begin() + min_size; } } @@ -1199,8 +1376,7 @@ namespace xt template inline bool operator<(const svector& lhs, const svector& rhs) { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end()); + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template @@ -1227,76 +1403,34 @@ namespace xt lhs.swap(rhs); } - #define XTENSOR_SELECT_ALIGN (XTENSOR_ALIGNMENT != 0 ? XTENSOR_ALIGNMENT : alignof(T)) - template struct rebind_container> { - using allocator = typename A::template rebind::other; + using traits = std::allocator_traits; + using allocator = typename traits::template rebind_alloc; using type = svector; }; /** - * This array class is modeled after ``std::array`` but adds optional alignment through a template parameter. + * This array class is modeled after ``std::array`` but adds optional alignment through a template + * parameter. * * To be moved to xtl, along with the rest of xstorage.hpp */ - template + template class alignas(Align) aligned_array : public std::array { public: + // Note: this is for alignment detection. The allocator serves no other purpose than // that of a trait here. - using allocator_type = std::conditional_t, - std::allocator>; + using allocator_type = std::conditional_t, std::allocator>; }; #if defined(_MSC_VER) - #define XTENSOR_CONST +#define XTENSOR_CONST #else - #define XTENSOR_CONST const -#endif - -#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) - #define GCC4_FALLBACK - - namespace const_array_detail - { - template - struct array_traits - { - using storage_type = T[N]; - - static constexpr T& ref(const storage_type& t, std::size_t n) noexcept - { - return const_cast(t[n]); - } - - static constexpr T* ptr(const storage_type& t) noexcept - { - return const_cast(t); - } - }; - - template - struct array_traits - { - struct empty {}; - - using storage_type = empty; - - static constexpr T& ref(const storage_type& /*t*/, std::size_t /*n*/) noexcept - { - return *static_cast(nullptr); - } - - static constexpr T* ptr(const storage_type& /*t*/) noexcept - { - return nullptr; - } - }; - } +#define XTENSOR_CONST const #endif /** @@ -1321,11 +1455,7 @@ namespace xt constexpr const_reference operator[](std::size_t idx) const { - #ifdef GCC4_FALLBACK - return const_array_detail::array_traits::ref(m_data, idx); - #else return m_data[idx]; - #endif } constexpr const_iterator begin() const noexcept @@ -1371,30 +1501,22 @@ namespace xt constexpr const_pointer data() const noexcept { - #ifdef GCC4_FALLBACK - return const_array_detail::array_traits::ptr(m_data); - #else return m_data; - #endif } constexpr const_reference front() const noexcept { - #ifdef GCC4_FALLBACK - return const_array_detail::array_traits::ref(m_data, 0); - #else return m_data[0]; - #endif } constexpr const_reference back() const noexcept { - #ifdef GCC4_FALLBACK - return N ? const_array_detail::array_traits::ref(m_data, N - 1) : - const_array_detail::array_traits::ref(m_data, 0); - #else return m_data[size() - 1]; - #endif + } + + constexpr bool empty() const noexcept + { + return size() == size_type(0); } constexpr size_type size() const noexcept @@ -1402,18 +1524,47 @@ namespace xt return N; } - #ifdef GCC4_FALLBACK - XTENSOR_CONST typename const_array_detail::array_traits::storage_type m_data; - #else XTENSOR_CONST T m_data[N > 0 ? N : 1]; - #endif }; -#undef GCC4_FALLBACK + template + inline bool operator==(const const_array& lhs, const const_array& rhs) + { + return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + } + + template + inline bool operator!=(const const_array& lhs, const const_array& rhs) + { + return !(lhs == rhs); + } + + template + inline bool operator<(const const_array& lhs, const const_array& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + template + inline bool operator<=(const const_array& lhs, const const_array& rhs) + { + return !(lhs > rhs); + } + + template + inline bool operator>(const const_array& lhs, const const_array& rhs) + { + return rhs < lhs; + } + template + inline bool operator>=(const const_array& lhs, const const_array& rhs) + { + return !(lhs < rhs); + } -// Workaround for rebind_container problems on GCC 8 with C++17 enabled -#if defined(__GNUC__) && __GNUC__ > 6 && !defined(__clang__) && __cplusplus >= 201703L +// Workaround for rebind_container problems when C++17 feature is enabled +#ifdef __cpp_template_template_args template struct rebind_container> { @@ -1437,32 +1588,34 @@ namespace xt { public: -#if defined(_MSC_VER) - using cast_type = std::array; - #define XTENSOR_FIXED_SHAPE_CONSTEXPR inline -#else using cast_type = const_array; - #define XTENSOR_FIXED_SHAPE_CONSTEXPR constexpr -#endif using value_type = std::size_t; using size_type = std::size_t; + using const_iterator = typename cast_type::const_iterator; - constexpr static std::size_t size() + static constexpr std::size_t size() { return sizeof...(X); } - XTENSOR_FIXED_SHAPE_CONSTEXPR operator cast_type() const + template + static constexpr auto get() + { + using tmp_cast_type = std::array; + return std::get(tmp_cast_type{X...}); + } + + constexpr operator cast_type() const { return cast_type({X...}); } - XTENSOR_FIXED_SHAPE_CONSTEXPR auto begin() const + constexpr auto begin() const { return m_array.begin(); } - XTENSOR_FIXED_SHAPE_CONSTEXPR auto end() const + constexpr auto end() const { return m_array.end(); } @@ -1477,33 +1630,41 @@ namespace xt return m_array.rend(); } - XTENSOR_FIXED_SHAPE_CONSTEXPR auto cbegin() const + constexpr auto cbegin() const { return m_array.cbegin(); } - XTENSOR_FIXED_SHAPE_CONSTEXPR auto cend() const + constexpr auto cend() const { return m_array.cend(); } - XTENSOR_FIXED_SHAPE_CONSTEXPR std::size_t operator[](std::size_t idx) const + auto crbegin() const + { + return m_array.crbegin(); + } + + auto crend() const + { + return m_array.crend(); + } + + constexpr std::size_t operator[](std::size_t idx) const { return m_array[idx]; } + constexpr bool empty() const + { + return sizeof...(X) == 0; + } + private: - XTENSOR_CONSTEXPR_ENHANCED_STATIC cast_type m_array = cast_type({X...}); + XTENSOR_CONSTEXPR_ENHANCED_STATIC cast_type m_array = cast_type({X...}); }; -#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED - template - constexpr typename fixed_shape::cast_type fixed_shape::m_array; -#endif - -#undef XTENSOR_FIXED_SHAPE_CONSTEXPR - template class sequence_view { @@ -1528,6 +1689,10 @@ namespace xt template explicit sequence_view(const sequence_view& other); + template ().begin())> + operator T() const; + + bool empty() const; size_type size() const; const_reference operator[](std::size_t idx) const; @@ -1547,6 +1712,7 @@ namespace xt const E& storage() const; private: + const E& m_sequence; }; @@ -1563,6 +1729,21 @@ namespace xt { } + template + template + sequence_view::operator T() const + { + T ret = xtl::make_sequence(this->size()); + std::copy(this->cbegin(), this->cend(), ret.begin()); + return ret; + } + + template + bool sequence_view::empty() const + { + return size() == size_type(0); + } + template auto sequence_view::size() const -> size_type { @@ -1583,7 +1764,7 @@ namespace xt } template - auto sequence_view::end() const -> const_iterator + auto sequence_view::end() const -> const_iterator { if (End != -1) { @@ -1596,19 +1777,19 @@ namespace xt } template - auto sequence_view::begin() const -> const_iterator + auto sequence_view::begin() const -> const_iterator { return m_sequence.begin() + Start; } template - auto sequence_view::cend() const -> const_iterator + auto sequence_view::cend() const -> const_iterator { return end(); } template - auto sequence_view::cbegin() const -> const_iterator + auto sequence_view::cbegin() const -> const_iterator { return begin(); } @@ -1662,7 +1843,6 @@ namespace xt return m_sequence; } - template inline bool operator==(const sequence_view& lhs, const sequence_view& rhs) { @@ -1684,28 +1864,29 @@ namespace xt // G++ 8 C++ library does define it as a struct hence we get // clang warnings here +// Do not remove space between "#" and "pragma". This is required for CRAN checks. +// clang-format off #if defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wmismatched-tags" + # pragma clang diagnostic push + # pragma clang diagnostic ignored "-Wmismatched-tags" #endif +// clang-format on namespace std { template - class tuple_size> : - public integral_constant + class tuple_size> : public integral_constant { }; template - class tuple_size> : - public integral_constant + class tuple_size> : public integral_constant { }; template - class tuple_size> : - public integral_constant + class tuple_size> + : public integral_constant { }; @@ -1714,12 +1895,13 @@ namespace std class tuple_size>; } +// Do not remove space between "#" and "pragma". This is required for CRAN checks. +// clang-format off #if defined(__clang__) - #pragma clang diagnostic pop + # pragma clang diagnostic pop #endif +// clang-format on #undef XTENSOR_CONST -#undef XTENSOR_ALIGNMENT -#undef XTENSOR_SELECT_ALIGN #endif diff --git a/include/xtensor/containers/xtensor.hpp b/include/xtensor/containers/xtensor.hpp new file mode 100644 index 000000000..db8d92385 --- /dev/null +++ b/include/xtensor/containers/xtensor.hpp @@ -0,0 +1,983 @@ +/*************************************************************************** + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#ifndef XTENSOR_TENSOR_HPP +#define XTENSOR_TENSOR_HPP + +#include +#include +#include +#include +#include + +#include "../containers/xbuffer_adaptor.hpp" +#include "../containers/xcontainer.hpp" +#include "../core/xsemantic.hpp" + +namespace xt +{ + + /*********************** + * xtensor declaration * + ***********************/ + + namespace extension + { + template + struct xtensor_container_base; + + template + struct xtensor_container_base + { + using type = xtensor_empty_base; + }; + + template + using xtensor_container_base_t = typename xtensor_container_base::type; + } + + template + struct xcontainer_inner_types> + { + using storage_type = EC; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; + using shape_type = std::array; + using strides_type = get_strides_t; + using backstrides_type = get_strides_t; + using inner_shape_type = shape_type; + using inner_strides_type = strides_type; + using inner_backstrides_type = backstrides_type; + using temporary_type = xtensor_container; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @class xtensor_container + * @brief Dense multidimensional container with tensor semantic and fixed + * dimension. + * + * The xtensor_container class implements a dense multidimensional container + * with tensor semantics and fixed dimension + * + * @tparam EC The type of the container holding the elements. + * @tparam N The dimension of the container. + * @tparam L The layout_type of the tensor. + * @tparam Tag The expression tag. + * @sa xtensor, xstrided_container, xcontainer + */ + template + class xtensor_container : public xstrided_container>, + public xcontainer_semantic>, + public extension::xtensor_container_base_t + { + public: + + using self_type = xtensor_container; + using base_type = xstrided_container; + using semantic_base = xcontainer_semantic; + using extension_base = extension::xtensor_container_base_t; + using storage_type = typename base_type::storage_type; + using allocator_type = typename base_type::allocator_type; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using shape_type = typename base_type::shape_type; + using inner_shape_type = typename base_type::inner_shape_type; + using strides_type = typename base_type::strides_type; + using backstrides_type = typename base_type::backstrides_type; + using inner_backstrides_type = typename base_type::inner_backstrides_type; + using inner_strides_type = typename base_type::inner_strides_type; + using temporary_type = typename semantic_base::temporary_type; + using expression_tag = Tag; + static constexpr std::size_t rank = N; + + xtensor_container(); + xtensor_container(nested_initializer_list_t t); + explicit xtensor_container(const shape_type& shape, layout_type l = L); + explicit xtensor_container(const shape_type& shape, const_reference value, layout_type l = L); + explicit xtensor_container(const shape_type& shape, const strides_type& strides); + explicit xtensor_container(const shape_type& shape, const strides_type& strides, const_reference value); + explicit xtensor_container(storage_type&& storage, inner_shape_type&& shape, inner_strides_type&& strides); + + template + static xtensor_container from_shape(S&& s); + + ~xtensor_container() = default; + + xtensor_container(const xtensor_container&) = default; + xtensor_container& operator=(const xtensor_container&) = default; + + xtensor_container(xtensor_container&&) = default; + xtensor_container& operator=(xtensor_container&&) = default; + + template + explicit xtensor_container(xarray_container&&); + template + xtensor_container& operator=(xarray_container&&); + + template + xtensor_container(const xexpression& e); + + template + xtensor_container& operator=(const xexpression& e); + + private: + + storage_type m_storage; + + storage_type& storage_impl() noexcept; + const storage_type& storage_impl() const noexcept; + + friend class xcontainer>; + }; + + /***************************************** + * xtensor_container_adaptor declaration * + *****************************************/ + + namespace extension + { + template + struct xtensor_adaptor_base; + + template + struct xtensor_adaptor_base + { + using type = xtensor_empty_base; + }; + + template + using xtensor_adaptor_base_t = typename xtensor_adaptor_base::type; + } + + template + struct xcontainer_inner_types> + { + using storage_type = std::remove_reference_t; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; + using shape_type = std::array; + using strides_type = get_strides_t; + using backstrides_type = get_strides_t; + using inner_shape_type = shape_type; + using inner_strides_type = strides_type; + using inner_backstrides_type = backstrides_type; + using temporary_type = xtensor_container, N, L, Tag>; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @class xtensor_adaptor + * @brief Dense multidimensional container adaptor with tensor + * semantics and fixed dimension. + * + * The xtensor_adaptor class implements a dense multidimensional + * container adaptor with tensor semantics and fixed dimension. It + * is used to provide a multidimensional container semantic and a + * tensor semantic to stl-like containers. + * + * @tparam EC The closure for the container type to adapt. + * @tparam N The dimension of the adaptor. + * @tparam L The layout_type of the adaptor. + * @tparam Tag The expression tag. + * @sa xstrided_container, xcontainer + */ + template + class xtensor_adaptor : public xstrided_container>, + public xcontainer_semantic>, + public extension::xtensor_adaptor_base_t + { + public: + + using container_closure_type = EC; + + using self_type = xtensor_adaptor; + using base_type = xstrided_container; + using semantic_base = xcontainer_semantic; + using extension_base = extension::xtensor_adaptor_base_t; + using storage_type = typename base_type::storage_type; + using allocator_type = typename base_type::allocator_type; + using shape_type = typename base_type::shape_type; + using strides_type = typename base_type::strides_type; + using backstrides_type = typename base_type::backstrides_type; + using temporary_type = typename semantic_base::temporary_type; + using expression_tag = Tag; + static constexpr std::size_t rank = N; + + xtensor_adaptor(storage_type&& storage); + xtensor_adaptor(const storage_type& storage); + + template + xtensor_adaptor(D&& storage, const shape_type& shape, layout_type l = L); + + template + xtensor_adaptor(D&& storage, const shape_type& shape, const strides_type& strides); + + ~xtensor_adaptor() = default; + + xtensor_adaptor(const xtensor_adaptor&) = default; + xtensor_adaptor& operator=(const xtensor_adaptor&); + + xtensor_adaptor(xtensor_adaptor&&) = default; + xtensor_adaptor& operator=(xtensor_adaptor&&); + xtensor_adaptor& operator=(temporary_type&&); + + template + xtensor_adaptor& operator=(const xexpression& e); + + template + void reset_buffer(P&& pointer, S&& size); + + private: + + container_closure_type m_storage; + + storage_type& storage_impl() noexcept; + const storage_type& storage_impl() const noexcept; + + friend class xcontainer>; + }; + + /**************************** + * xtensor_view declaration * + ****************************/ + + template + class xtensor_view; + + namespace extension + { + template + struct xtensor_view_base; + + template + struct xtensor_view_base + { + using type = xtensor_empty_base; + }; + + template + using xtensor_view_base_t = typename xtensor_view_base::type; + } + + template + struct xcontainer_inner_types> + { + using storage_type = std::remove_reference_t; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; + using shape_type = std::array; + using strides_type = get_strides_t; + using backstrides_type = get_strides_t; + using inner_shape_type = shape_type; + using inner_strides_type = strides_type; + using inner_backstrides_type = backstrides_type; + using temporary_type = xtensor_container, N, L, Tag>; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @class xtensor_view + * @brief Dense multidimensional container adaptor with view + * semantics and fixed dimension. + * + * The xtensor_view class implements a dense multidimensional + * container adaptor with viewsemantics and fixed dimension. It + * is used to provide a multidimensional container semantic and a + * view semantic to stl-like containers. + * + * @tparam EC The closure for the container type to adapt. + * @tparam N The dimension of the view. + * @tparam L The layout_type of the view. + * @tparam Tag The expression tag. + * @sa xstrided_container, xcontainer + */ + template + class xtensor_view : public xstrided_container>, + public xview_semantic>, + public extension::xtensor_view_base_t + { + public: + + using container_closure_type = EC; + + using self_type = xtensor_view; + using base_type = xstrided_container; + using semantic_base = xview_semantic; + using extension_base = extension::xtensor_adaptor_base_t; + using storage_type = typename base_type::storage_type; + using allocator_type = typename base_type::allocator_type; + using shape_type = typename base_type::shape_type; + using strides_type = typename base_type::strides_type; + using backstrides_type = typename base_type::backstrides_type; + using temporary_type = typename semantic_base::temporary_type; + using expression_tag = Tag; + + xtensor_view(storage_type&& storage); + xtensor_view(const storage_type& storage); + + template + xtensor_view(D&& storage, const shape_type& shape, layout_type l = L); + + template + xtensor_view(D&& storage, const shape_type& shape, const strides_type& strides); + + ~xtensor_view() = default; + + xtensor_view(const xtensor_view&) = default; + xtensor_view& operator=(const xtensor_view&); + + xtensor_view(xtensor_view&&) = default; + xtensor_view& operator=(xtensor_view&&); + + template + self_type& operator=(const xexpression& e); + + template + disable_xexpression& operator=(const E& e); + + private: + + container_closure_type m_storage; + + storage_type& storage_impl() noexcept; + const storage_type& storage_impl() const noexcept; + + void assign_temporary_impl(temporary_type&& tmp); + + friend class xcontainer>; + friend class xview_semantic>; + }; + + namespace detail + { + template + struct tensor_view_simd_helper + { + using valid_return_type = detail::has_simd_interface_impl; + using valid_reference = std::is_lvalue_reference; + static constexpr bool value = valid_return_type::value && valid_reference::value; + using type = std::integral_constant; + }; + } + + // xtensor_view can be used on pseudo containers, i.e. containers + // whose access operator does not return a reference. Since it + // is not possible to take the address f a temporary, the load_simd + // method implementation leads to a compilation error. + template + struct has_simd_interface> + : detail::tensor_view_simd_helper>::type + { + }; + + /************************************ + * xtensor_container implementation * + ************************************/ + + /** + * @name Constructors + */ + //@{ + /** + * Allocates an uninitialized xtensor_container that holds 0 elements. + */ + template + inline xtensor_container::xtensor_container() + : base_type() + , m_storage(N == 0 ? 1 : 0, value_type()) + { + } + + /** + * Allocates an xtensor_container with nested initializer lists. + */ + template + inline xtensor_container::xtensor_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t), true); + constexpr auto tmp = layout_type::row_major; + L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + + /** + * Allocates an uninitialized xtensor_container with the specified shape and + * layout_type. + * @param shape the shape of the xtensor_container + * @param l the layout_type of the xtensor_container + */ + template + inline xtensor_container::xtensor_container(const shape_type& shape, layout_type l) + : base_type() + { + base_type::resize(shape, l); + } + + /** + * Allocates an xtensor_container with the specified shape and layout_type. Elements + * are initialized to the specified value. + * @param shape the shape of the xtensor_container + * @param value the value of the elements + * @param l the layout_type of the xtensor_container + */ + template + inline xtensor_container::xtensor_container( + const shape_type& shape, + const_reference value, + layout_type l + ) + : base_type() + { + base_type::resize(shape, l); + std::fill(m_storage.begin(), m_storage.end(), value); + } + + /** + * Allocates an uninitialized xtensor_container with the specified shape and strides. + * @param shape the shape of the xtensor_container + * @param strides the strides of the xtensor_container + */ + template + inline xtensor_container::xtensor_container(const shape_type& shape, const strides_type& strides) + : base_type() + { + base_type::resize(shape, strides); + } + + /** + * Allocates an uninitialized xtensor_container with the specified shape and strides. + * Elements are initialized to the specified value. + * @param shape the shape of the xtensor_container + * @param strides the strides of the xtensor_container + * @param value the value of the elements + */ + template + inline xtensor_container::xtensor_container( + const shape_type& shape, + const strides_type& strides, + const_reference value + ) + : base_type() + { + base_type::resize(shape, strides); + std::fill(m_storage.begin(), m_storage.end(), value); + } + + /** + * Allocates an xtensor_container by moving specified data, shape and strides + * + * @param storage the data for the xtensor_container + * @param shape the shape of the xtensor_container + * @param strides the strides of the xtensor_container + */ + template + inline xtensor_container::xtensor_container( + storage_type&& storage, + inner_shape_type&& shape, + inner_strides_type&& strides + ) + : base_type(std::move(shape), std::move(strides)) + , m_storage(std::move(storage)) + { + } + + template + template + inline xtensor_container::xtensor_container(xarray_container&& rhs) + : base_type( + xtl::forward_sequence(rhs.shape()), + xtl::forward_sequence(rhs.strides()), + xtl::forward_sequence(rhs.backstrides()), + std::move(rhs.layout()) + ) + , m_storage(std::move(rhs.storage())) + { + } + + template + template + inline xtensor_container& + xtensor_container::operator=(xarray_container&& rhs) + { + XTENSOR_ASSERT_MSG(N == rhs.dimension(), "Cannot change dimension of xtensor."); + std::copy(rhs.shape().begin(), rhs.shape().end(), this->shape_impl().begin()); + std::copy(rhs.strides().cbegin(), rhs.strides().cend(), this->strides_impl().begin()); + std::copy(rhs.backstrides().cbegin(), rhs.backstrides().cend(), this->backstrides_impl().begin()); + this->mutable_layout() = std::move(rhs.layout()); + m_storage = std::move(std::move(rhs.storage())); + return *this; + } + + template + template + inline xtensor_container xtensor_container::from_shape(S&& s) + { + XTENSOR_ASSERT_MSG(s.size() == N, "Cannot change dimension of xtensor."); + shape_type shape = xtl::forward_sequence(s); + return self_type(shape); + } + + //@} + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended copy constructor. + */ + template + template + inline xtensor_container::xtensor_container(const xexpression& e) + : base_type() + { + XTENSOR_ASSERT_MSG(N == e.derived_cast().dimension(), "Cannot change dimension of xtensor."); + // Avoids uninitialized data because of (m_shape == shape) condition + // in resize (called by assign), which is always true when dimension() == 0. + if (e.derived_cast().dimension() == 0) + { + detail::resize_data_container(m_storage, std::size_t(1)); + } + semantic_base::assign(e); + } + + /** + * The extended assignment operator. + */ + template + template + inline auto xtensor_container::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + + //@} + + template + inline auto xtensor_container::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xtensor_container::storage_impl() const noexcept -> const storage_type& + { + return m_storage; + } + + /********************************** + * xtensor_adaptor implementation * + **********************************/ + + /** + * @name Constructors + */ + //@{ + /** + * Constructs an xtensor_adaptor of the given stl-like container. + * @param storage the container to adapt + */ + template + inline xtensor_adaptor::xtensor_adaptor(storage_type&& storage) + : base_type() + , m_storage(std::move(storage)) + { + } + + /** + * Constructs an xtensor_adaptor of the given stl-like container. + * @param storage the container to adapt + */ + template + inline xtensor_adaptor::xtensor_adaptor(const storage_type& storage) + : base_type() + , m_storage(storage) + { + } + + /** + * Constructs an xtensor_adaptor of the given stl-like container, + * with the specified shape and layout_type. + * @param storage the container to adapt + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + */ + template + template + inline xtensor_adaptor::xtensor_adaptor(D&& storage, const shape_type& shape, layout_type l) + : base_type() + , m_storage(std::forward(storage)) + { + base_type::resize(shape, l); + } + + /** + * Constructs an xtensor_adaptor of the given stl-like container, + * with the specified shape and strides. + * @param storage the container to adapt + * @param shape the shape of the xtensor_adaptor + * @param strides the strides of the xtensor_adaptor + */ + template + template + inline xtensor_adaptor::xtensor_adaptor( + D&& storage, + const shape_type& shape, + const strides_type& strides + ) + : base_type() + , m_storage(std::forward(storage)) + { + base_type::resize(shape, strides); + } + + //@} + + template + inline auto xtensor_adaptor::operator=(const xtensor_adaptor& rhs) -> self_type& + { + base_type::operator=(rhs); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xtensor_adaptor::operator=(xtensor_adaptor&& rhs) -> self_type& + { + base_type::operator=(std::move(rhs)); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xtensor_adaptor::operator=(temporary_type&& rhs) -> self_type& + { + base_type::shape_impl() = std::move(const_cast(rhs.shape())); + base_type::strides_impl() = std::move(const_cast(rhs.strides())); + base_type::backstrides_impl() = std::move(const_cast(rhs.backstrides())); + m_storage = std::move(rhs.storage()); + return *this; + } + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended assignment operator. + */ + template + template + inline auto xtensor_adaptor::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + + //@} + + template + inline auto xtensor_adaptor::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xtensor_adaptor::storage_impl() const noexcept -> const storage_type& + { + return m_storage; + } + + template + template + inline void xtensor_adaptor::reset_buffer(P&& pointer, S&& size) + { + return m_storage.reset_data(std::forward

(pointer), std::forward(size)); + } + + /******************************* + * xtensor_view implementation * + *******************************/ + + /** + * @name Constructors + */ + //@{ + /** + * Constructs an xtensor_view of the given stl-like container. + * @param storage the container to adapt + */ + template + inline xtensor_view::xtensor_view(storage_type&& storage) + : base_type() + , m_storage(std::move(storage)) + { + } + + /** + * Constructs an xtensor_view of the given stl-like container. + * @param storage the container to adapt + */ + template + inline xtensor_view::xtensor_view(const storage_type& storage) + : base_type() + , m_storage(storage) + { + } + + /** + * Constructs an xtensor_view of the given stl-like container, + * with the specified shape and layout_type. + * @param storage the container to adapt + * @param shape the shape of the xtensor_view + * @param l the layout_type of the xtensor_view + */ + template + template + inline xtensor_view::xtensor_view(D&& storage, const shape_type& shape, layout_type l) + : base_type() + , m_storage(std::forward(storage)) + { + base_type::resize(shape, l); + } + + /** + * Constructs an xtensor_view of the given stl-like container, + * with the specified shape and strides. + * @param storage the container to adapt + * @param shape the shape of the xtensor_view + * @param strides the strides of the xtensor_view + */ + template + template + inline xtensor_view::xtensor_view(D&& storage, const shape_type& shape, const strides_type& strides) + : base_type() + , m_storage(std::forward(storage)) + { + base_type::resize(shape, strides); + } + + //@} + + template + inline auto xtensor_view::operator=(const xtensor_view& rhs) -> self_type& + { + base_type::operator=(rhs); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xtensor_view::operator=(xtensor_view&& rhs) -> self_type& + { + base_type::operator=(std::move(rhs)); + m_storage = rhs.m_storage; + return *this; + } + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended assignment operator. + */ + template + template + inline auto xtensor_view::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + + //@} + + template + template + inline auto xtensor_view::operator=(const E& e) -> disable_xexpression& + { + std::fill(m_storage.begin(), m_storage.end(), e); + return *this; + } + + template + inline auto xtensor_view::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xtensor_view::storage_impl() const noexcept -> const storage_type& + { + return m_storage; + } + + template + inline void xtensor_view::assign_temporary_impl(temporary_type&& tmp) + { + std::copy(tmp.cbegin(), tmp.cend(), m_storage.begin()); + } + + /** + * Converts ``std::vector`` (returned e.g. from ``xt::argwhere``) to ``xtensor``. + * + * @param idx vector of indices + * + * @return ``xt::xtensor`` (e.g. ``xt::xtensor``) + */ + template + inline auto from_indices(const std::vector& idx) + { + using return_type = xtensor; + using size_type = typename return_type::size_type; + + if (idx.size() == 0) + { + return return_type::from_shape({size_type(0), size_type(0)}); + } + + return_type out = return_type::from_shape({idx.size(), idx[0].size()}); + + for (size_type i = 0; i < out.shape()[0]; ++i) + { + for (size_type j = 0; j < out.shape()[1]; ++j) + { + out(i, j) = idx[i][j]; + } + } + + return out; + } + + /** + * Converts ``std::vector`` (returned e.g. from ``xt::argwhere``) to a flattened + * ``xtensor``. + * + * @param idx a vector of indices + * + * @return ``xt::xtensor`` (e.g. ``xt::xtensor``) + */ + template + inline auto flatten_indices(const std::vector& idx) + { + auto n = idx.size(); + if (n != 0) + { + n *= idx[0].size(); + } + + using return_type = xtensor; + return_type out = return_type::from_shape({n}); + auto iter = out.begin(); + for_each( + idx.begin(), + idx.end(), + [&iter](const auto& t) + { + iter = std::copy(t.cbegin(), t.cend(), iter); + } + ); + + return out; + } + + struct ravel_vector_tag; + struct ravel_tensor_tag; + + namespace detail + { + template + struct ravel_return_type; + + template + struct ravel_return_type + { + using index_type = typename C::value_type; + using value_type = typename index_type::value_type; + using type = std::vector; + + template + static std::vector init(T n) + { + return std::vector(n); + } + }; + + template + struct ravel_return_type + { + using index_type = typename C::value_type; + using value_type = typename index_type::value_type; + using type = xt::xtensor; + + template + static xt::xtensor init(T n) + { + return xtensor::from_shape({n}); + } + }; + } + + template + using ravel_return_type_t = typename detail::ravel_return_type::type; + + /** + * Converts ``std::vector`` (returned e.g. from ``xt::argwhere``) to ``xtensor`` + * whereby the indices are ravelled. For 1-d input there is no conversion. + * + * @param idx vector of indices + * @param shape the shape of the original array + * @param l the layout type (row-major or column-major) + * + * @return ``xt::xtensor`` (e.g. ``xt::xtensor``) + */ + template + ravel_return_type_t + ravel_indices(const C& idx, const S& shape, layout_type l = layout_type::row_major) + { + using return_type = typename detail::ravel_return_type::type; + using value_type = typename detail::ravel_return_type::value_type; + using strides_type = get_strides_t; + strides_type strides = xtl::make_sequence(shape.size(), 0); + compute_strides(shape, l, strides); + return_type out = detail::ravel_return_type::init(idx.size()); + auto out_iter = out.begin(); + auto idx_iter = idx.begin(); + for (; out_iter != out.end(); ++out_iter, ++idx_iter) + { + *out_iter = element_offset(strides, (*idx_iter).cbegin(), (*idx_iter).cend()); + } + return out; + } +} + +#endif diff --git a/include/xtensor/core/xaccessible.hpp b/include/xtensor/core/xaccessible.hpp new file mode 100644 index 000000000..8ca55f8a4 --- /dev/null +++ b/include/xtensor/core/xaccessible.hpp @@ -0,0 +1,347 @@ +/*************************************************************************** + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#ifndef XTENSOR_ACCESSIBLE_HPP +#define XTENSOR_ACCESSIBLE_HPP + +#include "../core/xstrides.hpp" +#include "../core/xtensor_forward.hpp" +#include "../utils/xexception.hpp" + +namespace xt +{ + /** + * @class xconst_accessible + * @brief Base class for implementation of common expression constant access methods. + * + * The xaccessible class implements constant access methods common to all expressions. + * + * @tparam D The derived type, i.e. the inheriting class for which xconst_accessible + * provides the interface. + */ + template + class xconst_accessible + { + public: + + using derived_type = D; + using inner_types = xcontainer_inner_types; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using size_type = typename inner_types::size_type; + + size_type size() const noexcept(noexcept(derived_cast().shape())); + size_type dimension() const noexcept; + size_type shape(size_type index) const; + + template + const_reference at(Args... args) const; + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference periodic(Args... args) const; + + template + bool in_bounds(Args... args) const; + + const_reference front() const; + const_reference back() const; + + protected: + + xconst_accessible() = default; + ~xconst_accessible() = default; + + xconst_accessible(const xconst_accessible&) = default; + xconst_accessible& operator=(const xconst_accessible&) = default; + + xconst_accessible(xconst_accessible&&) = default; + xconst_accessible& operator=(xconst_accessible&&) = default; + + private: + + const derived_type& derived_cast() const noexcept; + }; + + /** + * @class xaccessible + * @brief Base class for implementation of common expression access methods. + * + * The xaccessible class implements access methods common to all expressions. + * + * @tparam D The derived type, i.e. the inheriting class for which xaccessible + * provides the interface. + */ + template + class xaccessible : public xconst_accessible + { + public: + + using base_type = xconst_accessible; + using derived_type = typename base_type::derived_type; + using reference = typename base_type::reference; + using size_type = typename base_type::size_type; + + template + reference at(Args... args); + + template + disable_integral_t operator[](const S& index); + template + reference operator[](std::initializer_list index); + reference operator[](size_type i); + + template + reference periodic(Args... args); + + reference front(); + reference back(); + + using base_type::at; + using base_type::operator[]; + using base_type::back; + using base_type::front; + using base_type::periodic; + + protected: + + xaccessible() = default; + ~xaccessible() = default; + + xaccessible(const xaccessible&) = default; + xaccessible& operator=(const xaccessible&) = default; + + xaccessible(xaccessible&&) = default; + xaccessible& operator=(xaccessible&&) = default; + + private: + + derived_type& derived_cast() noexcept; + }; + + /************************************ + * xconst_accessible implementation * + ************************************/ + + /** + * Returns the size of the expression. + */ + template + inline auto xconst_accessible::size() const noexcept(noexcept(derived_cast().shape())) -> size_type + { + return compute_size(derived_cast().shape()); + } + + /** + * Returns the number of dimensions of the expression. + */ + template + inline auto xconst_accessible::dimension() const noexcept -> size_type + { + return derived_cast().shape().size(); + } + + /** + * Returns the i-th dimension of the expression. + */ + template + inline auto xconst_accessible::shape(size_type index) const -> size_type + { + return derived_cast().shape()[index]; + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xconst_accessible::at(Args... args) const -> const_reference + { + check_access(derived_cast().shape(), args...); + return derived_cast().operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the expression. + */ + template + template + inline auto xconst_accessible::operator[](const S& index) const + -> disable_integral_t + { + return derived_cast().element(index.cbegin(), index.cend()); + } + + template + template + inline auto xconst_accessible::operator[](std::initializer_list index) const -> const_reference + { + return derived_cast().element(index.begin(), index.end()); + } + + template + inline auto xconst_accessible::operator[](size_type i) const -> const_reference + { + return derived_cast().operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after applying periodicity to the indices (negative and 'overflowing' indices are changed). + * @param args a list of indices specifying the position in the expression. Indices + * must be integers, the number of indices should be equal to the number of dimensions + * of the expression. + */ + template + template + inline auto xconst_accessible::periodic(Args... args) const -> const_reference + { + normalize_periodic(derived_cast().shape(), args...); + return derived_cast()(static_cast(args)...); + } + + /** + * Returns a constant reference to first the element of the expression + */ + template + inline auto xconst_accessible::front() const -> const_reference + { + return *derived_cast().begin(); + } + + /** + * Returns a constant reference to last the element of the expression + */ + template + inline auto xconst_accessible::back() const -> const_reference + { + return *std::prev(derived_cast().end()); + } + + /** + * Returns ``true`` only if the the specified position is a valid entry in the expression. + * @param args a list of indices specifying the position in the expression. + * @return bool + */ + template + template + inline bool xconst_accessible::in_bounds(Args... args) const + { + return check_in_bounds(derived_cast().shape(), args...); + } + + template + inline auto xconst_accessible::derived_cast() const noexcept -> const derived_type& + { + return *static_cast(this); + } + + /****************************** + * xaccessible implementation * + ******************************/ + + /** + * Returns a reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xaccessible::at(Args... args) -> reference + { + check_access(derived_cast().shape(), args...); + return derived_cast().operator()(args...); + } + + /** + * Returns a reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the expression. + */ + template + template + inline auto xaccessible::operator[](const S& index) -> disable_integral_t + { + return derived_cast().element(index.cbegin(), index.cend()); + } + + template + template + inline auto xaccessible::operator[](std::initializer_list index) -> reference + { + return derived_cast().element(index.begin(), index.end()); + } + + template + inline auto xaccessible::operator[](size_type i) -> reference + { + return derived_cast().operator()(i); + } + + /** + * Returns a reference to the element at the specified position in the expression, + * after applying periodicity to the indices (negative and 'overflowing' indices are changed). + * @param args a list of indices specifying the position in the expression. Indices + * must be integers, the number of indices should be equal to the number of dimensions + * of the expression. + */ + template + template + inline auto xaccessible::periodic(Args... args) -> reference + { + normalize_periodic(derived_cast().shape(), args...); + return derived_cast()(args...); + } + + /** + * Returns a reference to the first element of the expression. + */ + template + inline auto xaccessible::front() -> reference + { + return *derived_cast().begin(); + } + + /** + * Returns a reference to the last element of the expression. + */ + template + inline auto xaccessible::back() -> reference + { + return *std::prev(derived_cast().end()); + } + + template + inline auto xaccessible::derived_cast() noexcept -> derived_type& + { + return *static_cast(this); + } + +} + +#endif diff --git a/include/xtensor/core/xassign.hpp b/include/xtensor/core/xassign.hpp new file mode 100644 index 000000000..174ddcdc0 --- /dev/null +++ b/include/xtensor/core/xassign.hpp @@ -0,0 +1,1361 @@ +/*************************************************************************** + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#ifndef XTENSOR_ASSIGN_HPP +#define XTENSOR_ASSIGN_HPP + +#include +#include +#include +#include + +#include +#include + +#include "../core/xexpression.hpp" +#include "../core/xfunction.hpp" +#include "../core/xiterator.hpp" +#include "../core/xstrides.hpp" +#include "../core/xtensor_config.hpp" +#include "../core/xtensor_forward.hpp" +#include "../utils/xutils.hpp" + +#if defined(XTENSOR_USE_TBB) +#include +#endif + +namespace xt +{ + + /******************** + * Assign functions * + ********************/ + + template + void assign_data(xexpression& e1, const xexpression& e2, bool trivial); + + template + void assign_xexpression(xexpression& e1, const xexpression& e2); + + template + void computed_assign(xexpression& e1, const xexpression& e2); + + template + void scalar_computed_assign(xexpression& e1, const E2& e2, F&& f); + + template + void assert_compatible_shape(const xexpression& e1, const xexpression& e2); + + template + void strided_assign(E1& e1, const E2& e2, std::false_type /*disable*/); + + template + void strided_assign(E1& e1, const E2& e2, std::true_type /*enable*/); + + /************************ + * xexpression_assigner * + ************************/ + + template + class xexpression_assigner_base; + + template <> + class xexpression_assigner_base + { + public: + + template + static void assign_data(xexpression& e1, const xexpression& e2, bool trivial); + }; + + template + class xexpression_assigner : public xexpression_assigner_base + { + public: + + using base_type = xexpression_assigner_base; + + template + static void assign_xexpression(E1& e1, const E2& e2); + + template + static void computed_assign(xexpression& e1, const xexpression& e2); + + template + static void scalar_computed_assign(xexpression& e1, const E2& e2, F&& f); + + template + static void assert_compatible_shape(const xexpression& e1, const xexpression& e2); + + private: + + template + static bool resize(E1& e1, const E2& e2); + + template + static bool resize(E1& e1, const xfunction& e2); + }; + + /******************** + * stepper_assigner * + ********************/ + + template + class stepper_assigner + { + public: + + using lhs_iterator = typename E1::stepper; + using rhs_iterator = typename E2::const_stepper; + using shape_type = typename E1::shape_type; + using index_type = xindex_type_t; + using size_type = typename lhs_iterator::size_type; + using difference_type = typename lhs_iterator::difference_type; + + stepper_assigner(E1& e1, const E2& e2); + + void run(); + + void step(size_type i); + void step(size_type i, size_type n); + void reset(size_type i); + + void to_end(layout_type); + + private: + + E1& m_e1; + + lhs_iterator m_lhs; + rhs_iterator m_rhs; + + index_type m_index; + }; + + /******************* + * linear_assigner * + *******************/ + + template + class linear_assigner + { + public: + + template + static void run(E1& e1, const E2& e2); + }; + + template <> + class linear_assigner + { + public: + + template + static void run(E1& e1, const E2& e2); + + private: + + template + static void run_impl(E1& e1, const E2& e2, std::true_type); + + template + static void run_impl(E1& e1, const E2& e2, std::false_type); + }; + + /************************* + * strided_loop_assigner * + *************************/ + + namespace strided_assign_detail + { + struct loop_sizes_t + { + bool can_do_strided_assign; + bool is_row_major; + std::size_t inner_loop_size; + std::size_t outer_loop_size; + std::size_t cut; + std::size_t dimension; + }; + } + + template + class strided_loop_assigner + { + public: + + using loop_sizes_t = strided_assign_detail::loop_sizes_t; + // is_row_major, inner_loop_size, outer_loop_size, cut + template + static void run(E1& e1, const E2& e2, const loop_sizes_t& loop_sizes); + template + static loop_sizes_t get_loop_sizes(E1& e1, const E2& e2); + template + static void run(E1& e1, const E2& e2); + }; + + /*********************************** + * Assign functions implementation * + ***********************************/ + + template + inline void assign_data(xexpression& e1, const xexpression& e2, bool trivial) + { + using tag = xexpression_tag_t; + xexpression_assigner::assign_data(e1, e2, trivial); + } + + template + inline void assign_xexpression(xexpression& e1, const xexpression& e2) + { + if constexpr (assignable_to_expression) + { + e2.derived_cast().assign_to(e1); + } + else + { + using tag = xexpression_tag_t; + xexpression_assigner::assign_xexpression(e1, e2); + } + } + + template + inline void computed_assign(xexpression& e1, const xexpression& e2) + { + using tag = xexpression_tag_t; + xexpression_assigner::computed_assign(e1, e2); + } + + template + inline void scalar_computed_assign(xexpression& e1, const E2& e2, F&& f) + { + using tag = xexpression_tag_t; + xexpression_assigner::scalar_computed_assign(e1, e2, std::forward(f)); + } + + template + inline void assert_compatible_shape(const xexpression& e1, const xexpression& e2) + { + using tag = xexpression_tag_t; + xexpression_assigner::assert_compatible_shape(e1, e2); + } + + /*************************************** + * xexpression_assigner implementation * + ***************************************/ + + namespace detail + { + template + constexpr bool linear_static_layout() + { + // A row_major or column_major container with a dimension <= 1 is computed as + // layout any, leading to some performance improvements, for example when + // assigning a col-major vector to a row-major vector etc + return compute_layout( + select_layout::value, + select_layout::value + ) + != layout_type::dynamic; + } + + template + inline auto is_linear_assign(const E1& e1, const E2& e2) + -> std::enable_if_t, bool> + { + return (E1::contiguous_layout && E2::contiguous_layout && linear_static_layout()) + || (e1.is_contiguous() && e2.has_linear_assign(e1.strides())); + } + + template + inline auto is_linear_assign(const E1&, const E2&) -> std::enable_if_t, bool> + { + return false; + } + + template + inline bool linear_dynamic_layout(const E1& e1, const E2& e2) + { + return e1.is_contiguous() && e2.is_contiguous() + && compute_layout(e1.layout(), e2.layout()) != layout_type::dynamic; + } + + template + struct has_step_leading : std::false_type + { + }; + + template + struct has_step_leading().step_leading())>> : std::true_type + { + }; + + template + struct use_strided_loop + { + static constexpr bool stepper_deref() + { + return std::is_reference::value; + } + + static constexpr bool value = strided_expression + && has_step_leading::value && stepper_deref(); + }; + + template + struct use_strided_loop> + { + static constexpr bool value = true; + }; + + template + struct use_strided_loop> + { + static constexpr bool value = std::conjunction>...>::value; + }; + + /** + * Considering the assignment LHS = RHS, if the requested value type used for + * loading simd from RHS is not complex while LHS value_type is complex, + * the assignment fails. The reason is that SIMD batches of complex values cannot + * be implicitly instantiated from batches of scalar values. + * Making the constructor implicit does not fix the issue since in the end, + * the assignment is done with vec.store(buffer) where vec is a batch of scalars + * and buffer an array of complex. SIMD batches of scalars do not provide overloads + * of store that accept buffer of complex values and that SHOULD NOT CHANGE. + * Load and store overloads must accept SCALAR BUFFERS ONLY. + * Therefore, the solution is to explicitly force the instantiation of complex + * batches in the assignment mechanism. A common situation that triggers this + * issue is: + * xt::xarray rhs = { 1, 2, 3 }; + * xt::xarray> lhs = rhs; + */ + template + struct conditional_promote_to_complex + { + static constexpr bool cond = xtl::is_gen_complex::value && !xtl::is_gen_complex::value; + // Alternative: use std::complex or xcomplex depending on T1 + using type = std::conditional_t; + }; + + template + using conditional_promote_to_complex_t = typename conditional_promote_to_complex::type; + } + + template + class xassign_traits + { + private: + + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + + template + using is_bool = std::is_same; + + static constexpr bool is_bool_conversion() + { + return is_bool::value && !is_bool::value; + } + + static constexpr bool contiguous_layout() + { + return E1::contiguous_layout && E2::contiguous_layout; + } + + static constexpr bool convertible_types() + { + return std::is_convertible::value && !is_bool_conversion(); + } + + static constexpr bool use_xsimd() + { + return xt_simd::simd_traits::size > 1; + } + + template + static constexpr bool simd_size_impl() + { + return xt_simd::simd_traits::size > 1 || (is_bool::value && use_xsimd()); + } + + static constexpr bool simd_size() + { + return simd_size_impl() && simd_size_impl(); + } + + static constexpr bool simd_interface() + { + return has_simd_interface() + && has_simd_interface(); + } + + public: + + // constexpr methods instead of constexpr data members avoid the need of definitions at namespace + // scope of these data members (since they are odr-used). + + static constexpr bool simd_assign() + { + return convertible_types() && simd_size() && simd_interface(); + } + + static constexpr bool linear_assign(const E1& e1, const E2& e2, bool trivial) + { + return trivial && detail::is_linear_assign(e1, e2); + } + + static constexpr bool strided_assign() + { + return detail::use_strided_loop::value && detail::use_strided_loop::value; + } + + static constexpr bool simd_linear_assign() + { + return contiguous_layout() && simd_assign(); + } + + static constexpr bool simd_strided_assign() + { + return strided_assign() && simd_assign(); + } + + static constexpr bool simd_linear_assign(const E1& e1, const E2& e2) + { + return simd_assign() && detail::linear_dynamic_layout(e1, e2); + } + + using e2_requested_value_type = std:: + conditional_t::value, typename E2::bool_load_type, e2_value_type>; + using requested_value_type = detail::conditional_promote_to_complex_t; + }; + + template + inline void xexpression_assigner_base::assign_data( + xexpression& e1, + const xexpression& e2, + bool trivial + ) + { + E1& de1 = e1.derived_cast(); + const E2& de2 = e2.derived_cast(); + using traits = xassign_traits; + + bool linear_assign = traits::linear_assign(de1, de2, trivial); + constexpr bool simd_assign = traits::simd_assign(); + constexpr bool simd_linear_assign = traits::simd_linear_assign(); + constexpr bool simd_strided_assign = traits::simd_strided_assign(); + if (linear_assign) + { + if (simd_linear_assign || traits::simd_linear_assign(de1, de2)) + { + // Do not use linear_assigner here since it will make the compiler + // instantiate this branch even if the runtime condition is false, resulting + // in compilation error for expressions that do not provide a SIMD interface. + // simd_assign is true if simd_linear_assign() or simd_linear_assign(de1, de2) + // is true. + linear_assigner::run(de1, de2); + } + else + { + linear_assigner::run(de1, de2); + } + } + else if (simd_strided_assign) + { + strided_loop_assigner::run(de1, de2); + } + else + { + stepper_assigner(de1, de2).run(); + } + } + + template + template + inline void xexpression_assigner::assign_xexpression(E1& e1, const E2& e2) + { + bool trivial_broadcast = resize(e1.derived_cast(), e2.derived_cast()); + base_type::assign_data(e1, e2, trivial_broadcast); + } + + template + template + inline void xexpression_assigner::computed_assign(xexpression& e1, const xexpression& e2) + { + using shape_type = typename E1::shape_type; + using comperator_type = std::greater; + + using size_type = typename E1::size_type; + + E1& de1 = e1.derived_cast(); + const E2& de2 = e2.derived_cast(); + + size_type dim2 = de2.dimension(); + shape_type shape = uninitialized_shape(dim2); + + bool trivial_broadcast = de2.broadcast_shape(shape, true); + + auto&& de1_shape = de1.shape(); + if (dim2 > de1.dimension() + || std::lexicographical_compare( + shape.begin(), + shape.end(), + de1_shape.begin(), + de1_shape.end(), + comperator_type() + )) + { + typename E1::temporary_type tmp(shape); + base_type::assign_data(tmp, e2, trivial_broadcast); + de1.assign_temporary(std::move(tmp)); + } + else + { + base_type::assign_data(e1, e2, trivial_broadcast); + } + } + + template + template + inline void xexpression_assigner::scalar_computed_assign(xexpression& e1, const E2& e2, F&& f) + { + E1& d = e1.derived_cast(); + using size_type = typename E1::size_type; + auto dst = d.storage().begin(); + for (size_type i = d.size(); i > 0; --i) + { + *dst = f(*dst, e2); + ++dst; + } + } + + template + template + inline void + xexpression_assigner::assert_compatible_shape(const xexpression& e1, const xexpression& e2) + { + const E1& de1 = e1.derived_cast(); + const E2& de2 = e2.derived_cast(); + if (!broadcastable(de2.shape(), de1.shape())) + { + throw_broadcast_error(de2.shape(), de1.shape()); + } + } + + namespace detail + { + template + struct static_trivial_broadcast; + + template + struct static_trivial_broadcast + { + static constexpr bool value = detail::promote_index::shape_type...>::value; + }; + + template + struct static_trivial_broadcast + { + static constexpr bool value = false; + }; + } + + template + template + inline bool xexpression_assigner::resize(E1& e1, const E2& e2) + { + // If our RHS is not a xfunction, we know that the RHS is at least potentially trivial + // We check the strides of the RHS in detail::is_trivial_broadcast to see if they match up! + // So we can skip a shape copy and a call to broadcast_shape(...) + e1.resize(e2.shape()); + return true; + } + + template + template + inline bool xexpression_assigner::resize(E1& e1, const xfunction& e2) + { + if constexpr (detail::is_fixed::shape_type>::value) + { + /* + * If the shape of the xfunction is statically known, we can compute the broadcast triviality + * at compile time plus we can resize right away. + */ + // resize in case LHS is not a fixed size container. If it is, this is a NOP + e1.resize(typename xfunction::shape_type{}); + return detail::static_trivial_broadcast< + detail::is_fixed::shape_type>::value, + CT...>::value; + } + else + { + using index_type = xindex_type_t; + using size_type = typename E1::size_type; + size_type size = e2.dimension(); + index_type shape = uninitialized_shape(size); + bool trivial_broadcast = e2.broadcast_shape(shape, true); + e1.resize(std::move(shape)); + return trivial_broadcast; + } + } + + /*********************************** + * stepper_assigner implementation * + ***********************************/ + + template + struct is_narrowing_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = xtl::is_arithmetic::value + && (sizeof(result_type) < sizeof(argument_type) + || (xtl::is_integral::value + && std::is_floating_point::value)); + }; + + template + struct has_sign_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = xtl::is_signed::value != xtl::is_signed::value; + }; + + template + struct has_assign_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = is_narrowing_conversion::value + || has_sign_conversion::value; + }; + + template + inline stepper_assigner::stepper_assigner(E1& e1, const E2& e2) + : m_e1(e1) + , m_lhs(e1.stepper_begin(e1.shape())) + , m_rhs(e2.stepper_begin(e1.shape())) + , m_index(xtl::make_sequence(e1.shape().size(), size_type(0))) + { + } + + template + inline void stepper_assigner::run() + { + using tmp_size_type = typename E1::size_type; + using argument_type = std::decay_t; + using result_type = std::decay_t; + constexpr bool needs_cast = has_assign_conversion::value; + + tmp_size_type s = m_e1.size(); + for (tmp_size_type i = 0; i < s; ++i) + { + *m_lhs = conditional_cast(*m_rhs); + stepper_tools::increment_stepper(*this, m_index, m_e1.shape()); + } + } + + template + inline void stepper_assigner::step(size_type i) + { + m_lhs.step(i); + m_rhs.step(i); + } + + template + inline void stepper_assigner::step(size_type i, size_type n) + { + m_lhs.step(i, n); + m_rhs.step(i, n); + } + + template + inline void stepper_assigner::reset(size_type i) + { + m_lhs.reset(i); + m_rhs.reset(i); + } + + template + inline void stepper_assigner::to_end(layout_type l) + { + m_lhs.to_end(l); + m_rhs.to_end(l); + } + + /********************************** + * linear_assigner implementation * + **********************************/ + + template + template + inline void linear_assigner::run(E1& e1, const E2& e2) + { + using lhs_align_mode = xt_simd::container_alignment_t; + constexpr bool is_aligned = std::is_same::value; + using rhs_align_mode = std::conditional_t; + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + using value_type = typename xassign_traits::requested_value_type; + using simd_type = xt_simd::simd_type; + using size_type = typename E1::size_type; + size_type size = e1.size(); + constexpr size_type simd_size = simd_type::size; + constexpr bool needs_cast = has_assign_conversion::value; + + size_type align_begin = is_aligned ? 0 : xt_simd::get_alignment_offset(e1.data(), size, simd_size); + size_type align_end = align_begin + ((size - align_begin) & ~(simd_size - 1)); + + for (size_type i = 0; i < align_begin; ++i) + { + e1.data_element(i) = conditional_cast(e2.data_element(i)); + } + +#if defined(XTENSOR_USE_TBB) + if (size >= XTENSOR_TBB_THRESHOLD) + { + tbb::static_partitioner ap; + tbb::parallel_for( + align_begin, + align_end, + simd_size, + [&e1, &e2](size_t i) + { + e1.template store_simd( + i, + e2.template load_simd(i) + ); + }, + ap + ); + } + else + { + for (size_type i = align_begin; i < align_end; i += simd_size) + { + e1.template store_simd(i, e2.template load_simd(i)); + } + } +#elif defined(XTENSOR_USE_OPENMP) + if (size >= size_type(XTENSOR_OPENMP_TRESHOLD)) + { +#pragma omp parallel for default(none) shared(align_begin, align_end, e1, e2) +#ifndef _WIN32 + for (size_type i = align_begin; i < align_end; i += simd_size) + { + e1.template store_simd(i, e2.template load_simd(i)); + } +#else + for (auto i = static_cast(align_begin); i < static_cast(align_end); + i += static_cast(simd_size)) + { + size_type ui = static_cast(i); + e1.template store_simd(ui, e2.template load_simd(ui)); + } +#endif + } + else + { + for (size_type i = align_begin; i < align_end; i += simd_size) + { + e1.template store_simd(i, e2.template load_simd(i)); + } + } +#else + for (size_type i = align_begin; i < align_end; i += simd_size) + { + e1.template store_simd(i, e2.template load_simd(i)); + } +#endif + for (size_type i = align_end; i < size; ++i) + { + e1.data_element(i) = conditional_cast(e2.data_element(i)); + } + } + + template + inline void linear_assigner::run(E1& e1, const E2& e2) + { + using is_convertible = std:: + is_convertible::value_type, typename std::decay_t::value_type>; + // If the types are not compatible, this function is still instantiated but never called. + // To avoid compilation problems in effectively unused code trivial_assigner_run_impl is + // empty in this case. + run_impl(e1, e2, is_convertible()); + } + + template + inline void linear_assigner::run_impl(E1& e1, const E2& e2, std::true_type /*is_convertible*/) + { + using value_type = typename E1::value_type; + using size_type = typename E1::size_type; + auto src = linear_begin(e2); + auto dst = linear_begin(e1); + size_type n = e1.size(); +#if defined(XTENSOR_USE_TBB) + tbb::static_partitioner sp; + tbb::parallel_for( + std::ptrdiff_t(0), + static_cast(n), + [&](std::ptrdiff_t i) + { + *(dst + i) = static_cast(*(src + i)); + }, + sp + ); +#elif defined(XTENSOR_USE_OPENMP) + if (n >= XTENSOR_OPENMP_TRESHOLD) + { +#pragma omp parallel for default(none) shared(src, dst, n) + for (std::ptrdiff_t i = std::ptrdiff_t(0); i < static_cast(n); i++) + { + *(dst + i) = static_cast(*(src + i)); + } + } + else + { + for (; n > size_type(0); --n) + { + *dst = static_cast(*src); + ++src; + ++dst; + } + } +#else + for (; n > size_type(0); --n) + { + *dst = static_cast(*src); + ++src; + ++dst; + } +#endif + } + + template + inline void linear_assigner::run_impl(E1&, const E2&, std::false_type /*is_convertible*/) + { + XTENSOR_PRECONDITION(false, "Internal error: linear_assigner called with unrelated types."); + } + + /**************************************** + * strided_loop_assigner implementation * + ****************************************/ + + namespace strided_assign_detail + { + template + struct idx_tools; + + template <> + struct idx_tools + { + template + static void next_idx(T& outer_index, T& outer_shape) + { + auto i = outer_index.size(); + for (; i > 0; --i) + { + if (outer_index[i - 1] + 1 >= outer_shape[i - 1]) + { + outer_index[i - 1] = 0; + } + else + { + outer_index[i - 1]++; + break; + } + } + } + + template + static void nth_idx(size_t n, T& outer_index, const T& outer_shape) + { + dynamic_shape stride_sizes; + xt::resize_container(stride_sizes, outer_shape.size()); + // compute strides + using size_type = typename T::size_type; + for (size_type i = outer_shape.size(); i > 0; i--) + { + stride_sizes[i - 1] = (i == outer_shape.size()) ? 1 : stride_sizes[i] * outer_shape[i]; + } + + // compute index + for (size_type i = 0; i < outer_shape.size(); i++) + { + auto d_idx = n / stride_sizes[i]; + outer_index[i] = d_idx; + n -= d_idx * stride_sizes[i]; + } + } + }; + + template <> + struct idx_tools + { + template + static void next_idx(T& outer_index, T& outer_shape) + { + using size_type = typename T::size_type; + size_type i = 0; + auto sz = outer_index.size(); + for (; i < sz; ++i) + { + if (outer_index[i] + 1 >= outer_shape[i]) + { + outer_index[i] = 0; + } + else + { + outer_index[i]++; + break; + } + } + } + + template + static void nth_idx(size_t n, T& outer_index, const T& outer_shape) + { + dynamic_shape stride_sizes; + xt::resize_container(stride_sizes, outer_shape.size()); + + using size_type = typename T::size_type; + + // compute required strides + for (size_type i = 0; i < outer_shape.size(); i++) + { + stride_sizes[i] = (i == 0) ? 1 : stride_sizes[i - 1] * outer_shape[i - 1]; + } + + // compute index + for (size_type i = outer_shape.size(); i > 0;) + { + i--; + auto d_idx = n / stride_sizes[i]; + outer_index[i] = d_idx; + n -= d_idx * stride_sizes[i]; + } + } + }; + + template + struct check_strides_functor + { + using strides_type = S; + + check_strides_functor(const S& strides) + : m_cut(L == layout_type::row_major ? 0 : strides.size()) + , m_strides(strides) + { + } + + template + std::enable_if_t operator()(const T& el) + { + // All dimenions less than var have differing strides + auto var = check_strides_overlap::get(m_strides, el.strides()); + if (var > m_cut) + { + m_cut = var; + } + return m_cut; + } + + template + std::enable_if_t operator()(const T& el) + { + auto var = check_strides_overlap::get(m_strides, el.strides()); + // All dimensions >= var have differing strides + if (var < m_cut) + { + m_cut = var; + } + return m_cut; + } + + template + std::size_t operator()(const xt::xscalar& /*el*/) + { + return m_cut; + } + + template + std::size_t operator()(const xt::xfunction& xf) + { + xt::for_each(*this, xf.arguments()); + return m_cut; + } + + private: + + std::size_t m_cut; + const strides_type& m_strides; + }; + + template || !possible, bool> = true> + loop_sizes_t get_loop_sizes(const E1& e1, const E2&) + { + return {false, true, 1, e1.size(), e1.dimension(), e1.dimension()}; + } + + template && possible, bool> = true> + loop_sizes_t get_loop_sizes(const E1& e1, const E2& e2) + { + using shape_value_type = typename E1::shape_type::value_type; + bool is_row_major = true; + + // Try to find a row-major scheme first, where the outer loop is on the first N = `cut` + // dimensions, and the inner loop is + is_row_major = true; + auto is_zero = [](auto i) + { + return i == 0; + }; + auto&& strides = e1.strides(); + auto it_bwd = std::find_if_not(strides.rbegin(), strides.rend(), is_zero); + bool de1_row_contiguous = it_bwd != strides.rend() && *it_bwd == 1; + auto it_fwd = std::find_if_not(strides.begin(), strides.end(), is_zero); + bool de1_col_contiguous = it_fwd != strides.end() && *it_fwd == 1; + if (de1_row_contiguous) + { + is_row_major = true; + } + else if (de1_col_contiguous) + { + is_row_major = false; + } + else + { + // No strided loop possible. + return {false, true, 1, e1.size(), e1.dimension(), e1.dimension()}; + } + + // Cut is the number of dimensions in the outer loop + std::size_t cut = 0; + + if (is_row_major) + { + auto csf = check_strides_functor(e1.strides()); + cut = csf(e2); + // This makes that only one dimension will be treated in the inner loop. + if (cut < e1.strides().size() - 1) + { + // Only make the inner loop go over one dimension by default for now + cut = e1.strides().size() - 1; + } + } + else if (!is_row_major) + { + auto csf = check_strides_functor(e1.strides() + ); + cut = csf(e2); + if (cut > 1) + { + // Only make the inner loop go over one dimension by default for now + cut = 1; + } + } // can't reach here because this would have already triggered the fallback + + std::size_t outer_loop_size = static_cast(std::accumulate( + e1.shape().begin(), + e1.shape().begin() + static_cast(cut), + shape_value_type(1), + std::multiplies{} + )); + std::size_t inner_loop_size = static_cast(std::accumulate( + e1.shape().begin() + static_cast(cut), + e1.shape().end(), + shape_value_type(1), + std::multiplies{} + )); + + if (!is_row_major) + { + std::swap(outer_loop_size, inner_loop_size); + } + + return {inner_loop_size > 1, is_row_major, inner_loop_size, outer_loop_size, cut, e1.dimension()}; + } + } + + template + template + inline strided_assign_detail::loop_sizes_t strided_loop_assigner::get_loop_sizes(E1& e1, const E2& e2) + { + return strided_assign_detail::get_loop_sizes(e1, e2); + } + +#define strided_parallel_assign + + template + template + inline void strided_loop_assigner::run(E1& e1, const E2& e2, const loop_sizes_t& loop_sizes) + { + bool is_row_major = loop_sizes.is_row_major; + std::size_t inner_loop_size = loop_sizes.inner_loop_size; + std::size_t outer_loop_size = loop_sizes.outer_loop_size; + std::size_t cut = loop_sizes.cut; + + + // TODO can we get rid of this and use `shape_type`? + dynamic_shape idx, max_shape; + + if (is_row_major) + { + xt::resize_container(idx, cut); + max_shape.assign(e1.shape().begin(), e1.shape().begin() + static_cast(cut)); + } + else + { + xt::resize_container(idx, e1.shape().size() - cut); + max_shape.assign(e1.shape().begin() + static_cast(cut), e1.shape().end()); + } + + // add this when we have std::array index! + // std::fill(idx.begin(), idx.end(), 0); + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + constexpr bool needs_cast = has_assign_conversion::value; + using value_type = typename xassign_traits::requested_value_type; + using simd_type = std::conditional_t< + std::is_same::value, + xt_simd::simd_bool_type, + xt_simd::simd_type>; + + std::size_t simd_size = inner_loop_size / simd_type::size; + std::size_t simd_rest = inner_loop_size % simd_type::size; + + auto fct_stepper = e2.stepper_begin(e1.shape()); + auto res_stepper = e1.stepper_begin(e1.shape()); + + // TODO in 1D case this is ambiguous -- could be RM or CM. + // Use default layout to make decision + std::size_t step_dim = 0; + if (!is_row_major) // row major case + { + step_dim = cut; + } +#if defined(XTENSOR_USE_OPENMP) && defined(strided_parallel_assign) + if (outer_loop_size >= XTENSOR_OPENMP_TRESHOLD / inner_loop_size) + { + std::size_t first_step = true; +#pragma omp parallel for schedule(static) firstprivate(first_step, fct_stepper, res_stepper, idx) + for (std::size_t ox = 0; ox < outer_loop_size; ++ox) + { + if (first_step) + { + is_row_major + ? strided_assign_detail::idx_tools::nth_idx(ox, idx, max_shape) + : strided_assign_detail::idx_tools::nth_idx(ox, idx, max_shape); + + for (std::size_t i = 0; i < idx.size(); ++i) + { + fct_stepper.step(i + step_dim, idx[i]); + res_stepper.step(i + step_dim, idx[i]); + } + first_step = false; + } + + for (std::size_t i = 0; i < simd_size; ++i) + { + res_stepper.store_simd(fct_stepper.template step_simd()); + } + for (std::size_t i = 0; i < simd_rest; ++i) + { + *(res_stepper) = conditional_cast(*(fct_stepper)); + res_stepper.step_leading(); + fct_stepper.step_leading(); + } + + // next unaligned index + is_row_major + ? strided_assign_detail::idx_tools::next_idx(idx, max_shape) + : strided_assign_detail::idx_tools::next_idx(idx, max_shape); + + fct_stepper.to_begin(); + + // need to step E1 as well if not contigous assign (e.g. view) + if (!E1::contiguous_layout) + { + res_stepper.to_begin(); + for (std::size_t i = 0; i < idx.size(); ++i) + { + fct_stepper.step(i + step_dim, idx[i]); + res_stepper.step(i + step_dim, idx[i]); + } + } + else + { + for (std::size_t i = 0; i < idx.size(); ++i) + { + fct_stepper.step(i + step_dim, idx[i]); + } + } + } + } + else + { +#elif defined(strided_parallel_assign) && defined(XTENSOR_USE_TBB) + if (outer_loop_size > XTENSOR_TBB_THRESHOLD / inner_loop_size) + { + tbb::static_partitioner sp; + tbb::parallel_for( + tbb::blocked_range(0ul, outer_loop_size), + [&e1, &e2, is_row_major, step_dim, simd_size, simd_rest, &max_shape, &idx_ = idx]( + const tbb::blocked_range& r + ) + { + auto idx = idx_; + auto fct_stepper = e2.stepper_begin(e1.shape()); + auto res_stepper = e1.stepper_begin(e1.shape()); + std::size_t first_step = true; + // #pragma omp parallel for schedule(static) firstprivate(first_step, fct_stepper, + // res_stepper, idx) + for (std::size_t ox = r.begin(); ox < r.end(); ++ox) + { + if (first_step) + { + is_row_major + ? strided_assign_detail::idx_tools::nth_idx(ox, idx, max_shape) + : strided_assign_detail::idx_tools::nth_idx( + ox, + idx, + max_shape + ); + + for (std::size_t i = 0; i < idx.size(); ++i) + { + fct_stepper.step(i + step_dim, idx[i]); + res_stepper.step(i + step_dim, idx[i]); + } + first_step = false; + } + + for (std::size_t i = 0; i < simd_size; ++i) + { + res_stepper.store_simd(fct_stepper.template step_simd()); + } + for (std::size_t i = 0; i < simd_rest; ++i) + { + *(res_stepper) = conditional_cast(*(fct_stepper)); + res_stepper.step_leading(); + fct_stepper.step_leading(); + } + + // next unaligned index + is_row_major + ? strided_assign_detail::idx_tools::next_idx(idx, max_shape) + : strided_assign_detail::idx_tools::next_idx(idx, max_shape); + + fct_stepper.to_begin(); + + // need to step E1 as well if not contigous assign (e.g. view) + if (!E1::contiguous_layout) + { + res_stepper.to_begin(); + for (std::size_t i = 0; i < idx.size(); ++i) + { + fct_stepper.step(i + step_dim, idx[i]); + res_stepper.step(i + step_dim, idx[i]); + } + } + else + { + for (std::size_t i = 0; i < idx.size(); ++i) + { + fct_stepper.step(i + step_dim, idx[i]); + } + } + } + }, + sp + ); + } + else + { + +#endif + for (std::size_t ox = 0; ox < outer_loop_size; ++ox) + { + for (std::size_t i = 0; i < simd_size; ++i) + { + res_stepper.store_simd(fct_stepper.template step_simd()); + } + for (std::size_t i = 0; i < simd_rest; ++i) + { + *(res_stepper) = conditional_cast(*(fct_stepper)); + res_stepper.step_leading(); + fct_stepper.step_leading(); + } + + is_row_major + ? strided_assign_detail::idx_tools::next_idx(idx, max_shape) + : strided_assign_detail::idx_tools::next_idx(idx, max_shape); + + fct_stepper.to_begin(); + + // need to step E1 as well if not contigous assign (e.g. view) + if (!E1::contiguous_layout) + { + res_stepper.to_begin(); + for (std::size_t i = 0; i < idx.size(); ++i) + { + fct_stepper.step(i + step_dim, idx[i]); + res_stepper.step(i + step_dim, idx[i]); + } + } + else + { + for (std::size_t i = 0; i < idx.size(); ++i) + { + fct_stepper.step(i + step_dim, idx[i]); + } + } + } +#if (defined(XTENSOR_USE_OPENMP) || defined(XTENSOR_USE_TBB)) && defined(strided_parallel_assign) + } +#endif + } + + template <> + template + inline void strided_loop_assigner::run(E1& e1, const E2& e2) + { + strided_assign_detail::loop_sizes_t loop_sizes = strided_loop_assigner::get_loop_sizes(e1, e2); + if (loop_sizes.can_do_strided_assign) + { + run(e1, e2, loop_sizes); + } + else + { + // trigger the fallback assigner + stepper_assigner(e1, e2).run(); + } + } + + template <> + template + inline void strided_loop_assigner::run(E1& /*e1*/, const E2& /*e2*/, const loop_sizes_t&) + { + } + + template <> + template + inline void strided_loop_assigner::run(E1& e1, const E2& e2) + { + // trigger the fallback assigner + stepper_assigner(e1, e2).run(); + } +} + +#endif diff --git a/include/xtensor/core/xeval.hpp b/include/xtensor/core/xeval.hpp new file mode 100644 index 000000000..d0ba070e9 --- /dev/null +++ b/include/xtensor/core/xeval.hpp @@ -0,0 +1,177 @@ +/*************************************************************************** + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#ifndef XTENSOR_EVAL_HPP +#define XTENSOR_EVAL_HPP + +#include "../core/xexpression_traits.hpp" +#include "../core/xshape.hpp" +#include "../core/xtensor_forward.hpp" + +namespace xt +{ + + /** + * @defgroup xt_xeval Evaluation + * + * Evaluation functions. + * Defined in ``xtensor/xeval.hpp`` + */ + + namespace detail + { + template + using is_container = std::is_base_of>, T>; + } + + /** + * Force evaluation of xexpression. + * + * @code{.cpp} + * xt::xarray a = {1, 2, 3, 4}; + * auto&& b = xt::eval(a); // b is a reference to a, no copy! + * auto&& c = xt::eval(a + b); // c is xarray, not an xexpression + * @endcode + * + * @ingroup xt_xeval + * @return xt::xarray or xt::xtensor depending on shape type + */ + template + inline auto eval(T&& t) -> std::enable_if_t>::value, T&&> + { + return std::forward(t); + } + + /// @cond DOXYGEN_INCLUDE_SFINAE + template + inline auto eval(T&& t) + -> std::enable_if_t>::value, temporary_type_t> + { + return std::forward(t); + } + + /// @endcond + + namespace detail + { + /********************************** + * has_same_layout implementation * + **********************************/ + + template + constexpr bool has_same_layout() + { + return (std::decay_t::static_layout == L) || (L == layout_type::any); + } + + template + constexpr bool has_same_layout(E&&) + { + return has_same_layout(); + } + + template + constexpr bool has_same_layout(E1&&, E2&&) + { + return has_same_layout::static_layout, E2>(); + } + + /********************************* + * has_fixed_dims implementation * + *********************************/ + + template + constexpr bool has_fixed_dims() + { + return detail::is_array::shape_type>::value; + } + + template + constexpr bool has_fixed_dims(E&&) + { + return has_fixed_dims(); + } + + /**************************************** + * as_xarray_container_t implementation * + ****************************************/ + + template + using as_xarray_container_t = xarray::value_type, layout_remove_any(L)>; + + /***************************************** + * as_xtensor_container_t implementation * + *****************************************/ + + template + using as_xtensor_container_t = xtensor< + typename std::decay_t::value_type, + std::tuple_size::shape_type>::value, + layout_remove_any(L)>; + } + + /** + * Force evaluation of xexpression not providing a data interface + * and convert to the required layout. + * + * @code{.cpp} + * xt::xarray a = {1, 2, 3, 4}; + * + * // take reference to a (no copy!) + * auto&& b = xt::as_strided(a); + * + * // xarray with the required layout + * auto&& c = xt::as_strided(a); + * + * // xexpression + * auto&& a_cast = xt::cast(a); + * + * // xarray, not an xexpression + * auto&& d = xt::as_strided(a_cast); + * + * // xarray with the required layout + * auto&& e = xt::as_strided(a_cast); + * @endcode + * + * @warning This function should be used in a local context only. + * Returning the value returned by this function could lead to a dangling reference. + * @ingroup xt_xeval + * @return The expression when it already provides a data interface with the correct layout, + * an evaluated xt::xarray or xt::xtensor depending on shape type otherwise. + */ + template + inline auto as_strided(E&& e) + -> std::enable_if_t> && detail::has_same_layout(), E&&> + { + return std::forward(e); + } + + /// @cond DOXYGEN_INCLUDE_SFINAE + template + inline auto as_strided(E&& e) -> std::enable_if_t< + (!(data_interface_expression> && detail::has_same_layout())) + && detail::has_fixed_dims(), + detail::as_xtensor_container_t> + { + return e; + } + + template + inline auto as_strided(E&& e) -> std::enable_if_t< + (!(data_interface_expression> && detail::has_same_layout())) + && (!detail::has_fixed_dims()), + detail::as_xarray_container_t> + { + return e; + } + + /// @endcond +} + +#endif diff --git a/include/xtensor/core/xexpression.hpp b/include/xtensor/core/xexpression.hpp new file mode 100644 index 000000000..49a662f17 --- /dev/null +++ b/include/xtensor/core/xexpression.hpp @@ -0,0 +1,823 @@ +/*************************************************************************** + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#ifndef XTENSOR_EXPRESSION_HPP +#define XTENSOR_EXPRESSION_HPP + +#include +#include + +#include +#include +#include + +#include "../core/xiterator.hpp" +#include "../core/xlayout.hpp" +#include "../core/xshape.hpp" +#include "../core/xtensor_forward.hpp" +#include "../utils/xutils.hpp" + +namespace xt +{ + + /*************************** + * xexpression declaration * + ***************************/ + + /** + * @class xexpression + * @brief Base class for xexpressions + * + * The xexpression class is the base class for all classes representing an expression + * that can be evaluated to a multidimensional container with tensor semantic. + * Functions that can apply to any xexpression regardless of its specific type should take a + * xexpression argument. + * + * @tparam E The derived type. + * + */ + template + class xexpression + { + public: + + using derived_type = D; + + derived_type& derived_cast() & noexcept; + const derived_type& derived_cast() const& noexcept; + derived_type derived_cast() && noexcept; + + protected: + + xexpression() = default; + ~xexpression() = default; + + xexpression(const xexpression&) = default; + xexpression& operator=(const xexpression&) = default; + + xexpression(xexpression&&) = default; + xexpression& operator=(xexpression&&) = default; + }; + + /************************************ + * xsharable_expression declaration * + ************************************/ + + template + class xshared_expression; + + template + class xsharable_expression; + + namespace detail + { + template + xshared_expression make_xshared_impl(xsharable_expression&&); + } + + template + class xsharable_expression : public xexpression + { + protected: + + xsharable_expression(); + ~xsharable_expression() = default; + + xsharable_expression(const xsharable_expression&) = default; + xsharable_expression& operator=(const xsharable_expression&) = default; + + xsharable_expression(xsharable_expression&&) = default; + xsharable_expression& operator=(xsharable_expression&&) = default; + + private: + + std::shared_ptr p_shared; + + friend xshared_expression detail::make_xshared_impl(xsharable_expression&&); + }; + + /****************************** + * xexpression implementation * + ******************************/ + + /** + * @name Downcast functions + */ + //@{ + /** + * Returns a reference to the actual derived type of the xexpression. + */ + template + inline auto xexpression::derived_cast() & noexcept -> derived_type& + { + return *static_cast(this); + } + + /** + * Returns a constant reference to the actual derived type of the xexpression. + */ + template + inline auto xexpression::derived_cast() const& noexcept -> const derived_type& + { + return *static_cast(this); + } + + /** + * Returns a constant reference to the actual derived type of the xexpression. + */ + template + inline auto xexpression::derived_cast() && noexcept -> derived_type + { + return *static_cast(this); + } + + //@} + + /*************************************** + * xsharable_expression implementation * + ***************************************/ + + template + inline xsharable_expression::xsharable_expression() + : p_shared(nullptr) + { + } + + /** + * is_crtp_base_of + * Resembles std::is_base_of, but adresses the problem of whether _some_ instantiation + * of a CRTP templated class B is a base of class E. A CRTP templated class is correctly + * templated with the most derived type in the CRTP hierarchy. Using this assumption, + * this implementation deals with either CRTP final classes (checks for inheritance + * with E as the CRTP parameter of B) or CRTP base classes (which are singly templated + * by the most derived class, and that's pulled out to use as a templete parameter for B). + */ + + namespace detail + { + template

(pointer), std::forward(size)); + } } #endif diff --git a/include/xtensor/containers/xbuffer_adaptor.hpp b/include/xtensor/containers/xbuffer_adaptor.hpp new file mode 100644 index 000000000..e59503f3a --- /dev/null +++ b/include/xtensor/containers/xbuffer_adaptor.hpp @@ -0,0 +1,1282 @@ +/*************************************************************************** + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#ifndef XTENSOR_BUFFER_ADAPTOR_HPP +#define XTENSOR_BUFFER_ADAPTOR_HPP + +#include +#include +#include +#include +#include + +#include + +#include "../containers/xstorage.hpp" +#include "../core/xtensor_config.hpp" + +namespace xt +{ + + struct no_ownership + { + }; + + using smart_ownership = no_ownership; + + struct acquire_ownership + { + }; + + template >>> + class xbuffer_adaptor; + + /******************** + * buffer_storage_t * + ********************/ + + namespace detail + { + template + class xbuffer_storage + { + public: + + using self_type = xbuffer_storage; + using allocator_type = A; + using destructor_type = allocator_type; + using allocator_traits = std::allocator_traits; + using value_type = typename allocator_traits::value_type; + using reference = std::conditional_t< + std::is_const>>::value, + const value_type&, + value_type&>; + using const_reference = const value_type&; + using pointer = std::conditional_t< + std::is_const>>::value, + typename allocator_traits::const_pointer, + typename allocator_traits::pointer>; + using const_pointer = typename allocator_traits::const_pointer; + using size_type = typename allocator_traits::size_type; + using difference_type = typename allocator_traits::difference_type; + + xbuffer_storage(); + + template + xbuffer_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type()); + + size_type size() const noexcept; + void resize(size_type size); + + pointer data() noexcept; + const_pointer data() const noexcept; + + void swap(self_type& rhs) noexcept; + + template + void reset_data(P&& data, size_type size) noexcept; + + private: + + pointer p_data; + size_type m_size; + }; + + template + class xbuffer_smart_pointer + { + public: + + using self_type = xbuffer_storage; + using destructor_type = D; + using value_type = std::remove_const_t>>; + using allocator_type = std::allocator; + using allocator_traits = std::allocator_traits; + using reference = std::conditional_t< + std::is_const>>::value, + const value_type&, + value_type&>; + using const_reference = const value_type&; + using pointer = std::conditional_t< + std::is_const>>::value, + typename allocator_traits::const_pointer, + typename allocator_traits::pointer>; + using const_pointer = typename allocator_traits::const_pointer; + using size_type = typename allocator_traits::size_type; + using difference_type = typename allocator_traits::difference_type; + + xbuffer_smart_pointer(); + + template + xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct); + + size_type size() const noexcept; + void resize(size_type size); + + pointer data() noexcept; + const_pointer data() const noexcept; + + void swap(self_type& rhs) noexcept; + + template + void reset_data(P&& data, size_type size, DT&& destruct) noexcept; + + private: + + pointer p_data; + size_type m_size; + destructor_type m_destruct; + }; + + template + class xbuffer_owner_storage + { + public: + + using self_type = xbuffer_owner_storage; + using allocator_type = A; + using destructor_type = allocator_type; + using allocator_traits = std::allocator_traits; + using value_type = typename allocator_traits::value_type; + using reference = std::conditional_t< + std::is_const>>::value, + const value_type&, + value_type&>; + using const_reference = const value_type&; + using pointer = std::conditional_t< + std::is_const>>::value, + typename allocator_traits::const_pointer, + typename allocator_traits::pointer>; + using const_pointer = typename allocator_traits::const_pointer; + using size_type = typename allocator_traits::size_type; + using difference_type = typename allocator_traits::difference_type; + + xbuffer_owner_storage() = default; + + template + xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type()); + + ~xbuffer_owner_storage(); + + xbuffer_owner_storage(const self_type&) = delete; + self_type& operator=(const self_type&); + + xbuffer_owner_storage(self_type&&); + self_type& operator=(self_type&&); + + size_type size() const noexcept; + void resize(size_type size); + + pointer data() noexcept; + const_pointer data() const noexcept; + + allocator_type get_allocator() const noexcept; + + void swap(self_type& rhs) noexcept; + + template + void reset_data(P&& data, size_type size, const allocator_type& alloc = allocator_type()) noexcept; + + private: + + xtl::xclosure_wrapper m_data; + size_type m_size; + bool m_moved_from; + allocator_type m_allocator; + }; + + // Workaround for MSVC2015: using void_t results in some + // template instantiation caching that leads to wrong + // type deduction later in xfunction. + template + struct msvc2015_void + { + using type = void; + }; + + template + using msvc2015_void_t = typename msvc2015_void::type; + + template + struct is_lambda_type : std::false_type + { + }; + + // check if operator() is available + template + struct is_lambda_type> : std::true_type + { + }; + + template + struct self_type + { + using type = T; + }; + + template + struct get_buffer_storage + { + using type = xtl::mpl::eval_if_t< + is_lambda_type, + self_type>, + self_type>>; + }; + + template + struct get_buffer_storage + { + using type = xbuffer_owner_storage; + }; + + template + struct get_buffer_storage, no_ownership> + { + using type = xbuffer_smart_pointer>; + }; + + template + struct get_buffer_storage, no_ownership> + { + using type = xbuffer_smart_pointer>; + }; + + template + using buffer_storage_t = typename get_buffer_storage::type; + } + + /************************ + * xbuffer_adaptor_base * + ************************/ + + template + struct buffer_inner_types; + + template + class xbuffer_adaptor_base + { + public: + + using self_type = xbuffer_adaptor_base; + using derived_type = D; + using inner_types = buffer_inner_types; + using value_type = typename inner_types::value_type; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using pointer = typename inner_types::pointer; + using const_pointer = typename inner_types::const_pointer; + using size_type = typename inner_types::size_type; + using difference_type = typename inner_types::difference_type; + using iterator = typename inner_types::iterator; + using const_iterator = typename inner_types::const_iterator; + using reverse_iterator = typename inner_types::reverse_iterator; + using const_reverse_iterator = typename inner_types::const_reverse_iterator; + using index_type = typename inner_types::index_type; + + bool empty() const noexcept; + + reference operator[](size_type i); + const_reference operator[](size_type i) const; + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + iterator begin() noexcept; + iterator end() noexcept; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + reverse_iterator rbegin() noexcept; + reverse_iterator rend() noexcept; + + const_reverse_iterator rbegin() const noexcept; + const_reverse_iterator rend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + derived_type& derived_cast() noexcept; + const derived_type& derived_cast() const noexcept; + + protected: + + xbuffer_adaptor_base() = default; + ~xbuffer_adaptor_base() = default; + + xbuffer_adaptor_base(const self_type&) = default; + self_type& operator=(const self_type&) = default; + + xbuffer_adaptor_base(self_type&&) = default; + self_type& operator=(self_type&&) = default; + }; + + template + bool operator==(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); + + template + bool operator!=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); + + template + bool operator<(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); + + template + bool operator<=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); + + template + bool operator>(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); + + template + bool operator>=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); + + /******************* + * xbuffer_adaptor * + *******************/ + + template + struct buffer_inner_types> + { + using base_type = detail::buffer_storage_t; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using size_type = typename base_type::size_type; + using difference_type = typename base_type::difference_type; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using index_type = size_type; + }; + + template + class xbuffer_adaptor : private detail::buffer_storage_t, + public xbuffer_adaptor_base> + { + public: + + using self_type = xbuffer_adaptor; + using base_type = detail::buffer_storage_t; + using buffer_base_type = xbuffer_adaptor_base; + using allocator_type = typename base_type::allocator_type; + using destructor_type = typename base_type::destructor_type; + using value_type = typename buffer_base_type::value_type; + using reference = typename buffer_base_type::reference; + using const_reference = typename buffer_base_type::const_reference; + using pointer = typename buffer_base_type::pointer; + using const_pointer = typename buffer_base_type::const_pointer; + using size_type = typename buffer_base_type::size_type; + using difference_type = typename buffer_base_type::difference_type; + using iterator = typename buffer_base_type::iterator; + using const_iterator = typename buffer_base_type::const_iterator; + using reverse_iterator = typename buffer_base_type::reverse_iterator; + using const_reverse_iterator = typename buffer_base_type::const_reverse_iterator; + using temporary_type = uvector; + + xbuffer_adaptor() = default; + + using base_type::base_type; + + ~xbuffer_adaptor() = default; + + xbuffer_adaptor(const self_type&) = default; + self_type& operator=(const self_type&) = default; + + xbuffer_adaptor(self_type&&) = default; + xbuffer_adaptor& operator=(self_type&&) = default; + + self_type& operator=(temporary_type&&); + + using base_type::data; + using base_type::reset_data; + using base_type::resize; + using base_type::size; + using base_type::swap; + }; + + template + void swap(xbuffer_adaptor& lhs, xbuffer_adaptor& rhs) noexcept; + + /********************* + * xiterator_adaptor * + *********************/ + + template + class xiterator_adaptor; + + template + struct buffer_inner_types> + { + using traits = std::iterator_traits; + using const_traits = std::iterator_traits; + + using value_type = std::common_type_t; + using reference = typename traits::reference; + using const_reference = typename const_traits::reference; + using pointer = typename traits::pointer; + using const_pointer = typename const_traits::pointer; + using difference_type = std::common_type_t; + using size_type = std::make_unsigned_t; + + using iterator = I; + using const_iterator = CI; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using index_type = difference_type; + }; + + template + class xiterator_adaptor : public xbuffer_adaptor_base> + { + public: + + using self_type = xiterator_adaptor; + using base_type = xbuffer_adaptor_base; + using value_type = typename base_type::value_type; + using allocator_type = std::allocator; + using size_type = typename base_type::size_type; + using iterator = typename base_type::iterator; + using const_iterator = typename base_type::const_iterator; + using temporary_type = uvector; + + xiterator_adaptor() = default; + xiterator_adaptor(I it, CI cit, size_type size); + + ~xiterator_adaptor() = default; + + xiterator_adaptor(const self_type&) = default; + xiterator_adaptor& operator=(const self_type&) = default; + + xiterator_adaptor(self_type&&) = default; + xiterator_adaptor& operator=(self_type&&) = default; + + xiterator_adaptor& operator=(const temporary_type& rhs); + xiterator_adaptor& operator=(temporary_type&& rhs); + + size_type size() const noexcept; + void resize(size_type size); + + iterator data() noexcept; + const_iterator data() const noexcept; + + void swap(self_type& rhs) noexcept; + + private: + + I m_it; + CI m_cit; + size_type m_size; + }; + + template + void swap(xiterator_adaptor& lhs, xiterator_adaptor& rhs) noexcept; + + template + struct is_contiguous_container> : is_contiguous_container + { + }; + + /*************************** + * xiterator_owner_adaptor * + ***************************/ + + template + class xiterator_owner_adaptor; + + template + struct buffer_inner_types> + { + using iterator = typename IG::iterator; + using const_iterator = typename IG::const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + using traits = std::iterator_traits; + using const_traits = std::iterator_traits; + + using value_type = std::common_type_t; + using reference = typename traits::reference; + using const_reference = typename const_traits::reference; + using pointer = typename traits::pointer; + using const_pointer = typename const_traits::pointer; + using difference_type = std::common_type_t; + using size_type = std::make_unsigned_t; + using index_type = difference_type; + }; + + template + class xiterator_owner_adaptor : public xbuffer_adaptor_base> + { + public: + + using self_type = xiterator_owner_adaptor; + using base_type = xbuffer_adaptor_base; + using value_type = typename base_type::value_type; + using allocator_type = std::allocator; + using size_type = typename base_type::size_type; + using iterator = typename base_type::iterator; + using const_iterator = typename base_type::const_iterator; + using temporary_type = uvector; + + xiterator_owner_adaptor(C&& c); + + ~xiterator_owner_adaptor() = default; + + xiterator_owner_adaptor(const self_type&); + xiterator_owner_adaptor& operator=(const self_type&); + + xiterator_owner_adaptor(self_type&&); + xiterator_owner_adaptor& operator=(self_type&&); + + xiterator_owner_adaptor& operator=(const temporary_type& rhs); + xiterator_owner_adaptor& operator=(temporary_type&& rhs); + + size_type size() const noexcept; + void resize(size_type size); + + iterator data() noexcept; + const_iterator data() const noexcept; + + void swap(self_type& rhs) noexcept; + + private: + + void init_iterators(); + + C m_container; + iterator m_it; + const_iterator m_cit; + size_type m_size; + }; + + template + void swap(xiterator_owner_adaptor& lhs, xiterator_owner_adaptor& rhs) noexcept; + + template + struct is_contiguous_container> + : is_contiguous_container + { + }; + + /************************** + * make_xiterator_adaptor * + **************************/ + + template + auto make_xiterator_adaptor(C&& container, IG iterator_getter); + + /************************************ + * temporary_container metafunction * + ************************************/ + + template + struct temporary_container + { + using type = C; + }; + + template + struct temporary_container> + { + using type = typename xbuffer_adaptor::temporary_type; + }; + + template + struct temporary_container> + { + using type = typename xiterator_adaptor::temporary_type; + }; + + template + struct temporary_container> + { + using type = typename xiterator_owner_adaptor::temporary_type; + }; + + template + using temporary_container_t = typename temporary_container::type; + + /********************************** + * xbuffer_storage implementation * + **********************************/ + + namespace detail + { + template + inline xbuffer_storage::xbuffer_storage() + : p_data(nullptr) + , m_size(0) + { + } + + template + template + inline xbuffer_storage::xbuffer_storage(P&& data, size_type size, const allocator_type&) + : p_data(std::forward