diff --git a/.github/workflows/wheels.yaml b/.github/workflows/wheels.yaml index 7f549c41..1395c1c8 100644 --- a/.github/workflows/wheels.yaml +++ b/.github/workflows/wheels.yaml @@ -334,7 +334,7 @@ jobs: LIBRAPID_GET_FFTW: OFF CC: /usr/local/opt/llvm/bin/clang CXX: /usr/local/opt/llvm/bin/clang++ - CIBW_ENVIRONMENT: CC=/usr/local/opt/llvm/bin/clang CXX=/usr/local/opt/llvm/bin/clang++ + CIBW_ENVIRONMENT: CC=/usr/local/opt/llvm/bin/clang CXX=/usr/local/opt/llvm/bin/clang++ CMAKE_BUILD_PARALLEL_LEVEL=1 CMAKE_C_COMPILER: /usr/local/opt/llvm/bin/clang CMAKE_CXX_COMPILER: /usr/local/opt/llvm/bin/clang++ @@ -357,7 +357,7 @@ jobs: LIBRAPID_GET_FFTW: OFF CC: ${RUNNER_TOOL_CACHE}/llvm/bin/clang CXX: ${RUNNER_TOOL_CACHE}/llvm/bin/clang++ - CIBW_ENVIRONMENT: CC=${RUNNER_TOOL_CACHE}/llvm/bin/clang CXX=${RUNNER_TOOL_CACHE}/llvm/bin/clang++ + CIBW_ENVIRONMENT: CC=${RUNNER_TOOL_CACHE}/llvm/bin/clang CXX=${RUNNER_TOOL_CACHE}/llvm/bin/clang++ CMAKE_BUILD_PARALLEL_LEVEL=1 CMAKE_C_COMPILER: ${RUNNER_TOOL_CACHE}/llvm/bin/clang CMAKE_CXX_COMPILER: ${RUNNER_TOOL_CACHE}/llvm/bin/clang++ @@ -378,6 +378,7 @@ jobs: GITHUB_ACTIONS: ON LIBRAPID_GET_BLAS: ON LIBRAPID_GET_FFTW: OFF + CIBW_ENVIRONMENT: CMAKE_BUILD_PARALLEL_LEVEL=1 - name: Store Artifacts uses: actions/upload-artifact@v3 diff --git a/CMakeLists.txt b/CMakeLists.txt index 816aa1d4..90158fb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,12 @@ if (${SKBUILD}) ) FetchContent_MakeAvailable(pybind11) + # Set CMAKE_BUILD_PARALLEL_LEVEL=1 to reduce memory usage + set(CMAKE_BUILD_PARALLEL_LEVEL 1) + + # Set environment variable CMAKE_BUILD_PARALLEL_LEVEL=1 to reduce memory usage + set(ENV{CMAKE_BUILD_PARALLEL_LEVEL} 1) + # Run auto-generation script # 1. Find the Python executable # 2. cd into 'librapid/bindings/generators' diff --git a/examples/example-cuda.cpp b/examples/example-cuda.cpp index 24ea1070..3783bd92 100644 --- a/examples/example-cuda.cpp +++ b/examples/example-cuda.cpp @@ -4,7 +4,7 @@ namespace lrc = librapid; auto main() -> int { #if defined(LIBRAPID_HAS_CUDA) - auto cudaArray = lrc::Array::fromData({{1, 2, 3}, {4, 5, 6}}); + auto cudaArray = lrc::Array({{1, 2, 3}, {4, 5, 6}}); fmt::print("CUDA Array:\n{}\n", cudaArray); // Operations on CUDA arrays work exactly the same as on CPU arrays @@ -26,13 +26,13 @@ auto main() -> int { // Linear algebra operations also work fmt::print("Transposed CUDA Array:\n{}\n", lrc::transpose(prod)); - auto vector = lrc::Array::fromData({{1, 2, 3}}); + auto vector = lrc::Array({{1, 2, 3}}); fmt::print("Array: \n{}\n", cudaArray); fmt::print("Vector: \n{}\n", vector); fmt::print("Matrix dot Vector^T:\n{}\n", lrc::dot(cudaArray, lrc::transpose(vector))); #else fmt::print("CUDA not enabled in this build of librapid\n"); - fmt::print("Check the documentation for more information on enabling OpenCL\n"); + fmt::print("Check the documentation for more information on enabling CUDA\n"); fmt::print("https://librapid.readthedocs.io/en/latest/cmakeIntegration.html#librapid-use-cuda\n"); #endif // LIBRAPID_HAS_CUDA diff --git a/examples/example-opencl.cpp b/examples/example-opencl.cpp index 55ce19de..3d88112d 100644 --- a/examples/example-opencl.cpp +++ b/examples/example-opencl.cpp @@ -9,7 +9,7 @@ auto main() -> int { // (You can pass (true, true) to select the device manually) lrc::configureOpenCL(true); - auto openclArray = lrc::Array::fromData({{1, 2, 3}, {4, 5, 6}}); + auto openclArray = lrc::Array({{1, 2, 3}, {4, 5, 6}}); fmt::print("OpenCL Array:\n{}\n", openclArray); // Operations on OpenCL arrays work exactly the same as on CPU arrays @@ -31,7 +31,7 @@ auto main() -> int { // Linear algebra operations also work fmt::print("Transposed OpenCL Array:\n{}\n", lrc::transpose(prod)); - auto vector = lrc::Array::fromData({{1, 2, 3}}); + auto vector = lrc::Array({{1, 2, 3}}); fmt::print("Array: \n{}\n", openclArray); fmt::print("Vector: \n{}\n", vector); fmt::print("Matrix dot Vector^T:\n{}\n", lrc::dot(openclArray, lrc::transpose(vector))); diff --git a/librapid/include/librapid/array/shape.hpp b/librapid/include/librapid/array/shape.hpp index 5440413f..1098f757 100644 --- a/librapid/include/librapid/array/shape.hpp +++ b/librapid/include/librapid/array/shape.hpp @@ -784,8 +784,7 @@ namespace librapid { /// \param shapes Remaining (optional) inputs /// \return True if all inputs have the same shape, false otherwise template - requires(typetraits::IsSizeType::value && - typetraits::IsSizeType::value && + requires(typetraits::IsSizeType::value && typetraits::IsSizeType::value && (typetraits::IsSizeType::value && ...)) LIBRAPID_NODISCARD LIBRAPID_INLINE bool shapesMatch(const std::tuple &shapes) { @@ -797,17 +796,21 @@ namespace librapid { [](auto, auto, auto... rest) { return std::make_tuple(rest...); }, shapes)); } } - + + template + requires(typetraits::IsSizeType::value) + LIBRAPID_NODISCARD LIBRAPID_INLINE bool + shapesMatch(const std::tuple &shapes) { + return true; + } + /// \sa shapesMatch // template - // requires(typetraits::IsSizeType::value && typetraits::IsSizeType::value && - // (typetraits::IsSizeType::value && ...)) - // LIBRAPID_NODISCARD LIBRAPID_INLINE bool shapesMatch(const First &first, const Second &second, - // const Rest &...shapes) { - // if constexpr (sizeof...(Rest) == 0) { - // return first == second; - // } else { - // return first == second && shapesMatch(first, shapes...); + // requires(typetraits::IsSizeType::value && typetraits::IsSizeType::value + //&& (typetraits::IsSizeType::value && ...)) LIBRAPID_NODISCARD LIBRAPID_INLINE bool + //shapesMatch(const First &first, const Second &second, const Rest &...shapes) { if constexpr + //(sizeof...(Rest) == 0) { return first == second; } else { return first == second && + //shapesMatch(first, shapes...); // } // } diff --git a/librapid/include/librapid/autodiff/dual.hpp b/librapid/include/librapid/autodiff/dual.hpp index 7ba0e749..17500870 100644 --- a/librapid/include/librapid/autodiff/dual.hpp +++ b/librapid/include/librapid/autodiff/dual.hpp @@ -2,426 +2,406 @@ #define LIBRAPID_AUTODIFF_DUAL #if defined(LIBRAPID_IN_JITIFY) -# define IS_SCALAR(TYPE) false +# define IS_SCALAR(TYPE) false #else -# define IS_SCALAR(TYPE) std::is_scalar_v +# define IS_SCALAR(TYPE) std::is_scalar_v #endif // LIBRAPID_IN_JITIFY #if !defined(LIBRAPID_IN_JITIFY) namespace librapid { #endif - template - class Dual { - public: + template + class Dual { + public: #if defined(LIBRAPID_IN_JITIFY) - using Scalar = T; - using Packet = T; - static constexpr uint64_t packetWidth = 1; + using Scalar = T; + using Packet = T; + static constexpr uint64_t packetWidth = 1; #else - using Scalar = typename typetraits::TypeInfo::Scalar; - using Packet = typename typetraits::TypeInfo::Packet; - static constexpr uint64_t packetWidth = typetraits::TypeInfo::packetWidth; + using Scalar = typename typetraits::TypeInfo::Scalar; + using Packet = typename typetraits::TypeInfo::Packet; + static constexpr uint64_t packetWidth = typetraits::TypeInfo::packetWidth; #endif - Scalar value; - Scalar derivative; - - Dual() = default; - explicit Dual(Scalar value) : value(value), derivative(Scalar()) {} - Dual(Scalar value, Scalar derivative) : value(value), derivative(derivative) {} - - template - explicit Dual(const Dual &other) : value(other.value), derivative(other.derivative) {} - - template - explicit Dual(Dual &&other) : - value(std::move(other.value)), derivative(std::move(other.derivative)) {} - - template - auto operator=(const Dual &other) -> Dual & { - value = other.value; - derivative = other.derivative; - return *this; - } - - template - auto operator=(Dual &&other) -> Dual & { - value = std::move(other.value); - derivative = std::move(other.derivative); - return *this; - } - - static constexpr auto size() -> size_t { return typetraits::TypeInfo::packetWidth; } - - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator+=(const Dual &other) -> Dual & { - value += other.value; - derivative += other.derivative; - return *this; - } - - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator-=(const Dual &other) -> Dual & { - value -= other.value; - derivative -= other.derivative; - return *this; - } - - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator*=(const Dual &other) -> Dual & { - value *= other.value; - derivative = derivative * other.value + value * other.derivative; - return *this; - } - - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator/=(const Dual &other) -> Dual & { - value /= other.value; - derivative = - (derivative * other.value - value * other.derivative) / (other.value * other.value); - return *this; - } - - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator+=(const T &other) -> Dual & { - value += other; - return *this; - } - - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator-=(const T &other) -> Dual & { - value -= other; - return *this; - } - - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator*=(const T &other) -> Dual & { - value *= other; - derivative *= other; - return *this; - } - - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator/=(const T &other) -> Dual & { - value /= other; - derivative /= other; - return *this; - } + Scalar value; + Scalar derivative; + + Dual() = default; + explicit Dual(Scalar value) : value(value), derivative(Scalar()) {} + Dual(Scalar value, Scalar derivative) : value(value), derivative(derivative) {} + + template + explicit Dual(const Dual &other) : value(other.value), derivative(other.derivative) {} + + template + explicit Dual(Dual &&other) : + value(std::move(other.value)), derivative(std::move(other.derivative)) {} + + template + auto operator=(const Dual &other) -> Dual & { + value = other.value; + derivative = other.derivative; + return *this; + } + + template + auto operator=(Dual &&other) -> Dual & { + value = std::move(other.value); + derivative = std::move(other.derivative); + return *this; + } + + static constexpr auto size() -> size_t { return typetraits::TypeInfo::packetWidth; } + + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator+=(const Dual &other) -> Dual & { + value += other.value; + derivative += other.derivative; + return *this; + } + + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator-=(const Dual &other) -> Dual & { + value -= other.value; + derivative -= other.derivative; + return *this; + } + + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator*=(const Dual &other) -> Dual & { + value *= other.value; + derivative = derivative * other.value + value * other.derivative; + return *this; + } + + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator/=(const Dual &other) -> Dual & { + value /= other.value; + derivative = + (derivative * other.value - value * other.derivative) / (other.value * other.value); + return *this; + } + + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator+=(const T &other) -> Dual & { + value += other; + return *this; + } + + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator-=(const T &other) -> Dual & { + value -= other; + return *this; + } + + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator*=(const T &other) -> Dual & { + value *= other; + derivative *= other; + return *this; + } + + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto operator/=(const T &other) -> Dual & { + value /= other; + derivative /= other; + return *this; + } #if !defined(LIBRAPID_IN_JITIFY) - template - void str(const fmt::formatter &format, Ctx &ctx) const { - fmt::format_to(ctx.out(), "Dual("); - format.format(value, ctx); - fmt::format_to(ctx.out(), ", "); - format.format(derivative, ctx); - fmt::format_to(ctx.out(), ")"); - } + template + void str(const fmt::formatter &format, Ctx &ctx) const { + fmt::format_to(ctx.out(), "Dual("); + format.format(value, ctx); + fmt::format_to(ctx.out(), ", "); + format.format(derivative, ctx); + fmt::format_to(ctx.out(), ")"); + } #endif // !defined(LIBRAPID_IN_JITIFY) - }; - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator+(const Dual &lhs, const Dual &rhs) { - return {lhs.value + rhs.value, lhs.derivative + rhs.derivative}; - } - - template requires(IS_SCALAR(V)) - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator+(const Dual &lhs, const V &rhs) { - return {lhs.value + rhs, lhs.derivative}; - } - - template requires(IS_SCALAR(V)) - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator+(const V &lhs, const Dual &rhs) { - return {lhs + rhs.value, rhs.derivative}; - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator-(const Dual &lhs, const Dual &rhs) { - return {lhs.value - rhs.value, lhs.derivative - rhs.derivative}; - } - - template requires(IS_SCALAR(V)) - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator-(const Dual &lhs, const V &rhs) { - return {lhs.value - rhs, lhs.derivative}; - } - - template requires(IS_SCALAR(V)) - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator-(const V &lhs, const Dual &rhs) { - return {lhs - rhs.value, -rhs.derivative}; - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator*(const Dual &lhs, const Dual &rhs) { - return {lhs.value * rhs.value, lhs.derivative * rhs.value + lhs.value * rhs.derivative}; - } - - template requires(IS_SCALAR(V)) - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator*(const Dual &lhs, const V &rhs) { - return {lhs.value * rhs, lhs.derivative * rhs}; - } - - template requires(IS_SCALAR(V)) - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator*(const V &lhs, const Dual &rhs) { - return {lhs * rhs.value, lhs * rhs.derivative}; - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator/(const Dual &lhs, const Dual &rhs) { - return {lhs.value / rhs.value, - (lhs.derivative * rhs.value - lhs.value * rhs.derivative) / - (rhs.value * rhs.value)}; - } - - template requires(IS_SCALAR(V)) - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator/(const Dual &lhs, const V &rhs) { - return {lhs.value / rhs, lhs.derivative / rhs}; - } - - template requires(IS_SCALAR(V)) - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual - operator/(const V &lhs, const Dual &rhs) { - return {lhs / rhs.value, -lhs * rhs.derivative / (rhs.value * rhs.value)}; - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual operator-(const Dual &lhs) { - return {-lhs.value, -lhs.derivative}; - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual operator+(const Dual &lhs) { - return {lhs.value, lhs.derivative}; - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual sin(const Dual &x) { - using Ret = decltype(::librapid::sin(x.value)); - return Dual(::librapid::sin(x.value), ::librapid::cos(x.value) * x.derivative); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual cos(const Dual &x) { - using Ret = decltype(::librapid::cos(x.value)); - return Dual(::librapid::cos(x.value), -::librapid::sin(x.value) * x.derivative); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual tan(const Dual &x) { - using Ret = decltype(::librapid::tan(x.value)); - auto cosX = ::librapid::cos(x.value); - return Dual(::librapid::tan(x.value), x.derivative / (cosX * cosX)); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual asin(const Dual &x) { - using Ret = decltype(::librapid::asin(x.value)); - return Dual(::librapid::asin(x.value), - x.derivative / ::librapid::sqrt(1 - x.value * x.value)); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual acos(const Dual &x) { - using Ret = decltype(::librapid::acos(x.value)); - return Dual(::librapid::acos(x.value), - -x.derivative / ::librapid::sqrt(1 - x.value * x.value)); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual atan(const Dual &x) { - using Ret = decltype(::librapid::atan(x.value)); - return Dual(::librapid::atan(x.value), x.derivative / (1 + x.value * x.value)); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual sinh(const Dual &x) { - using Ret = decltype(::librapid::sinh(x.value)); - return Dual(::librapid::sinh(x.value), ::librapid::cosh(x.value) * x.derivative); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual cosh(const Dual &x) { - using Ret = decltype(::librapid::cosh(x.value)); - return Dual(::librapid::cosh(x.value), ::librapid::sinh(x.value) * x.derivative); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual tanh(const Dual &x) { - using Ret = decltype(::librapid::tanh(x.value)); - auto coshX = ::librapid::cosh(x.value); - return Dual(::librapid::tanh(x.value), x.derivative / (coshX * coshX)); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual asinh(const Dual &x) { - using Ret = decltype(::librapid::asinh(x.value)); - return Dual(::librapid::asinh(x.value), - x.derivative / ::librapid::sqrt(1 + x.value * x.value)); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual acosh(const Dual &x) { - using Ret = decltype(::librapid::acosh(x.value)); - return Dual(::librapid::acosh(x.value), - x.derivative / ::librapid::sqrt(x.value * x.value - 1)); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual atanh(const Dual &x) { - using Ret = decltype(::librapid::atanh(x.value)); - return Dual(::librapid::atanh(x.value), x.derivative / (1 - x.value * x.value)); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual exp(const Dual &x) { - using Ret = decltype(::librapid::exp(x.value)); - auto expX = ::librapid::exp(x.value); - return Dual(expX, expX * x.derivative); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual exp2(const Dual &x) { - using Ret = decltype(::librapid::exp2(x.value)); - auto exp2X = ::librapid::exp2(x.value); - return Dual(exp2X, exp2X * ::librapid::log(2) * x.derivative); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual exp10(const Dual &x) { - using Ret = decltype(::librapid::exp2(x.value)); - auto exp2X = ::librapid::exp10(x.value); - return Dual(exp2X, exp2X * ::librapid::log(10) * x.derivative); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual log(const Dual &x) { - using Ret = decltype(::librapid::log(x.value)); - return Dual(::librapid::log(x.value), x.derivative / x.value); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual log10(const Dual &x) { - using Ret = decltype(::librapid::log10(x.value)); - return Dual(::librapid::log10(x.value), - x.derivative / (x.value * ::librapid::log(10))); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual log2(const Dual &x) { - using Ret = decltype(::librapid::log2(x.value)); - return Dual(::librapid::log2(x.value), x.derivative / (x.value * ::librapid::log(2))); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual sqrt(const Dual &x) { - using Ret = decltype(::librapid::sqrt(x.value)); - return Dual(::librapid::sqrt(x.value), x.derivative / (2 * ::librapid::sqrt(x.value))); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual cbrt(const Dual &x) { - using Ret = decltype(::librapid::cbrt(x.value)); - return Dual(::librapid::cbrt(x.value), - x.derivative / (3 * ::librapid::cbrt(x.value * x.value))); - } - - template requires(IS_SCALAR(V)) - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual pow(const Dual &x, const V &y) { - using Ret = decltype(::librapid::pow(x.value, y)); - return Dual(::librapid::pow(x.value, y), - y * ::librapid::pow(x.value, y - 1) * x.derivative); - } - - template requires(IS_SCALAR(V)) - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual pow(const V &x, const Dual &y) { - using Ret = decltype(::librapid::pow(x, y.value)); - return Dual(::librapid::pow(x, y.value), - ::librapid::log(x) * ::librapid::pow(x, y.value) * y.derivative); - } - - template - LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual pow(const Dual &x, const Dual &y) { - using Ret = decltype(::librapid::pow(x.value, y.value)); - return Dual( - ::librapid::pow(x.value, y.value), - ::librapid::pow(x.value, y.value) * - (y.derivative * ::librapid::log(x.value) + y.value * x.derivative / x.value)); - } + }; + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator+(const Dual &lhs, const Dual &rhs) { + return {lhs.value + rhs.value, lhs.derivative + rhs.derivative}; + } + + template + requires(IS_SCALAR(V)) + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator+(const Dual &lhs, const V &rhs) { + return {lhs.value + rhs, lhs.derivative}; + } + + template + requires(IS_SCALAR(V)) + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator+(const V &lhs, const Dual &rhs) { + return {lhs + rhs.value, rhs.derivative}; + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator-(const Dual &lhs, const Dual &rhs) { + return {lhs.value - rhs.value, lhs.derivative - rhs.derivative}; + } + + template + requires(IS_SCALAR(V)) + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator-(const Dual &lhs, const V &rhs) { + return {lhs.value - rhs, lhs.derivative}; + } + + template + requires(IS_SCALAR(V)) + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator-(const V &lhs, const Dual &rhs) { + return {lhs - rhs.value, -rhs.derivative}; + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator*(const Dual &lhs, const Dual &rhs) { + return {lhs.value * rhs.value, lhs.derivative * rhs.value + lhs.value * rhs.derivative}; + } + + template + requires(IS_SCALAR(V)) + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator*(const Dual &lhs, const V &rhs) { + return {lhs.value * rhs, lhs.derivative * rhs}; + } + + template + requires(IS_SCALAR(V)) + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator*(const V &lhs, const Dual &rhs) { + return {lhs * rhs.value, lhs * rhs.derivative}; + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator/(const Dual &lhs, const Dual &rhs) { + return {lhs.value / rhs.value, + (lhs.derivative * rhs.value - lhs.value * rhs.derivative) / + (rhs.value * rhs.value)}; + } + + template + requires(IS_SCALAR(V)) + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator/(const Dual &lhs, const V &rhs) { + return {lhs.value / rhs, lhs.derivative / rhs}; + } + + template + requires(IS_SCALAR(V)) + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual + operator/(const V &lhs, const Dual &rhs) { + return {lhs / rhs.value, -lhs * rhs.derivative / (rhs.value * rhs.value)}; + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual operator-(const Dual &lhs) { + return {-lhs.value, -lhs.derivative}; + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual operator+(const Dual &lhs) { + return {lhs.value, lhs.derivative}; + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual sin(const Dual &x) { + using Ret = decltype(::librapid::sin(x.value)); + return Dual(::librapid::sin(x.value), ::librapid::cos(x.value) * x.derivative); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual cos(const Dual &x) { + using Ret = decltype(::librapid::cos(x.value)); + return Dual(::librapid::cos(x.value), -::librapid::sin(x.value) * x.derivative); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual tan(const Dual &x) { + using Ret = decltype(::librapid::tan(x.value)); + auto cosX = ::librapid::cos(x.value); + return Dual(::librapid::tan(x.value), x.derivative / (cosX * cosX)); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual asin(const Dual &x) { + using Ret = decltype(::librapid::asin(x.value)); + return Dual(::librapid::asin(x.value), + x.derivative / ::librapid::sqrt(1 - x.value * x.value)); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual acos(const Dual &x) { + using Ret = decltype(::librapid::acos(x.value)); + return Dual(::librapid::acos(x.value), + -x.derivative / ::librapid::sqrt(1 - x.value * x.value)); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual atan(const Dual &x) { + using Ret = decltype(::librapid::atan(x.value)); + return Dual(::librapid::atan(x.value), x.derivative / (1 + x.value * x.value)); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual sinh(const Dual &x) { + using Ret = decltype(::librapid::sinh(x.value)); + return Dual(::librapid::sinh(x.value), ::librapid::cosh(x.value) * x.derivative); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual cosh(const Dual &x) { + using Ret = decltype(::librapid::cosh(x.value)); + return Dual(::librapid::cosh(x.value), ::librapid::sinh(x.value) * x.derivative); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual tanh(const Dual &x) { + using Ret = decltype(::librapid::tanh(x.value)); + auto coshX = ::librapid::cosh(x.value); + return Dual(::librapid::tanh(x.value), x.derivative / (coshX * coshX)); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual asinh(const Dual &x) { + using Ret = decltype(::librapid::asinh(x.value)); + return Dual(::librapid::asinh(x.value), + x.derivative / ::librapid::sqrt(1 + x.value * x.value)); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual acosh(const Dual &x) { + using Ret = decltype(::librapid::acosh(x.value)); + return Dual(::librapid::acosh(x.value), + x.derivative / ::librapid::sqrt(x.value * x.value - 1)); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual atanh(const Dual &x) { + using Ret = decltype(::librapid::atanh(x.value)); + return Dual(::librapid::atanh(x.value), x.derivative / (1 - x.value * x.value)); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual exp(const Dual &x) { + using Ret = decltype(::librapid::exp(x.value)); + auto expX = ::librapid::exp(x.value); + return Dual(expX, expX * x.derivative); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual exp2(const Dual &x) { + using Ret = decltype(::librapid::exp2(x.value)); + auto exp2X = ::librapid::exp2(x.value); + return Dual(exp2X, exp2X * ::librapid::log(2) * x.derivative); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual exp10(const Dual &x) { + using Ret = decltype(::librapid::exp2(x.value)); + auto exp2X = ::librapid::exp10(x.value); + return Dual(exp2X, exp2X * ::librapid::log(10) * x.derivative); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual log(const Dual &x) { + using Ret = decltype(::librapid::log(x.value)); + return Dual(::librapid::log(x.value), x.derivative / x.value); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual log10(const Dual &x) { + using Ret = decltype(::librapid::log10(x.value)); + return Dual(::librapid::log10(x.value), + x.derivative / (x.value * ::librapid::log(10))); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual log2(const Dual &x) { + using Ret = decltype(::librapid::log2(x.value)); + return Dual(::librapid::log2(x.value), x.derivative / (x.value * ::librapid::log(2))); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual sqrt(const Dual &x) { + using Ret = decltype(::librapid::sqrt(x.value)); + return Dual(::librapid::sqrt(x.value), x.derivative / (2 * ::librapid::sqrt(x.value))); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual cbrt(const Dual &x) { + using Ret = decltype(::librapid::cbrt(x.value)); + return Dual(::librapid::cbrt(x.value), + x.derivative / (3 * ::librapid::cbrt(x.value * x.value))); + } + + template + requires(IS_SCALAR(V)) + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual pow(const Dual &x, const V &y) { + using Ret = decltype(::librapid::pow(x.value, y)); + return Dual(::librapid::pow(x.value, y), + y * ::librapid::pow(x.value, y - 1) * x.derivative); + } + + template + requires(IS_SCALAR(V)) + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual pow(const V &x, const Dual &y) { + using Ret = decltype(::librapid::pow(x, y.value)); + return Dual(::librapid::pow(x, y.value), + ::librapid::log(x) * ::librapid::pow(x, y.value) * y.derivative); + } + + template + LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE Dual pow(const Dual &x, const Dual &y) { + using Ret = decltype(::librapid::pow(x.value, y.value)); + return Dual( + ::librapid::pow(x.value, y.value), + ::librapid::pow(x.value, y.value) * + (y.derivative * ::librapid::log(x.value) + y.value * x.derivative / x.value)); + } #if !defined(LIBRAPID_IN_JITIFY) - namespace typetraits { - template - struct TypeInfo> { - static constexpr detail::LibRapidType type = detail::LibRapidType::Dual; - using Scalar = T; - using Packet = std::false_type; // Dual::Packet>; - static constexpr int64_t packetWidth = - 0; // TypeInfo::Scalar>::packetWidth; - using Backend = backend::CPU; - - static constexpr char name[] = "Dual_T"; - - static constexpr bool supportsArithmetic = TypeInfo::supportsArithmetic; - static constexpr bool supportsLogical = TypeInfo::supportsLogical; - static constexpr bool supportsBinary = TypeInfo::supportsBinary; - static constexpr bool allowVectorisation = false; // TypeInfo::allowVectorisation; - -# if defined(LIBRAPID_HAS_CUDA) - static constexpr cudaDataType_t CudaType = TypeInfo::CudaType; - static constexpr int64_t cudaPacketWidth = 1; -# endif // LIBRAPID_HAS_CUDA - - static constexpr bool canAlign = TypeInfo::canAlign; - static constexpr int64_t canMemcpy = TypeInfo::canMemcpy; - - LIMIT_IMPL_CONSTEXPR(min) { return NUM_LIM(min); } - LIMIT_IMPL_CONSTEXPR(max) { return NUM_LIM(max); } - LIMIT_IMPL_CONSTEXPR(epsilon) { return NUM_LIM(epsilon); } - LIMIT_IMPL_CONSTEXPR(roundError) { return NUM_LIM(round_error); } - LIMIT_IMPL_CONSTEXPR(denormMin) { return NUM_LIM(denorm_min); } - LIMIT_IMPL_CONSTEXPR(infinity) { return NUM_LIM(infinity); } - LIMIT_IMPL_CONSTEXPR(quietNaN) { return NUM_LIM(quiet_NaN); } - LIMIT_IMPL_CONSTEXPR(signalingNaN) { return NUM_LIM(signaling_NaN); } - }; - - template<> - struct TypeInfo> { - static constexpr detail::LibRapidType type = detail::LibRapidType::Dual; - using Scalar = float; - using Packet = std::false_type; // Dual::Packet>; - static constexpr int64_t packetWidth = - 0; // TypeInfo::Scalar>::packetWidth; - using Backend = backend::CPU; - - static constexpr char name[] = "Dual_float"; - - static constexpr bool supportsArithmetic = TypeInfo::supportsArithmetic; - static constexpr bool supportsLogical = TypeInfo::supportsLogical; - static constexpr bool supportsBinary = TypeInfo::supportsBinary; - static constexpr bool allowVectorisation = - false; // TypeInfo::allowVectorisation; - -# if defined(LIBRAPID_HAS_CUDA) - static constexpr cudaDataType_t CudaType = TypeInfo::CudaType; - static constexpr int64_t cudaPacketWidth = 1; -# endif // LIBRAPID_HAS_CUDA - - static constexpr bool canAlign = TypeInfo::canAlign; - static constexpr int64_t canMemcpy = TypeInfo::canMemcpy; - - LIMIT_IMPL_CONSTEXPR(min) { return NUM_LIM(min); } - LIMIT_IMPL_CONSTEXPR(max) { return NUM_LIM(max); } - LIMIT_IMPL_CONSTEXPR(epsilon) { return NUM_LIM(epsilon); } - LIMIT_IMPL_CONSTEXPR(roundError) { return NUM_LIM(round_error); } - LIMIT_IMPL_CONSTEXPR(denormMin) { return NUM_LIM(denorm_min); } - LIMIT_IMPL_CONSTEXPR(infinity) { return NUM_LIM(infinity); } - LIMIT_IMPL_CONSTEXPR(quietNaN) { return NUM_LIM(quiet_NaN); } - LIMIT_IMPL_CONSTEXPR(signalingNaN) { return NUM_LIM(signaling_NaN); } - }; - } // namespace typetraits + namespace typetraits { + template + struct TypeInfo> { + static constexpr detail::LibRapidType type = detail::LibRapidType::Dual; + using Scalar = T; + using Packet = std::false_type; // Dual::Packet>; + static constexpr int64_t packetWidth = + 0; // TypeInfo::Scalar>::packetWidth; + using Backend = backend::CPU; + + static constexpr char name[] = "Dual_T"; + + static constexpr bool supportsArithmetic = TypeInfo::supportsArithmetic; + static constexpr bool supportsLogical = TypeInfo::supportsLogical; + static constexpr bool supportsBinary = TypeInfo::supportsBinary; + static constexpr bool allowVectorisation = false; // TypeInfo::allowVectorisation; + +# if defined(LIBRAPID_HAS_CUDA) + static constexpr cudaDataType_t CudaType = TypeInfo::CudaType; + static constexpr int64_t cudaPacketWidth = 1; +# endif // LIBRAPID_HAS_CUDA + + static constexpr bool canAlign = TypeInfo::canAlign; + static constexpr int64_t canMemcpy = TypeInfo::canMemcpy; + }; + + template + struct NumericInfo> { + using Scalar = typename TypeInfo::Scalar; + + LIMIT_IMPL_CONSTEXPR(min) { return NUM_LIM(min); } + LIMIT_IMPL_CONSTEXPR(max) { return NUM_LIM(max); } + LIMIT_IMPL_CONSTEXPR(epsilon) { return NUM_LIM(epsilon); } + LIMIT_IMPL_CONSTEXPR(roundError) { return NUM_LIM(round_error); } + LIMIT_IMPL_CONSTEXPR(denormMin) { return NUM_LIM(denorm_min); } + LIMIT_IMPL_CONSTEXPR(infinity) { return NUM_LIM(infinity); } + LIMIT_IMPL_CONSTEXPR(quietNaN) { return NUM_LIM(quiet_NaN); } + LIMIT_IMPL_CONSTEXPR(signalingNaN) { return NUM_LIM(signaling_NaN); } + }; + } // namespace typetraits #endif // !LIBRAPID_IN_JITIFY #if !defined(LIBRAPID_IN_JITIFY) @@ -430,12 +410,12 @@ namespace librapid { #if defined(LIBRAPID_HAS_CUDA) namespace jitify::reflection::detail { - template - struct type_reflection<::librapid::Dual> { - inline static std::string name() { - return fmt::format("Dual<{}>", type_reflection::name()); - } - }; + template + struct type_reflection<::librapid::Dual> { + inline static std::string name() { + return fmt::format("Dual<{}>", type_reflection::name()); + } + }; } // namespace jitify::reflection::detail #endif // LIBRAPID_HAS_CUDA @@ -444,22 +424,22 @@ namespace jitify::reflection::detail { template struct fmt::formatter, Char> { private: - using Type = librapid::Dual; - using Scalar = typename Type::Scalar; - using Base = fmt::formatter; - Base m_base; + using Type = librapid::Dual; + using Scalar = typename Type::Scalar; + using Base = fmt::formatter; + Base m_base; public: - template - FMT_CONSTEXPR auto parse(ParseContext &ctx) -> const char * { - return m_base.parse(ctx); - } - - template - FMT_CONSTEXPR auto format(const Type &val, FormatContext &ctx) const -> decltype(ctx.out()) { - val.str(m_base, ctx); - return ctx.out(); - } + template + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> const char * { + return m_base.parse(ctx); + } + + template + FMT_CONSTEXPR auto format(const Type &val, FormatContext &ctx) const -> decltype(ctx.out()) { + val.str(m_base, ctx); + return ctx.out(); + } }; #endif // FMT_API diff --git a/librapid/include/librapid/math/complex.hpp b/librapid/include/librapid/math/complex.hpp index 85f72fd4..f4c8da8a 100644 --- a/librapid/include/librapid/math/complex.hpp +++ b/librapid/include/librapid/math/complex.hpp @@ -2077,6 +2077,11 @@ namespace librapid { static constexpr bool canAlign = TypeInfo::canAlign; static constexpr bool canMemcpy = TypeInfo::canMemcpy; + }; + + template + struct NumericInfo> { + using Scalar = typename TypeInfo>::Scalar; LIMIT_IMPL(min) { return TypeInfo::min(); } LIMIT_IMPL(max) { return TypeInfo::max(); } diff --git a/pyproject.toml b/pyproject.toml index 9561753e..fb555857 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,8 +15,7 @@ build-backend = "scikit_build_core.build" [tool.scikit-build] cmake.build-type = "Release" -cmake.args = ["-DCMAKE_BUILD_TYPE=Release", "-DCMAKE_PARALLEL_LEVEL=1"] -cmake.parallel = false +cmake.args = ["-DCMAKE_BUILD_TYPE=Release", "-DCMAKE_BUILD_PARALLEL_LEVEL=1"] ninja.make-fallback = true sdist.cmake = true diff --git a/test/test-sizetype.cpp b/test/test-sizetype.cpp index f8266717..c1dabaaa 100644 --- a/test/test-sizetype.cpp +++ b/test/test-sizetype.cpp @@ -6,37 +6,38 @@ namespace lrc = librapid; TEST_CASE("Test Storage", "[storage]") { - lrc::Shape shape1({1, 2, 3, 4}); - REQUIRE(fmt::format("{}", shape1) == "Shape(1, 2, 3, 4)"); - - lrc::Shape zero = lrc::Shape::zeros(3); - REQUIRE(fmt::format("{}", zero) == "Shape(0, 0, 0)"); - - lrc::Shape ones = lrc::Shape::ones(3); - REQUIRE(fmt::format("{}", ones) == "Shape(1, 1, 1)"); - - REQUIRE(shape1.ndim() == 4); - REQUIRE(shape1[0] == 1); - REQUIRE(shape1[1] == 2); - REQUIRE(shape1[2] == 3); - REQUIRE(shape1[3] == 4); - - REQUIRE(shape1.size() == 24); - REQUIRE(zero.size() == 0); - REQUIRE(ones.size() == 1); - - REQUIRE(shape1 == shape1); - REQUIRE_FALSE(shape1 != shape1); - REQUIRE_FALSE(shape1 == zero); - REQUIRE(shape1 != zero); - - REQUIRE(ones == lrc::Shape({1, 1, 1})); - REQUIRE(zero == lrc::Shape({0, 0, 0})); - REQUIRE(lrc::Shape({1, 2, 3, 4}) == lrc::Shape({1, 2, 3, 4})); - REQUIRE(lrc::Shape({1, 2, 3, 4}) != lrc::Shape({1, 2, 3, 5})); - - REQUIRE(lrc::shapesMatch(lrc::Shape({1, 2, 3, 4}), lrc::Shape({1, 2, 3, 4}))); - REQUIRE_FALSE(lrc::shapesMatch(lrc::Shape({1, 2, 3, 4}), lrc::Shape({1, 2, 3, 5}))); - REQUIRE(lrc::shapesMatch( - lrc::Shape({1, 2, 3, 4}), lrc::Shape({1, 2, 3, 4}), lrc::Shape({1, 2, 3, 4}))); + lrc::Shape shape1({1, 2, 3, 4}); + REQUIRE(fmt::format("{}", shape1) == "Shape(1, 2, 3, 4)"); + + lrc::Shape zero = lrc::Shape::zeros(3); + REQUIRE(fmt::format("{}", zero) == "Shape(0, 0, 0)"); + + lrc::Shape ones = lrc::Shape::ones(3); + REQUIRE(fmt::format("{}", ones) == "Shape(1, 1, 1)"); + + REQUIRE(shape1.ndim() == 4); + REQUIRE(shape1[0] == 1); + REQUIRE(shape1[1] == 2); + REQUIRE(shape1[2] == 3); + REQUIRE(shape1[3] == 4); + + REQUIRE(shape1.size() == 24); + REQUIRE(zero.size() == 0); + REQUIRE(ones.size() == 1); + + REQUIRE(shape1 == shape1); + REQUIRE_FALSE(shape1 != shape1); + REQUIRE_FALSE(shape1 == zero); + REQUIRE(shape1 != zero); + + REQUIRE(ones == lrc::Shape({1, 1, 1})); + REQUIRE(zero == lrc::Shape({0, 0, 0})); + REQUIRE(lrc::Shape({1, 2, 3, 4}) == lrc::Shape({1, 2, 3, 4})); + REQUIRE(lrc::Shape({1, 2, 3, 4}) != lrc::Shape({1, 2, 3, 5})); + + REQUIRE(lrc::shapesMatch(std::make_tuple(lrc::Shape({1, 2, 3, 4}), lrc::Shape({1, 2, 3, 4})))); + REQUIRE_FALSE( + lrc::shapesMatch(std::make_tuple(lrc::Shape({1, 2, 3, 4}), lrc::Shape({1, 2, 3, 5})))); + REQUIRE(lrc::shapesMatch(std::make_tuple( + lrc::Shape({1, 2, 3, 4}), lrc::Shape({1, 2, 3, 4}), lrc::Shape({1, 2, 3, 4})))); }