#ifndef FESA_SRC_FESA_MATH_DENSE_BLAS_INTERNAL_H_ #define FESA_SRC_FESA_MATH_DENSE_BLAS_INTERNAL_H_ #include #include #include "fesa/core/status.h" #include "fesa/math/matrix.h" #include "fesa/math/vector.h" namespace fesa::dense_blas_internal { /// @brief Limits only default-policy one-equation backend calls to one thread. /// @note Existing caller TLS overrides are retained. Destruction restores the /// default request; process-wide MKL/OpenMP settings are never changed. class ScopedSingleEquationThreads { public: explicit ScopedSingleEquationThreads(std::size_t equation_count) noexcept; ScopedSingleEquationThreads(const ScopedSingleEquationThreads&) = delete; ScopedSingleEquationThreads& operator=(const ScopedSingleEquationThreads&) = delete; ~ScopedSingleEquationThreads(); private: bool restore_default_{false}; }; /// @brief Limits element-local dense work under the caller's default policy. /// @note Positive caller TLS overrides are retained. Default requests are /// restored on success and unwind; process-wide settings are never changed. class ScopedLocalDenseThreads { public: ScopedLocalDenseThreads() noexcept; ScopedLocalDenseThreads(const ScopedLocalDenseThreads&) = delete; ScopedLocalDenseThreads& operator=(const ScopedLocalDenseThreads&) = delete; ~ScopedLocalDenseThreads(); private: bool restore_default_{false}; }; /// @brief Converts a dense storage length to the private MKL integer type. /// @return The converted length or an uncategorized overflow failure. Result ToMklSize(std::size_t size); /// @brief Computes left-transpose times right through ordinary dense MKL. /// @throws std::invalid_argument for mismatched rows or nonfinite operands. Matrix MultiplyTransposeLeft(const Matrix& left, const Matrix& right); /// @brief Multiplies a compact diagonal matrix by a vector through MKL. /// @throws std::invalid_argument if shapes differ or inputs are nonfinite. /// @throws std::length_error if the size exceeds the backend integer range. Vector MultiplyDiagonal(const Vector& diagonal, const Vector& rhs); /// @brief Writes one row-major outer product through MKL without allocation. /// @note Source arrays and destination must not alias. A nonfinite input /// returns false before writing; finite product overflow remains for the /// owner's gate. A zero dimension accepts null pointers and performs no backend /// call. /// @throws std::invalid_argument for null storage of a nonempty product. /// @throws std::length_error for dimensions outside the backend integer range. bool OuterProduct(const double* left, std::size_t rows, const double* right, std::size_t columns, double* destination); /// @brief Writes left times right-transpose to nonaliased contiguous storage. /// @note Inputs are row-major rows-by-inner and columns-by-inner. Nonfinite /// input returns false before writing. Finite output overflow is not hidden. /// Zero output dimensions accept null pointers; inner zero writes exact zeros. /// @throws std::invalid_argument for missing nonempty storage. /// @throws std::length_error for dimension or storage-size overflow. bool MultiplyTransposeRight(const double* left, std::size_t rows, const double* right, std::size_t columns, std::size_t inner, double* destination); /// @brief Distinguishes positive-factor failure from inverse failure. enum class CholeskyFailure { kNone, kPivot, kInverse }; /// @brief Computes a lower Cholesky factor and its inverse with MKL LAPACK. /// @return False for a nonpositive pivot or nonfinite factor/inverse. /// @note Outputs are replaced only after both finite candidates succeed. /// The optional failure output is initialized even when validation throws. /// @throws std::invalid_argument for a nonsquare or nonfinite input. /// @throws std::length_error for a backend size overflow. bool CholeskyLowerAndInverse(const Matrix& matrix, Matrix& lower, Matrix& inverse_lower, CholeskyFailure* failure = nullptr); /// @brief Copies contiguous double values through the private BLAS backend. /// @param source Readable storage for size values when size is nonzero. /// @param size Number of contiguous values to copy. /// @param destination Writable storage for size values when size is nonzero. /// @throws std::length_error if size exceeds the MKL integer range. /// @note A zero-length copy accepts null pointers and does not call BLAS. void CopyValues(const double* source, std::size_t size, double* destination); } // namespace fesa::dense_blas_internal #endif // FESA_SRC_FESA_MATH_DENSE_BLAS_INTERNAL_H_