| // SPDX-FileCopyrightText: The Eigen Authors |
| // SPDX-License-Identifier: MPL-2.0 |
| |
| // Exercise the shared kernel even when an ISA-specific TRSM implementation is available. |
| #define EIGEN_USE_AVX512_TRSM_KERNELS 0 |
| // Keep the cancelling terms in one diagonal panel; synthetic kc=1 moves them into separate GEMM updates. |
| #define EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS |
| |
| #include "main.h" |
| #include <Eigen/Core> |
| |
| template <typename Scalar> |
| void trsm_packet_cancellation() { |
| STATIC_CHECK((internal::triangular_solve_packet_traits<Scalar>::UseUnblocked == |
| internal::triangular_solve_packet_traits<Scalar>::Enabled)); |
| using Triangle = Matrix<Scalar, Dynamic, Dynamic, RowMajor>; |
| using Operand = Matrix<Scalar, Dynamic, Dynamic, ColMajor>; |
| std::ptrdiff_t saved_l1, saved_l2, saved_l3, saved_l3_per_cpu; |
| internal::manage_caching_sizes(GetAction, &saved_l1, &saved_l2, &saved_l3, &saved_l3_per_cpu); |
| // Deterministic panels for the blocked cases, including AVX-512 double precision. |
| setCpuCacheSizes(64 * 1024, 2 * 1024 * 1024, 16 * 1024 * 1024); |
| const Index packet = internal::packet_traits<Scalar>::size; |
| const Scalar half_max = (std::numeric_limits<Scalar>::max)() / Scalar(2); |
| const Scalar large = ((std::numeric_limits<Scalar>::max)() / Scalar(4)) * Scalar(3); |
| for (Index n : {4, 8, 16, 128, 256}) { |
| for (Index offset : {Index(0), n - 4}) { |
| Triangle a = Triangle::Identity(n, n); |
| a(offset + 3, offset) = -half_max; |
| a(offset + 3, offset + 1) = half_max; |
| a.template triangularView<StrictlyUpper>().setConstant(NumTraits<Scalar>::quiet_NaN()); |
| const Index widths[] = {packet, 2 * packet, 2 * packet + 1, 4 * packet + 3}; |
| for (Index nrhs : widths) { |
| Operand b = Operand::Ones(n, nrhs), x(n, nrhs); |
| b.row(offset + 3).setConstant(large); |
| // Only alternating columns overflow, exercising mixed packet lanes and scalar tails. |
| for (Index j = 1; j < nrhs; j += 2) b(offset + 3, j) = Scalar(1); |
| x = b; |
| a.template triangularView<Lower>().solveInPlace(x); |
| VERIFY(x.array().isFinite().all()); |
| // Four eps covers reciprocal/multiply rounding, including fast-math reciprocals. |
| VERIFY(((x - b).cwiseAbs().array() <= Scalar(4) * NumTraits<Scalar>::epsilon() * b.array()).all()); |
| |
| Triangle upper = a.reverse(); |
| const Operand reversed = b.colwise().reverse(); |
| x = reversed; |
| upper.template triangularView<Upper>().solveInPlace(x); |
| VERIFY(x.array().isFinite().all()); |
| VERIFY( |
| ((x - reversed).cwiseAbs().array() <= Scalar(4) * NumTraits<Scalar>::epsilon() * reversed.array()).all()); |
| |
| a.diagonal().setConstant(NumTraits<Scalar>::quiet_NaN()); |
| upper.diagonal().setConstant(NumTraits<Scalar>::quiet_NaN()); |
| x = b; |
| a.template triangularView<UnitLower>().solveInPlace(x); |
| VERIFY(x.array().isFinite().all()); |
| VERIFY_IS_CWISE_EQUAL(x, b); |
| x = reversed; |
| upper.template triangularView<UnitUpper>().solveInPlace(x); |
| VERIFY(x.array().isFinite().all()); |
| VERIFY_IS_CWISE_EQUAL(x, reversed); |
| |
| Matrix<Scalar, Dynamic, Dynamic, RowMajor> right = b.transpose(); |
| a.transpose().template triangularView<UnitUpper>().template solveInPlace<OnTheRight>(right); |
| VERIFY(right.array().isFinite().all()); |
| VERIFY_IS_CWISE_EQUAL(right, b.transpose()); |
| a.diagonal().setOnes(); |
| } |
| } |
| } |
| internal::manage_caching_sizes(SetAction, &saved_l1, &saved_l2, &saved_l3, &saved_l3_per_cpu); |
| } |
| |
| EIGEN_DECLARE_TEST(trsm_packet_cancellation) { |
| for (int i = 0; i < g_repeat; ++i) { |
| CALL_SUBTEST_1(trsm_packet_cancellation<float>()); |
| CALL_SUBTEST_2(trsm_packet_cancellation<double>()); |
| } |
| } |