| // SPDX-FileCopyrightText: The Eigen Authors |
| // SPDX-License-Identifier: MPL-2.0 |
| |
| #include "main.h" |
| #include <Eigen/Core> |
| |
| // Component access must not assume that a user-defined complex scalar has std::complex's layout. |
| struct PaddedComplex : std::complex<double> { |
| using std::complex<double>::complex; |
| double padding = 123; |
| }; |
| |
| template <> |
| struct Eigen::NumTraits<PaddedComplex> : Eigen::NumTraits<std::complex<double>> {}; |
| |
| template <typename Derived> |
| void check_component(const DenseBase<Derived>& component) { |
| using Real = typename Derived::Scalar; |
| Matrix<Real, Dynamic, Dynamic, Derived::IsRowMajor ? RowMajor : ColMajor> copy = component; |
| Real sum = 0, minimum = component(0, 0), maximum = minimum, abs_maximum = numext::abs(minimum); |
| for (Index col = 0; col < component.cols(); ++col) { |
| for (Index row = 0; row < component.rows(); ++row) { |
| const Real value = component(row, col); |
| VERIFY_IS_EQUAL(copy(row, col), value); |
| sum += value; |
| if (value < minimum) minimum = value; |
| if (value > maximum) maximum = value; |
| if (numext::abs(value) > abs_maximum) abs_maximum = numext::abs(value); |
| } |
| } |
| VERIFY_IS_EQUAL(component.sum(), sum); |
| VERIFY_IS_EQUAL(component.template minCoeff<PropagateNaN>(), minimum); |
| VERIFY_IS_EQUAL(component.template maxCoeff<PropagateNaN>(), maximum); |
| VERIFY_IS_EQUAL(component.derived().cwiseAbs().template maxCoeff<PropagateNaN>(), abs_maximum); |
| VERIFY_IS_CWISE_EQUAL(component.derived().colwise().sum().eval(), copy.colwise().sum().eval()); |
| VERIFY_IS_CWISE_EQUAL(component.derived().rowwise().sum().eval(), copy.rowwise().sum().eval()); |
| } |
| |
| template <typename MatrixType> |
| void component_expressions(Index rows, Index cols) { |
| using Complex = typename MatrixType::Scalar; |
| using Real = typename NumTraits<Complex>::Real; |
| MatrixType values(rows, cols); |
| for (Index i = 0; i < values.size(); ++i) values.data()[i] = Complex(Real(i % 13 - 6), Real(i % 17 + 1)); |
| const MatrixType& const_values = values; |
| check_component(values.real()); |
| check_component(values.imag()); |
| check_component(const_values.real()); |
| check_component(const_values.imag()); |
| check_component(values.transpose().real()); |
| check_component(values.transpose().imag()); |
| check_component(values.conjugate().real()); |
| check_component(values.conjugate().imag()); |
| check_component(values.block(0, 0, rows - 1, cols - 1).real()); |
| check_component(values.block(0, 0, rows - 1, cols - 1).imag()); |
| check_component(const_values.block(0, 0, rows - 1, cols - 1).real()); |
| check_component(const_values.block(0, 0, rows - 1, cols - 1).imag()); |
| const auto real = values.real(); |
| const auto imag = values.imag(); |
| check_component(real.block(0, 0, rows - 1, cols - 1)); |
| check_component(imag.block(0, 0, rows - 1, cols - 1)); |
| |
| MatrixType original = values; |
| values.real() = original.imag(); |
| values.imag() = original.real(); |
| for (Index i = 0; i < values.size(); ++i) { |
| VERIFY_IS_EQUAL(values.data()[i], Complex(original.data()[i].imag(), original.data()[i].real())); |
| } |
| values.real().block(0, 0, rows - 1, cols - 1).setConstant(Real(3)); |
| values.imag().array() += Real(2); |
| for (Index col = 0; col < cols; ++col) { |
| for (Index row = 0; row < rows; ++row) { |
| VERIFY_IS_EQUAL(values(row, col).imag(), original(row, col).real() + Real(2)); |
| VERIFY_IS_EQUAL(values(row, col).real(), row < rows - 1 && col < cols - 1 ? Real(3) : original(row, col).imag()); |
| } |
| } |
| } |
| |
| template <typename Real> |
| void component_reductions() { |
| using Complex = std::complex<Real>; |
| using Vector = Matrix<Complex, Dynamic, 1>; |
| constexpr bool vectorizable = (std::is_same<Real, float>::value || std::is_same<Real, double>::value) && |
| internal::packet_traits<Real>::Vectorizable; |
| using View = decltype(std::declval<Vector&>().real()); |
| using ConstOp = decltype(std::declval<const Vector&>().imag()); |
| STATIC_CHECK(bool(internal::redux_evaluator<View>::Flags & PacketAccessBit) == vectorizable); |
| STATIC_CHECK(bool(internal::evaluator<ConstOp>::Flags & PacketAccessBit) == vectorizable); |
| STATIC_CHECK(!(internal::evaluator<View>::Flags & PacketAccessBit)); |
| using Strided = Map<Vector, Unaligned, InnerStride<2>>; |
| using StridedView = decltype(std::declval<Strided&>().real()); |
| STATIC_CHECK(!(internal::redux_evaluator<StridedView>::Flags & PacketAccessBit)); |
| using DynamicStride = Map<Vector, Unaligned, InnerStride<Dynamic>>; |
| using DynamicView = decltype(std::declval<const DynamicStride&>().imag()); |
| STATIC_CHECK(!(internal::evaluator<DynamicView>::Flags & PacketAccessBit)); |
| using SumView = decltype((std::declval<Vector>() + std::declval<Vector>()).real()); |
| STATIC_CHECK(!(internal::evaluator<SumView>::Flags & PacketAccessBit)); |
| |
| const Real nan = NumTraits<Real>::quiet_NaN(); |
| const Real inf = NumTraits<Real>::infinity(); |
| constexpr Index packet_size = internal::packet_traits<Real>::size; |
| for (Index size : {Index(1), packet_size, packet_size + 1, 2 * packet_size - 1, Index(65)}) { |
| Vector buffer(2 * size + 1); |
| buffer.setConstant(Complex(Real(7), Real(-3))); |
| Map<Vector> values(buffer.data() + 1, size); |
| const auto& const_values = values; |
| check_component(values.real()); |
| check_component(values.imag()); |
| Strided strided(buffer.data() + 1, size); |
| check_component(strided.real()); |
| check_component(strided.imag()); |
| DynamicStride dynamic(buffer.data() + 1, size, InnerStride<Dynamic>(2)); |
| check_component(dynamic.real()); |
| check_component(dynamic.imag()); |
| for (Index i = 0; i < size; ++i) { |
| for (Real special : {nan, inf, -inf, Real(0), -Real(0), std::numeric_limits<Real>::denorm_min()}) { |
| values.setConstant(Complex(Real(7), Real(-3))); |
| values(i) = Complex(special, Real(-3)); |
| Matrix<Real, Dynamic, 1> real = const_values.real(); |
| if ((numext::isnan)(special)) { |
| VERIFY((numext::isnan)(real(i))); |
| VERIFY((numext::isnan)(values.real().template maxCoeff<PropagateNaN>())); |
| VERIFY((numext::isnan)(const_values.real().template minCoeff<PropagateNaN>())); |
| if (size > 1) VERIFY_IS_EQUAL(values.real().template maxCoeff<PropagateNumbers>(), Real(7)); |
| } else { |
| VERIFY_IS_EQUAL(real(i), special); |
| VERIFY_IS_EQUAL((std::signbit)(real(i)), (std::signbit)(special)); |
| } |
| VERIFY_IS_EQUAL(values.imag().template maxCoeff<PropagateNaN>(), Real(-3)); |
| values(i) = Complex(Real(7), special); |
| Matrix<Real, Dynamic, 1> imag = const_values.imag(); |
| if ((numext::isnan)(special)) { |
| VERIFY((numext::isnan)(imag(i))); |
| VERIFY((numext::isnan)(values.imag().template minCoeff<PropagateNaN>())); |
| VERIFY((numext::isnan)(const_values.imag().template maxCoeff<PropagateNaN>())); |
| if (size > 1) VERIFY_IS_EQUAL(values.imag().template minCoeff<PropagateNumbers>(), Real(-3)); |
| } else { |
| VERIFY_IS_EQUAL(imag(i), special); |
| VERIFY_IS_EQUAL((std::signbit)(imag(i)), (std::signbit)(special)); |
| } |
| VERIFY_IS_EQUAL(values.real().template minCoeff<PropagateNaN>(), Real(7)); |
| } |
| } |
| } |
| } |
| |
| void component_custom_scalar() { |
| using Vector = Matrix<PaddedComplex, Dynamic, 1>; |
| Vector values(17); |
| for (Index i = 0; i < values.size(); ++i) values(i) = PaddedComplex(double(i), double(2 * i + 1)); |
| const Vector& const_values = values; |
| using RealView = decltype(const_values.real()); |
| using ImagView = decltype(const_values.imag()); |
| STATIC_CHECK(!(internal::evaluator<RealView>::Flags & PacketAccessBit)); |
| STATIC_CHECK(!(internal::evaluator<ImagView>::Flags & PacketAccessBit)); |
| check_component(const_values.real()); |
| check_component(const_values.imag()); |
| } |
| |
| EIGEN_DECLARE_TEST(complex_components) { |
| CALL_SUBTEST_1(component_reductions<float>()); |
| CALL_SUBTEST_2(component_reductions<double>()); |
| CALL_SUBTEST_3(component_reductions<long double>()); |
| CALL_SUBTEST_3(component_custom_scalar()); |
| for (Index rows : {Index(2), Index(7), Index(17)}) { |
| for (Index cols : {Index(3), Index(9)}) { |
| EIGEN_UNUSED_VARIABLE(rows); |
| EIGEN_UNUSED_VARIABLE(cols); |
| CALL_SUBTEST_1((component_expressions<Matrix<std::complex<float>, Dynamic, Dynamic, ColMajor>>(rows, cols))); |
| CALL_SUBTEST_1((component_expressions<Matrix<std::complex<float>, Dynamic, Dynamic, RowMajor>>(rows, cols))); |
| CALL_SUBTEST_2((component_expressions<Matrix<std::complex<double>, Dynamic, Dynamic, ColMajor>>(rows, cols))); |
| CALL_SUBTEST_2((component_expressions<Matrix<std::complex<double>, Dynamic, Dynamic, RowMajor>>(rows, cols))); |
| } |
| } |
| CALL_SUBTEST_1((component_expressions<Matrix<std::complex<float>, 3, 5>>(3, 5))); |
| CALL_SUBTEST_2((component_expressions<Matrix<std::complex<double>, 2, 2>>(2, 2))); |
| } |