From 2272ba9e81833fc7eaee37aa8a9ad8080d7156f0 Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Fri, 14 Jul 2023 17:09:34 +0100 Subject: [PATCH 01/37] bump lal --- external/libalgebra_lite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/libalgebra_lite b/external/libalgebra_lite index fd066abb..e28335aa 160000 --- a/external/libalgebra_lite +++ b/external/libalgebra_lite @@ -1 +1 @@ -Subproject commit fd066abb6b806df718f85af2376bf4d0c0f315b8 +Subproject commit e28335aa91a49563240e44dd9f013c9c2f6b4c08 From 3820df2d0f131e90263c337c4b465f23431fcca2 Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Fri, 14 Jul 2023 21:43:56 +0100 Subject: [PATCH 02/37] Clean up CMakeLists.txt --- CMakeLists.txt | 220 ++++++++++++++++++++++--------------------------- 1 file changed, 98 insertions(+), 122 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dc49533..70f0f5fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.21) +cmake_minimum_required(VERSION 3.22) message(STATUS "Toolchain file: ${CMAKE_TOOLCHAIN_FILE}") list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/Modules) @@ -16,42 +16,19 @@ endif () project(RoughPy VERSION ${_rpy_version}) -set(CMAKE_INSTALL_LIBDIR "roughpy" CACHE STRING "install library dir") -set(CMAKE_INSTALL_BINDIR "roughpy" CACHE STRING "install binary dir") - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -if (LINUX) - set(CMAKE_INSTALL_RPATH "$ORIGIN") -elseif (APPLE) - execute_process(COMMAND "brew" "--prefix" - RESULT_VARIABLE _brew_prefix_found - OUTPUT_VARIABLE _brew_prefix - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - message(STATUS "Adding brew prefix: ${_brew_prefix}") - if (_brew_prefix_found) - list(APPEND CMAKE_PREFIX_PATH "${_brew_prefix}") - endif () - - - # set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) - set(CMAKE_MACOSX_RPATH ON) - # set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON) - # set(CMAKE_INSTALL_RPATH @loader_path) - # set(CMAKE_INSTALL_NAME_DIR @rpath) -endif () +include(CMakeDependentOption) option(ROUGHPY_BUILD_LA_CONTEXTS "Build the collection of libalgebra contexts" OFF) option(ROUGHPY_BUILD_TESTS "Build C++ tests for RoughPy" ON) option(ROUGHPY_BUILD_PYMODULE_INPLACE "Buildg the pymodule in the project roughpy directory" OFF) +option(ROUGHPY_LINK_NUMPY "Link with Numpy library for array handling" ON) +option(ROUGHPY_GENERATE_DEVICE_CODE "Generate code for objects on devices" OFF) +cmake_dependent_option(ROUGHPY_PREFER_ACCELERATE + "Prefer Accelerate framework on MacOS always" OFF APPLE OFF) -if (MSVC) - # add_compile_options(/permissive-) -endif () - -find_package(GTest CONFIG QUIET) -if (ROUGHPY_BUILD_TESTS AND GTest_FOUND) +# If testing is enabled, find GTest to make sure the tests can be +# successfully built. +if (ROUGHPY_BUILD_TESTS) find_package(GTest CONFIG REQUIRED) if (NOT TARGET GTest::gtest) @@ -59,17 +36,33 @@ if (ROUGHPY_BUILD_TESTS AND GTest_FOUND) endif () enable_testing() -else () - set(ROUGHPY_BUILD_TESTS OFF CACHE INTERNAL "") + + # If we are building roughpy tests and gtest is available then we also + # to build the libalgebra_lite tests. + set(LIBALGEBRA_LITE_BUILD_TESTS ON CACHE INTERNAL "") endif () +# Load the helper functions include(cmake/roughpy_helpers.cmake) +# On apple, try to use homebrew to locate the few system libraries that we need. +if (APPLE) + execute_process(COMMAND "brew" "--prefix" + RESULT_VARIABLE _brew_prefix_found + OUTPUT_VARIABLE _brew_prefix + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + message(STATUS "Adding brew prefix: ${_brew_prefix}") + if (_brew_prefix_found) + list(APPEND CMAKE_PREFIX_PATH "${_brew_prefix}") + endif () +endif() -option(ROUGHPY_LINK_NUMPY "Link with Numpy library for array handling" ON) -option(ROUGHPY_GENERATE_DEVICE_CODE "Generate code for objects on devices" OFF) - - +# We need to provide some help to make sure we find the correct version of +# Python. Ideally, if we're using Scikit-Build-Core to build the library (via +# pip) and the Python executable is provided via the PYTHON_EXECUTABLE cache +# variable. In this case, make sure that this is the version of Python that gets +# found. set(PYBIND11_FINDPYTHON ON) if (NOT PYTHON_FOUND AND SKBUILD) cmake_path(GET PYTHON_EXECUTABLE PARENT_PATH _sk_env_dir) @@ -84,44 +77,33 @@ if (NOT PYTHON_FOUND AND SKBUILD) # clean up temporary unset(_sk_env_dir) else () + # If we're not using Scikit-Build-Core (i.e. a pure CMake build) then try + # looking for a Python virtual environment first. set(Python_FIND_VIRTUALENV FIRST) + + # In particular, if ENV{VIRTUAL_ENV} is set then add this to the cmake + # prefix path so FindPython is more likely to find this environemnt. + if (DEFINED ENV{VIRTUAL_ENV}) + # Put venv/lib on the prefix path so we can find + # a pip installed MKL + message(STATUS "Adding python virtual environment to path") + list(PREPEND CMAKE_PREFIX_PATH "$ENV{VIRTUAL_ENV}") + endif () endif () + +# At minimum we need Interpreter and Development.Module in order to build a +# Python extension module. +set(PYTHON_COMPONENTS_NEEDED Interpreter Development.Module) if (ROUGHPY_LINK_NUMPY) - find_package(Python 3.8 REQUIRED COMPONENTS Interpreter Development.Module NumPy) -else () - find_package(Python 3.8 REQUIRED COMPONENTS Interpreter Development.Module) + list(APPEND PYTHON_COMPONENTS_NEEDED NumPy) endif () -if (DEFINED ENV{VIRTUAL_ENV}) - # Put venv/lib on the prefix path so we can find - # a pip installed MKL - message(STATUS "Adding python virtual environment to path") - list(PREPEND CMAKE_PREFIX_PATH "$ENV{VIRTUAL_ENV}/lib") -endif () +find_package(Python 3.8 REQUIRED COMPONENTS ${PYTHON_COMPONENTS_NEEDED}) -# Before we get too far, let's make use of Python's import -# system to make sure MKL can be found if it was pip installed -execute_process(COMMAND ${Python_EXECUTABLE} - "${CMAKE_CURRENT_LIST_DIR}/tools/python-get-binary-obj-path.py" - "--directory" "mkl-devel" "cmake/mkl/MKLConfig.cmake" - RESULT_VARIABLE _python_mkl_dir_found - OUTPUT_VARIABLE _python_mkl_dir - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - ) -if (NOT _python_mkl_dir_found AND EXISTS "${_python_mkl_dir}") - cmake_path(GET _python_mkl_dir PARENT_PATH _python_mkl_dir) - message(STATUS "Adding MKL dir from pip-installed mkl: ${_python_mkl_dir}") - list(APPEND CMAKE_PREFIX_PATH "${_python_mkl_dir}") - if (NOT MKL_ROOT) - set(MKL_ROOT "${_python_mkl_dir}") - endif () - set(MKL_DIR "${_python_mkl_dir}") -endif () if (NOT DEFINED pybind11_ROOT) execute_process(COMMAND @@ -152,7 +134,35 @@ find_package(SndFile CONFIG REQUIRED) find_package(tomlplusplus CONFIG REQUIRED) message(STATUS "Target architecture ${RPY_ARCH}") -if (RPY_ARCH MATCHES "[xX](86(_64)?|64)|[aA][mM][dD]64") +if (RPY_ARCH MATCHES "[xX](86(_64)?|64)|[aA][mM][dD]64" AND NOT + ROUGHPY_PREFER_ACCELERATE) + + # If we're looking for MKL then we might have installed it via pip. + # To make sure we can find this, let's use Python's importlib metadata to + # locate the directory containing MKLConfig.cmake and add the relevant + # directory to the prefix path. + execute_process(COMMAND ${Python_EXECUTABLE} + "${CMAKE_CURRENT_LIST_DIR}/tools/python-get-binary-obj-path.py" + "--directory" "mkl-devel" "cmake/mkl/MKLConfig.cmake" + RESULT_VARIABLE _python_mkl_dir_found + OUTPUT_VARIABLE _python_mkl_dir + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + if (NOT _python_mkl_dir_found AND EXISTS "${_python_mkl_dir}") + cmake_path(GET _python_mkl_dir PARENT_PATH _python_mkl_dir) + message(STATUS "Adding MKL dir from pip-installed mkl: ${_python_mkl_dir}") + list(APPEND CMAKE_PREFIX_PATH "${_python_mkl_dir}") + if (NOT MKL_ROOT) + set(MKL_ROOT "${_python_mkl_dir}") + endif () + set(MKL_DIR "${_python_mkl_dir}") + endif () + + # Set the variables that determine the actual MKL library that we need to + # link. At the moment, we force 32-bit addressing on both 32- and 64-bit + # platforms, statically linked, and using the Intel OMP library (except on + # Windows). if (RPY_ARCH STREQUAL "x86") set(MKL_ARCH ia32) else () @@ -174,18 +184,13 @@ if (RPY_ARCH MATCHES "[xX](86(_64)?|64)|[aA][mM][dD]64") add_library(BLAS::BLAS ALIAS MKL::MKL) add_library(LAPACK::LAPACK ALIAS MKL::MKL) - # if (DEFINED MKL_OMP_LIB AND MKL_OMP_LIB) - # foreach (LANG IN ITEMS C CXX) - # set(OpenMP_${LANG}_LIB_NAMES ${MKL_OMP_LIB} CACHE STRING "Intel OpenMP runtime library") - # endforeach () - # endif () if (DEFINED MKL_OMP_LIB AND MKL_OMP_LIB) - foreach (LANG IN ITEMS C CXX) - if (APPLE) + if (APPLE) + foreach (LANG IN ITEMS C CXX) set(OpenMP_${LANG}_FLAGS "-XPreprocessor -fopenmp=${MKL_OMP_LIB}") set(OpenMP_${LANG}_LIB_NAMES "${MKL_OMP_LIB}" CACHE STRING "libomp location for OpenMP") - endif () - endforeach () + endforeach () + endif () set(OpenMP_${MKL_OMP_LIB}_LIBRARY "${MKL_THREAD_LIB}") endif () else () @@ -211,41 +216,19 @@ find_package(pybind11 REQUIRED) find_package(cereal REQUIRED) find_package(PCGRandom REQUIRED) +# Now we get to adding our components. Let's do some global setup such as +# setting the CXX standard and the shared library details. +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) -add_subdirectory(external/libalgebra_lite) -#set_target_properties(Libalgebra_lite PROPERTIES NO_SONAME ON) - -#add_subdirectory(external/pybind11) - - -# Make an imported target for PCG-CPP because it is a -# makefile based project -#if(NOT TARGET PCGRandom::pcg_random) -# add_library(PCGRandom::pcg_random IMPORTED INTERFACE) -# target_include_directories(PCGRandom::pcg_random INTERFACE -# external/pcg-cpp/include) -#endif() - - -#add_subdirectory(external/recombine) - -set(LIBALGEBRA_NO_SERIALIZATION ON CACHE INTERNAL "") -add_subdirectory(external/libalgebra) +if (LINUX) + set(CMAKE_INSTALL_RPATH "$ORIGIN") +elseif (APPLE) + set(CMAKE_MACOSX_RPATH ON) +endif () -#add_subdirectory(external/csv-parser) -# The csv-parser CMakeLists.txt leaves much to be desired -# Let's fix some of the problems now -#if(NOT TARGET csv::csv) -# add_library(csv::csv ALIAS csv) -# target_include_directories(csv INTERFACE -# external/csv-parser/include) -# set_target_properties(csv PROPERTIES POSITION_INDEPENDENT_CODE ON) -#endif() +add_subdirectory(external/libalgebra_lite) -#set(BUILD_DOC OFF CACHE INTERNAL "disable cereal docs") -#set(BUILD_SANDBOX OFF CACHE INTERNAL "disable cereal sandbox examples") -#set(SKIP_PERFORMANCE_COMPARISON ON CACHE INTERNAL "disable building cereal performance tests") -#add_subdirectory(external/cereal) add_subdirectory(core) add_subdirectory(platform) @@ -260,10 +243,17 @@ if (ROUGHPY_GENERATE_DEVICE_CODE) endif () if (ROUGHPY_BUILD_LA_CONTEXTS) + set(LIBALGEBRA_NO_SERIALIZATION ON CACHE INTERNAL "") + add_subdirectory(external/libalgebra) add_subdirectory(la_context) endif () +# TODO: Maybe we should replace this with a custom install target rather than +# messing with the install directories. +set(CMAKE_INSTALL_LIBDIR "roughpy" CACHE STRING "install library dir") +set(CMAKE_INSTALL_BINDIR "roughpy" CACHE STRING "install binary dir") + install(TARGETS RoughPy_PyModule EXPORT RoughPy_EXPORTS @@ -296,17 +286,3 @@ foreach (_rpy_lib IN LISTS ROUGHPY_LIBS) endif () endforeach () install(FILES ${_runtime_deps} DESTINATION roughpy) - -# -#install(EXPORT RoughPy_EXPORTS -# DESTINATION roughpy -# NAMESPACE RoughPy -# FILE RoughPy.cmake -# COMPONENT Development -# EXCLUDE_FROM_ALL -# ) -# -# -#if (TARGET MKL::MKL AND DEFINED MKL_THREAD_LIB) -# install(FILES ${MKL_THREAD_LIB} DESTINATION roughpy) -#endif () From ad0f219a454a745729df133dff002fc8f7e2f1f0 Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Mon, 17 Jul 2023 13:15:52 +0100 Subject: [PATCH 03/37] remove unnecessary variable --- streams/src/stream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/streams/src/stream.cpp b/streams/src/stream.cpp index 0b73f342..3856ff6d 100644 --- a/streams/src/stream.cpp +++ b/streams/src/stream.cpp @@ -110,7 +110,7 @@ rpy::streams::Stream::Lie rpy::streams::Stream::log_signature( rpy::resolution_t resolution, const rpy::streams::Stream::Context& ctx ) const { - const auto& md = metadata(); +// const auto& md = metadata(); return p_impl->log_signature(m_support, resolution, ctx); } rpy::streams::Stream::Lie rpy::streams::Stream::log_signature( From 27b9ce22061b5b06e9271b96274393a01c627c31 Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Mon, 17 Jul 2023 16:00:52 +0100 Subject: [PATCH 04/37] Added prototypes for free multiply functions --- .../include/roughpy/algebra/algebra_base.h | 13 ++ algebra/include/roughpy/algebra/context.h | 160 +++++++++--------- algebra/src/context.cpp | 33 ++++ algebra/src/lite_context.h | 52 ++++++ 4 files changed, 180 insertions(+), 78 deletions(-) diff --git a/algebra/include/roughpy/algebra/algebra_base.h b/algebra/include/roughpy/algebra/algebra_base.h index 1ddb6bd7..e5aa5699 100644 --- a/algebra/include/roughpy/algebra/algebra_base.h +++ b/algebra/include/roughpy/algebra/algebra_base.h @@ -397,6 +397,19 @@ class AlgebraBase return static_cast(p_impl); } + RPY_NO_DISCARD + explicit inline operator const Interface*() const noexcept + { + return p_impl.get(); + } + + RPY_NO_DISCARD + explicit inline operator Interface*() noexcept + { + return p_impl.get(); + } + + RPY_NO_DISCARD dimn_t dimension() const; RPY_NO_DISCARD diff --git a/algebra/include/roughpy/algebra/context.h b/algebra/include/roughpy/algebra/context.h index bcb7930b..8257c0f2 100644 --- a/algebra/include/roughpy/algebra/context.h +++ b/algebra/include/roughpy/algebra/context.h @@ -87,15 +87,11 @@ class RPY_EXPORT ContextBase : public boost::intrusive_ref_counter public: virtual ~ContextBase(); - RPY_NO_DISCARD - deg_t width() const noexcept { return m_width; } - RPY_NO_DISCARD - deg_t depth() const noexcept { return m_depth; } - - RPY_NO_DISCARD - dimn_t lie_size(deg_t deg) const noexcept; - RPY_NO_DISCARD - dimn_t tensor_size(deg_t deg) const noexcept; + RPY_NO_DISCARD deg_t width() const noexcept { return m_width; } + RPY_NO_DISCARD deg_t depth() const noexcept { return m_depth; } + + RPY_NO_DISCARD dimn_t lie_size(deg_t deg) const noexcept; + RPY_NO_DISCARD dimn_t tensor_size(deg_t deg) const noexcept; }; class RPY_EXPORT Context : public ContextBase @@ -114,115 +110,123 @@ class RPY_EXPORT Context : public ContextBase {} public: - RPY_NO_DISCARD - const scalars::ScalarType* ctype() const noexcept { return p_ctype; } - RPY_NO_DISCARD - const string& backend() const noexcept { return m_ctx_backend; } - - RPY_NO_DISCARD - virtual context_pointer get_alike(deg_t new_depth) const = 0; - RPY_NO_DISCARD - virtual context_pointer get_alike(const scalars::ScalarType* new_ctype - ) const = 0; - RPY_NO_DISCARD - virtual context_pointer + RPY_NO_DISCARD const scalars::ScalarType* ctype() const noexcept + { + return p_ctype; + } + RPY_NO_DISCARD const string& backend() const noexcept + { + return m_ctx_backend; + } + + RPY_NO_DISCARD virtual context_pointer get_alike(deg_t new_depth) const = 0; + RPY_NO_DISCARD virtual context_pointer + get_alike(const scalars::ScalarType* new_ctype) const + = 0; + RPY_NO_DISCARD virtual context_pointer get_alike(deg_t new_depth, const scalars::ScalarType* new_ctype) const = 0; - RPY_NO_DISCARD - virtual context_pointer get_alike( + RPY_NO_DISCARD virtual context_pointer get_alike( deg_t new_width, deg_t new_depth, const scalars::ScalarType* new_ctype ) const = 0; - RPY_NO_DISCARD - virtual bool check_compatible(const Context& other_ctx) const noexcept; + RPY_NO_DISCARD virtual bool check_compatible(const Context& other_ctx + ) const noexcept; - RPY_NO_DISCARD - virtual LieBasis get_lie_basis() const = 0; - RPY_NO_DISCARD - virtual TensorBasis get_tensor_basis() const = 0; + RPY_NO_DISCARD virtual LieBasis get_lie_basis() const = 0; + RPY_NO_DISCARD virtual TensorBasis get_tensor_basis() const = 0; - RPY_NO_DISCARD - virtual FreeTensor + RPY_NO_DISCARD virtual FreeTensor convert(const FreeTensor& arg, optional new_vec_type) const = 0; - RPY_NO_DISCARD - virtual ShuffleTensor + RPY_NO_DISCARD virtual ShuffleTensor convert(const ShuffleTensor& arg, optional new_vec_type) const = 0; - RPY_NO_DISCARD - virtual Lie convert(const Lie& arg, optional new_vec_type) const + RPY_NO_DISCARD virtual Lie + convert(const Lie& arg, optional new_vec_type) const = 0; - RPY_NO_DISCARD - virtual FreeTensor construct_free_tensor(const VectorConstructionData& arg - ) const = 0; - RPY_NO_DISCARD - virtual ShuffleTensor + RPY_NO_DISCARD virtual FreeTensor + construct_free_tensor(const VectorConstructionData& arg) const + = 0; + RPY_NO_DISCARD virtual ShuffleTensor construct_shuffle_tensor(const VectorConstructionData& arg) const = 0; - RPY_NO_DISCARD - virtual Lie construct_lie(const VectorConstructionData& arg) const = 0; + RPY_NO_DISCARD virtual Lie construct_lie(const VectorConstructionData& arg + ) const = 0; - RPY_NO_DISCARD - virtual UnspecifiedAlgebraType + RPY_NO_DISCARD virtual UnspecifiedAlgebraType construct(AlgebraType type, const VectorConstructionData& data) const = 0; - RPY_NO_DISCARD - FreeTensor zero_free_tensor(VectorType vtype) const; - RPY_NO_DISCARD - ShuffleTensor zero_shuffle_tensor(VectorType vtype) const; - RPY_NO_DISCARD - Lie zero_lie(VectorType vtype) const; + RPY_NO_DISCARD FreeTensor zero_free_tensor(VectorType vtype) const; + RPY_NO_DISCARD ShuffleTensor zero_shuffle_tensor(VectorType vtype) const; + RPY_NO_DISCARD Lie zero_lie(VectorType vtype) const; protected: void lie_to_tensor_fallback(FreeTensor& result, const Lie& arg) const; void tensor_to_lie_fallback(Lie& result, const FreeTensor& arg) const; public: - RPY_NO_DISCARD - virtual FreeTensor lie_to_tensor(const Lie& arg) const = 0; - RPY_NO_DISCARD - virtual Lie tensor_to_lie(const FreeTensor& arg) const = 0; + RPY_NO_DISCARD virtual FreeTensor lie_to_tensor(const Lie& arg) const = 0; + RPY_NO_DISCARD virtual Lie tensor_to_lie(const FreeTensor& arg) const = 0; protected: void cbh_fallback(FreeTensor& collector, const std::vector& lies) const; public: - RPY_NO_DISCARD - virtual Lie cbh(const std::vector& lies, VectorType vtype) const; - RPY_NO_DISCARD - virtual Lie cbh(const Lie& left, const Lie& right, VectorType vtype) const; - - RPY_NO_DISCARD - virtual FreeTensor to_signature(const Lie& log_signature) const; - RPY_NO_DISCARD - virtual FreeTensor signature(const SignatureData& data) const = 0; - RPY_NO_DISCARD - virtual Lie log_signature(const SignatureData& data) const = 0; - - RPY_NO_DISCARD - virtual FreeTensor sig_derivative( + RPY_NO_DISCARD virtual Lie + cbh(const std::vector& lies, VectorType vtype) const; + RPY_NO_DISCARD virtual Lie + cbh(const Lie& left, const Lie& right, VectorType vtype) const; + + RPY_NO_DISCARD virtual FreeTensor to_signature(const Lie& log_signature + ) const; + RPY_NO_DISCARD virtual FreeTensor signature(const SignatureData& data) const + = 0; + RPY_NO_DISCARD virtual Lie log_signature(const SignatureData& data) const + = 0; + + RPY_NO_DISCARD virtual FreeTensor sig_derivative( const std::vector& info, VectorType vtype ) const = 0; // Functions to aid serialization - RPY_NO_DISCARD - virtual std::vector + RPY_NO_DISCARD virtual std::vector to_raw_bytes(AlgebraType atype, RawUnspecifiedAlgebraType alg) const; - RPY_NO_DISCARD - virtual UnspecifiedAlgebraType + RPY_NO_DISCARD virtual UnspecifiedAlgebraType from_raw_bytes(AlgebraType atype, Slice raw_bytes) const; + + virtual UnspecifiedAlgebraType free_multiply( + const ConstRawUnspecifiedAlgebraType left, + const ConstRawUnspecifiedAlgebraType right + ) const; + + virtual UnspecifiedAlgebraType shuffle_multiply( + ConstRawUnspecifiedAlgebraType left, + ConstRawUnspecifiedAlgebraType right + ) const; + + virtual UnspecifiedAlgebraType half_shuffle_multiply( + ConstRawUnspecifiedAlgebraType left, + ConstRawUnspecifiedAlgebraType right + ) const; + + virtual UnspecifiedAlgebraType adjoint_to_left_multiply_by( + ConstRawUnspecifiedAlgebraType multiplier, + ConstRawUnspecifiedAlgebraType argument + ) const; + + + }; -RPY_EXPORT -base_context_pointer get_base_context(deg_t width, deg_t depth); +RPY_EXPORT base_context_pointer get_base_context(deg_t width, deg_t depth); -RPY_EXPORT -context_pointer get_context( +RPY_EXPORT context_pointer get_context( deg_t width, deg_t depth, const scalars::ScalarType* ctype, const std::vector>& preferences = {} ); @@ -267,8 +271,8 @@ class RPY_EXPORT ContextMaker get_base_context(deg_t width, deg_t depth) const = 0; }; -RPY_EXPORT -const ContextMaker* register_context_maker(std::unique_ptr maker); +RPY_EXPORT const ContextMaker* +register_context_maker(std::unique_ptr maker); template class RegisterMakerHelper diff --git a/algebra/src/context.cpp b/algebra/src/context.cpp index 6b8909d6..ef64771e 100644 --- a/algebra/src/context.cpp +++ b/algebra/src/context.cpp @@ -308,3 +308,36 @@ void rpy::algebra::intrusive_ptr_add_ref(const rpy::algebra::ContextBase* ptr) ContextBase, boost::thread_safe_counter>*>(ptr )); } + +UnspecifiedAlgebraType Context::free_multiply( + const ConstRawUnspecifiedAlgebraType left, + const ConstRawUnspecifiedAlgebraType right +) const +{ + throw std::runtime_error("free tensor multiply is not implemented for " + "arbitrary types with this backend"); +} +UnspecifiedAlgebraType Context::shuffle_multiply( + ConstRawUnspecifiedAlgebraType left, + ConstRawUnspecifiedAlgebraType right +) const +{ + throw std::runtime_error("shuffle multiply is not implemented for " + "arbitrary types with this backend"); +} +UnspecifiedAlgebraType Context::half_shuffle_multiply( + ConstRawUnspecifiedAlgebraType left, + ConstRawUnspecifiedAlgebraType right +) const +{ + throw std::runtime_error("half shuffle multiply is not implemented for " + "arbitrary types with this backend"); +} +UnspecifiedAlgebraType Context::adjoint_to_left_multiply_by( + ConstRawUnspecifiedAlgebraType multiplier, + ConstRawUnspecifiedAlgebraType argument +) const +{ + throw std::runtime_error("adjoint of left multiply is not implemented for " + "arbitrary types with this backend"); +} diff --git a/algebra/src/lite_context.h b/algebra/src/lite_context.h index 22453a90..d0abf1c9 100644 --- a/algebra/src/lite_context.h +++ b/algebra/src/lite_context.h @@ -226,7 +226,59 @@ class LiteContext : private dtl::LiteContextBasisHolder, public Context FreeTensor sig_derivative( const std::vector& info, VectorType vtype ) const override; + + UnspecifiedAlgebraType free_multiply( + const ConstRawUnspecifiedAlgebraType left, + const ConstRawUnspecifiedAlgebraType right + ) const override; + UnspecifiedAlgebraType shuffle_multiply( + ConstRawUnspecifiedAlgebraType left, + ConstRawUnspecifiedAlgebraType right + ) const override; + UnspecifiedAlgebraType half_shuffle_multiply( + ConstRawUnspecifiedAlgebraType left, + ConstRawUnspecifiedAlgebraType right + ) const override; + UnspecifiedAlgebraType adjoint_to_left_multiply_by( + ConstRawUnspecifiedAlgebraType multiplier, + ConstRawUnspecifiedAlgebraType argument + ) const override; }; +template +UnspecifiedAlgebraType LiteContext::free_multiply( + const ConstRawUnspecifiedAlgebraType left, + const ConstRawUnspecifiedAlgebraType right +) const +{ + + + + +} +template +UnspecifiedAlgebraType LiteContext::shuffle_multiply( + ConstRawUnspecifiedAlgebraType left, + ConstRawUnspecifiedAlgebraType right +) const +{ + return Context::shuffle_multiply(left, right); +} +template +UnspecifiedAlgebraType LiteContext::half_shuffle_multiply( + ConstRawUnspecifiedAlgebraType left, + ConstRawUnspecifiedAlgebraType right +) const +{ + return Context::half_shuffle_multiply(left, right); +} +template +UnspecifiedAlgebraType LiteContext::adjoint_to_left_multiply_by( + ConstRawUnspecifiedAlgebraType multiplier, + ConstRawUnspecifiedAlgebraType argument +) const +{ + return Context::adjoint_to_left_multiply_by(multiplier, argument); +} class LiteContextMaker : public ContextMaker { From 14cb3bec97a0b81804d3a33815d3bf156d90b6c2 Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Mon, 17 Jul 2023 16:08:03 +0100 Subject: [PATCH 05/37] No lite implementation for now --- algebra/include/roughpy/algebra/algebra_fwd.h | 1 + algebra/src/lite_context.h | 72 +++++++++---------- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/algebra/include/roughpy/algebra/algebra_fwd.h b/algebra/include/roughpy/algebra/algebra_fwd.h index 4056e919..27c1ad4d 100644 --- a/algebra/include/roughpy/algebra/algebra_fwd.h +++ b/algebra/include/roughpy/algebra/algebra_fwd.h @@ -82,6 +82,7 @@ class AlgebraInterfaceBase; } using RawUnspecifiedAlgebraType = dtl::AlgebraInterfaceBase*; +using ConstRawUnspecifiedAlgebraType = const dtl::AlgebraInterfaceBase*; using UnspecifiedAlgebraType = std::unique_ptr; class FreeTensor; diff --git a/algebra/src/lite_context.h b/algebra/src/lite_context.h index d0abf1c9..35201410 100644 --- a/algebra/src/lite_context.h +++ b/algebra/src/lite_context.h @@ -244,42 +244,42 @@ class LiteContext : private dtl::LiteContextBasisHolder, public Context ConstRawUnspecifiedAlgebraType argument ) const override; }; -template -UnspecifiedAlgebraType LiteContext::free_multiply( - const ConstRawUnspecifiedAlgebraType left, - const ConstRawUnspecifiedAlgebraType right -) const -{ - - - - -} -template -UnspecifiedAlgebraType LiteContext::shuffle_multiply( - ConstRawUnspecifiedAlgebraType left, - ConstRawUnspecifiedAlgebraType right -) const -{ - return Context::shuffle_multiply(left, right); -} -template -UnspecifiedAlgebraType LiteContext::half_shuffle_multiply( - ConstRawUnspecifiedAlgebraType left, - ConstRawUnspecifiedAlgebraType right -) const -{ - return Context::half_shuffle_multiply(left, right); -} -template -UnspecifiedAlgebraType LiteContext::adjoint_to_left_multiply_by( - ConstRawUnspecifiedAlgebraType multiplier, - ConstRawUnspecifiedAlgebraType argument -) const -{ - return Context::adjoint_to_left_multiply_by(multiplier, argument); -} - +//template +//UnspecifiedAlgebraType LiteContext::free_multiply( +// const ConstRawUnspecifiedAlgebraType left, +// const ConstRawUnspecifiedAlgebraType right +//) const +//{ +// +// +// +// +//} +//template +//UnspecifiedAlgebraType LiteContext::shuffle_multiply( +// ConstRawUnspecifiedAlgebraType left, +// ConstRawUnspecifiedAlgebraType right +//) const +//{ +// return Context::shuffle_multiply(left, right); +//} +//template +//UnspecifiedAlgebraType LiteContext::half_shuffle_multiply( +// ConstRawUnspecifiedAlgebraType left, +// ConstRawUnspecifiedAlgebraType right +//) const +//{ +// return Context::half_shuffle_multiply(left, right); +//} +//template +//UnspecifiedAlgebraType LiteContext::adjoint_to_left_multiply_by( +// ConstRawUnspecifiedAlgebraType multiplier, +// ConstRawUnspecifiedAlgebraType argument +//) const +//{ +// return Context::adjoint_to_left_multiply_by(multiplier, argument); +//} +// class LiteContextMaker : public ContextMaker { using ContextMaker::preference_list; From e341734e774059c736bcb8d32de97830dbbb723d Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Mon, 17 Jul 2023 16:08:08 +0100 Subject: [PATCH 06/37] bump lal --- external/libalgebra_lite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/libalgebra_lite b/external/libalgebra_lite index e28335aa..e5d6d985 160000 --- a/external/libalgebra_lite +++ b/external/libalgebra_lite @@ -1 +1 @@ -Subproject commit e28335aa91a49563240e44dd9f013c9c2f6b4c08 +Subproject commit e5d6d985795663c4c163a9e65dd30e776e6ec3ce From 37b2272b464ec78062bfa28fe7524b39ee02d9d6 Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Mon, 17 Jul 2023 16:09:10 +0100 Subject: [PATCH 07/37] no implementations for now --- algebra/src/lite_context.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/algebra/src/lite_context.h b/algebra/src/lite_context.h index 35201410..c2a3cd3e 100644 --- a/algebra/src/lite_context.h +++ b/algebra/src/lite_context.h @@ -227,22 +227,22 @@ class LiteContext : private dtl::LiteContextBasisHolder, public Context const std::vector& info, VectorType vtype ) const override; - UnspecifiedAlgebraType free_multiply( - const ConstRawUnspecifiedAlgebraType left, - const ConstRawUnspecifiedAlgebraType right - ) const override; - UnspecifiedAlgebraType shuffle_multiply( - ConstRawUnspecifiedAlgebraType left, - ConstRawUnspecifiedAlgebraType right - ) const override; - UnspecifiedAlgebraType half_shuffle_multiply( - ConstRawUnspecifiedAlgebraType left, - ConstRawUnspecifiedAlgebraType right - ) const override; - UnspecifiedAlgebraType adjoint_to_left_multiply_by( - ConstRawUnspecifiedAlgebraType multiplier, - ConstRawUnspecifiedAlgebraType argument - ) const override; +// UnspecifiedAlgebraType free_multiply( +// const ConstRawUnspecifiedAlgebraType left, +// const ConstRawUnspecifiedAlgebraType right +// ) const override; +// UnspecifiedAlgebraType shuffle_multiply( +// ConstRawUnspecifiedAlgebraType left, +// ConstRawUnspecifiedAlgebraType right +// ) const override; +// UnspecifiedAlgebraType half_shuffle_multiply( +// ConstRawUnspecifiedAlgebraType left, +// ConstRawUnspecifiedAlgebraType right +// ) const override; +// UnspecifiedAlgebraType adjoint_to_left_multiply_by( +// ConstRawUnspecifiedAlgebraType multiplier, +// ConstRawUnspecifiedAlgebraType argument +// ) const override; }; //template //UnspecifiedAlgebraType LiteContext::free_multiply( From e67c843c433106fec2efe0b502c13bee355b2957 Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Mon, 17 Jul 2023 16:50:52 +0100 Subject: [PATCH 08/37] Added free multiply functions to python interface --- roughpy/CMakeLists.txt | 2 + roughpy/src/algebra/algebra.cpp | 4 + roughpy/src/algebra/basis.cpp | 18 +- roughpy/src/algebra/free_multiply_funcs.cpp | 237 ++++++++++++++++++++ roughpy/src/algebra/free_multiply_funcs.h | 20 ++ 5 files changed, 278 insertions(+), 3 deletions(-) create mode 100644 roughpy/src/algebra/free_multiply_funcs.cpp create mode 100644 roughpy/src/algebra/free_multiply_funcs.h diff --git a/roughpy/CMakeLists.txt b/roughpy/CMakeLists.txt index 9842b777..67136a96 100644 --- a/roughpy/CMakeLists.txt +++ b/roughpy/CMakeLists.txt @@ -52,6 +52,8 @@ target_sources(RoughPy_PyModule PRIVATE src/algebra/basis.h src/algebra/context.cpp src/algebra/context.h + src/algebra/free_multiply_funcs.cpp + src/algebra/free_multiply_funcs.h src/algebra/free_tensor.h src/algebra/free_tensor.cpp src/algebra/lie.cpp diff --git a/roughpy/src/algebra/algebra.cpp b/roughpy/src/algebra/algebra.cpp index 8eac007a..1f806f02 100644 --- a/roughpy/src/algebra/algebra.cpp +++ b/roughpy/src/algebra/algebra.cpp @@ -40,6 +40,7 @@ #include "shuffle_tensor.h" #include "tensor_key.h" #include "tensor_key_iterator.h" +#include "free_multiply_funcs.h" void rpy::python::init_algebra(pybind11::module_& m) { @@ -59,4 +60,7 @@ void rpy::python::init_algebra(pybind11::module_& m) init_free_tensor(m); init_shuffle_tensor(m); init_lie(m); + + init_free_multiply_funcs(m); + } diff --git a/roughpy/src/algebra/basis.cpp b/roughpy/src/algebra/basis.cpp index 56a1a3f6..b72580f4 100644 --- a/roughpy/src/algebra/basis.cpp +++ b/roughpy/src/algebra/basis.cpp @@ -33,18 +33,24 @@ #include #include "lie_key.h" +#include "lie_key_iterator.h" #include "tensor_key.h" +#include "tensor_key_iterator.h" using namespace rpy; using namespace rpy::algebra; using namespace pybind11::literals; -template +template static void wordlike_basis_setup(py::module_& m, const char* name) { py::class_ basis(m, name); +// basis.def(py::init([](deg_t width, deg_t depth) { +// +// })); + basis.def_property_readonly("width", &T::width); basis.def_property_readonly("depth", &T::depth); basis.def_property_readonly("dimension", &T::dimension); @@ -69,11 +75,17 @@ static void wordlike_basis_setup(py::module_& m, const char* name) [](const T& self, const K& key) { return self.parents(0); }, "key"_a ); basis.def("size", &T::size); + +// basis.def("__iter__", [](const T& self) { +// return KIter(self); +// }); } void python::init_basis(py::module_& m) { - wordlike_basis_setup(m, "TensorBasis"); - wordlike_basis_setup(m, "LieBasis"); + wordlike_basis_setup( + m, "TensorBasis" + ); + wordlike_basis_setup(m, "LieBasis"); } diff --git a/roughpy/src/algebra/free_multiply_funcs.cpp b/roughpy/src/algebra/free_multiply_funcs.cpp new file mode 100644 index 00000000..922b7985 --- /dev/null +++ b/roughpy/src/algebra/free_multiply_funcs.cpp @@ -0,0 +1,237 @@ +// +// Created by user on 17/07/23. +// + +#include "free_multiply_funcs.h" +#include + +using namespace pybind11::literals; + +using namespace rpy; + +namespace { + +static const char FREE_MULTIPLY_DOC[] = R"rpydoc()rpydoc"; +py::object free_multiply(const py::object& left, const py::object& right) +{ + algebra::ConstRawUnspecifiedAlgebraType left_raw, right_raw; + algebra::AlgebraType result_alg_type; + algebra::context_pointer ctx; + if (py::isinstance(left)) { + const auto& left_real = left.cast(); + result_alg_type = algebra::AlgebraType::FreeTensor; + ctx = left_real.context(); + left_raw = (&*left_real); + if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else { + throw std::runtime_error("argument 'right' must be of type " + "FreeTensor or ShuffleTensor"); + } + } else if (py::isinstance(left)) { + result_alg_type = algebra::AlgebraType::ShuffleTensor; + const auto& left_real = left.cast(); + ctx = left_real.context(); + left_raw = (&*left_real); + if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else { + throw std::runtime_error("argument 'right' must be of type " + "FreeTensor or ShuffleTensor"); + } + } else { + throw std::runtime_error("argument 'left' must be of type FreeTensor " + "or ShuffleTensor"); + } + + RPY_CHECK(static_cast(ctx)); + + auto result_ptr = ctx->free_multiply(left_raw, right_raw); + + switch (result_alg_type) { + case algebra::AlgebraType::FreeTensor: + return py::cast(algebra::FreeTensor(std::move(result_ptr))); + case algebra::AlgebraType::ShuffleTensor: + return py::cast(algebra::ShuffleTensor(std::move(result_ptr))); + default: throw std::runtime_error("unexpected result algebra type"); + } + + RPY_UNREACHABLE_RETURN(py::none()); +} + +static const char SHUFFLE_MULTIPLY_DOC[] = R"rpydoc()rpydoc"; +py::object shuffle_multiply(const py::object& left, const py::object& right) +{ + algebra::ConstRawUnspecifiedAlgebraType left_raw, right_raw; + algebra::AlgebraType result_alg_type; + algebra::context_pointer ctx; + if (py::isinstance(left)) { + const auto& left_real = left.cast(); + result_alg_type = algebra::AlgebraType::FreeTensor; + ctx = left_real.context(); + left_raw = (&*left_real); + if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else { + throw std::runtime_error("argument 'right' must be of type " + "FreeTensor or ShuffleTensor"); + } + } else if (py::isinstance(left)) { + result_alg_type = algebra::AlgebraType::ShuffleTensor; + const auto& left_real = left.cast(); + ctx = left_real.context(); + left_raw = (&*left_real); + if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else { + throw std::runtime_error("argument 'right' must be of type " + "FreeTensor or ShuffleTensor"); + } + } else { + throw std::runtime_error("argument 'left' must be of type FreeTensor " + "or ShuffleTensor"); + } + + RPY_CHECK(static_cast(ctx)); + + auto result_ptr = ctx->shuffle_multiply(left_raw, right_raw); + + switch (result_alg_type) { + case algebra::AlgebraType::FreeTensor: + return py::cast(algebra::FreeTensor(std::move(result_ptr))); + case algebra::AlgebraType::ShuffleTensor: + return py::cast(algebra::ShuffleTensor(std::move(result_ptr))); + default: throw std::runtime_error("unexpected result algebra type"); + } + + RPY_UNREACHABLE_RETURN(py::none()); +} + +static const char HALF_SHUFFLE_MULTIPLY_DOC[] = R"rpydoc()rpydoc"; +py::object +half_shuffle_multiply(const py::object& left, const py::object& right) +{ + algebra::ConstRawUnspecifiedAlgebraType left_raw, right_raw; + algebra::AlgebraType result_alg_type; + algebra::context_pointer ctx; + if (py::isinstance(left)) { + const auto& left_real = left.cast(); + result_alg_type = algebra::AlgebraType::FreeTensor; + ctx = left_real.context(); + left_raw = (&*left_real); + if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else { + throw std::runtime_error("argument 'right' must be of type " + "FreeTensor or ShuffleTensor"); + } + } else if (py::isinstance(left)) { + result_alg_type = algebra::AlgebraType::ShuffleTensor; + const auto& left_real = left.cast(); + ctx = left_real.context(); + left_raw = (&*left_real); + if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else if (py::isinstance(right)) { + right_raw = &*right.cast(); + } else { + throw std::runtime_error("argument 'right' must be of type " + "FreeTensor or ShuffleTensor"); + } + } else { + throw std::runtime_error("argument 'left' must be of type FreeTensor " + "or ShuffleTensor"); + } + + RPY_CHECK(static_cast(ctx)); + + auto result_ptr = ctx->half_shuffle_multiply(left_raw, right_raw); + + switch (result_alg_type) { + case algebra::AlgebraType::FreeTensor: + return py::cast(algebra::FreeTensor(std::move(result_ptr))); + case algebra::AlgebraType::ShuffleTensor: + return py::cast(algebra::ShuffleTensor(std::move(result_ptr))); + default: throw std::runtime_error("unexpected result algebra type"); + } + + RPY_UNREACHABLE_RETURN(py::none()); +} + +static const char ADJOINT_FREE_MULTIPLY_DOC[] = R"rpydoc()rpydoc"; +py::object +adjoint_to_free_multiply(const py::object& multiplier, const py::object& arg) +{ + algebra::ConstRawUnspecifiedAlgebraType mul_raw, arg_raw; + algebra::AlgebraType result_alg_type; + algebra::context_pointer ctx; + if (py::isinstance(multiplier)) { + const auto& left_real = multiplier.cast(); + result_alg_type = algebra::AlgebraType::FreeTensor; + ctx = left_real.context(); + mul_raw = (&*left_real); + if (py::isinstance(arg)) { + arg_raw = &*arg.cast(); + } else if (py::isinstance(arg)) { + arg_raw = &*arg.cast(); + } else { + throw std::runtime_error("argument 'right' must be of type " + "FreeTensor or ShuffleTensor"); + } + } else if (py::isinstance(multiplier)) { + result_alg_type = algebra::AlgebraType::ShuffleTensor; + const auto& left_real = multiplier.cast(); + ctx = left_real.context(); + mul_raw = (&*left_real); + if (py::isinstance(arg)) { + arg_raw = &*arg.cast(); + } else if (py::isinstance(arg)) { + arg_raw = &*arg.cast(); + } else { + throw std::runtime_error("argument 'right' must be of type " + "FreeTensor or ShuffleTensor"); + } + } else { + throw std::runtime_error("argument 'left' must be of type FreeTensor " + "or ShuffleTensor"); + } + + RPY_CHECK(static_cast(ctx)); + + auto result_ptr = ctx->adjoint_to_left_multiply_by(mul_raw, arg_raw); + + switch (result_alg_type) { + case algebra::AlgebraType::FreeTensor: + return py::cast(algebra::FreeTensor(std::move(result_ptr))); + case algebra::AlgebraType::ShuffleTensor: + return py::cast(algebra::ShuffleTensor(std::move(result_ptr))); + default: throw std::runtime_error("unexpected result algebra type"); + } + + RPY_UNREACHABLE_RETURN(py::none()); +} + +}// namespace + +void rpy::python::init_free_multiply_funcs(py::module_& m) +{ + m.def("free_multiply", &free_multiply, FREE_MULTIPLY_DOC, "left"_a, + "right"_a); + m.def("shuffle_multiply", &shuffle_multiply, SHUFFLE_MULTIPLY_DOC, "left"_a, + "right"_a); + m.def("half_shuffle_multiply", &half_shuffle_multiply, + HALF_SHUFFLE_MULTIPLY_DOC, "left"_a, "right"_a); + m.def("adjoint_to_free_multiply", &adjoint_to_free_multiply, + ADJOINT_FREE_MULTIPLY_DOC, "multiplier"_a, "arg"_a); +} diff --git a/roughpy/src/algebra/free_multiply_funcs.h b/roughpy/src/algebra/free_multiply_funcs.h new file mode 100644 index 00000000..42e22af7 --- /dev/null +++ b/roughpy/src/algebra/free_multiply_funcs.h @@ -0,0 +1,20 @@ +// +// Created by user on 17/07/23. +// + +#ifndef ROUGHPY_ROUGHPY_SRC_ALGEBRA_FREE_MULTIPLY_FUNCS_H_ +#define ROUGHPY_ROUGHPY_SRC_ALGEBRA_FREE_MULTIPLY_FUNCS_H_ + +#include "roughpy_module.h" + +namespace rpy { +namespace python { + + + +void init_free_multiply_funcs(py::module_& m); + +} +}// namespace rpy + +#endif// ROUGHPY_ROUGHPY_SRC_ALGEBRA_FREE_MULTIPLY_FUNCS_H_ From 9d9e0ad0adbf2a467514bbfe25da13318a3207be Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Mon, 17 Jul 2023 16:51:46 +0100 Subject: [PATCH 09/37] Added constructor from unspecified algebra type --- algebra/include/roughpy/algebra/algebra_base.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/algebra/include/roughpy/algebra/algebra_base.h b/algebra/include/roughpy/algebra/algebra_base.h index e5aa5699..eb71f873 100644 --- a/algebra/include/roughpy/algebra/algebra_base.h +++ b/algebra/include/roughpy/algebra/algebra_base.h @@ -327,6 +327,10 @@ class AlgebraBase explicit AlgebraBase(std::unique_ptr impl) : p_impl(std::move(impl)) {} + explicit AlgebraBase(UnspecifiedAlgebraType&& impl) + : p_impl(reinterpret_cast(impl.release())) + {} + explicit AlgebraBase(Interface* impl) : p_impl(impl) {} using interface_t = Interface; From 84ea633650a8d26b39f050fc44eb2b68929d4ecb Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Mon, 17 Jul 2023 16:58:32 +0100 Subject: [PATCH 10/37] Tiny bit of cleanup --- roughpy/__init__.py | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/roughpy/__init__.py b/roughpy/__init__.py index cf9bc1c6..78a8781e 100644 --- a/roughpy/__init__.py +++ b/roughpy/__init__.py @@ -33,38 +33,3 @@ def _add_dynload_location(path: Path): import roughpy._roughpy from roughpy._roughpy import * - -# from _roughpy import ( -# TensorKey, -# LieKey, -# TensorKeyIterator, -# LieKeyIterator, -# FreeTensor, -# ShuffleTensor, -# Lie, -# Context, -# get_context -# ) -# -# -# from _roughpy import ( -# Scalar, -# float as SPReal, -# double as DPReal, -# rational as Rational, -# ) -# -# from _roughpy import ( -# Interval, -# IntervalType, -# RealInterval, -# Dyadic, -# DyadicInterval -# ) -# -# from _roughpy import ( -# Stream, -# LieIncrementStream, -# ) -# -# From ff7da6d95d7a2c725275082ec620b51f60480b0b Mon Sep 17 00:00:00 2001 From: Sam Morley Date: Wed, 19 Jul 2023 14:53:28 +0100 Subject: [PATCH 11/37] Implemented free functions! --- CHANGELOG | 6 + algebra/CMakeLists.txt | 4 + .../include/roughpy/algebra/algebra_base.h | 20 +- algebra/include/roughpy/algebra/algebra_fwd.h | 6 + algebra/include/roughpy/algebra/context_fwd.h | 14 +- algebra/src/algebra_base.cpp | 9 +- .../algebra_type_caster.h | 106 +++++++ .../algebra_type_helper.h | 65 +++++ .../unspecified_algebra_binary_op.h | 209 ++++++++++++++ .../vector_storage_type.h | 36 +++ algebra/src/lite_context.h | 259 +++++++++++++----- core/include/roughpy/core/traits.h | 6 + tests/algebra/test_free_multiply_functions.py | 48 ++++ 13 files changed, 716 insertions(+), 72 deletions(-) create mode 100644 algebra/src/libalgebra_lite_internal/algebra_type_caster.h create mode 100644 algebra/src/libalgebra_lite_internal/algebra_type_helper.h create mode 100644 algebra/src/libalgebra_lite_internal/unspecified_algebra_binary_op.h create mode 100644 algebra/src/libalgebra_lite_internal/vector_storage_type.h create mode 100644 tests/algebra/test_free_multiply_functions.py diff --git a/CHANGELOG b/CHANGELOG index 1435b8d4..118d25b7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +Version 0.0.5: + - Added free functions for performing free-tensor, shuffle, half-shuffle + multiplication between pairs of tensors (of either kind). + - Added free function for applying the adjoint of left free tensor + multiplication to arbitrary tensors. + Version 0.0.4: - Overhauled the RPY_CHECK macro so it now gives much better contextual information. diff --git a/algebra/CMakeLists.txt b/algebra/CMakeLists.txt index b6f36c67..b240670c 100644 --- a/algebra/CMakeLists.txt +++ b/algebra/CMakeLists.txt @@ -30,6 +30,8 @@ add_roughpy_component(Algebra src/double_lite_context.cpp src/rational_lite_context.cpp src/rational_poly_lite_context.cpp + src/libalgebra_lite_internal/algebra_type_caster.h + src/libalgebra_lite_internal/algebra_type_helper.h src/libalgebra_lite_internal/dense_vector_iterator.h src/libalgebra_lite_internal/free_tensor_info.h src/libalgebra_lite_internal/lie_basis_info.h @@ -39,6 +41,8 @@ add_roughpy_component(Algebra src/libalgebra_lite_internal/sparse_mutable_ref_scalar_trait.h src/libalgebra_lite_internal/sparse_vector_iterator.h src/libalgebra_lite_internal/tensor_basis_info.h + src/libalgebra_lite_internal/unspecified_algebra_binary_op.h + src/libalgebra_lite_internal/vector_storage_type.h src/libalgebra_lite_internal/vector_type_helper.h src/tensor_basis.cpp src/lie_basis.cpp diff --git a/algebra/include/roughpy/algebra/algebra_base.h b/algebra/include/roughpy/algebra/algebra_base.h index eb71f873..3b99c69b 100644 --- a/algebra/include/roughpy/algebra/algebra_base.h +++ b/algebra/include/roughpy/algebra/algebra_base.h @@ -66,10 +66,14 @@ class AlgebraInterfaceBase const scalars::ScalarType* p_coeff_type; VectorType m_vector_type; ImplementationType m_impl_type; + AlgebraType m_alg_type; explicit AlgebraInterfaceBase( - context_pointer&& ctx, VectorType vtype, - const scalars::ScalarType* stype, ImplementationType impl_type + context_pointer&& ctx, + VectorType vtype, + const scalars::ScalarType* stype, + ImplementationType impl_type, + AlgebraType alg_type ); public: @@ -86,6 +90,9 @@ class AlgebraInterfaceBase { return p_coeff_type; }; + RPY_NO_DISCARD + AlgebraType alg_type() const noexcept { return m_alg_type; } + }; template @@ -95,10 +102,13 @@ class AlgebraBasicProperties : public AlgebraInterfaceBase BasisType m_basis; AlgebraBasicProperties( - context_pointer&& ctx, VectorType vtype, - const scalars::ScalarType* stype, ImplementationType impl_type + context_pointer&& ctx, + VectorType vtype, + const scalars::ScalarType* stype, + ImplementationType impl_type ) - : AlgebraInterfaceBase(std::move(ctx), vtype, stype, impl_type), + : AlgebraInterfaceBase(std::move(ctx), vtype, stype, impl_type, + Algebra::s_alg_type), m_basis(basis_setup_helper::get(context())) {} diff --git a/algebra/include/roughpy/algebra/algebra_fwd.h b/algebra/include/roughpy/algebra/algebra_fwd.h index 27c1ad4d..571b606d 100644 --- a/algebra/include/roughpy/algebra/algebra_fwd.h +++ b/algebra/include/roughpy/algebra/algebra_fwd.h @@ -51,6 +51,9 @@ enum class VectorType Sparse }; +template +struct vector_type_tag {}; + /** * @brief Different algebra types required by RoughPy */ @@ -64,6 +67,9 @@ enum class AlgebraType : uint32_t LieBundle }; +template +struct algebra_type_tag {}; + template struct algebra_access; diff --git a/algebra/include/roughpy/algebra/context_fwd.h b/algebra/include/roughpy/algebra/context_fwd.h index c849184d..9ca1508f 100644 --- a/algebra/include/roughpy/algebra/context_fwd.h +++ b/algebra/include/roughpy/algebra/context_fwd.h @@ -40,7 +40,9 @@ switch (VTYPE) { \ case VectorType::Dense: return RPY_SWITCH_FN(VectorType::Dense); \ case VectorType::Sparse: return RPY_SWITCH_FN(VectorType::Sparse); \ - default: throw std::invalid_argument("invalid vector type"); \ + default: \ + RPY_UNREACHABLE(); \ + throw std::invalid_argument("invalid vector type"); \ } #define RPY_MAKE_ALGTYPE_SWITCH(ALGTYPE) \ @@ -50,7 +52,15 @@ case AlgebraType::Lie: return RPY_SWITCH_FN(AlgebraType::Lie); \ case AlgebraType::ShuffleTensor: \ return RPY_SWITCH_FN(AlgebraType::ShuffleTensor); \ - default: throw std::invalid_argument("invalid algebra type"); \ + case AlgebraType::FreeTensorBundle: \ + return RPY_SWITCH_FN(AlgebraType::FreeTensorBundle); \ + case AlgebraType::ShuffleTensorBundle: \ + return RPY_SWITCH_FN(AlgebraType::ShuffleTensorBundle); \ + case AlgebraType::LieBundle: \ + return RPY_SWITCH_FN(AlgebraType::LieBundle); \ + default: \ + RPY_UNREACHABLE(); \ + throw std::invalid_argument("invalid algebra type"); \ } namespace rpy { diff --git a/algebra/src/algebra_base.cpp b/algebra/src/algebra_base.cpp index c834991f..4c8460de 100644 --- a/algebra/src/algebra_base.cpp +++ b/algebra/src/algebra_base.cpp @@ -40,11 +40,14 @@ using namespace rpy; using namespace rpy::algebra; algebra::dtl::AlgebraInterfaceBase::AlgebraInterfaceBase( - context_pointer&& ctx, VectorType vtype, - const scalars::ScalarType* stype, ImplementationType impl_type + context_pointer&& ctx, + VectorType vtype, + const scalars::ScalarType* stype, + ImplementationType impl_type, + AlgebraType alg_type ) : p_ctx(std::move(ctx)), p_coeff_type(stype), m_vector_type(vtype), - m_impl_type(impl_type) + m_impl_type(impl_type), m_alg_type(alg_type) {} algebra::dtl::AlgebraInterfaceBase::~AlgebraInterfaceBase() = default; diff --git a/algebra/src/libalgebra_lite_internal/algebra_type_caster.h b/algebra/src/libalgebra_lite_internal/algebra_type_caster.h new file mode 100644 index 00000000..2882165f --- /dev/null +++ b/algebra/src/libalgebra_lite_internal/algebra_type_caster.h @@ -0,0 +1,106 @@ +// +// Created by user on 18/07/23. +// + +#ifndef ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_ALGEBRA_TYPE_CASTER_H_ +#define ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_ALGEBRA_TYPE_CASTER_H_ + +#include +#include +#include +#include +#include +#include + +#include "algebra_type_helper.h" +#include "lite_vector_selector.h" +#include "vector_type_helper.h" + +namespace rpy { +namespace algebra { + +template +struct algebra_type_selector; + +template <> +struct algebra_type_selector { + template + using type = typename dtl::vector_type_selector::template free_tensor; +}; +template <> +struct algebra_type_selector { + template + using type = + typename dtl::vector_type_selector::template shuffle_tensor; +}; +template <> +struct algebra_type_selector { + template + using type = typename dtl::vector_type_selector::template lie; +}; +template <> +struct algebra_type_selector { + template + using type = typename dtl::vector_type_selector::template free_tensor; +}; +template <> +struct algebra_type_selector { + template + using type = + typename dtl::vector_type_selector::template shuffle_tensor; +}; +template <> +struct algebra_type_selector { + template + using type = typename dtl::vector_type_selector::template lie; +}; + +template < + typename Coefficients, typename AlgebraTag = void, + typename VectorTag = void> +struct algebra_type_caster; + +template +struct algebra_type_caster { + template + using refine + = algebra_type_caster, void>; +}; + +template +struct algebra_type_caster { + template + using refine + = algebra_type_caster>; +}; + +template +struct algebra_type_caster< + Coefficients, algebra_type_tag, vector_type_tag> { + + using type = typename algebra_type_selector::template type< + Coefficients, VType>; + using info = dtl::alg_details_of; + using interface_t = typename info::interface_type; + + static type& cast(RawUnspecifiedAlgebraType arg) + { + RPY_CHECK(arg != nullptr); + RPY_CHECK(arg->alg_type() == AType); + RPY_CHECK(arg->storage_type() == VType); + auto* interface_ptr = reinterpret_cast(arg); + return algebra_cast(*interface_ptr); + } + static const type& cast(ConstRawUnspecifiedAlgebraType arg) { + RPY_CHECK(arg != nullptr); + RPY_CHECK(arg->alg_type() == AType); + RPY_CHECK(arg->storage_type() == VType); + const auto* interface_ptr = reinterpret_cast(arg); + return algebra_cast(*interface_ptr); + } +}; + +}// namespace algebra +}// namespace rpy + +#endif// ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_ALGEBRA_TYPE_CASTER_H_ diff --git a/algebra/src/libalgebra_lite_internal/algebra_type_helper.h b/algebra/src/libalgebra_lite_internal/algebra_type_helper.h new file mode 100644 index 00000000..0a140303 --- /dev/null +++ b/algebra/src/libalgebra_lite_internal/algebra_type_helper.h @@ -0,0 +1,65 @@ +// +// Created by user on 18/07/23. +// + +#ifndef ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_ALGEBRA_TYPE_HELPER_H_ +#define ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_ALGEBRA_TYPE_HELPER_H_ + +#include +#include +#include + +#include "vector_type_helper.h" +#include "vector_storage_type.h" + +namespace rpy { +namespace algebra { +namespace dtl { + +template +struct alg_details_of; + +template < + typename Coefficients, template class + LalVectorType, + template class StorageModel> +struct alg_details_of< + lal::free_tensor> { + using type = lal::free_tensor; + static constexpr AlgebraType alg_type = AlgebraType::FreeTensor; + using interface_type = FreeTensorInterface; + using wrapper_type = FreeTensor; + using implementation_type + = FreeTensorImplementation; +}; +template < + typename Coefficients, template class + LalVectorType, + template class StorageModel> +struct alg_details_of< + lal::shuffle_tensor> { + using type = lal::shuffle_tensor; + static constexpr AlgebraType alg_type = AlgebraType::ShuffleTensor; + using interface_type = ShuffleTensorInterface; + using wrapper_type = ShuffleTensor; + using implementation_type + = AlgebraImplementation; +}; + +template < + typename Coefficients, template class VectorType, + template class StorageModel> +struct alg_details_of> { + using type = lal::lie; + static constexpr AlgebraType alg_type = AlgebraType::Lie; + using interface_type = LieInterface; + using wrapper_type = Lie; + using implementation_type + = AlgebraImplementation; +}; +} + +}// namespace algebra +}// namespace rpy + +#endif// ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_ALGEBRA_TYPE_HELPER_H_ diff --git a/algebra/src/libalgebra_lite_internal/unspecified_algebra_binary_op.h b/algebra/src/libalgebra_lite_internal/unspecified_algebra_binary_op.h new file mode 100644 index 00000000..d44b38c0 --- /dev/null +++ b/algebra/src/libalgebra_lite_internal/unspecified_algebra_binary_op.h @@ -0,0 +1,209 @@ +// +// Created by user on 18/07/23. +// + +#ifndef ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_UNSPECIFIED_ALGEBRA_BINARY_OP_H_ +#define ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_UNSPECIFIED_ALGEBRA_BINARY_OP_H_ + +#include +#include + +namespace rpy { +namespace algebra { + +template < + template class CasterType, typename Context, + typename... ExpectedArgTypes> +class UnspecifiedFunctionInvoker; + +template < + template class CasterType, typename Context, + typename Current, typename... Remaining> +class UnspecifiedFunctionInvoker + : UnspecifiedFunctionInvoker +{ + using base = UnspecifiedFunctionInvoker; + + template < + AlgebraType AType, VectorType VType, typename Operation, + typename... Previous> + static UnspecifiedAlgebraType cast_and_continue( + const Context* ctx, Operation&& op, Current this_arg, + Remaining... remaining, Previous&&... previous + ) + { + using caster = CasterType; + return base::eval( + ctx, forward(op), remaining..., + forward(previous)..., + caster::cast(forward(this_arg)) + ); + } + + template + static enable_if_t< + Operation::template compatible::value, + UnspecifiedAlgebraType> + cast_vtype( + const Context* ctx, Operation&& op, Current this_arg, + Remaining... remaining, Previous&&... previous + ) + { +#define RPY_SWITCH_FN(VTYPE) \ + cast_and_continue( \ + ctx, forward(op), this_arg, remaining..., \ + forward(previous)... \ + ) + RPY_MAKE_VTYPE_SWITCH(this_arg->storage_type()) +#undef RPY_SWITCH_FN + } + + template + static enable_if_t< + !Operation::template compatible::value, + UnspecifiedAlgebraType> + cast_vtype( + const Context* ctx, Operation&& op, Current last_arg, + Previous&&... previous + ) + { + throw std::runtime_error("this operation is not defined for these " + "types"); + } + template + static UnspecifiedAlgebraType cast_atype( + const Context* ctx, Operation&& op, Current this_arg, + Remaining... remaining, Previous&&... previous + ) + { +#define RPY_SWITCH_FN(ATYPE) \ + cast_vtype( \ + ctx, forward(op), this_arg, remaining..., \ + forward(previous)... \ + ) + RPY_MAKE_ALGTYPE_SWITCH(this_arg->alg_type()) +#undef RPY_SWITCH_FN + } + +public: + template + static UnspecifiedAlgebraType + eval(const Context* ctx, Operation&& op, Current this_arg, + Remaining... remaining, Previous&&... previous) + { + return cast_atype( + ctx, forward(op), this_arg, remaining..., + forward(previous)... + ); + } + + // template + // static UnspecifiedAlgebraType + // eval(const Context* ctx, Operation&& op, Current&& this_arg, + // Remaining&&... remaining) + // { + // return cast_atype( + // ctx, + // forward(op), + // forward(this_arg), + // forward(remaining)... + // ); + // } +}; + +template < + template class CasterType, typename Context, + typename Last> +class UnspecifiedFunctionInvoker +{ + + template + static UnspecifiedAlgebraType + eval_func(const Context* ctx, Operation&& op, Args&&... args) + { + using out_type = decltype(op(forward(args)...)); + using impl_t = + typename dtl::alg_details_of::implementation_type; + return UnspecifiedAlgebraType( + new impl_t(ctx, op(forward(args)...)) + ); + } + + template < + AlgebraType AType, VectorType VType, typename Operation, + typename... Previous> + static UnspecifiedAlgebraType cast_and_continue( + const Context* ctx, Operation&& op, Last this_arg, + Previous&&... previous + ) + { + using caster = CasterType; + return eval_func( + ctx, forward(op), forward(previous)..., + caster::cast(this_arg) + ); + } + + template + static enable_if_t< + Operation::template compatible::value, + UnspecifiedAlgebraType> + cast_vtype( + const Context* ctx, Operation&& op, Last this_arg, + Previous&&... previous + ) + { +#define RPY_SWITCH_FN(VTYPE) \ + cast_and_continue( \ + ctx, forward(op), this_arg, \ + forward(previous)... \ + ) + RPY_MAKE_VTYPE_SWITCH(this_arg->storage_type()) +#undef RPY_SWITCH_FN + } + + template + static enable_if_t< + !Operation::template compatible::value, + UnspecifiedAlgebraType> + cast_vtype( + const Context* ctx, Operation&& op, Last last_arg, + Previous&&... previous + ) + { + throw std::runtime_error("this operation is not defined for these " + "types"); + } + + template + static UnspecifiedAlgebraType cast_atype( + const Context* ctx, Operation&& op, Last this_arg, + Previous&&... previous + ) + { +#define RPY_SWITCH_FN(ATYPE) \ + cast_vtype( \ + ctx, forward(op), this_arg, \ + forward(previous)... \ + ) + RPY_MAKE_ALGTYPE_SWITCH(this_arg->alg_type()) +#undef RPY_SWITCH_FN + } + +public: + template + static UnspecifiedAlgebraType + eval(const Context* ctx, Operation&& op, Last this_arg, + Previous&&... previous) + { + return cast_atype( + ctx, forward(op), this_arg, + forward(previous)... + ); + } +}; + +}// namespace algebra +}// namespace rpy + +#endif// ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_UNSPECIFIED_ALGEBRA_BINARY_OP_H_ diff --git a/algebra/src/libalgebra_lite_internal/vector_storage_type.h b/algebra/src/libalgebra_lite_internal/vector_storage_type.h new file mode 100644 index 00000000..42e422f6 --- /dev/null +++ b/algebra/src/libalgebra_lite_internal/vector_storage_type.h @@ -0,0 +1,36 @@ +// +// Created by user on 18/07/23. +// + +#ifndef ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_VECTOR_STORAGE_TYPE_H_ +#define ROUGHPY_ALGEBRA_SRC_LIBALGEBRA_LITE_INTERNAL_VECTOR_STORAGE_TYPE_H_ + +#include +#include + +#include + +namespace rpy { +namespace algebra { +namespace dtl { + +template