Repository: xtensor-stack/xframe Branch: master Commit: 05f3addf21bc Files: 125 Total size: 871.0 KB Directory structure: gitextract_7cvkifeh/ ├── .appveyor.yml ├── .azure-pipelines/ │ ├── azure-pipelines-linux-clang.yml │ ├── azure-pipelines-linux-gcc.yml │ ├── azure-pipelines-osx.yml │ └── unix-build.yml ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── docs/ │ ├── Doxyfile │ ├── Makefile │ ├── environment.yml │ ├── make.bat │ └── source/ │ ├── _static/ │ │ └── main_stylesheet.css │ ├── api/ │ │ ├── axis_index.rst │ │ ├── coordinate_index.rst │ │ ├── variable_index.rst │ │ ├── xaxis.rst │ │ ├── xaxis_base.rst │ │ ├── xaxis_default.rst │ │ ├── xaxis_expression_leaf.rst │ │ ├── xaxis_function.rst │ │ ├── xaxis_variant.rst │ │ ├── xaxis_view.rst │ │ ├── xcoordinate.rst │ │ ├── xcoordinate_base.rst │ │ ├── xcoordinate_chain.rst │ │ ├── xcoordinate_expanded.rst │ │ ├── xcoordinate_view.rst │ │ ├── xdimension.rst │ │ ├── xexpand_dims_view.rst │ │ ├── xnamed_axis.rst │ │ └── xvariable_masked_view.rst │ ├── computation.rst │ ├── conf.py │ ├── data_structure.rst │ ├── getting_started.rst │ ├── index.rst │ ├── indexing.rst │ ├── installation.rst │ ├── xarray.rst │ └── xframe_summary_drawio.xml ├── environment-dev.yml ├── environment.yml ├── include/ │ └── xframe/ │ ├── xaxis.hpp │ ├── xaxis_base.hpp │ ├── xaxis_default.hpp │ ├── xaxis_expression_leaf.hpp │ ├── xaxis_function.hpp │ ├── xaxis_index_slice.hpp │ ├── xaxis_label_slice.hpp │ ├── xaxis_math.hpp │ ├── xaxis_meta.hpp │ ├── xaxis_scalar.hpp │ ├── xaxis_variant.hpp │ ├── xaxis_view.hpp │ ├── xcoordinate.hpp │ ├── xcoordinate_base.hpp │ ├── xcoordinate_chain.hpp │ ├── xcoordinate_expanded.hpp │ ├── xcoordinate_system.hpp │ ├── xcoordinate_view.hpp │ ├── xdimension.hpp │ ├── xdynamic_variable.hpp │ ├── xdynamic_variable_impl.hpp │ ├── xexpand_dims_view.hpp │ ├── xframe_config.hpp │ ├── xframe_expression.hpp │ ├── xframe_trace.hpp │ ├── xframe_utils.hpp │ ├── xio.hpp │ ├── xnamed_axis.hpp │ ├── xreindex_data.hpp │ ├── xreindex_view.hpp │ ├── xselecting.hpp │ ├── xsequence_view.hpp │ ├── xvariable.hpp │ ├── xvariable_assign.hpp │ ├── xvariable_base.hpp │ ├── xvariable_function.hpp │ ├── xvariable_masked_view.hpp │ ├── xvariable_math.hpp │ ├── xvariable_meta.hpp │ ├── xvariable_scalar.hpp │ ├── xvariable_variant.hpp │ ├── xvariable_view.hpp │ └── xvector_variant.hpp ├── notebooks/ │ └── xframe.ipynb ├── readthedocs.yml ├── test/ │ ├── CMakeLists.txt │ ├── copyGTest.cmake.in │ ├── downloadGTest.cmake.in │ ├── main.cpp │ ├── test_fixture.hpp │ ├── test_fixture_view.hpp │ ├── test_xaxis.cpp │ ├── test_xaxis_default.cpp │ ├── test_xaxis_function.cpp │ ├── test_xaxis_variant.cpp │ ├── test_xaxis_view.cpp │ ├── test_xcoordinate.cpp │ ├── test_xcoordinate_chain.cpp │ ├── test_xcoordinate_expanded.cpp │ ├── test_xcoordinate_view.cpp │ ├── test_xdimension.cpp │ ├── test_xdynamic_variable.cpp │ ├── test_xexpand_dims_view.cpp │ ├── test_xframe_utils.cpp │ ├── test_xnamed_axis.cpp │ ├── test_xreindex_view.cpp │ ├── test_xsequence_view.cpp │ ├── test_xvariable.cpp │ ├── test_xvariable_assign.cpp │ ├── test_xvariable_function.cpp │ ├── test_xvariable_masked_view.cpp │ ├── test_xvariable_math.cpp │ ├── test_xvariable_noalias.cpp │ ├── test_xvariable_scalar.cpp │ ├── test_xvariable_view.cpp │ ├── test_xvariable_view_assign.cpp │ └── test_xvector_variant.cpp ├── xframe.pc.in └── xframeConfig.cmake.in ================================================ FILE CONTENTS ================================================ ================================================ FILE: .appveyor.yml ================================================ build: false os: Visual Studio 2015 platform: - x64 environment: matrix: - MINICONDA: C:\xframe-conda init: - "ECHO %MINICONDA%" - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat %PLATFORM% - 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:\xframe-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 env create --file environment-dev.yml - CALL conda.bat activate xframe - cmake -G "NMake Makefiles" -D CMAKE_INSTALL_PREFIX=%MINICONDA%\\LIBRARY -DDOWNLOAD_GTEST=ON . - nmake test_xframe - cd test build_script: - .\test_xframe ================================================ FILE: .azure-pipelines/azure-pipelines-linux-clang.yml ================================================ jobs: - job: 'Linux_0' strategy: matrix: clang_4: llvm_version: '4.0' clang_5: llvm_version: '5.0' clang_6: llvm_version: '6.0' clang_7: llvm_version: '7' clang_8: llvm_version: '8' clang_9: llvm_version: '9' clang_10: llvm_version: '10' pool: vmImage: ubuntu-16.04 variables: CC: clang-$(llvm_version) CXX: clang++-$(llvm_version) timeoutInMinutes: 360 steps: - script: | sudo add-apt-repository ppa:ubuntu-toolchain-r/test if [[ $(llvm_version) == '4.0' || $(llvm_version) == '5.0' ]]; then sudo apt-get update sudo apt-get --no-install-suggests --no-install-recommends install gcc-4.9 clang-$(llvm_version) else LLVM_VERSION=$(llvm_version) get -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo add-apt-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-$LLVM_VERSION main" sudo apt-get update sudo apt-get --no-install-suggests --no-install-recommends install clang-$(llvm_version) fi displayName: Install build toolchain - bash: echo "##vso[task.prependpath]$CONDA/bin" displayName: Add conda to PATH - template: unix-build.yml ================================================ FILE: .azure-pipelines/azure-pipelines-linux-gcc.yml ================================================ jobs: - job: 'Linux_1' strategy: matrix: gcc_4: gcc_version: '4.9' gcc_5: gcc_version: '5' gcc_6: gcc_version: '6' gcc_7: gcc_version: '7' gcc_8: gcc_version: '8' gcc_9: gcc_version: '9' pool: vmImage: ubuntu-16.04 variables: CC: gcc-$(gcc_version) CXX: g++-$(gcc_version) timeoutInMinutes: 360 steps: - script: | if [[ $(gcc_version) == '4.9' || $(gcc_version) == '6' ]]; then sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get --no-install-suggests --no-install-recommends install g++-$(gcc_version) fi displayName: Install build toolchain - bash: echo "##vso[task.prependpath]$CONDA/bin" displayName: Add conda to PATH - template: unix-build.yml ================================================ FILE: .azure-pipelines/azure-pipelines-osx.yml ================================================ jobs: - job: 'OSX' strategy: matrix: macOS_10_14: image_name: 'macOS-10.14' macOS_10_15: image_name: 'macOS-10.15' pool: vmImage: $(image_name) variables: CC: clang CXX: clang++ timeoutInMinutes: 360 steps: - script: | echo "Removing homebrew for Azure to avoid conflicts with conda" curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall > ~/uninstall_homebrew chmod +x ~/uninstall_homebrew ~/uninstall_homebrew -f -q displayName: Remove homebrew - bash: | echo "##vso[task.prependpath]$CONDA/bin" sudo chown -R $USER $CONDA displayName: Add conda to PATH - template: unix-build.yml ================================================ FILE: .azure-pipelines/unix-build.yml ================================================ steps: - script: | conda config --set always_yes yes --set changeps1 no conda update -q conda conda env create --file environment-dev.yml source activate xframe - script: | source activate xframe mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DDOWNLOAD_GTEST=ON $(Build.SourcesDirectory) displayName: Configure xframe workingDirectory: $(Build.BinariesDirectory) - script: | source activate xxframe make -j2 test_xframe displayName: Build xframe workingDirectory: $(Build.BinariesDirectory)/build - script: | source activate xframe cd test ./test_xframe displayName: Test xframe workingDirectory: $(Build.BinariesDirectory)/build/test ================================================ FILE: .gitignore ================================================ # Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app # Vim tmp files *.swp # Build directory build/ # Test build artefacts test/test_xtensor test/CMakeCache.txt test/Makefile test/CMakeFiles/ test/cmake_install.cmake # Documentation build artefacts docs/CMakeCache.txt docs/xml/ docs/build/ # Jupyter artefacts .ipynb_checkpoints/ # Generated files *.pc ================================================ FILE: .travis.yml ================================================ language: cpp dist: xenial matrix: 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 - os: linux addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-6 env: COMPILER=gcc GCC=6 - os: linux addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-7 env: COMPILER=gcc GCC=7 - os: linux addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-xenial-4.0 packages: - g++-4.9 - clang-4.0 env: COMPILER=clang CLANG=4.0 - os: linux addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-xenial-5.0 packages: - g++-4.9 - clang-5.0 env: COMPILER=clang CLANG=5.0 - os: linux addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-xenial-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 # The 2 following lines are a workaround to https://github.com/conda/conda/issues/9337 - pip uninstall -y setuptools - conda install setuptools - conda update -q conda - conda install cmake -c conda-forge - conda install xtensor=0.21.4 -c conda-forge # Testing - mkdir build - cd build - cmake -DDOWNLOAD_GTEST=ON ..; - make -j2 test_xframe - cd test script: - ./test_xframe ================================================ FILE: CMakeLists.txt ================================================ ############################################################################ # Copyright (c) Johan Mabille and Sylvain Corlay # # 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(xframe) set(XFRAME_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) # Versionning # =========== file(STRINGS "${XFRAME_INCLUDE_DIR}/xframe/xframe_config.hpp" xframe_version_defines REGEX "#define XFRAME_VERSION_(MAJOR|MINOR|PATCH)") foreach(ver ${xframe_version_defines}) if(ver MATCHES "#define XFRAME_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") set(XFRAME_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") endif() endforeach() set(${PROJECT_NAME}_VERSION ${XFRAME_VERSION_MAJOR}.${XFRAME_VERSION_MINOR}.${XFRAME_VERSION_PATCH}) message(STATUS "xframe v${${PROJECT_NAME}_VERSION}") # Dependencies # ============ find_package(xtensor REQUIRED) include_directories(${xtensor_INCLUDE_DIRS}) find_package(xtl REQUIRED) include_directories(${xtl_INCLUDE_DIRS}) # Build # ===== set(XFRAME_HEADERS ${XFRAME_INCLUDE_DIR}/xframe/xaxis.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_base.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_default.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_expression_leaf.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_function.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_index_slice.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_label_slice.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_math.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_meta.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_scalar.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_variant.hpp ${XFRAME_INCLUDE_DIR}/xframe/xaxis_view.hpp ${XFRAME_INCLUDE_DIR}/xframe/xcoordinate.hpp ${XFRAME_INCLUDE_DIR}/xframe/xcoordinate_base.hpp ${XFRAME_INCLUDE_DIR}/xframe/xcoordinate_chain.hpp ${XFRAME_INCLUDE_DIR}/xframe/xcoordinate_expanded.hpp ${XFRAME_INCLUDE_DIR}/xframe/xcoordinate_system.hpp ${XFRAME_INCLUDE_DIR}/xframe/xcoordinate_view.hpp ${XFRAME_INCLUDE_DIR}/xframe/xdimension.hpp ${XFRAME_INCLUDE_DIR}/xframe/xdynamic_variable_impl.hpp ${XFRAME_INCLUDE_DIR}/xframe/xdynamic_variable.hpp ${XFRAME_INCLUDE_DIR}/xframe/xexpand_dims_view.hpp ${XFRAME_INCLUDE_DIR}/xframe/xframe_config.hpp ${XFRAME_INCLUDE_DIR}/xframe/xframe_expression.hpp ${XFRAME_INCLUDE_DIR}/xframe/xframe_trace.hpp ${XFRAME_INCLUDE_DIR}/xframe/xframe_utils.hpp ${XFRAME_INCLUDE_DIR}/xframe/xio.hpp ${XFRAME_INCLUDE_DIR}/xframe/xnamed_axis.hpp ${XFRAME_INCLUDE_DIR}/xframe/xreindex_view.hpp ${XFRAME_INCLUDE_DIR}/xframe/xreindex_data.hpp ${XFRAME_INCLUDE_DIR}/xframe/xselecting.hpp ${XFRAME_INCLUDE_DIR}/xframe/xsequence_view.hpp ${XFRAME_INCLUDE_DIR}/xframe/xvariable.hpp ${XFRAME_INCLUDE_DIR}/xframe/xvariable_assign.hpp ${XFRAME_INCLUDE_DIR}/xframe/xvariable_base.hpp ${XFRAME_INCLUDE_DIR}/xframe/xvariable_function.hpp ${XFRAME_INCLUDE_DIR}/xframe/xvariable_masked_view.hpp ${XFRAME_INCLUDE_DIR}/xframe/xvariable_math.hpp ${XFRAME_INCLUDE_DIR}/xframe/xvariable_meta.hpp ${XFRAME_INCLUDE_DIR}/xframe/xvariable_scalar.hpp ${XFRAME_INCLUDE_DIR}/xframe/xvariable_view.hpp ${XFRAME_INCLUDE_DIR}/xframe/xvector_variant.hpp ) OPTION(BUILD_TESTS "xframe test suite" OFF) OPTION(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF) if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) set(BUILD_TESTS ON) endif() if(BUILD_TESTS) add_subdirectory(test) endif() # Installation # ============ include(GNUInstallDirs) include(CMakePackageConfigHelpers) install(FILES ${XFRAME_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xframe) set(XFRAME_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for xframeConfig.cmake") configure_package_config_file(${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION ${XFRAME_CMAKECONFIG_INSTALL_DIR}) # xframe is header-only and does not depend on the architecture. # Remove CMAKE_SIZEOF_VOID_P from xframeConfigVersion.cmake so that an xframeConfig.cmake # generated for a 64 bit target can be used for 32 bit targets and vice versa. set(_XFRAME_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) unset(CMAKE_SIZEOF_VOID_P) write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${${PROJECT_NAME}_VERSION} COMPATIBILITY AnyNewerVersion) set(CMAKE_SIZEOF_VOID_P ${_XFRAME_CMAKE_SIZEOF_VOID_P}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${XFRAME_CMAKECONFIG_INSTALL_DIR}) 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/") ================================================ FILE: LICENSE ================================================ BSD 3-Clause License Copyright (c) 2017, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Copyright (c) 2017, QuantStack All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: README.md ================================================ # ![xframe](docs/source/xframe.svg) [![Travis](https://travis-ci.org/xtensor-stack/xframe.svg?branch=master)](https://travis-ci.org/xtensor-stack/xframe) [![Appveyor](https://ci.appveyor.com/api/projects/status/nhjtyvkefhyo26v5?svg=true)](https://ci.appveyor.com/project/xtensor-stack/xframe) [![Documentation](http://readthedocs.org/projects/xframe/badge/?version=latest)](https://xframe.readthedocs.io/en/latest/?badge=latest) [![Binder](https://img.shields.io/badge/launch-binder-brightgreen.svg)](https://mybinder.org/v2/gh/xtensor-stack/xframe/stable?filepath=notebooks%2Fxframe.ipynb) [![Zulip](https://img.shields.io/badge/social_chat-zulip-blue.svg)](https://xtensor.zulipchat.com/#narrow/channel/539553-Ask-anything) ## Introduction **xframe is an early developer preview, and is not suitable for general usage yet. Features and implementation are subject to change.** `xframe` is a dataframe for C++, based on [xtensor](https://github.com/xtensor-stack/xtensor) and [xtl](https://github.com/xtensor-stack/xtl). For more information on using `xframe`, check out the reference documentation https://xframe.readthedocs.io/ # Installation ## Package managers We provide a package for the mamba (or conda) package manager: ``` mamba install -c conda-forge xtensor ``` ## Dependencies `xframe` depends on the [xtensor](https://github.com/xtensor-stack/xtensor) library: | xframe | xtensor | |----------|-----------| | master | ^0.21.4 | | 0.3.0 | ^0.21.4 | | 0.2.0 | ^0.20.0 | | 0.1.0 | ^0.19.1 | | 0.0.2 | ^0.19.1 | | 0.0.1 | ^0.19.1 | ## License We use a shared copyright model that enables all contributors to maintain the copyright on their contributions. This software is licensed under the BSD-3-Clause license. See the [LICENSE](LICENSE) file for details. ================================================ FILE: azure-pipelines.yml ================================================ trigger: - master jobs: - template: ./.azure-pipelines/azure-pipelines-linux-clang.yml - template: ./.azure-pipelines/azure-pipelines-linux-gcc.yml - template: ./.azure-pipelines/azure-pipelines-osx.yml ================================================ FILE: docs/Doxyfile ================================================ PROJECT_NAME = "xframe" 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 JAVADOC_AUTOBRIEF = YES WARN_IF_UNDOCUMENTED = NO MACRO_EXPANSION = YES ================================================ FILE: docs/Makefile ================================================ # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext api default: html 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 " applehelp to make an Apple Help Book" @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 " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of 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)" clean: rm -rf $(BUILDDIR)/* rm -rf xml html: doxygen $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: doxygen $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: doxygen $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: doxygen $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: doxygen $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: doxygen $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." epub: doxygen $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: doxygen $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: doxygen $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: doxygen $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: doxygen $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: doxygen $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: doxygen $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: doxygen $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: doxygen $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: doxygen $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: doxygen $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: doxygen $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." coverage: doxygen $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." xml: doxygen $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: doxygen $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." ================================================ FILE: docs/environment.yml ================================================ name: xframe-docs channels: - QuantStack dependencies: - breathe ================================================ FILE: docs/make.bat ================================================ @ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( 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% ) 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 ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 1>NUL 2>NUL if errorlevel 9009 goto sphinx_python goto sphinx_ok :sphinx_python 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 ) :sphinx_ok 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 ) 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 ) 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 ) 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 ) 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 ) 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 ^ .hhp project file in %BUILDDIR%/htmlhelp. 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 ^ .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 ) if "%1" == "devhelp" ( %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 ) 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 ) 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 ) 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 ) 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 ) 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 ) 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 ) 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 ) 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 ) 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 ^ or in %BUILDDIR%/linkcheck/output.txt. 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 ^ results in %BUILDDIR%/doctest/output.txt. 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 ^ results in %BUILDDIR%/coverage/python.txt. 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 ) 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 ) :end ================================================ FILE: docs/source/_static/main_stylesheet.css ================================================ .wy-nav-content{ max-width: 1000px; margin: auto; } ================================================ FILE: docs/source/api/axis_index.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Axes ==== .. toctree:: xaxis_base xaxis xaxis_default xaxis_function xaxis_expression_leaf xaxis_view xaxis_variant xnamed_axis ================================================ FILE: docs/source/api/coordinate_index.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Coordinates and dimensions ========================== .. toctree:: xcoordinate_base xcoordinate xcoordinate_view xcoordinate_chain xcoordinate_expanded xdimension ================================================ FILE: docs/source/api/variable_index.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Variables ========= .. toctree:: xexpand_dims_view xvariable_masked_view ================================================ FILE: docs/source/api/xaxis.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xaxis ===== Defined in ``xframe/xaxis.hpp`` .. doxygenclass:: xf::xaxis :project: xframe :members: .. doxygenfunction:: xf::axis(L, L, L) :project: xframe .. doxygenfunction:: xf::axis(std::initializer_list) :project: xframe ================================================ FILE: docs/source/api/xaxis_base.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xaxis_base ========== Defined in ``xframe/xaxis_base.hpp`` .. doxygenclass:: xf::xaxis_base :project: xframe :members: .. doxygenfunction:: operator==(const xaxis_base&, const xaxis_base&) :project: xframe .. doxygenfunction:: operator!=(const xaxis_base&, const xaxis_base&) :project: xframe ================================================ FILE: docs/source/api/xaxis_default.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xaxis_default ============= Defined in ``xframe/xaxis_default.hpp`` .. doxygenclass:: xf::xaxis_default :project: xframe :members: .. doxygenfunction:: xf::axis(L) :project: xframe ================================================ FILE: docs/source/api/xaxis_expression_leaf.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xaxis_expression_leaf ===================== Defined in ``xframe/xaxis_expression_leaf.hpp`` .. doxygenclass:: xf::xaxis_expression_leaf :project: xframe :members: ================================================ FILE: docs/source/api/xaxis_function.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xaxis_function ============== Defined in ``xframe/xaxis_function.hpp`` .. doxygenclass:: xf::xaxis_function :project: xframe :members: ================================================ FILE: docs/source/api/xaxis_variant.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xaxis_variant ============= Defined in ``xframe/xaxis_variant.hpp`` .. doxygenclass:: xf::xaxis_variant :project: xframe :members: ================================================ FILE: docs/source/api/xaxis_view.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xaxis_view ========== Defined in ``xframe/xaxis_view.hpp`` .. doxygenclass:: xf::xaxis_view :project: xframe :members: .. doxygenfunction:: operator==(const xaxis_view&, const xaxis_view&) :project: xframe .. doxygenfunction:: operator!=(const xaxis_view&, const xaxis_view&) :project: xframe .. doxygenfunction:: operator==(const xaxis_view&, const xaxis_variant&) :project: xframe .. doxygenfunction:: operator!=(const xaxis_view&, const xaxis_variant&) :project: xframe .. doxygenfunction:: operator==(const xaxis_variant&, const xaxis_view&) :project: xframe .. doxygenfunction:: operator!=(const xaxis_variant&, const xaxis_view&) :project: xframe ================================================ FILE: docs/source/api/xcoordinate.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xcoordinate =========== Defined in ``xframe/xcoordinate.hpp`` .. doxygenclass:: xf::xcoordinate :project: xframe :members: .. doxygenfunction:: coordinate(const std::map>&) :project: xframe .. doxygenfunction:: coordinate(std::map>&&) :project: xframe .. doxygenfunction:: coordinate(xnamed_axis, xnamed_axis...) :project: xframe .. doxygenfunction:: broadcast_coordinates(xcoordinate&, const Args&...) :project: xframe ================================================ FILE: docs/source/api/xcoordinate_base.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xcoordinate_base ================ Defined in ``xframe/xcoordinate_base.hpp`` .. doxygenclass:: xf::xcoordinate_base :project: xframe :members: .. doxygenfunction:: operator==(const xcoordinate_base&, const xcoordinate_base&) :project: xframe .. doxygenfunction:: operator!=(const xcoordinate_base&, const xcoordinate_base&) :project: xframe ================================================ FILE: docs/source/api/xcoordinate_chain.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xcoordinate_chain ================= Defined in ``xframe/xcoordinate_chain.hpp`` .. doxygenclass:: xf::xcoordinate_chain :project: xframe :members: .. doxygenfunction:: reindex(const C&, const typename C::map_type&) :project: xframe .. doxygenfunction:: reindex(const C&, typename C::map_type&&) :project: xframe ================================================ FILE: docs/source/api/xcoordinate_expanded.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xcoordinate_expanded ==================== Defined in ``xframe/xcoordinate_expanded.hpp`` .. doxygenclass:: xf::xcoordinate_expanded :project: xframe :members: .. doxygenfunction:: expand_dims(const C&, const typename C::map_type&) :project: xframe .. doxygenfunction:: expand_dims(const C&, typename C::map_type&&) :project: xframe ================================================ FILE: docs/source/api/xcoordinate_view.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xcoordinate_view ================ Defined in ``xframe/xcoordinate_view.hpp`` .. doxygenclass:: xf::xcoordinate_view :project: xframe :members: .. doxygenfunction:: coordinate_view(const std::map>&) :project: xframe .. doxygenfunction:: coordinate_view(std::map>&&) :project: xframe ================================================ FILE: docs/source/api/xdimension.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xdimension ========== Defined in ``xframe/xdimension.hpp`` .. doxygenclass:: xf::xdimension :project: xframe :members: .. doxygenfunction:: operator==(const xdimension&, const xdimension&) :project: xframe .. doxygenfunction:: operator!=(const xdimension&, const xdimension&) :project: xframe ================================================ FILE: docs/source/api/xexpand_dims_view.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xexpand_dims_view ================= Defined in ``xframe/xexpand_dims_view.hpp`` .. doxygenclass:: xf::xexpand_dims_view :project: xframe :members: .. doxygenfunction:: expand_dims(E&&, std::initializer_list) :project: xframe .. doxygenfunction:: expand_dims(E&&, std::initializer_list::key_type, std::size_t>>) :project: xframe ================================================ FILE: docs/source/api/xnamed_axis.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xnamed_axis =========== Defined in ``xframe/xnamed_axis.hpp`` .. doxygenclass:: xf::xnamed_axis :project: xframe :members: .. doxygenfunction:: xf::named_axis(const K&, A&&) :project: xframe ================================================ FILE: docs/source/api/xvariable_masked_view.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. xvariable_masked_view ===================== Defined in ``xframe/xvariable_masked_view.hpp`` .. doxygenclass:: xf::xvariable_masked_view :project: xframe :members: .. doxygenfunction:: where(EV&&, EAX&&) :project: xframe ================================================ FILE: docs/source/computation.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Computation =========== `xframe` is actually more than a multi-dimensional data frame library; like `xtensor`_, it is an expression engine that allows numerical computation on any object implementing the variable or the frame interfaces. Expressions ----------- Assume ``x``, ``y`` and ``z`` are variables with *compatible coordinates* (we'll come back to that later), the return type of an expression such as ``x + exp(y) * sin(z)`` is **not a variable**. The result is a variable expression which offers the same interface as ``xvariable`` but does not hold any value. Such expressions can be plugged into others to build more cmoplex expressions: .. code:: auto f = x + exp(y) * sin(z); auto f2 = x + exp(w) * cos(f); The expression engines avoids the evaluation of intermediate results and their storage in temporary variables, so you can achieve the same performance as if you had written a loop. Such a loop is quite more complicated than an array loop since labels and dimension names are involved in the assignment mechanism. Since a variable expression provides the same API as ``xvariable``, all the indexing and selection operations are available: .. code:: auto v = (x + exp(y) * sin(z)).select({{"city", "Paris"}, {"group", "a"}}); auto view = select(x + exp(y) * sin(z), {{"city", xf::keep("Paris")}, {"group", xf::drop({"b", "d", "h"})}}); Lazy evaluation --------------- An expression such as ``x + exp(y) * sin(z)`` does not hold the result. **Values are only computed upon access or when the expression is assigned to a variable**. this allows to operate symbolically on very large data sets and only compute the result for the indices of interest: .. code:: // Assuming x and y are variables each holding ~1M values auto f = cos(x) + sin(y); double first_res = f.locate("a", "London"); double second_res = f.locate("b", "Pekin"); // Only two values have been computed That means if you use the same expression in two assign statements, the computation of the expression will be done twice. Depending on the complexity of the cmoputation and the size of the data, it might be convenient to store the result of the expression in a temporary variable: .. code:: variable_type tmp = cos(x) + sin(y); variable_type res1 = tmp + 2 * exp(z); variable_type res2 = tmp - 3 * exp(w); Broadcasting by dimension names ------------------------------- Like `xarray`_, broadcasting in *xframe* is done according to the dimension names rather than their positions. This way, you do not need to transpose variable or insert dimensions of length 1 to to get array operations to work, as commonly done in `xtensor`_ with ``xt::reshape`` or ``xt::newaxis``. This can be illustrated with the following examples. First, consider two one-dimensional variable aligned along different dimensions: .. code:: auto v1 = variable_type(data_type({1., 2.}), {{"x", xf::axis(1, 3)}}); auto v2 = variable_type(data_type({3., 7.}), {{"y", xf::axis(2, 5)}}); We can apply mathematical operations to these variables, their dimension are expanded automatically: .. code:: variable_type res = v1 + v2; std::cout << res << std::endl; // Output: // {{ 4. 8.} // { 5. 9.}} // Coordinates: // x: (1, 3, ) // y: (2, 5, ) Contrary to `xarray`_ , dimensions are not reordered to the order in which they first appeared: .. code:: auto v3 = variable_type(data_type({{1., 2.}, {3., 4.}}), {{"y", xf::axis({2, 5})}, {"x", xf::axis({1, 4})}}); variable_type res2 = v1 + v3; std::cout << res2 << std::endl; // Output: // {{ 2. 4. } // { 4. 6. }} // Coordinates: // y: (2, 5, ) // x: (1, 3, ) This allows many optimizations in the assignment mechanism. Automatic alignment ------------------- `xframe` enforces alignment between coordinate labels on objects involved in operations. The default result of an operation is by the *intersection* of the coordinate labels: .. code:: auto v4 = variable_type(data_type({1., 2., 3.}), {{"x", xf::axis({1, 3, 5})}}); auto v5 = variable_type(data_type({4., 7., 12.}), {{"x", xf::axis({1, 5, 7})}}); variable_type res3 = v4 + v5; std::cout << res3 << std::endl; // Output: // { 5. 10. } // Coordinates: // x: (1, 5,) Operations are slower when variables are not aligned, so it might be useful to explicitly align variables involved in loops of performance critical code. Operators and functions ----------------------- `xframe` provides all the basic operators and mathematical functions: - arithmetic operators: ``+``, ``-``, ``*``, ``/`` - logical operators: ``&&``, ``||``, ``!`` - comparison operators: ``==``, ``!=``, ``<``, ``<=``, ``>``, ``>=`` - 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``, ... Actually, any function operating on ``xtensor`` expressions can work with ``xvariable`` expressions without any additional work; the only constraint is to accept and return expressions: .. code:: template inline auto distance(const xexpression& e1, const xexpression& e2) { const E1& de1 = e1.derived_cast(); const E2& de2 = e2.derived_cast(); // return sqrt(de1 * de1 + de2 * de2); } This function can work with both tnesor and variable expressions, performing broadcasting according to the rules of `xtensor` or `xframe` depending on its argument type: .. code:: xt::xarray a1 = {1., 2. }; xt::xarray a2 = {{1., 3.}, {4., 7.}}; // Broadcasting is applied according to xtensor rules, // that is by dimension order xt::xarray ares = distance(a1, a2); // Broadcasting is applied according to xframe rules, // that is by dimension name variable_type vres = distance(v1, v3); Missing values -------------- Contrary to `pandas`_ or `xarray`_, `xframe` does not use particular values for representing missing values. Instead, it makes use of the dedicated type ``xtl::xoptional`` which gathers the value and a flag to specify whether the value is missing or not: .. code:: data_type d = {1., 2., 3. }; d(1).has_value() = false; auto v = variable_type(d, {{"x", xf::axis({1, 3, 4})}}); std::cout << v << std::endl; // Output: // { 1. N/A 3. } // Coordinates: // x: (1, 3, 4,) .. _pandas: https://pandas.pydata.org .. _xarray: https://xarray.pydata.org .. _xtensor: https://github.com/xtensor-stack/xtensor ================================================ FILE: docs/source/conf.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import subprocess on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if on_rtd: subprocess.call('cd ..; doxygen', shell=True) import sphinx_rtd_theme html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] def setup(app): app.add_stylesheet("main_stylesheet.css") extensions = ['breathe'] breathe_projects = { 'xframe': '../xml' } templates_path = ['_templates'] html_static_path = ['_static'] source_suffix = '.rst' master_doc = 'index' project = 'xframe' copyright = '2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou' author = 'Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou' html_logo = 'quantstack-white.svg' exclude_patterns = [] highlight_language = 'c++' pygments_style = 'sphinx' todo_include_todos = False htmlhelp_basename = 'xframedoc' ================================================ FILE: docs/source/data_structure.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Data structures =============== Axes ---- An axis is a mapping of labels to positions in a given dimension. It is the equivalent of the ``index`` object from `pandas`_. `xframe` supports many types of labels, the most common are strings, char, integers and dates. An axis is created from a list of labels, a builder function is provided so the type of the axis can be inferred. The following example illustrates the two main ways of creating an axis: .. code:: using saxis_type = xf::xaxis; saxis_type s1({ "a", "b", "d", "e" }); auto s2 = xf::axis({ "a", "b", "d", "e" }); // s1 and s2 are similar axes It is also possible to create an axis given the size of the axis or the start, stop and step: .. code:: auto s3 = xf::axis(5); // == xf::axis({ 0, 1, 2, 3, 4 }); auto s4 = xf::axis(2, 7); // == xf::axis({ 2, 3, 4, 5, 6 }); auto s5 = xf::axis(0, 10, 2); // == xf::axis({ 0, 2, 4, 6, 8 }); auto s6 = xf::axis("a", "d"); // == xf::axis({ "a", "b", "c" }); The axis API is similar to the one of a constant ``std::map`` that throws an exception when asked a missing key: .. code:: std::size_t i0 = s1["a"]; try { std::size_t i1 = s1["c"]; } catch(std::exception& e) { // The exception will be catch since "c" is not a label of s1 std::cout << e.what() << std::endl; } ``xaxis`` also provides iterators and methods to compute the union and the intersection of axes. However a user rarely needs to manipulate the axes directly, the most common operation is to create them and then store them in a coordinate system. Coordinates ----------- Coordinates are mappings of dimension names to axes. `xframe` provides different methods to easily create them: .. code:: using coordinate_type = xf::xcoordinate; coordinate_type c1({{"group", xf::axis({"a", "b", "d", "e"})}, {"city", xf::axis({"London", "Paris", "Brussels"})}}); auto c2 = xf::coordinate({{"group", xf::axis({"a", "b", "d", "e"})}, {"city", xf::axis({"London", "Paris", "Brussels"})}}); // c1 and c2 are similar coordinates .. note:: The builder function ``xf::coordinate`` converts the ``const char*`` arguments to ``fstring`` and returns a ``xcoordinate`` object. You can modify this behavior by specifying the key type of the coordinate as the first template parameter of the ``coordinate`` function: ``auto c2 = xf::coordinate({{"group", xf::axis({"a", "b", "d", "e"})}, ...});`` ``xnamed_axis`` allows to store a dimension name - axis pair that you can reuse in different coordinates objects; if you want to create a coordinate object from a named axis, all the arguments must be named axes; fortunately, a ``xnamed_axis`` can be created in place, as shown below: .. code:: // This object will be used in different coordinates objects auto a1 = xf::named_axis("igroup", xf::axis({1, 2, 4, 5})}); auto c1 = xf::coordinate(a1, xf::named_axis("city", xf::axis({"London", "Parid", "Brussels"}))); auto c2 = xf::coordinate(a1, xf::named_axis("country", xf::axis({"USA", "Japan"}))); As you can notice, coordinates objects can store axes with different label types. By default, these types are ``int``, ``std::size_t``, ``char`` and ``xf::fstring``, you can specify a different type list: .. code:: using coordinate_type = xf::xcoordinate>; coordinate_type c({{"group", xf::axis({"a", "b", "d", "e"})}, {"city", xf::axis({"London", "Paris", "Brussels"})}}); Dimension --------- A dimension object is the mapping of the dimension names to the dimension positions in the data tensor. Creating a ``xdimension`` is as simple as creating an ``xcoordinate`` or an ``xaxis``: .. code:: using dimension_type = xf::xdimension; dimension_type dim1({"city", "group"}); auto dim2 = xf::dimension({"city", "group"}); // dim1 and dim2 are similar dimensions ``xdimension`` provides an API similar to ``xaxis`` and therefore can be considered as a special axis. Together a dimension object and a coordinate object form a coordinate system which maps labels and dimension names to indexes in the data tensor. .. note:: Like ``xf::coordinate``, the builder function ``xf::dimension`` converts the ``const char*`` arguments to ``fstring`` and returns a ``xdimension`` object. You can modify this behavior by specifying the label type of the dimension as the first template parameter of the ``dimension`` function: ``auto d = xf::dimension({"city", "group"});`` Variables --------- A variable is a data tensor with a coordinate system, that is an ``xcoordinate`` object and an ``xdimension`` object. It is the C++ equivalent of the ``xarray.DataArray`` Python class. ``xvariable`` provides many constructors: .. code:: using coordinate_type = xf::xcoordinate; using dimension_type = xf::xdimension; using variable_type = xvariable; data_type d = xt::eval(xt::random::rand({3, 4})); auto c = xf::coordinate({{"group", xf::axis({"a", "b", "d", "e"})}, {"city", xf::axis({"London", "Paris", "Brussels"})}}); auto dim = xf::dimension({"city", "group"}); variable_type v1(d, c, dim); // Coordinates and dimension can be built in place variable_type v2(d, xf::coordinate({{"group", xf::axis({"a", "b", "d", "e"})}, {"city", xf::axis({"London", "Paris", "Brussels"})}}), xf::dimension({"city", "group"})); The data parameter can be omitted, in that case the variable creates an uninitialized data tensor: .. code:: variable_type v3(c, dim); variable_type v4(xf::coordinate({{"group", xf::axis({"a", "b", "d", "e"})}, {"city", xf::axis({"London", "Paris", "Brussels"})}}), xf::dimension({"city", "group"})); A variable can also be created from a map of axes and a list of dimension names: .. code:: variable_type::coordinate_map coord_map; coord_map["group"] = xf::axis({"a", "b", "d", "e"}); coord_map["city"] = xf::axis({"London", "Paris", "Brussels"}); dimension_type::label_list dim_list = {"group", "city"}; variable_type v5(d, coord_map, dim_list); variable_type v6(coord_map, dim_list); If the dimension object is omitted, the dimension mapping is inferred from the coordinate object. In the code below, the mapping is different from the previous defined variables, ``group`` is the name of the first dimension and ``city`` is the name of the second one: .. code:: variable_type v7(d, {{"group", xf::axis({"a", "b", "d", "e"})}, {"city", xf::axis({"london", "Paris", "Brussels"})}}); // variable with same coordinate system but uninitialized data variable_type v8({{"group", xf::axis({"a", "b", "d", "e"})}, {"city", xf::axis({"london", "Paris", "Brussels"})}}); `xframe` also provides builder functions, so that the type of the variable can be inferred: .. code:: auto v10 = variable(d, c, dim); auto v11 = variable(d, xf::coordinate({{"group", xf::axis({"a", "b", "d", "e"})}, {"city", xf::axis({"London", "Paris", "Brussels"})}}), xf::dimension({"city", "group"})); auto v12 = variable(c, dim); auto v13 = variable(xf::coordinate({{"group", xf::axis({"a", "b", "d", "e"})}, {"city", xf::axis({"London", "Paris", "Brussels"})}}), xf::dimension({"city", "group"})); Summary ------- .. image:: xframe_summary.png :alt: xframe summay .. _pandas: https://pandas.pydata.org ================================================ FILE: docs/source/getting_started.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Getting started =============== This short guide explains how to get started with `xframe` once you have installed it with one of the methods described in the installation section. First example ------------- .. code:: #include #include "xtensor/xrandom.hpp" #include "xframe/xio.hpp" #include "xframe/xvariable.hpp" int main(int argc, char* argv[]) { using coordinate_type = xf::xcoordinate; using variable_type = xf::xvariable; using data_type = variable_type::data_type; // Creation of the data data_type data = xt::eval(xt::random::rand({6, 3}, 15., 25.)); data(0, 0).has_value() = false; data(2, 1).has_value() = false; // Creation of coordinates and dimensions auto time_axis = xf::axis({"2018-01-01", "2018-01-02", "2018-01-03", "2018-01-04", "2018-01-05", "2018-01-06"}); auto city_axis = xf::axis({"London", "Paris", "Brussels"}); auto coord = xf::coordinate({{"date", time_axis}, {"city", city_axis}}); auto dim = xf::dimension({"date", "city"}); // Creation of the variable auto var = variable_type(data, coord, dim); std::cout << var << std::endl; return 0; } This example creates a variable, that is, a tensor data (here random) with labels and dimension names. Compiling the first example --------------------------- `xframe` 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 `xframe` and those of its dependencies, that is, `xtensor` and `xtl`; this is usually done by having the directory containing the headers in the include path. With GCC, 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/headers/ example.cpp -o example When you run the program, it produces the following output (data should be different since it is randomly generated): .. code:: {{ N/A, 23.3501, 24.6887}, {17.2103, 18.0817, 20.4722}, {16.8838, N/A, 24.9646}, {24.6769, 22.2584, 24.8111}, {16.0986, 22.9811, 17.9703}, {15.0478, 16.1246, 21.3976}} Coordinates: date: (2018-01-01, 2018-01-02, 2018-01-03, 2018-01-04, 2018-01-05, 2018-01-06, ) city: (London, Paris, Brussels) Building with cmake ------------------- A better alternative for building programs using `xframe` is to use `cmake`, especially if you are developing for several platforms. Assuming the following folder structure: .. code:: bash first_example |- src | |- example.cpp |- CMakeLists.txt The following minimal ``CMakeLists.txt`` is enough to build the first example: .. code:: cmake cmake_minimum_required(VERSION 3.1) project(first_example) find_package(xtl REQUIRED) find_package(xframeREQUIRED) add_executable(first_example src/example.cpp) target_link_libraries(first_example xtensor) `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 subfolders: ``include``, ``lib`` and ``bin``, so you don't have to pass any additional option for linking. Examples of valid values for ``CMAKE_INSTALL_PREFIX`` on Unix platforms are ``/usr/local``, ``/opt``. The following commands create a directory for building (avoid building in the source folder), builds the first example with cmake and then runs the program: .. code:: bash mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=your_prefix .. make ./first_program Second example: simplified variable creation -------------------------------------------- `xframe` provides many shortcuts so coordinates and variables can be created with a concise syntax. The following example creates the same variable as the previous one: .. code:: #include #include "xtensor/xrandom.hpp" #include "xframe/xio.hpp" #include "xframe/xvariable.hpp" int main(int argc, char* argv[]) { using coordinate_type = xf::xcoordinate; using variable_type = xf::xvariable; using data_type = variable_type::data_type; // Creation of the data data_type data = xt::eval(xt::random::rand({6, 3}, 15., 25.)); data(0, 0).has_value() = false; data(2, 1).has_value() = false; // Creation of the variable auto var = variable_type( data, { {"date", xf::axis({"2018-01-01", "2018-01-02", "2018-01-03", "2018-01-04", "2018-01-05", "2018-01-06"})}, {"city", xf::axis({"London", "Paris", "Brussels"})} } ); std::cout << var << std::endl; return 0; } When compiled and run, this produces output similar to the one of the previous example (same coordinate system but different data due to random generation). Third example: data access -------------------------- `xframe` provides different ways to access data in a variable. .. code:: #include #include "xtensor/xrandom.hpp" #include "xframe/xio.hpp" #include "xframe/xvariable.hpp" int main(int argc, char* argv[]) { using coordinate_type = xf::xcoordinate; using variable_type = xf::xvariable; using data_type = variable_type::data_type; // Creation of the data data_type data = xt::eval(xt::random::rand({6, 3}, 15., 25.)); data(0, 0).has_value() = false; data(2, 1).has_value() = false; // Creation of the variable auto var = variable_type( data, { {"date", xf::axis({"2018-01-01", "2018-01-02", "2018-01-03", "2018-01-04", "2018-01-05", "2018-01-06"})}, {"city", xf::axis({"London", "Paris", "Brussels"})} } ); // Data access std::cout << "operator() - " << var(3, 0) << std::endl; std::cout << "locate - " << var.locate("2018-01-04", "London") << std::endl; std::cout << "iselect - " << var.iselect({{"date", 3}, {"city", 0}}) << std::endl; std::cout << "select - " << var.select({{"date", "2018-01-04"}, {"city", "London"}}) << std::endl; return 0; } Outputs: .. code:: operator() - 24.6769 locate - 24.6769 iselect - 24.6769 select - 24.6769 ================================================ FILE: docs/source/index.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. .. image:: xframe.svg :alt: xframe Multi-dimensional labeled arrays and data frame based on `xtensor`_. Introduction ------------ `xframe` is a C++ library meant for numerical analysis with multi-dimensional labeled array expressions (also referred as variable expressions) and data frame expressions. It is built upon `xtensor`_ and provides similar features: - an extensible expression system enabling **lazy broadcasting** based on dimension names. - an API following the idioms of the C++ standard library. - tools to manipulate variable expressions and build upon *xframe*. The API of `xframe` is inspired by the ones of `pandas`_ and `xarray`_. `xframe` 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 - On Unix platforms, gcc 4.9 or a recent version of Clang Licensing --------- We use a shared copyright model that enables all contributors to maintain the copyright on their contributions. This software is licensed under the BSD-3-Clause license. See the LICENSE file for details. .. toctree:: :caption: INSTALLATION :maxdepth: 1 installation .. toctree:: :caption: USAGE :maxdepth: 2 getting_started data_structure indexing computation .. toctree:: :caption: API REFERENCE :maxdepth: 2 api/axis_index api/coordinate_index api/variable_index .. toctree:: :caption: MISCELLANEOUS xarray .. _xtensor: https://github.com/xtensor-stack/xtensor .. _pandas: https://pandas.pydata.org .. _xarray: https://xarray.pydata.org ================================================ FILE: docs/source/indexing.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Indexing and selecting data =========================== In this section, we consider the following variable: .. code:: using coordinate_type = xf::xcoordinate; using dimension_type = xf::xdimension; using variable_type = xf::xvariable; data_type d = xt::eval(xt::random::rand({6, 3}, 15., 25.)); variable_type v(std::move(d), { {"group", xf::axis({"a", "b", "d", "e", "g", "h"})}, {"city", xf::axis({"London", "Paris", "Brussels"})} }); Printing this variable in a Jupyter Notebook gives: +-------+---------+---------+----------+ | | London | Paris | Brussels | +=======+=========+=========+==========+ | **a** | 16.3548 | 23.3501 | 24.6887 | +-------+---------+---------+----------+ | **b** | 17.2103 | 18.0817 | 20.4722 | +-------+---------+---------+----------+ | **d** | 16.8838 | 24.9288 | 24.9646 | +-------+---------+---------+----------+ | **e** | 24.6769 | 22.2584 | 24.8111 | +-------+---------+---------+----------+ | **g** | 16.0986 | 22.9811 | 17.9703 | +-------+---------+---------+----------+ | **h** | 15.0478 | 16.1246 | 21.3976 | +-------+---------+---------+----------+ `xframe` provides flexible indexing methods for data selection, similar to the ones of `xarray`_. These methods are summarized in the following table: +------------------+--------------+---------------------------------------------------+ | Dimension lookup | Index lookup | ``xvariable`` syntax | +==================+==============+===================================================+ | Positional | By integer | ``v(2, 1)`` | +------------------+--------------+---------------------------------------------------+ | Positional | By label | ``v.locate("d", "Paris")`` | +------------------+--------------+---------------------------------------------------+ | By name | By integer | ``v.iselect({{"group", 2}, {"city", 1}})`` | +------------------+--------------+---------------------------------------------------+ | By name | By label | ``v.select({{"group", "d"}, {"city", "Paris"}})`` | +------------------+--------------+---------------------------------------------------+ Positional indexing ------------------- The most basic way to access elements of an ``xvariable`` is to use ``operator()``, like you would do with an ``xtensor``: .. code:: std::cout << v(2, 1) << std::endl; Contrary to Python, it is not possible to have different return types for a same method in C++. Multi selection is done with free functions that return views on the variable:, .. code:: #include "xvariable_view.hpp" auto view1 = xf::ilocate(v, xf::irange(0, 5, 2), xf::irange(1, 3)); std::cout << view1 << std::endl; +-------+---------+----------+ | | Paris | Brussels | +=======+=========+==========+ | **a** | 23.3501 | 24.6887 | +-------+---------+----------+ | **d** | 24.9288 | 24.9646 | +-------+---------+----------+ | **g** | 22.9811 | 17.9703 | +-------+---------+----------+ Therefore a change in the view will reflect in the underlying variable: .. code:: view1(0, 1) = 0.; std::cout << v(2, 2) << std::endl; // Outputs 0. In the code creating the view, ``irange`` returns a range slice from `xtensor`, so any multi selection in `xtensor` is also supported in `xframe`. ``xvariable`` also supports label-based indexing, with the ``locate`` method for single point selection, and ``locate`` free function for multi selection: .. code:: std::cout << v.locate("d", "Paris") << std::endl; auto view2 = xf::locate(v, xf::range("a", "h", 2), xf::range("Paris", "Brussels")); std::cout << view2 << std::endl; // Same output as previous code Be aware of the difference between ``range`` and ``irange`` parameters: for the former one, accepting labels, the last value is *included* while for the latter one, accepting integral indices, the las value is *excluded*. `xframe` provides label-based slices similar to those of `xtensor`, so label-based multi selection is really similar to positional multi selection. Indxing with dimension names ---------------------------- With the dimension names, we do not have to rely on the dimension order. We can use them explicitely to select data; Like positional indexing, `xframe` provides methods and free functions depending on the kind of selection you want to do: .. code:: // Dimension by name, index by position std::cout << v.iselect({{"city", 1}, {"group", 2}}) << std::endl; auto view3 = xf::iselect(v, {{"city", xf::irange(1, 3)}, {"group", xf::irange(0, 5, 2)}}); // Dimension by name, index by label std::cout << v.select({{"city", "Paris"}, {"group", "d"}}) << std::endl; auto view4 = xf::select(v, {{"city", xf::range("Paris", "Brussels")}, {"group", xf::range("a", "h", 2)}}); // view3 and view4 gives the same output as view2 and view1 Contrary to `xarray`_, `xframe` does not provide a selection operator accepting a map argument. Keeping and dropping labels --------------------------- ``drop`` and ``keep`` functions return slices that can be used to create a view with the listed labels along the specified dimensions dropped or kept: .. code:: auto view5 = xf::select(v, {{"city", xf::drop("London")}, {"group", xf::keep("a", "d", "g")}}); // view5 is equivalent to view4 This is different form `xarray`_ where the ``xarray.DataArray.drop`` method returns a new object. To achieve the same with `xframe`, simply assign the view to a new ``xvariable`` object: .. code:: variable_type v2 = view5; Masking views ------------- Masking views allow to select data points based on conditions expresses on labels. These conditions can be arbitrary complicated boolean expressions. Contrary to other views which are generally a subset of the original data, a masking view has the same shape as its underlying ``xvariable``. Masking views are created with the ``where`` function: .. code:: data_type d2 = {{ 1., 2., 3. }, { 4., 5., 6. }, { 7., 8., 9. }}; auto v3 = variable_type( d2, { {"x", xf::axis(3)}, {"y", xf::axis(3)}, } ); auto view6 = xf::where( v3, not_equal(v3.axis("x"), 2) && v3.axis("y") < 2 ); std::cout << view6 << std::endl; In a Jupyter Notebookn, this outputs the following: +-------+--------+--------+--------+ | | 0 | 1 | 2 | +=======+========+========+========+ | **0** | 1 | 2 | masked | +-------+--------+--------+--------+ | **1** | 4 | 5 | masked | +-------+--------+--------+--------+ | **2** | masked | masked | masked | +-------+--------+--------+--------+ When assigning to a masked view, masked values are not changed. Like other views, a masking view is a proxy on its underlying variable, no copy is made, so changing an unmasked value actually changes the corresponding value in the undnerlying variable. Assigning values with indexing ------------------------------ Data selection in variables return either references or views; therefore, contrary to `xarray`_, it is *possible* to assign values to a subset of a variable with any of the indexing method: .. code:: // The next four lines are equivalent, they change a single value of v: v(2, 1) = 2.5; v.locate("d", "Paris") = 2.5; v.iselect({{"city", 1}, {"group", 2}}) = 2.5; v.select({{"city", "Paris"}, {"group", "d"}}) = 2.5; data_type d3 = {{0., 1.}, {2., 3.}, {4., 5.}}; auto v4 = variable_type( d3, { {"group", xf::axis({"a", "d", "g"})}, {"city", xf::axis({"Paris", "Brussels"})} } ); // The next four lines are equivalent, they change a subset of v xf::ilocate(v, xf::irange(0, 5, 2), xf::irange(1, 3)) = v4; xf::locate(v, xf::range("a", "h", 2), xf::range("Paris", "Brussels")) = v4; xf::iselect(v, {{"city", xf::irange(1, 3)}, {"group", xf::irange(0, 5, 2)}}) = v4; xf::select(v, {{"city", xr::range("Paris", "Brussels")}, {"group", xf::range("a", "h", 2)}}) = v4; Printing ``v`` after the assign gives +-------+---------+---------+----------+ | | London | Paris | Brussels | +=======+=========+=========+==========+ | **a** | 16.3548 | 0 | 1 | +-------+---------+---------+----------+ | **b** | 17.2103 | 18.0817 | 20.4722 | +-------+---------+---------+----------+ | **d** | 16.8838 | 2 | 3 | +-------+---------+---------+----------+ | **e** | 24.6769 | 22.2584 | 24.8111 | +-------+---------+---------+----------+ | **g** | 16.0986 | 4 | 5 | +-------+---------+---------+----------+ | **h** | 15.0478 | 16.1246 | 21.3976 | +-------+---------+---------+----------+ Reindexing views ---------------- Reindexing views give variables new set of coordinates to corresponding dimensions. Like other views, no copy is involved. Asking for values corresponding to new labels not found in the original set of coordinates returns missing values. In the next example, we reindex the ``city`` dimension: .. code:: auto view7 = xf::reindex(v, {{"city", xf::axis({"London", "New York", "Brussels"})}}); +-------+---------+----------+----------+ | | London | New York | Brussels | +=======+=========+==========+==========+ | **a** | 16.3548 | N/A | 24.6887 | +-------+---------+----------+----------+ | **b** | 17.2103 | N/A | 20.4722 | +-------+---------+----------+----------+ | **d** | 16.8838 | N/A | 24.9646 | +-------+---------+----------+----------+ | **e** | 24.6769 | N/A | 24.8111 | +-------+---------+----------+----------+ | **g** | 16.0986 | N/A | 17.9703 | +-------+---------+----------+----------+ | **h** | 15.0478 | N/A | 21.3976 | +-------+---------+----------+----------+ Like `xarray`_, `xframe` provides the useful ``reindex_like`` shortcut which allows to reindex a variable given the set of coordinates of another variable: .. code:: auto v5 = variable_type( d, { {"group", xf::axis({"a", "b", "d", "e", "g", "h"})}, {"city", xf::axis({"London", "New York", "Brussels"})} } ); auto view8 = xf::reindex_like(v, v5); // view8 is equivalent to view7 A reindexing view is a read-only view, it is not possible to change its value with indexing. This allows memory optimizations, the view does not have to store the missing values, it can return a proxy to a static-allocated missing value. The ``align`` function allows to reindex many variables with more flexible options: .. code:: auto t1 = xf::align(v, v5); std::cout << std::get<0>(t1) << std::endl; std::cout << std::get<1>(t1) << std::endl; The last lines print the same output: +-------+---------+----------+ | | London | Brussels | +=======+=========+==========+ | **a** | 16.3548 | 24.6887 | +-------+---------+----------+ | **b** | 17.2103 | 20.4722 | +-------+---------+----------+ | **d** | 16.8838 | 24.9646 | +-------+---------+----------+ | **e** | 24.6769 | 24.8111 | +-------+---------+----------+ | **g** | 16.0986 | 17.9703 | +-------+---------+----------+ | **h** | 15.0478 | 21.3976 | +-------+---------+----------+ In the following, the variables are aligned w.r.t the union of the coordinates instead of their intersection: .. code:: auto t2 = xf::align(v, v5); std::cout << std::get<0>(t2) << std::endl; std::cout << std::get<1>(t2) << std::endl; The first outuput is +-------+---------+---------+----------+----------+ | | London | Paris | Brussels | New York | +=======+=========+=========+==========+==========+ | **a** | 16.3548 | 23.3501 | 24.6887 | N/A | +-------+---------+---------+----------+----------+ | **b** | 17.2103 | 18.0817 | 20.4722 | N/A | +-------+---------+---------+----------+----------+ | **d** | 16.8838 | 24.9288 | 24.9646 | N/A | +-------+---------+---------+----------+----------+ | **e** | 24.6769 | 22.2584 | 24.8111 | N/A | +-------+---------+---------+----------+----------+ | **g** | 16.0986 | 22.9811 | 17.9703 | N/A | +-------+---------+---------+----------+----------+ | **h** | 15.0478 | 16.1246 | 21.3976 | N/A | +-------+---------+---------+----------+----------+ While the second have ``N/A`` in the ``Paris`` column. .. _xarray: https://xarray.pydata.org ================================================ FILE: docs/source/installation.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay and Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. .. raw:: html Installation ============ Although ``xframe`` is a header-only library, we provide standardized means to install it, with package managers or with cmake. Besides the xframe headers, all these methods place the ``cmake`` project configuration file in the right location so that third-party projects can use cmake's ``find_package`` to locate xframe headers. .. image:: conda.svg Using the conda-forge package ----------------------------- A package for xframe is available for the mamba (or conda) package manager. .. code:: mamba install -c conda-forge xframe .. image:: cmake.svg From source with cmake ---------------------- You can also install ``xframe`` from source with cmake. This requires that you have the xtensor_ library installed on your system. On Unix platforms, from the source directory: .. code:: mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=path_to_prefix .. make install On Windows platforms, from the source directory: .. code:: mkdir build cd build cmake -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=path_to_prefix .. nmake nmake install ``path_to_prefix`` is the absolute path to the folder where cmake searches for dependencies and installs libraries. ``xframe`` installation from cmake assumes this folder contains ``include`` and ``lib`` subfolders. Including xframe in your project -------------------------------- The different packages of ``xframe`` are built with cmake, so whatever the installation mode you choose, you can add ``xframe`` to your project using cmake: .. code:: find_package(xframe REQUIRED) target_include_directories(your_target PUBLIC ${xframe_INCLUDE_DIRS}) target_link_libraries(your_target PUBLIC xframe) .. _xtensor: https://github.com/xtensor-stack/xtensor ================================================ FILE: docs/source/xarray.rst ================================================ .. Copyright (c) 2018, Johan Mabille, Sylvain Corlay, Wolf Vollprecht and Martin Renou Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. From xarray to xframe ===================== .. raw:: html .. |_| unicode:: 0xA0 Containers ---------- +------------------------------------------------+--------------------------------------------------+ | Python 3 - xarray | C++ 14 - xframe | +================================================+==================================================+ | | ``xr.DataArray([[1, 2], [3, 4]],`` | | ``xf::variable({{1, 2}, {3, 4}},`` | | | |_| |_| |_| ``[('x', ['a', 'b']),`` | | |_| |_| |_| ``{{"x", xf::axis({"a", "b"})},`` | | | |_| |_| |_| |_| ``('y', [1, 4])])`` | | |_| |_| |_| |_| ``{"y", xf::axis({1, 4})}})`` | +------------------------------------------------+--------------------------------------------------+ Indexing -------- `xframe` returns views for multi-selection, no copy is made. +-----------------------------------------------+-------------------------------------------------------------+ | Python 3 - xarray | C++ 14 - xframe | +===============================================+=============================================================+ | ``da[0, 1]`` | ``v(0, 1)`` | +-----------------------------------------------+-------------------------------------------------------------+ | ``da.loc['a', 'Paris']`` | ``v.locate("a", "Paris")`` | +-----------------------------------------------+-------------------------------------------------------------+ | ``da.isel(city=1, group=0)`` | ``v.iselect({{"city", 1}, {"group", 0}})`` | +-----------------------------------------------+-------------------------------------------------------------+ | ``da.sel(city='Paris', group='a')`` | ``v.select({{"city", "Paris"}, {"group", "a"}})`` | +-----------------------------------------------+-------------------------------------------------------------+ | ``da[:, 1]`` | ``xf::ilocate(v, xf::iall(), 1)`` | +-----------------------------------------------+-------------------------------------------------------------+ | ``da.loc[:, 'Paris']`` | ``xf::locate(v, xf::all(), "Paris")`` | +-----------------------------------------------+-------------------------------------------------------------+ | ``da.isel(city=1)`` | ``xf::iselect(v, {{"city", 1}})`` | +-----------------------------------------------+-------------------------------------------------------------+ | ``da.sel(city='Paris')`` | ``xf::select(v, {{"city", "Paris"}})`` | +-----------------------------------------------+-------------------------------------------------------------+ | ``da.reindex(city=['NYC', 'Paris'])`` | ``xf::reindex(v, {{"city", xf::axis({"NYC", "Paris"})}})`` | +-----------------------------------------------+-------------------------------------------------------------+ | ``da.reindex_like(df)`` | ``xf::reindex_like(v, v2)`` | +-----------------------------------------------+-------------------------------------------------------------+ Logical ------- Logical universal functions are truly lazy. ``xf::where(condition, a, b)`` does not evaluate ``a`` where ``condition`` is falsy, and it does not evaluate ``b`` where ``condition`` is truthy. `xarray` relies on `numpy` functions, that can also operate on ``xarray.DataArray``. +-----------------------------------------------+-----------------------------------------------+ | Python 3 - xarray | C++ 14 - xframe | +===============================================+===============================================+ | ``xr.where(a > 5, a, b)`` | ``xf::where(a > 5, a, b)`` | | ``xr.where(a > 5, 100, a)`` | ``xf::where(a > 5, 100, a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.any(a)`` | ``xf::any(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.all(a)`` | ``xf::all(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.logical_and(a, b)`` | ``a && b`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.logical_or(a, b)`` | ``a || b`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.isclose(a, b)`` | ``xf::isclose(a, b)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.allclose(a, b)`` | ``xf::allclose(a, b)`` | +-----------------------------------------------+-----------------------------------------------+ Comparisons ----------- `xarray` relies on `numpy` functions, that can also operate on ``xarray.DataArray``. +-----------------------------------------------+-----------------------------------------------+ | Python 3 - xarray | C++ 14 - xframe | +===============================================+===============================================+ | ``np.equal(a, b)`` | ``xf::equal(a, b)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.not_equal(a, b)`` | ``xf::not_equal(a, b)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.less(a, b)`` || ``xf::less(a, b)`` | | || ``a < b`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.less_equal(a, b)`` || ``xf::less_equal(a, b)`` | | || ``a <= b`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.greater(a, b)`` || ``xf::greater(a, b)`` | | || ``a > b`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.greater_equal(a, b)`` || ``xf::greater_equal(a, b)`` | | || ``a >= b`` | +-----------------------------------------------+-----------------------------------------------+ Mathematical functions ---------------------- xframe universal functions are provided for a large set number of mathematical functions. `xarray` relies on `numpy` functions, that can also operate on ``xarray.DataArray``. **Basic functions:** +-----------------------------------------------+-----------------------------------------------+ | Python 3 - xarray | C++ 14 - xframe | +===============================================+===============================================+ | ``np.absolute(a)`` | ``xf::abs(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.sign(a)`` | ``xf::sign(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.remainder(a, b)`` | ``xf::remainder(a, b)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.clip(a, min, max)`` | ``xf::clip(a, min, max)`` | +-----------------------------------------------+-----------------------------------------------+ | | ``xf::fma(a, b, c)`` | +-----------------------------------------------+-----------------------------------------------+ **Exponential functions:** +-----------------------------------------------+-----------------------------------------------+ | Python 3 - xarray | C++ 14 - xframe | +===============================================+===============================================+ | ``np.exp(a)`` | ``xf::exp(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.expm1(a)`` | ``xf::expm1(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.log(a)`` | ``xf::log(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.log1p(a)`` | ``xf::log1p(a)`` | +-----------------------------------------------+-----------------------------------------------+ **Power functions:** +-----------------------------------------------+-----------------------------------------------+ | Python 3 - xarray | C++ 14 - xframe | +===============================================+===============================================+ | ``np.power(a, p)`` | ``xf::pow(a, b)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.sqrt(a)`` | ``xf::sqrt(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.square(a)`` | ``xf::square(a)`` | | | ``xf::cube(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.cbrt(a)`` | ``xf::cbrt(a)`` | +-----------------------------------------------+-----------------------------------------------+ **Trigonometric functions:** +-----------------------------------------------+-----------------------------------------------+ | Python 3 - xarray | C++ 14 - xframe | +===============================================+===============================================+ | ``np.sin(a)`` | ``xf::sin(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.cos(a)`` | ``xf::cos(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.tan(a)`` | ``xf::tan(a)`` | +-----------------------------------------------+-----------------------------------------------+ **Hyperbolic functions:** +-----------------------------------------------+-----------------------------------------------+ | Python 3 - xarray | C++ 14 - xframe | +===============================================+===============================================+ | ``np.sinh(a)`` | ``xf::sinh(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.cosh(a)`` | ``xf::cosh(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``np.tanh(a)`` | ``xf::tanh(a)`` | +-----------------------------------------------+-----------------------------------------------+ **Error and gamma functions:** +-----------------------------------------------+-----------------------------------------------+ | Python 3 - xarray | C++ 14 - xframe | +===============================================+===============================================+ | ``scipy.special.erf(a)`` | ``xf::erf(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``scipy.special.gamma(a)`` | ``xf::tgamma(a)`` | +-----------------------------------------------+-----------------------------------------------+ | ``scipy.special.gammaln(a)`` | ``xf::lgamma(a)`` | +-----------------------------------------------+-----------------------------------------------+ ================================================ FILE: docs/source/xframe_summary_drawio.xml ================================================ 7Z3dc6M2EMD/Gs+0D70BBNg8xo5z7fTaaece2t5LhxjFpoeRC3Ji96+vMOJz1x8Xg3ACfriDBcuwP620u6zIiMzWu4+Ru1n9wjwajAzN243I/cgwdMd0xH+JZC8lumamkmXke1JWCD77/1Ep1KR063s0rpzIGQu4v6kKFywM6YJXZG4UsZfqaU8sqP7qxl1SIPi8cAMo/cP3+CqVTiytkP9I/eWK5/cnj6zd7GQpiFeux15KIjIfkVnEGE+31rsZDRLtZXpJv/dw5Gh+YREN+SVfsOa7TyR4Cb/8tFxv519+5/TnyQ+WkTbz7AZbecfyavk+U0HEtqFHk1a0EZm+rHxOP2/cRXL0RVAXshVfB2JPF5tPLOSSop6c7gb+MhQ7Uaqj6ZMfBDMWsEjIQhaK86Yxj9hXmglHBiE2cYj4vannxqvDDyctw/uVKnimEae7kkje/0fK1pRHe3GKPDqRKGRnJBmrl4KsZUvZqkw1Y+jK3rTMmy4ULjakzr9B/4bTY/3rk+71P+mx/u3O1a8D7e/cnR83hsDQMP1qmuNomjwTk6ffyMZ7oxnlO1XlI31fdxDlT1rr+kD3+v1h3tps/HA5IneAgrhRXlV1VbWyPyNdvG4FidZ8McneSfna97zkV1C0VfgNkKjbAYICI0HaImEBTVNPOCFyl0V8xZYsdIN5Ia0ppYTkH8r5XnZ/d8uZEBUtfGJsk6NzI36XeEjJb2xomMke/OTqD83S0KudISSV4+L2/yzv/JXsfLCy3ftd+eD9/hzDmG2jBT2hKuk8iutcUn7iPDs9L9HjyR4R0cDl/nPV2cMAy6/+xnxxyXlPsvRqT3Ksagvpdcov1XpJfhWv7zgmMOHAfaTBteNnyX7FqPhw+GDjqK6NiTOH42gub2UcJeetd6LSem0AYcNin/ssvA5DK8qzjNtS3hgoj+7c9SZRWH/mn9y/6moCusAJLk0Fi8CNY39x2uk6qqazQ3LZG0WUkMmuHLnro4hu1pSbTkVg6AYN2dqZhlqeAy4IIEvspD28J3DWK8GBhupRTsvgMtehN+RMoyFyoKH6wNg2ORi2vnNydlPk6g2pJgeD3vdNzqrPTq8lBxpSTY70jZzZFLl6Q6rJwShVA+iud+0XgiONrvPt68nbo33kG6LV8RGMpV5kIL1I1453mOtSrhbAIe7ADhL1P0Zia8nzO+8DIFO/NUAwoWD0GpB1a4Bg0oL0GpBza4BgPsPsDw6L3BqOvqUorKZSFKAhxa6bgQW69r/bpGRl6habb8S4jj2maMDogJuHPFtXanSZjaHoHgd0JxzAztFhoW7Giw7oTriGnaODsW7BazmgO+E0do4OxsUFL39Ad8LB7BwdjJhhSc1tYmoCx61lmAwYHxfmsxss6QS6ri0ps+xyQeaCscjzQ5dTAKzZssyHB8chBGo8l6soyzSQmnC1dZkEBl2/in/6WJiJwVBaGEMI0PVQmnlMV5fWZhI5OasuzjR0tdWZBAYDnr+mYXwoDdRCd93AiFoaJ+/mpk4MbGStHWm5IBOzWqVFhQS68g0sK7iRZQT1Cs7utQ297x7WcBqI1612qsK87pry45W7STYX2yjYTyN38TUZqM91/EJ32AKnWucnxHEO1eJ1XE0MNHVfzbzMXa6n35vTOVY4m+fHH+OFH8dvPk2eTx4NEDSzwPwEQRMh2NoCNII9m8p4FXHPQPAowXHHBE0YsrYz7ygApR0+DYEanx8sdaWgkIeJAygEFGJRakEZAFTiPX83Gk+PPP0Vv6MdebpYPUSPHyo/HRnff99Cvwjo05V+49leIR3/JnrF5PxMqWcBrZpuAR9LZt1CS2GS9D/dGAAiADGzVgsQCYtLCYnmc7vlyBdEz7atabMZZJDLG2BQixcIss5ObW7XhLFyXxfdCxgfNDJxrPHEnhCNWDZgozR+NsdA9UOq95iuZNx7NtWbvf5JdaqXEMUL8WEioBepXmxEVZp8NGH8/oZW33euviwz1u/cLUFcM7UvgLlgQek7y92SC0sdWsvdWqeqLIfc7fnMX060q8yfdarYcsjdXkAQsUG1BJGayyElCFOCmKkpTQlaMG4dQGGgEItSCwo+BdZawKQgE9cgpMn5YU9tJs6C4aI+UDrvXiim1Od385pIaKr45bA2DE5Lxch/x/uY03VjRI7krS9+GaJ9+GBBVfJpJZ9tYs+ElOazbQPxC+5v3y8wzHYHM0Cq6yoJG0a77/zZT/2FRaixZEvT1RgLjFff++IKYl4AAUv7tAcBW+b3BnIDbY9Y9TezdT9iISFnb7wvC7ET1d4XUts6TO1G0eMzVF2nQW0Ypuy4mNjFzRsa3W0iGncyyedKbxFGfZK30NBe5SQ/RoKWZzfy3ceg7Sn+rMJVrJ9ECSid4cfYw7RhhgczfOcD1xgGjz2P743xBcbUUIAvdou/PZbWwRR/wo3M/wc= ================================================ FILE: environment-dev.yml ================================================ name: xframe channels: - conda-forge dependencies: - cmake - xtensor=0.21.4 ================================================ FILE: environment.yml ================================================ name: xframe channels: - QuantStack - conda-forge dependencies: - xframe=0.3.0 - xeus-cling=0.8.1 - notebook ================================================ FILE: include/xframe/xaxis.hpp ================================================ /*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * 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 XFRAME_XAXIS_HPP #define XFRAME_XAXIS_HPP #include #include #include #include #include #include #include #include "xtl/xiterator_base.hpp" #include "xtensor/xbuilder.hpp" #include "xaxis_base.hpp" #include "xframe_utils.hpp" namespace xf { template class xaxis_iterator; template class xaxis_default; /********************* * map container tag * *********************/ struct map_tag {}; struct hash_map_tag {}; template struct map_container; template struct map_container { using type = std::map; }; template struct map_container { using type = std::unordered_map; }; template using map_container_t = typename map_container::type; /********* * xaxis * *********/ /** * @class xaxis * @brief Class modeling an axis in a coordinate system. * * The xaxis class is used for modeling general axes; an axis is a mapping * of labels to positions in a given dimension. It is the equivalent of * the \c Index object from pandas. * * @tparam L the type of labels. * @tparam T the integer type used to represent positions. Default value is * \c std::size_t. * @tparam MT the tag used for choosing the map type which holds the label- * position pairs. Possible values are \c map_tag and \c hash_map_tag. * Default value is \c hash_map_tag. */ template class xaxis : public xaxis_base> { public: using base_type = xaxis_base; using self_type = xaxis; using key_type = typename base_type::key_type; using label_list = typename base_type::label_list; using mapped_type = typename base_type::mapped_type; using map_type = map_container_t; using value_type = typename map_type::value_type; using reference = typename map_type::const_reference; using const_reference = typename map_type::const_reference; using pointer = typename map_type::const_pointer; using const_pointer = typename map_type::const_pointer; using size_type = typename base_type::size_type; using difference_type = typename base_type::difference_type; using iterator = typename base_type::iterator; using const_iterator = typename base_type::const_iterator; using reverse_iterator = typename base_type::reverse_iterator; using const_reverse_iterator = typename base_type::const_reverse_iterator; explicit xaxis(); explicit xaxis(const label_list& labels); explicit xaxis(label_list&& labels); xaxis(std::initializer_list init); template explicit xaxis(xaxis_default axis); template xaxis(InputIt first, InputIt last); bool is_sorted() const noexcept; bool contains(const key_type& key) const; mapped_type operator[](const key_type& key) const; template self_type filter(const F& f) const noexcept; template self_type filter(const F& f, size_type size) const noexcept; const_iterator find(const key_type& key) const; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; template bool merge(const Args&... axes); template bool intersect(const Args&... axes); protected: void populate_index(); void set_labels(const label_list& labels); template bool merge_unsorted(bool broadcasting, const Arg& a, const Args&... axes); bool merge_unsorted(bool broadcasting); template bool intersect_unsorted(const Arg& al, const Args&... axes_labels); bool intersect_unsorted(); private: xaxis(const label_list& labels, bool is_sorted); xaxis(label_list&& labels, bool is_sorted); typename map_type::const_iterator find_index(const key_type& key) const; template bool merge_impl(const Args&... axes); template bool merge_empty(const Arg1& a, const Args&... axes); bool merge_empty(); bool init_is_sorted() const noexcept; template bool all_sorted(const Arg& a, const Args&... axes) const noexcept; template bool all_sorted(const Arg& a) const noexcept; map_type m_index; bool m_is_sorted; friend class xaxis_iterator; friend class xaxis_default; }; template bool merge_axes(xaxis& output, const Args&... axes); template bool intersect_axes(xaxis& output, const Args&... axes); /****************** * xaxis builders * ******************/ template xaxis axis(L start, L stop, L step = 1) noexcept; template xaxis axis(std::initializer_list init) noexcept; template xaxis axis(std::initializer_list init) noexcept; /******************** * xaxis_inner_types * *********************/ template struct xaxis_inner_types> { using key_type = L; using mapped_type = T; using iterator = xaxis_iterator; }; /****************** * xaxis_iterator * ******************/ template class xaxis_iterator : public xtl::xrandom_access_iterator_base, typename xaxis::value_type, typename xaxis::difference_type, typename xaxis::const_pointer, typename xaxis::const_reference> { public: using self_type = xaxis_iterator; using container_type = xaxis; using label_list = typename container_type::label_list; using label_iterator = typename label_list::const_iterator; using value_type = typename container_type::value_type; using reference = typename container_type::const_reference; using pointer = typename container_type::const_pointer; using difference_type = typename container_type::difference_type; using iterator_category = std::random_access_iterator_tag; xaxis_iterator() = default; xaxis_iterator(const container_type* c, label_iterator it); self_type& operator++(); self_type& operator--(); self_type& operator+=(difference_type n); self_type& operator-=(difference_type n); difference_type operator-(const self_type& rhs) const; reference operator*() const; pointer operator->() const; bool equal(const self_type& rhs) const noexcept; bool less_than(const self_type& rhs) const noexcept; private: const container_type* p_c; label_iterator m_it; }; template typename xaxis_iterator::difference_type operator-(const xaxis_iterator& lhs, const xaxis_iterator& rhs); template bool operator==(const xaxis_iterator& lhs, const xaxis_iterator& rhs) noexcept; template bool operator<(const xaxis_iterator& lhs, const xaxis_iterator& rhs) noexcept; /************************ * xaxis implementation * ************************/ /** * @name Constructors */ //@{ /** * Constructs an empty axis. */ template inline xaxis::xaxis() : base_type(), m_index(), m_is_sorted(true) { } /** * Constructs an axis with the given list of labels. This list * is copied and the constructor internally checks whether it * is sorted. * @param labels the list of labels. */ template inline xaxis::xaxis(const label_list& labels) : base_type(labels), m_index(), m_is_sorted() { m_is_sorted = init_is_sorted(); populate_index(); } /** * Constructs an axis with the given list of labels. The list is * moved and therefore it is invalid after the axis has been * constructed. The constructor internally checks whether the list * is sorted. * @param labels the list of labels. */ template inline xaxis::xaxis(label_list&& labels) : base_type(std::move(labels)), m_index(), m_is_sorted() { m_is_sorted = init_is_sorted(); populate_index(); } /** * Constructs an axis with the given list of labels, and a boolean * specifying if the labels list is sorted. This is an optimization * that prevents the constructor to check if the labels list is sorted. * The list is copied. * @param labels th list of labels. * @param is_sorted a boolean parameter indicating if the labels list * is sorted. */ template inline xaxis::xaxis(const label_list& labels, bool is_sorted) : base_type(labels), m_index(), m_is_sorted(is_sorted) { populate_index(); } /** * Constructs an axis with the given list of labels, and a boolean * specifying if the labels list is sorted. This is an optimization * that prevents the constructor to check if the labels list is sorted. * The list is moved and therefore invalid after the axis has been * constructed. * @param labels th list of labels. * @param is_sorted a boolean parameter indicating if the labels list * is sorted. */ template inline xaxis::xaxis(label_list&& labels, bool is_sorted) : base_type(labels), m_index(), m_is_sorted(is_sorted) { populate_index(); } /** * Constructs an axis from the given initializer list of labels. The * constructor internally checks whether the list is sorted. */ template inline xaxis::xaxis(std::initializer_list init) : base_type(init), m_index(), m_is_sorted() { m_is_sorted = init_is_sorted(); populate_index(); } /** * Constructs an axis from a \c default_axis. * @sa default_axis */ template template inline xaxis::xaxis(xaxis_default axis) : base_type(axis.labels()), m_index(), m_is_sorted(true) { static_assert(std::is_same::value, "key_type L and key_type L1 must be the same"); populate_index(); } /** * Constructs an axis from the content of the range [first, last) * @param first An iterator to the first label. * @param last An iterator the the element following the last label. */ template template inline xaxis::xaxis(InputIt first, InputIt last) : base_type(first, last), m_index(), m_is_sorted() { m_is_sorted = init_is_sorted(); populate_index(); } //@} /** * Returns true if the labels list is sorted. */ template inline bool xaxis::is_sorted() const noexcept { return m_is_sorted; } /** * @name Data */ //@{ /** * Returns true if the axis contains the speficied label. * @param key the label to search for. */ template inline bool xaxis::contains(const key_type& key) const { return m_index.count(key) != typename map_type::size_type(0); } /** * Returns the position of the specified label. If this last one is * not found, an exception is thrown. * @param key the label to search for. */ template inline auto xaxis::operator[](const key_type& key) const -> mapped_type { return m_index.at(key); } //@} /** * @name Filters */ //@{ /** * Builds an return a new axis by applying the given filter to the axis. * @param f the filter used to select the labels to keep in the new axis. */ template template inline auto xaxis::filter(const F& f) const noexcept -> self_type { return self_type(base_type::filter_labels(f), m_is_sorted); } /** * Builds an return a new axis by applying the given filter to the axis. When * the size of the new list of labels is known, this method allows some * optimizations compared to the previous one. * @param f the filter used to select the labels to keep in the new axis. * @param size the size of the new label list. */ template template inline auto xaxis::filter(const F& f, size_type size) const noexcept -> self_type { return self_type(base_type::filter_labels(f, size), m_is_sorted); } //@} /** * @name Iterator */ //@{ /** * Returns a constant iterator to the element with label equivalent to \c key. If * no such element is found, past-the-end iterator is returned. * @param key the label to search for. */ template inline auto xaxis::find(const key_type& key) const -> const_iterator { auto map_iter = m_index.find(key); return map_iter != m_index.end() ? cbegin() + map_iter->second : cend(); } /** * Returns a constant iterator to the first element of the axis. * This element is a pair label - position. */ template inline auto xaxis::cbegin() const noexcept -> const_iterator { return const_iterator(this, this->labels().begin()); } /** * Returns a constant iterator to the element following the last element * of the axis. */ template inline auto xaxis::cend() const noexcept -> const_iterator { return const_iterator(this, this->labels().end()); } //@} /** * @name Set operations */ //@{ /** * Merges all the axes arguments into this ones. After this function call, * the axis contains all the labels from all the arguments. * @param axes the axes to merge. * @return true is the axis already contained all the labels. */ template template inline bool xaxis::merge(const Args&... axes) { return this->empty() ? merge_empty(axes...) : merge_impl(axes...); } /** * Replaces the labels with the intersection of the labels of * the axes arguments and the labels of this axis. * @param axes the axes to intersect. * @return true if the intersection is equivalent to this axis. */ template template inline bool xaxis::intersect(const Args&... axes) { bool res = true; if (all_sorted(*this, axes...)) { res = intersect_to(this->mutable_labels(), axes.labels()...); populate_index(); } else { res = intersect_unsorted(axes.labels()...); } return res; } //@} template inline void xaxis::populate_index() { for(size_type i = 0; i < this->labels().size(); ++i) { m_index[this->labels()[i]] = T(i); } } template void xaxis::set_labels(const label_list& labels) { this->mutable_labels() = labels; populate_index(); } template inline auto xaxis::find_index(const key_type& key) const -> typename map_type::const_iterator { return m_index.find(key); } template template inline bool xaxis::merge_impl(const Args&... axes) { bool res = true; if(all_sorted(*this, axes...)) { res = merge_to(this->mutable_labels(), axes.labels()...); populate_index(); } else { m_is_sorted = false; if (m_index.empty()) { populate_index(); } res = merge_unsorted(false, axes.labels()...); } return res; } template template inline bool xaxis::merge_empty(const Arg1& a, const Args&... axes) { this->mutable_labels() = a.labels(); return merge_impl(axes...); } template inline bool xaxis::merge_empty() { return true; } template inline bool xaxis::init_is_sorted() const noexcept { return std::is_sorted(this->labels().begin(), this->labels().end()); } template template inline bool xaxis::all_sorted(const Arg& a, const Args&... axes) const noexcept { return a.is_sorted() && all_sorted(axes...); } template template inline bool xaxis::all_sorted(const Arg& a) const noexcept { return a.is_sorted(); } template template inline bool xaxis::merge_unsorted(bool broadcasting, const Arg& a, const Args&... axes_labels) { bool res = merge_unsorted(broadcasting, axes_labels...); auto& labels = this->mutable_labels(); auto output_iter = labels.rbegin(); auto output_end = labels.rend(); auto input_iter = a.rbegin(); auto input_end = a.rend(); while ((output_iter != output_end) && (input_iter != input_end) && (*output_iter == *input_iter)) { ++output_iter; ++input_iter; } if(input_iter == input_end) { if(output_iter != output_end) { res &= broadcasting; } } else if(output_iter == output_end) { std::copy(a.begin(), a.begin() + std::distance(input_iter, input_end), std::inserter(labels, labels.begin())); populate_index(); res &= broadcasting; } else { while(input_iter != input_end) { if(!contains(*input_iter)) { if(output_iter != labels.rbegin()) { labels.insert(labels.begin(), *input_iter); } else { labels.push_back(*input_iter); } } ++input_iter; } populate_index(); res = false; } return res; } template inline bool xaxis::merge_unsorted(bool /*broadcasting*/) { return true; } template template inline bool xaxis::intersect_unsorted(const Arg& al, const Args&... axes_labels) { bool res = intersect_unsorted(axes_labels...); auto& labels = this->mutable_labels(); auto iter = labels.begin(); auto iter_end = labels.end(); bool must_populate = false; while (iter != iter_end) { auto it = std::find(al.begin(), al.end(), *iter); if (it == al.end()) { iter = labels.erase(iter, iter + 1); iter_end = labels.end(); res = false; must_populate = true; } else { if (it - al.begin() != iter - labels.begin()) { res = false; } ++iter; } } if (must_populate) { populate_index(); } return res; } template inline bool xaxis::intersect_unsorted() { return true; } template inline bool merge_axes(xaxis& output, const Args&... axes) { return output.merge(axes...); } template inline bool intersect_axes(xaxis& output, const Args&... axes) { return output.intersect(axes...); } /********************************* * xaxis_iterator implementation * *********************************/ template inline xaxis_iterator::xaxis_iterator(const container_type* c, label_iterator it) : p_c(c), m_it(it) { } template inline auto xaxis_iterator::operator++() -> self_type& { ++m_it; return *this; } template inline auto xaxis_iterator::operator--() -> self_type& { --m_it; return *this; } template inline auto xaxis_iterator::operator+=(difference_type n) -> self_type& { m_it += n; return *this; } template inline auto xaxis_iterator::operator-=(difference_type n) -> self_type& { m_it -= n; return *this; } template inline auto xaxis_iterator::operator-(const self_type& rhs) const -> difference_type { return m_it - rhs.m_it; } template inline auto xaxis_iterator::operator*() const -> reference { return *(p_c->find_index(*m_it)); } template inline auto xaxis_iterator::operator->() const -> pointer { return &(*(p_c->find_index(*m_it))); } template inline bool xaxis_iterator::equal(const self_type& rhs) const noexcept { return m_it == rhs.m_it; } template inline bool xaxis_iterator::less_than(const self_type& rhs) const noexcept { return m_it < rhs.m_it; } template inline typename xaxis_iterator::difference_type operator-(const xaxis_iterator& lhs, const xaxis_iterator& rhs) { return lhs.operator-(rhs); } template inline bool operator==(const xaxis_iterator& lhs, const xaxis_iterator& rhs) noexcept { return lhs.equal(rhs); } template inline bool operator<(const xaxis_iterator& lhs, const xaxis_iterator& rhs) noexcept { return lhs.less_than(rhs); } /******************************** * axis builders implementation * ********************************/ /** * Returns an axis containing a range of integral labels. * @param start the first value of the range. * @param stop the end of the range. The range doe snot contain * this value. * @param step Spacing between values. Default step is \c 1. * @tparam T the integral type used for positions. Default value * @tparam L the type of the labels. */ template inline xaxis axis(L start, L stop, L step) noexcept { auto range = xt::arange(start, stop, step); return xaxis(range.begin(), range.end()); } /** * Builds an returns an axis from the specified list of labels. * @param init the list of labels. * @tparam T the integral type used for positions. Default value * is \c std::size_t. * @tparam L the type of the labels. */ template inline xaxis axis(std::initializer_list init) noexcept { return xaxis(init); } template inline xaxis axis(std::initializer_list init) noexcept { return xaxis(init.begin(), init.end()); } } #endif ================================================ FILE: include/xframe/xaxis_base.hpp ================================================ /*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * 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 XFRAME_XAXIS_BASE_HPP #define XFRAME_XAXIS_BASE_HPP #include #include #include namespace xf { template struct xaxis_inner_types; /************** * xaxis_base * **************/ /** * @class xaxis_base * @brief Base class for axes. * * The xaxis_base class defines the common interface for axes, which define the * mapping of labels to positions in a given dimension. The axis_base class * embeds the list of labels only, the mapping is hold by the inheriting classes. * * @tparam D The derived type, i.e. the inheriting class for which xaxis_base * provides the interface. */ template class xaxis_base { public: using derived_type = D; using inner_types = xaxis_inner_types; using key_type = typename inner_types::key_type; using mapped_type = typename inner_types::mapped_type; using label_list = std::vector; using size_type = typename label_list::size_type; using difference_type = typename label_list::difference_type; using iterator = typename inner_types::iterator; using const_iterator = iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = reverse_iterator; static_assert(std::is_integral::value, "mapped_type T must be an integral type"); derived_type& derived_cast() & noexcept; const derived_type& derived_cast() const & noexcept; derived_type derived_cast() && noexcept; const label_list& labels() const noexcept; key_type label(size_type i) const; bool empty() const noexcept; size_type size() const noexcept; const_iterator begin() const noexcept; const_iterator end() const 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; protected: xaxis_base(); xaxis_base(const label_list& labels); xaxis_base(label_list&& labels); xaxis_base(std::initializer_list init); template xaxis_base(InputIt first, InputIt last); ~xaxis_base() = default; xaxis_base(const xaxis_base&) = default; xaxis_base& operator=(const xaxis_base&) = default; xaxis_base(xaxis_base&&) = default; xaxis_base& operator=(xaxis_base&&) = default; label_list& mutable_labels() noexcept; template label_list filter_labels(const F& f) const noexcept; template label_list filter_labels(const F& f, size_type size) const noexcept; label_list m_labels; }; template bool operator==(const xaxis_base& lhs, const xaxis_base& rhs) noexcept; template bool operator!=(const xaxis_base& lhs, const xaxis_base& rhs) noexcept; template OS& operator<<(OS& out, const xaxis_base& axis); /************************ * is_axis metafunction * ************************/ template struct is_axis : std::is_base_of, T> { }; /***************************** * xaxis_base implementation * *****************************/ template inline xaxis_base::xaxis_base() : m_labels() { } template inline xaxis_base::xaxis_base(const label_list& labels) : m_labels(labels) { } template inline xaxis_base::xaxis_base(label_list&& labels) : m_labels(std::move(labels)) { } template inline xaxis_base::xaxis_base(std::initializer_list init) : m_labels(init) { } template template inline xaxis_base::xaxis_base(InputIt first, InputIt last) : m_labels(first, last) { } /** * @name Downcast */ //@{ /** * Casts the object to its inheriting type (i.e. D); this method * is called when the object is an lvalue. */ template inline auto xaxis_base::derived_cast() & noexcept -> derived_type& { return *static_cast(this); } /** * Casts the object to its inheriting type (i.e. D); this method * is called when the object is a constant lvalue. */ template inline auto xaxis_base::derived_cast() const & noexcept -> const derived_type& { return *static_cast(this); } /** * Casts the object to its inheriting type (i.e. D); this method * is called when the object is an rvalue. */ template inline auto xaxis_base::derived_cast() && noexcept -> derived_type { return *static_cast(this); } //@} /** * @name Labels */ //@{ /** * Returns the list of labels contained in the axis. */ template inline auto xaxis_base::labels() const noexcept -> const label_list& { return m_labels; } /** * Return the i-th label of the axis. * @param i the position of the label. */ template inline auto xaxis_base::label(size_type i) const -> key_type { return m_labels[i]; } /** * Checks if the axis has no labels. */ template inline bool xaxis_base::empty() const noexcept { return m_labels.empty(); } /** * Returns the number of labels in the axis. */ template inline auto xaxis_base::size() const noexcept -> size_type { return m_labels.size(); } //@} /** * @name Iterators */ //@{ /** * Returns a constant iterator to the first element of the axis. * This element is a pair label - position. */ template inline auto xaxis_base::begin() const noexcept -> const_iterator { return derived_cast().cbegin(); } /** * Returns a constant iterator to the element following the last element * of the axis. */ template inline auto xaxis_base::end() const noexcept -> const_iterator { return derived_cast().cend(); } /** * Returns a constant iterator to the first element of the reverse axis. * This element is a pair labal - position. */ template inline auto xaxis_base::rbegin() const noexcept -> const_reverse_iterator { return crbegin(); } /** * Returns a constant iterator to the element following the last element * of the reversed axis. */ template inline auto xaxis_base::rend() const noexcept -> const_reverse_iterator { return crend(); } /** * Returns a constant iterator to the first element of the reverse axis. * This element is a pair labal - position. */ template inline auto xaxis_base::crbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(derived_cast().cend()); } /** * Returns a constant iterator to the element following the last element * of the reversed axis. */ template inline auto xaxis_base::crend() const noexcept -> const_reverse_iterator { return const_reverse_iterator(derived_cast().cbegin()); } //@} template inline auto xaxis_base::mutable_labels() noexcept -> label_list& { return m_labels; } template template inline auto xaxis_base::filter_labels(const F& f) const noexcept -> label_list { label_list l; std::copy_if(m_labels.cbegin(), m_labels.cend(), std::back_inserter(l), f); return l; } template template inline auto xaxis_base::filter_labels(const F& f, size_type size) const noexcept -> label_list { label_list l(size); std::copy_if(m_labels.cbegin(), m_labels.cend(), l.begin(), f); return l; } /** * Returns true is \c lhs and \c rhs are equivalent axes, i.e. they contain the same * label - position pairs. * @param lhs an axis. * @param rhs an axis. */ template inline bool operator==(const xaxis_base& lhs, const xaxis_base& rhs) noexcept { return lhs.labels() == rhs.labels(); } /** * Returns true is \c lhs and \c rhs are not equivalent axes, i.e. they contain different * label - position pairs. * @param lhs an axis. * @param rhs an axis. */ template inline bool operator!=(const xaxis_base& lhs, const xaxis_base& rhs) noexcept { return !(lhs == rhs); } template inline OS& operator<<(OS& out, const xaxis_base& axis) { using iterator = std::ostream_iterator::key_type, typename OS::char_type, typename OS::traits_type>; out << '('; std::copy(axis.labels().begin(), axis.labels().end(), iterator(out, ", ")); out << ')'; return out; } } #endif ================================================ FILE: include/xframe/xaxis_default.hpp ================================================ /*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * 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 XFRAME_XAXIS_DEFAULT_HPP #define XFRAME_XAXIS_DEFAULT_HPP #include #include #include #include #include "xtl/xiterator_base.hpp" #include "xaxis_base.hpp" #include "xaxis.hpp" namespace xf { template class xaxis_default_iterator; template class xaxis_variant; /***************** * xaxis_default * *****************/ /** * @class xaxis_default * @brief Default axis with integral labels. * * The xaxis_default class is used for modeling a default axis * that holds a contiguous sequence of integral labels starting at 0. * * @tparam L the type of labels. This must be an integral type. * @tparam T the integer type used to represent positions. Default value is * \c std::size_t. */ template class xaxis_default : public xaxis_base> { public: using base_type = xaxis_base; using self_type = xaxis_default; using axis_type = xaxis; using key_type = typename base_type::key_type; using label_list = typename base_type::label_list; using mapped_type = typename base_type::mapped_type; using value_type = std::pair; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; using const_pointer = const value_type*; using size_type = typename base_type::size_type; using difference_type = typename base_type::difference_type; using iterator = typename base_type::iterator; using const_iterator = typename base_type::const_iterator; using reverse_iterator = typename base_type::reverse_iterator; using const_reverse_iterator = typename base_type::const_reverse_iterator; static_assert(std::is_integral::value, "key_type L must be an integral type"); explicit xaxis_default(size_type size = 0); bool is_sorted() const noexcept; bool contains(const key_type& key) const; mapped_type operator[](const key_type& key) const; template axis_type filter(const F& f) const noexcept; template axis_type filter(const F& f, size_type size) const noexcept; const_iterator find(const key_type& key) const; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; protected: void populate_labels(const size_type& size = 0); private: template bool merge(const Args&... /*axes*/); template bool intersect(const Args&... /*axes*/); template friend class xaxis_variant; }; /************************* * xaxis_default builder * *************************/ template xaxis_default axis(L size) noexcept; /******************** * xaxis_inner_types * *********************/ template struct xaxis_inner_types> { using key_type = L; using mapped_type = T; using iterator = xaxis_default_iterator; }; /************************** * xaxis_default_iterator * **************************/ template class xaxis_default_iterator : public xtl::xrandom_access_iterator_base, typename xaxis_default::value_type, typename xaxis_default::difference_type, typename xaxis_default::const_pointer, typename xaxis_default::const_reference> { public: using self_type = xaxis_default_iterator; using container_type = xaxis_default; using label_list = typename container_type::label_list; using key_type = typename container_type::key_type; using mapped_type = typename container_type::mapped_type; using value_type = typename container_type::value_type; using reference = typename container_type::const_reference; using pointer = typename container_type::const_pointer; using difference_type = typename label_list::difference_type; using iterator_category = std::random_access_iterator_tag; xaxis_default_iterator() = default; xaxis_default_iterator(mapped_type value); self_type& operator++(); self_type& operator--(); self_type& operator+=(difference_type n); self_type& operator-=(difference_type n); difference_type operator-(const self_type& rhs) const; reference operator*() const; pointer operator->() const; bool equal(const self_type& rhs) const noexcept; bool less_than(const self_type& rhs) const noexcept; private: value_type m_value; }; template typename xaxis_default_iterator::difference_type operator-(const xaxis_default_iterator& lhs, const xaxis_default_iterator& rhs); template bool operator==(const xaxis_default_iterator& lhs, const xaxis_default_iterator& rhs) noexcept; template bool operator<(const xaxis_default_iterator& lhs, const xaxis_default_iterator& rhs) noexcept; /******************************** * xaxis_default implementation * ********************************/ /** * Constructs a default axis holding \c size integral elements. * The labels sequence is [0, 1, ..... size - 1) */ template inline xaxis_default::xaxis_default(size_type size) : base_type() { populate_labels(size); } /** * Returns true if the labels list is sorted. */ template inline bool xaxis_default::is_sorted() const noexcept { return true; } /** * Returns true if the axis contains the speficied label. * @param key the label to search for. */ template inline bool xaxis_default::contains(const key_type& key) const { return key_type(0) <= key && key < key_type(this->size()); } /** * Returns the position of the specified label. If this last one is * not found, an exception is thrown. * @param key the label to search for. */ template inline auto xaxis_default::operator[](const key_type& key) const -> mapped_type { return mapped_type(this->labels().at(key)); } /** * Builds an return a new axis by applying the given filter to the axis. * @param f the filter used to select the labels to keep in the new axis. */ template template inline auto xaxis_default::filter(const F& f) const noexcept -> axis_type { return axis_type(base_type::filter_labels(f), true); } /** * Builds an return a new axis by applying the given filter to the axis. When * the size of the new list of labels is known, this method allows some * optimizations compared to the previous one. * @param f the filter used to select the labels to keep in the new axis. * @param size the size of the new label list. */ template template inline auto xaxis_default::filter(const F& f, size_type size) const noexcept -> axis_type { return axis_type(base_type::filter_labels(f, size), true); } /** * Returns a constant iterator to the element with label equivalent to \c key. If * no such element is found, past-the-end iterator is returned. * @param key the label to search for. */ template inline auto xaxis_default::find(const key_type& key) const -> const_iterator { return contains(key) ? const_iterator(mapped_type(key)) : cend(); } /** * Returns a constant iterator to the first element of the axis. * This element is a pair label - position. */ template inline auto xaxis_default::cbegin() const noexcept -> const_iterator { return const_iterator(mapped_type(0)); } /** * Returns a constant iterator to the element following the last element * of the axis. */ template inline auto xaxis_default::cend() const noexcept -> const_iterator { return const_iterator(mapped_type(this->size())); } template inline void xaxis_default::populate_labels(const size_type& size) { auto& labels = this->mutable_labels(); for(size_type i = 0; i < size; ++i) { labels.push_back(key_type(i)); } } template template inline bool xaxis_default::merge(const Args&... /*axes*/) { throw std::runtime_error("merge forbidden for xaxis_default"); } template template inline bool xaxis_default::intersect(const Args&... /*axes*/) { throw std::runtime_error("intersect forbidden for xaxis_default"); } /**************************************** * xaxis_default builder implementation * ****************************************/ /** * Returns a default axis that holds \c size integral * labels. * @param size the number of labels. * @tparam T the integral type used for positions. Default value * is \c std::size_t. * @tparam L the type of the labels. This must be an integral type. */ template inline xaxis_default axis(L size) noexcept { return xaxis_default(size); } /***************************************** * xaxis_default_iterator implementation * *****************************************/ template inline xaxis_default_iterator::xaxis_default_iterator(mapped_type value) : m_value(std::make_pair(static_cast(value), value)) { } template inline auto xaxis_default_iterator::operator++() -> self_type& { ++m_value.first; ++m_value.second; return *this; } template inline auto xaxis_default_iterator::operator--() -> self_type& { --m_value.first; --m_value.second; return *this; } template inline auto xaxis_default_iterator::operator+=(difference_type n) -> self_type& { m_value.first = static_cast(m_value.first + n); m_value.second += static_cast(n); return *this; } template inline auto xaxis_default_iterator::operator-=(difference_type n) -> self_type& { m_value.first = static_cast(m_value.first - n); m_value.second -= static_cast(n); return *this; } template inline auto xaxis_default_iterator::operator-(const self_type& rhs) const -> difference_type { return m_value.first - rhs.m_value.first; return m_value.second - rhs.m_value.second; } template inline auto xaxis_default_iterator::operator*() const -> reference { return m_value; } template inline auto xaxis_default_iterator::operator->() const -> pointer { return &m_value; } template inline bool xaxis_default_iterator::equal(const self_type& rhs) const noexcept { return m_value.first == rhs.m_value.first; } template inline bool xaxis_default_iterator::less_than(const self_type& rhs) const noexcept { return m_value.first < rhs.m_value.first; } template inline typename xaxis_default_iterator::difference_type operator-(const xaxis_default_iterator& lhs, const xaxis_default_iterator& rhs) { return lhs.operator-(rhs); } template inline bool operator==(const xaxis_default_iterator& lhs, const xaxis_default_iterator& rhs) noexcept { return lhs.equal(rhs); } template inline bool operator<(const xaxis_default_iterator& lhs, const xaxis_default_iterator& rhs) noexcept { return lhs.less_than(rhs); } } #endif ================================================ FILE: include/xframe/xaxis_expression_leaf.hpp ================================================ /*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * 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 XFRAME_XAXIS_EXPRESSION_LEAF_HPP #define XFRAME_XAXIS_EXPRESSION_LEAF_HPP #include "xtl/xvariant.hpp" #include "xtl/xmeta_utils.hpp" #include "xtensor/xoptional.hpp" #include "xframe_config.hpp" #include "xframe_utils.hpp" #include "xframe_expression.hpp" namespace xf { /************************* * xaxis_expression_leaf * *************************/ /** * @class xaxis_expression_leaf * @brief An subset of an expression on axis * * The xaxis_expression_leaf class is used with xaxis_function for creating * an expression on xnamed_axis, e.g. `auto expr = not_equal(axis1, 2) && axis2 < 3`. * In the example above, `axis1`, `axis2` are xnamed_axis which will be converted to * xaxis expression leaves before stored in the xaxis_function object. * * @tparam CTA the named axis type. * @sa xaxis_function */ template class xaxis_expression_leaf : public xt::xexpression> { public: using named_axis_type = std::decay_t; using name_type = typename named_axis_type::name_type; using size_type = typename named_axis_type::size_type; using value_type = typename named_axis_type::value_type; using reference = typename named_axis_type::reference; using const_reference = typename named_axis_type::const_reference; using pointer = typename named_axis_type::pointer; using const_pointer = typename named_axis_type::const_pointer; template using selector_sequence_type = detail::xselector_sequence_t, N>; using expression_tag = xaxis_expression_tag; template xaxis_expression_leaf(AX&& n_axis) noexcept; template ::max()> const_reference operator()(const selector_sequence_type& selector) const; private: xaxis_closure_t m_named_axis; }; /**************************************** * xaxis_expression_leaf implementation * ****************************************/ /** * Builds an xaxis_expression_leaf. * @param n_axis the xnamed_axis. */ template template inline xaxis_expression_leaf::xaxis_expression_leaf(AX&& n_axis) noexcept : m_named_axis(std::forward(n_axis)) { } /** * Returns the label from the xnamed_axis, given a selector. * @param selector a selector_sequence_type. */ template template auto xaxis_expression_leaf::operator()(const selector_sequence_type& selector) const -> const_reference { for (const auto& sel: selector) { if (m_named_axis.name() == sel.first) { return m_named_axis.label(sel.second); } } throw std::runtime_error(std::string("Missing label for axis ") + std::string(m_named_axis.name())); } } #endif ================================================ FILE: include/xframe/xaxis_function.hpp ================================================ /*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * 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 XFRAME_XAXIS_FUNCTION_HPP #define XFRAME_XAXIS_FUNCTION_HPP #include "xtensor/xoptional.hpp" #include "xtensor/xgenerator.hpp" #include "xframe_expression.hpp" #include "xframe_utils.hpp" #include "xaxis_meta.hpp" #include "xaxis_expression_leaf.hpp" namespace xf { /****************** * xaxis_function * ******************/ /** * @class xaxis_function * @brief An expression of xaxis * * The xaxis_function class is used for creating an expression on named axis, e.g. * `auto expr = not_equal(axis1, 2) && axis2 < 2`. * * @tparam F the function type. * @tparam R the result type. * @tparam CT the function argument types. * @sa xaxis_expression_leaf * @sa xnamed_axis */ template class xaxis_function : public xt::xexpression> { public: using self_type = xaxis_function; using functor_type = std::remove_reference_t; using value_type = R; using reference = value_type; using const_reference = value_type; using pointer = value_type*; using const_pointer = const value_type*; using name_type = detail::common_name_type_t>...>; using size_type = xt::common_size_type_t>...>; template using selector_sequence_type = detail::xselector_sequence_t, N>; using expression_tag = xaxis_expression_tag; template ::value>> xaxis_function(Func&& f, CT... e) noexcept; template const_reference operator()(const selector_sequence_type& selector) const; private: template const_reference evaluate(std::index_sequence, const selector_sequence_type& selector) const; std::tuple...> m_e; functor_type m_f; }; /********************************* * xaxis_function implementation * *********************************/ /** * Builds an axis function. * @param f the function to apply. * @param e the function arguments. */ template template inline xaxis_function::xaxis_function(Func&& f, CT... e) noexcept : m_e(detail::get_axis_closure(std::forward(e))...), m_f(std::forward(f)) { } /** * Returns an evaluation of the xaxis_function. * Example: * \code{.cpp} * auto axis1 = named_axis("abs", axis(16)); * auto axis2 = named_axis("ord", axis({'a', 'c', 'i'})); * * auto func1 = axis1 < 5 && not_equal(axis2, 'i'); * * // This will evaluate the xaxis_function for `axis1.label(10) == 9` and `axis2.label(1) == 'c'`` * func1({{"abs", 10}, {"ord", 1}}); * \endcode * * @param selector a selector_sequence_type for selecting the position * where you want to evaluate the function. * @return the evaluation of the xaxis_function */ template template inline auto xaxis_function::operator()(const selector_sequence_type& selector) const -> const_reference { return evaluate(std::make_index_sequence(), selector); } template template inline auto xaxis_function::evaluate(std::index_sequence, const selector_sequence_type& selector) const -> const_reference { #ifdef _MSC_VER return m_f(std::get(m_e).operator()(selector)...); #else return m_f(std::get(m_e).template operator()(selector)...); #endif } /********************** * axis_function_mask * **********************/ namespace detail { template class axis_function_mask_impl { public: using axis_function_type = std::remove_reference_t; using value_type = typename axis_function_type::value_type; using name_type = typename axis_function_type::name_type; using size_type = typename axis_function_type::size_type; template using selector_sequence_type = detail::xselector_sequence_t, N>; axis_function_mask_impl(AF&& axis_function, DM&& dim_mapping) : m_axis_function(std::forward(axis_function)), m_dimension_mapping(std::forward(dim_mapping)) { } template inline value_type operator()(Args... args) const { auto selector = make_selector(std::make_index_sequence(), args...); #ifdef _MSC_VER return m_axis_function.operator()(selector); #else return m_axis_function.template operator()(selector); #endif } template inline value_type element(It first, It last) const { // TODO avoid dynamic allocation auto selector = selector_sequence_type(); std::size_t i = 0; for (It it = first; it != last; ++it) { selector.push_back(std::make_pair(m_dimension_mapping.label(i++), static_cast(*it))); } #ifdef _MSC_VER return m_axis_function.operator()(selector); #else return m_axis_function.template operator()(selector); #endif } private: AF m_axis_function; DM m_dimension_mapping; template inline selector_sequence_type make_selector(std::index_sequence, Args&&... args) const { return {std::make_pair(m_dimension_mapping.label(I), static_cast(args))...}; } }; } template inline auto axis_function_mask(AF&& axis_function, DM&& dim_mapping, const S& shape) noexcept { return xt::detail::make_xgenerator( detail::axis_function_mask_impl(std::forward(axis_function), std::forward(dim_mapping)), shape ); } } #endif ================================================ FILE: include/xframe/xaxis_index_slice.hpp ================================================ /*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * 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 XFRAME_XAXIS_INDEX_SLICE_HPP #define XFRAME_XAXIS_INDEX_SLICE_HPP #include #include #include "xtl/xvariant.hpp" #include "xtensor/xstorage.hpp" #include "xtensor/xslice.hpp" namespace xf { /********************* * xaxis_index_slice * *********************/ template class xaxis_index_slice; namespace detail { template struct is_xaxis_index_slice : std::false_type { }; template struct is_xaxis_index_slice> : std::true_type { }; template using disable_xaxis_index_slice_t = std::enable_if_t>::value, void>; } template class xaxis_index_slice { public: using self_type = xaxis_index_slice; using size_type = T; using storage_type = xtl::variant, xt::xstepped_range, xt::xkeep_slice, xt::xdrop_slice, xt::xall>; xaxis_index_slice() = default; template > xaxis_index_slice(S&& slice) noexcept; size_type size() const noexcept; bool contains(size_type i) const noexcept; size_type operator()(size_type i) const noexcept; size_type step_size(size_type i, size_type n = 1) const noexcept; size_type revert_index(size_type i) const noexcept; template V convert_storage() const; bool operator==(const self_type& rhs) const noexcept; bool operator!=(const self_type& rhs) const noexcept; private: storage_type m_slice; }; /********************* * Builder functions * *********************/ template auto irange(A start_val); template auto irange(A start_val, B stop_val); template auto irange(A start_val, B stop_val, C step); template auto ikeep(T&&... t); template auto idrop(T&&... t); auto iall() noexcept; /************************************ * xaxis_index_slice implementation * ************************************/ template template inline xaxis_index_slice::xaxis_index_slice(S&& slice) noexcept : m_slice(std::forward(slice)) { } template inline auto xaxis_index_slice::size() const noexcept -> size_type { return xtl::visit([](auto&& arg) { return arg.size(); }, m_slice); } template inline bool xaxis_index_slice::contains(size_type i) const noexcept { return xtl::visit([i](auto&& arg) { return arg.contains(i); }, m_slice); } template inline auto xaxis_index_slice::operator()(size_type i) const noexcept -> size_type { return xtl::visit([i](auto&& arg) { return arg(i); }, m_slice); } template inline auto xaxis_index_slice::step_size(size_type i, size_type n) const noexcept -> size_type { return xtl::visit([i, n](auto&& arg) { return arg.step_size(i, n); }, m_slice); } template inline auto xaxis_index_slice::revert_index(size_type i) const noexcept -> size_type { return xtl::visit([i](auto&& arg) { return arg.revert_index(i); }, m_slice); } // TODO: remove this when xrange and xstepped_range has been added // to xdynamic_slice in xtensor namespace detail { template inline xt::xrange_adaptor convert_range(const xt::xrange& r) { T start = r(T(0)); T stop = start + r.size(); return xt::xrange_adaptor(start, stop, T(1)); } template inline xt::xrange_adaptor convert_range(const xt::xstepped_range& r) { T start = r(T(0)); T stop = start + r.size(); T step = r.step_size(T(0)); return xt::xrange_adaptor(start, stop, step); } } template template inline V xaxis_index_slice::convert_storage() const { return xtl::visit( xtl::make_overload( /*[](const xt::xrange& s) -> V { return detail::convert_range(s); }, [](const xt::xstepped_range& s) -> V { return detail::convert_range(s); },*/ [](const xt::xrange& s) -> V { return xt::xrange(s); }, [](const xt::xstepped_range& s) -> V { return xt::xstepped_range(s); }, [](const xt::xkeep_slice& s) -> V { return xt::xkeep_slice(s); }, [](const xt::xdrop_slice& s) -> V { return xt::xdrop_slice(s); }, [](const xt::xall&) -> V { return xt::xall_tag(); }), m_slice); } template inline bool xaxis_index_slice::operator==(const self_type& rhs) const noexcept { return m_slice == rhs.m_slice; } template inline bool xaxis_index_slice::operator!=(const self_type& rhs) const noexcept { return !(*this == rhs); } /************************************ * Builder functions implementation * ************************************/ template inline auto irange(A start_val) { return xt::range(start_val); } template inline auto irange(A start_val, B stop_val) { return xt::range(start_val, stop_val); } template inline auto irange(A start_val, B stop_val, C step) { return xt::range(start_val, stop_val, step); } template inline auto ikeep(T&&... t) { return xt::keep(std::forward(t)...); } template inline auto idrop(T&&... t) { return xt::drop(std::forward(t)...); } inline auto iall() noexcept { return xt::all(); } } #endif ================================================ FILE: include/xframe/xaxis_label_slice.hpp ================================================ /*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * 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 XFRAME_XAXIS_LABEL_SLICE_HPP #define XFRAME_XAXIS_LABEL_SLICE_HPP #include #include #include "xaxis_index_slice.hpp" #include "xframe_config.hpp" namespace xf { /************************** * xlabel_slice_variant_t * **************************/ template using xlabel_variant_t = xtl::mpl::cast_t; /*************** * xaxis_range * ***************/ template class xaxis_range { public: using value_type = xlabel_variant_t; xaxis_range(const value_type& first, const value_type& last) noexcept; xaxis_range(value_type&& first, value_type&& last) noexcept; template using index_slice_type = xt::xrange; template index_slice_type build_index_slice(const A& axis) const; private: value_type m_first; value_type m_last; }; /*********************** * xaxis_stepped_range * ***********************/ template class xaxis_stepped_range { public: using value_type = xlabel_variant_t; using size_type = std::size_t; xaxis_stepped_range(const value_type& first, const value_type& last, size_type step) noexcept; xaxis_stepped_range(value_type&& first, value_type&& last, size_type step) noexcept; template using index_slice_type = xt::xstepped_range; template index_slice_type build_index_slice(const A& axis) const; private: value_type m_first; value_type m_last; size_type m_step; }; /************* * xaxis_all * *************/ class xaxis_all { public: template using index_slice_type = xt::xall; template index_slice_type build_index_slice(const A& axis) const; }; /******************** * xaxis_keep_slice * *******************/ template class xaxis_keep_slice; namespace detail { template struct is_xaxis_keep_slice : std::false_type { }; template struct is_xaxis_keep_slice> : std::true_type { }; template using disable_xaxis_keep_slice_t = std::enable_if_t>::value, void>; template using enable_xaxis_keep_slice_t = std::enable_if_t>::value, void>; } template class xaxis_keep_slice { public: using value_type = xlabel_variant_t; using container_type = xt::svector; template > explicit xaxis_keep_slice(C& cont); explicit xaxis_keep_slice(container_type&& cont); template using index_slice_type = xt::xkeep_slice; template index_slice_type build_index_slice(const A& axis) const; private: container_type m_labels; }; /******************** * xaxis_drop_slice * ********************/ template class xaxis_drop_slice; namespace detail { template struct is_axis_drop_slice : std::false_type { }; template struct is_axis_drop_slice> : std::true_type { }; template using disable_xaxis_drop_slice_t = std::enable_if_t>::value, void>; template using enable_xaxis_drop_slice_t = std::enable_if_t>::value, void>; } template class xaxis_drop_slice { public: using value_type = xlabel_variant_t; using container_type = xt::svector; template > explicit xaxis_drop_slice(C& cont); explicit xaxis_drop_slice(container_type&& cont); template using index_slice_type = xt::xdrop_slice; template index_slice_type build_index_slice(const A& axis) const; private: container_type m_labels; }; /*************** * xaxis_slice * ***************/ template class xaxis_slice { public: using squeeze_type = xlabel_variant_t; using storage_type = xtl::variant, xaxis_stepped_range, xaxis_keep_slice, xaxis_drop_slice, xaxis_all, squeeze_type>; xaxis_slice() = default; template xaxis_slice(const V& slice); template xaxis_slice(V&& slice); template using index_slice_type = xaxis_index_slice; template index_slice_type build_index_slice(const A& axis) const; const squeeze_type* get_squeeze() const noexcept; private: storage_type m_data; }; template xaxis_slice range(const xlabel_variant_t& first, const xlabel_variant_t& last); template xaxis_slice range(xlabel_variant_t&& first, xlabel_variant_t&& last); template xaxis_slice range(const xlabel_variant_t& first, const xlabel_variant_t& last, S step); template xaxis_slice range(xlabel_variant_t&& first, xlabel_variant_t&& last, S step); xaxis_all all() noexcept; namespace detail { template > struct has_size : std::false_type { }; template struct has_size().size())>> : std::true_type { }; template using enable_container_t = std::enable_if_t::value, R>; template using disable_container_t = std::enable_if_t::value, R>; } template detail::enable_container_t> keep(T&& indices); template detail::disable_container_t> keep(T index); template xaxis_slice keep(T0 t0, T1 t1, Args... args); template detail::enable_container_t> drop(T&& indices); template detail::disable_container_t> drop(T index); template xaxis_slice drop(T0 t0, T1 t1, Args... args); /****************************** * xaxis_range implementation * ******************************/ template inline xaxis_range::xaxis_range(const value_type& first, const value_type& last) noexcept : m_first(first), m_last(last) { } template inline xaxis_range::xaxis_range(value_type&& first, value_type&& last) noexcept : m_first(std::move(first)), m_last(std::move(last)) { } template template inline auto xaxis_range::build_index_slice(const A& axis) const -> index_slice_type { return index_slice_type(axis[m_first], axis[m_last] + 1); } /************************************** * xaxis_stepped_range implementation * **************************************/ template inline xaxis_stepped_range::xaxis_stepped_range(const value_type& first, const value_type& last, size_type step) noexcept : m_first(first), m_last(last), m_step(step) { } template inline xaxis_stepped_range::xaxis_stepped_range(value_type&& first, value_type&& last, size_type step) noexcept : m_first(std::move(first)), m_last(std::move(last)), m_step(step) { } template template inline auto xaxis_stepped_range::build_index_slice(const A& axis) const -> index_slice_type { return index_slice_type(axis[m_first], axis[m_last] + 1, m_step); } /**************************** * xaxis_all implementation * ****************************/ template inline auto xaxis_all::build_index_slice(const A& axis) const -> index_slice_type { return index_slice_type(axis.size()); } /***************************** * xaxis_keep_implementation * *****************************/ template template inline xaxis_keep_slice::xaxis_keep_slice(C& cont) : m_labels(cont.begin(), cont.end()) { } template inline xaxis_keep_slice::xaxis_keep_slice(container_type&& cont) : m_labels(std::move(cont)) { } template template inline auto xaxis_keep_slice::build_index_slice(const A& axis) const -> index_slice_type { using index_container_type = typename index_slice_type::container_type; index_container_type c(m_labels.size()); std::transform(m_labels.cbegin(), m_labels.cend(), c.begin(), [&axis](const auto& arg) { return axis[arg]; }); index_slice_type res(std::move(c)); res.normalize(axis.size()); return res; } /**************************** * xaxis_drop_implemenation * ****************************/ template template inline xaxis_drop_slice::xaxis_drop_slice(C& cont) : m_labels(cont.begin(), cont.end()) { } template inline xaxis_drop_slice::xaxis_drop_slice(container_type&& cont) : m_labels(std::move(cont)) { } template template inline auto xaxis_drop_slice::build_index_slice(const A& axis) const -> index_slice_type { using index_container_type = typename index_slice_type::container_type; index_container_type c(m_labels.size()); std::transform(m_labels.cbegin(), m_labels.cend(), c.begin(), [&axis](const auto& arg) { return axis[arg]; }); index_slice_type res(std::move(c)); res.normalize(axis.size()); return res; } /****************************** * xaxis_slice implementation * ******************************/ template template inline xaxis_slice::xaxis_slice(const V& slice) : m_data(slice) { } template template inline xaxis_slice::xaxis_slice(V&& slice) : m_data(std::move(slice)) { } template template inline auto xaxis_slice::build_index_slice(const A& axis) const -> index_slice_type { return xtl::visit( xtl::make_overload( [&axis](const auto& arg) { return index_slice_type(arg.build_index_slice(axis)); }, [&axis](const squeeze_type&) -> index_slice_type { throw std::runtime_error("build_islice forbidden for squeeze"); } ), m_data); } template inline auto xaxis_slice::get_squeeze() const noexcept -> const squeeze_type* { return xtl::get_if(&m_data); } /*********************************** * helper functions implementation * ***********************************/ template inline xaxis_slice range(const xlabel_variant_t& first, const xlabel_variant_t& last) { return xaxis_slice(xaxis_range(first, last)); } template inline xaxis_slice range(xlabel_variant_t&& first, xlabel_variant_t&& last) { return xaxis_slice(xaxis_range(std::move(first), std::move(last))); } template inline xaxis_slice range(const xlabel_variant_t& first, const xlabel_variant_t& last, S step) { return xaxis_slice(xaxis_stepped_range(first, last, step)); } template inline xaxis_slice range(xlabel_variant_t&& first, xlabel_variant_t&& last, S step) { return xaxis_slice(xaxis_stepped_range(std::move(first), std::move(last), step)); } namespace detail { template