include/maths/common/CLinearAlgebraShims.h (318 lines of code) (raw):

/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the following additional limitation. Functionality enabled by the * files subject to the Elastic License 2.0 may only be used in production when * invoked by an Elasticsearch process with a license key installed that permits * use of machine learning features. You may not use this file except in * compliance with the Elastic License 2.0 and the foregoing additional * limitation. */ #ifndef INCLUDED_ml_maths_common_CLinearAlgebraShims_h #define INCLUDED_ml_maths_common_CLinearAlgebraShims_h #include <maths/common/CLinearAlgebraFwd.h> #include <maths/common/CTypeTraits.h> #include <cmath> #include <cstddef> #include <type_traits> namespace ml { namespace maths { namespace common { namespace las { //! Get the dimension of one of our internal vectors. template<typename VECTOR> std::size_t dimension(const VECTOR& x) { return x.dimension(); } //! Get the dimension of an Eigen dense vector. template<typename SCALAR> std::size_t dimension(const CDenseVector<SCALAR>& x) { return static_cast<std::size_t>(x.size()); } //! Get the dimension of an Eigen memory mapped vector. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> std::size_t dimension(const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& x) { return static_cast<std::size_t>(x.size()); } //! Get the dimension of an annotated vector. template<typename VECTOR, typename ANNOTATION> std::size_t dimension(const CAnnotatedVector<VECTOR, ANNOTATION>& x) { return dimension(static_cast<const VECTOR&>(x)); } //! Get the number of columns of a matrix. template<typename MATRIX> std::size_t columns(const MATRIX& m) { return m.columns(); } //! Get the Euclidean norm of an Eigen dense vector. template<typename SCALAR> std::size_t columns(const CDenseMatrix<SCALAR>& x) { return x.cols(); } //! Get the Euclidean norm of an Eigen memory mapped matrix. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> std::size_t columns(const CMemoryMappedDenseMatrix<SCALAR, ALIGNMENT>& x) { return x.cols(); } //! Get the concomitant zero vector. template<typename VECTOR> auto zero(const VECTOR& x) -> decltype(SConstant<VECTOR>::get(dimension(x), 0)) { return SConstant<VECTOR>::get(dimension(x), 0); } //! Zero all the components of \p x. template<typename VECTOR> void setZero(VECTOR& x) { for (std::size_t i = 0; i < dimension(x); ++i) { x(i) = 0.0; } } //! Get the conformable zero initialized matrix for our internal stack vector. template<typename T, std::size_t N> CSymmetricMatrixNxN<T, N> conformableZeroMatrix(const CVectorNx1<T, N>& /*x*/) { return CSymmetricMatrixNxN<T, N>(0); } //! Get the conformable zero initialized matrix for our internal heap vector. template<typename T> CSymmetricMatrix<T> conformableZeroMatrix(const CVector<T>& x) { return CSymmetricMatrix<T>(x.dimension(), 0); } //! Get the conformable zero initialized matrix for the Eigen dense vector. template<typename SCALAR> CDenseMatrix<SCALAR> conformableZeroMatrix(const CDenseVector<SCALAR>& x) { return SConstant<CDenseMatrix<SCALAR>>::get(dimension(x), 0); } //! Get the conformable zero initialized matrix for the Eigen memory mapped vector. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> CDenseMatrix<SCALAR> conformableZeroMatrix(const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& x) { return SConstant<CMemoryMappedDenseMatrix<SCALAR, ALIGNMENT>>::get(dimension(x), 0); } //! Get the conformable zero initialized matrix for the underlying vector. template<typename VECTOR, typename ANNOTATION> typename SConformableMatrix<VECTOR>::Type conformableZeroMatrix(const CAnnotatedVector<VECTOR, ANNOTATION>& x) { return conformableZeroMatrix(static_cast<const VECTOR&>(x)); } //! Check if a vector is a zero vector. template<typename VECTOR> bool isZero(const VECTOR& x) { for (std::size_t i = 0; i < dimension(x); ++i) { if (x(i) != 0) { return false; } } return true; } //! Get the concomitant ones vector. template<typename VECTOR> auto ones(const VECTOR& x) -> decltype(SConstant<VECTOR>::get(dimension(x), 1)) { return SConstant<VECTOR>::get(dimension(x), 1); } //! Get the concomitant constant \p constant vector. template<typename VECTOR> auto constant(const VECTOR& x, typename SCoordinate<VECTOR>::Type constant) -> decltype(SConstant<VECTOR>::get(dimension(x), constant)) { return SConstant<VECTOR>::get(dimension(x), constant); } //! In-place minimum, writing to \p y. template<typename VECTOR> void min(const VECTOR& x, VECTOR& y) { for (std::size_t i = 0; i < dimension(x); ++i) { y(i) = std::min(x(i), y(i)); } } //! In-place maximum, writing to \p y. template<typename VECTOR> void max(const VECTOR& x, VECTOR& y) { for (std::size_t i = 0; i < dimension(x); ++i) { y(i) = std::max(x(i), y(i)); } } //! Expose componentwise operations for our internal vectors. template<typename VECTOR> VECTOR& componentwise(VECTOR& x) { return x; } //! Expose componentwise operations for Eigen dense vectors. template<typename SCALAR> auto componentwise(const CDenseVector<SCALAR>& x) -> decltype(x.array()) { return x.array(); } template<typename SCALAR> auto componentwise(CDenseVector<SCALAR>& x) -> decltype(x.array()) { return x.array(); } //! Expose componentwise operations for Eigen memory mapped vectors. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> auto componentwise(const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& x) -> decltype(x.array()) { return x.array(); } template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> auto componentwise(CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& x) -> decltype(x.array()) { return x.array(); } //! Expose componentwise operations for our annotated vectors. template<typename VECTOR, typename ANNOTATION> auto componentwise(const CAnnotatedVector<VECTOR, ANNOTATION>& x) -> decltype(componentwise(static_cast<const VECTOR&>(x))) { return componentwise(static_cast<const VECTOR&>(x)); } template<typename VECTOR, typename ANNOTATION> auto componentwise(CAnnotatedVector<VECTOR, ANNOTATION>& x) -> decltype(componentwise(static_cast<VECTOR&>(x))) { return componentwise(static_cast<VECTOR&>(x)); } //! Euclidean distance implementation for one of our internal vectors. template<typename VECTOR> typename SCoordinate<VECTOR>::Type distance(const VECTOR& x, const VECTOR& y) { using TCoordinate = typename SPromoted<typename SCoordinate<VECTOR>::Type>::Type; TCoordinate result(0); for (std::size_t i = 0; i < dimension(x); ++i) { TCoordinate x_(y(i) - x(i)); result += x_ * x_; } return std::sqrt(result); } //! Euclidean distance implementation for an Eigen dense vector. template<typename SCALAR> SCALAR distance(const CDenseVector<SCALAR>& x, const CDenseVector<SCALAR>& y) { return (y - x).norm(); } //! Euclidean distance implementation for an Eigen memory mapped vector. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> SCALAR distance(const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& x, const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& y) { return (y - x).norm(); } //! Euclidean distance implementation for an annotated vector. template<typename VECTOR, typename ANNOTATION> typename SCoordinate<VECTOR>::Type distance(const CAnnotatedVector<VECTOR, ANNOTATION>& x, const CAnnotatedVector<VECTOR, ANNOTATION>& y) { return distance(static_cast<const VECTOR&>(x), static_cast<const VECTOR&>(y)); } //! Get the Euclidean norm of one of our internal vectors. template<typename VECTOR> typename SCoordinate<VECTOR>::Type norm(const VECTOR& x) { return x.euclidean(); } //! Get the Euclidean norm of an Eigen dense vector. template<typename SCALAR> SCALAR norm(const CDenseVector<SCALAR>& x) { return x.norm(); } //! Get the Euclidean norm of an Eigen memory mapped vector. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> SCALAR norm(const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& x) { return x.norm(); } //! Get the Euclidean norm of an annotated vector. template<typename VECTOR, typename ANNOTATION> typename SCoordinate<VECTOR>::Type norm(const CAnnotatedVector<VECTOR, ANNOTATION>& x) { return norm(static_cast<const VECTOR&>(x)); } //! Get the Manhattan norm of one of our internal vector classes. template<typename VECTOR> typename SCoordinate<VECTOR>::Type L1(const VECTOR& x) { return x.L1(); } //! Get the Manhattan norm of an Eigen dense vector. template<typename SCALAR> SCALAR L1(const CDenseVector<SCALAR>& x) { return x.template lpNorm<1>(); } //! Get the Manhattan norm of an Eigen memory mapped vector. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> SCALAR L1(const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& x) { return x.template lpNorm<1>(); } //! Get the Manhattan norm of an annotated vector. template<typename VECTOR, typename ANNOTATION> typename SCoordinate<VECTOR>::Type L1(const CAnnotatedVector<VECTOR, ANNOTATION>& x) { return L1(static_cast<const VECTOR&>(x)); } //! Get the Manhattan norm of one of our internal vector classes. template<typename TENSOR> double mean(const TENSOR& x) { return x.mean(); } //! Get the mean of the elements of an annotated vector. template<typename VECTOR, typename ANNOTATION> double mean(const CAnnotatedVector<VECTOR, ANNOTATION>& x) { return mean(static_cast<const VECTOR&>(x)); } //! Get the Frobenius norm of one of our internal matrices. template<typename MATRIX> typename SCoordinate<MATRIX>::Type frobenius(const MATRIX& m) { return m.frobenius(); } //! Get the Frobenius norm of an Eigen dense matrix. template<typename SCALAR> SCALAR frobenius(const CDenseMatrix<SCALAR>& x) { return x.norm(); } //! Get the Frobenius norm of an Eigen memory mapped matrix. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> SCALAR frobenius(const CMemoryMappedDenseMatrix<SCALAR, ALIGNMENT>& x) { return x.norm(); } //! Get the inner product of two of our internal vectors. template<typename VECTOR> typename SCoordinate<VECTOR>::Type inner(const VECTOR& x, const VECTOR& y) { return x.inner(y); } //! Get the inner product of two Eigen dense vectors. template<typename SCALAR> SCALAR inner(const CDenseVector<SCALAR>& x, const CDenseVector<SCALAR>& y) { return x.dot(y); } //! Get the inner product of two Eigen memory mapped vectors. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> SCALAR inner(const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& x, const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& y) { return x.dot(y); } //! Get the inner product of Eigen dense and memory mapped vectors. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> SCALAR inner(const CDenseVector<SCALAR>& x, const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& y) { return x.dot(y); } //! Get the inner product of Eigen dense and memory mapped vectors. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> SCALAR inner(const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& x, const CDenseVector<SCALAR>& y) { return x.dot(y); } //! Get the inner product of two annotated vectors. template<typename V1, typename V2, typename ANNOTATION> typename std::common_type<typename SCoordinate<V1>::Type, typename SCoordinate<V2>::Type>::type inner(const CAnnotatedVector<V1, ANNOTATION>& x, const CAnnotatedVector<V2, ANNOTATION>& y) { return inner(static_cast<const V1&>(x), static_cast<const V2&>(y)); } //! Get the inner product of an annotated and some other vector. template<typename V1, typename V2, typename ANNOTATION> typename std::common_type<typename SCoordinate<V1>::Type, typename SCoordinate<V2>::Type>::type inner(const V1& x, const CAnnotatedVector<V2, ANNOTATION>& y) { return inner(x, static_cast<const V2&>(y)); } //! Get the inner product of an annotated and some other vector. template<typename V1, typename V2, typename ANNOTATION> typename std::common_type<typename SCoordinate<V1>::Type, typename SCoordinate<V2>::Type>::type inner(const CAnnotatedVector<V1, ANNOTATION>& x, const V2& y) { return inner(static_cast<const V1&>(x), y); } //! Get the outer product of one of our internal vector types. template<typename VECTOR> typename SConformableMatrix<VECTOR>::Type outer(const VECTOR& x) { return x.outer(); } //! Get the outer product of an Eigen dense vector. template<typename SCALAR> CDenseMatrix<SCALAR> outer(const CDenseVector<SCALAR>& x) { return x * x.transpose(); } //! Get the outer product of an Eigen memory mapped vector. template<typename SCALAR, Eigen::AlignmentType ALIGNMENT> CDenseMatrix<SCALAR> outer(const CMemoryMappedDenseVector<SCALAR, ALIGNMENT>& x) { return outer(CDenseVector<SCALAR>(x)); } //! Get the outer product of an annotated vector. template<typename VECTOR, typename ANNOTATION> typename SConformableMatrix<VECTOR>::Type outer(const CAnnotatedVector<VECTOR, ANNOTATION>& x) { return outer(static_cast<const VECTOR&>(x)); } namespace las_detail { template<typename VECTOR> struct SEstimateVectorMemoryUsage { static std::size_t value(std::size_t) { return 0; } }; template<typename T> struct SEstimateVectorMemoryUsage<CVector<T>> { static std::size_t value(std::size_t dimension) { return dimension * sizeof(T); } }; template<typename SCALAR> struct SEstimateVectorMemoryUsage<CDenseVector<SCALAR>> { static std::size_t value(std::size_t dimension) { // Ignore pad for alignment. return dimension * sizeof(SCALAR); } }; template<typename VECTOR, typename ANNOTATION> struct SEstimateVectorMemoryUsage<CAnnotatedVector<VECTOR, ANNOTATION>> { static std::size_t value(std::size_t dimension) { // Ignore any dynamic memory used by the annotation: we don't know how to // compute this here. It will be up to the calling code to estimate this // correctly. return SEstimateVectorMemoryUsage<VECTOR>::value(dimension); } }; template<typename MATRIX> struct SEstimateMatrixMemoryUsage { static std::size_t value(std::size_t, std::size_t) { return 0; } }; template<typename T> struct SEstimateMatrixMemoryUsage<CSymmetricMatrix<T>> { static std::size_t value(std::size_t rows, std::size_t) { return sizeof(T) * rows * (rows + 1) / 2; } }; template<typename SCALAR> struct SEstimateMatrixMemoryUsage<CDenseMatrix<SCALAR>> { static std::size_t value(std::size_t rows, std::size_t columns) { // Ignore pad for alignment. return sizeof(SCALAR) * rows * columns; } }; } //! Estimate the amount of memory a vector of type VECTOR and size \p dimension //! will use. template<typename VECTOR> std::size_t estimateMemoryUsage(std::size_t dimension) { return las_detail::SEstimateVectorMemoryUsage<VECTOR>::value(dimension); } //! Estimate the amount of memory a matrix of type MATRIX and size \p rows by //! \p columns will use. template<typename MATRIX> std::size_t estimateMemoryUsage(std::size_t rows, std::size_t columns) { return las_detail::SEstimateMatrixMemoryUsage<MATRIX>::value(rows, columns); } } } } } #endif // ml_maths_common_CLinearAlgebraShims_h