// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2025 The Eigen Authors // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #include "main.h" // wrapper that disables array-oriented access to real and imaginary components struct TestComplex : public std::complex { TestComplex() = default; TestComplex(std::complex x) : std::complex(x){}; TestComplex(float x) : std::complex(x){}; }; template <> struct Eigen::NumTraits : Eigen::NumTraits> {}; template <> struct Eigen::internal::random_impl : Eigen::internal::random_impl> {}; template void test_realview_readonly(const T&) { using Scalar = typename T::Scalar; using RealScalar = typename NumTraits::Real; constexpr Index minRows = T::RowsAtCompileTime == Dynamic ? 1 : T::RowsAtCompileTime; constexpr Index maxRows = T::MaxRowsAtCompileTime == Dynamic ? (EIGEN_TEST_MAX_SIZE / 2) : T::MaxRowsAtCompileTime; constexpr Index minCols = T::ColsAtCompileTime == Dynamic ? 1 : T::ColsAtCompileTime; constexpr Index maxCols = T::MaxColsAtCompileTime == Dynamic ? (EIGEN_TEST_MAX_SIZE / 2) : T::MaxColsAtCompileTime; constexpr Index rowFactor = (NumTraits::IsComplex && !T::IsRowMajor) ? 2 : 1; constexpr Index colFactor = (NumTraits::IsComplex && T::IsRowMajor) ? 2 : 1; constexpr Index sizeFactor = NumTraits::IsComplex ? 2 : 1; Index rows = internal::random(minRows, maxRows); Index cols = internal::random(minCols, maxCols); T A(rows, cols), B(rows, cols); VERIFY(A.realView().rows() == rowFactor * A.rows()); VERIFY(A.realView().cols() == colFactor * A.cols()); VERIFY(A.realView().size() == sizeFactor * A.size()); A.setRandom(); VERIFY_IS_APPROX(A.matrix().cwiseAbs2().sum(), A.realView().matrix().cwiseAbs2().sum()); RealScalar alpha = internal::random(RealScalar(1), RealScalar(2)); // B = A * alpha for (Index r = 0; r < rows; r++) { for (Index c = 0; c < cols; c++) { B.coeffRef(r, c) = A.coeff(r, c) * Scalar(alpha); } } VERIFY_IS_CWISE_APPROX(B.realView(), A.realView() * alpha); // B = A / alpha for (Index r = 0; r < rows; r++) { for (Index c = 0; c < cols; c++) { B.coeffRef(r, c) = A.coeff(r, c) / Scalar(alpha); } } VERIFY_IS_CWISE_APPROX(B.realView(), A.realView() / alpha); } template void test_realview(const T&) { using Scalar = typename T::Scalar; using RealScalar = typename NumTraits::Real; constexpr Index minRows = T::RowsAtCompileTime == Dynamic ? 1 : T::RowsAtCompileTime; constexpr Index maxRows = T::MaxRowsAtCompileTime == Dynamic ? (EIGEN_TEST_MAX_SIZE / 2) : T::MaxRowsAtCompileTime; constexpr Index minCols = T::ColsAtCompileTime == Dynamic ? 1 : T::ColsAtCompileTime; constexpr Index maxCols = T::MaxColsAtCompileTime == Dynamic ? (EIGEN_TEST_MAX_SIZE / 2) : T::MaxColsAtCompileTime; constexpr Index rowFactor = (NumTraits::IsComplex && !T::IsRowMajor) ? 2 : 1; constexpr Index colFactor = (NumTraits::IsComplex && T::IsRowMajor) ? 2 : 1; constexpr Index sizeFactor = NumTraits::IsComplex ? 2 : 1; const Index rows = internal::random(minRows, maxRows); const Index cols = internal::random(minCols, maxCols); const Index realViewRows = rowFactor * rows; const Index realViewCols = colFactor * cols; const T A = T::Random(rows, cols); T B; VERIFY_IS_EQUAL(A.realView().rows(), rowFactor * A.rows()); VERIFY_IS_EQUAL(A.realView().cols(), colFactor * A.cols()); VERIFY_IS_EQUAL(A.realView().size(), sizeFactor * A.size()); VERIFY_IS_APPROX(A.matrix().cwiseAbs2().sum(), A.realView().matrix().cwiseAbs2().sum()); // test re-sizing realView during assignment B.realView() = A.realView(); VERIFY_IS_APPROX(A, B); VERIFY_IS_APPROX(A.realView(), B.realView()); const RealScalar alpha = internal::random(RealScalar(1), RealScalar(2)); // B = A * alpha for (Index r = 0; r < rows; r++) { for (Index c = 0; c < cols; c++) { B.coeffRef(r, c) = A.coeff(r, c) * Scalar(alpha); } } VERIFY_IS_APPROX(B.realView(), A.realView() * alpha); B = A; B.realView() *= alpha; VERIFY_IS_APPROX(B.realView(), A.realView() * alpha); // B = A / alpha for (Index r = 0; r < rows; r++) { for (Index c = 0; c < cols; c++) { B.coeffRef(r, c) = A.coeff(r, c) / Scalar(alpha); } } VERIFY_IS_APPROX(B.realView(), A.realView() / alpha); B = A; B.realView() /= alpha; VERIFY_IS_APPROX(B.realView(), A.realView() / alpha); // force some usual access patterns Index malloc_size = (rows * cols * sizeof(Scalar)) + sizeof(RealScalar); void* data1 = internal::aligned_malloc(malloc_size); void* data2 = internal::aligned_malloc(malloc_size); Scalar* ptr1 = reinterpret_cast(reinterpret_cast(data1) + sizeof(RealScalar)); Scalar* ptr2 = reinterpret_cast(reinterpret_cast(data2) + sizeof(RealScalar)); Map C(ptr1, rows, cols), D(ptr2, rows, cols); C.setRandom(); D.setRandom(); for (Index r = 0; r < realViewRows; r++) { for (Index c = 0; c < realViewCols; c++) { C.realView().coeffRef(r, c) = D.realView().coeff(r, c); } } VERIFY_IS_CWISE_EQUAL(C, D); C = A; for (Index c = 0; c < realViewCols - 1; c++) { B.realView().row(0).coeffRef(realViewCols - 1 - c) = C.realView().row(0).coeff(c + 1); } D.realView().row(0).tail(realViewCols - 1) = C.realView().row(0).tail(realViewCols - 1).reverse(); VERIFY_IS_CWISE_EQUAL(B.realView().row(0).tail(realViewCols - 1), D.realView().row(0).tail(realViewCols - 1)); for (Index r = 0; r < realViewRows - 1; r++) { B.realView().col(0).coeffRef(realViewRows - 1 - r) = C.realView().col(0).coeff(r + 1); } D.realView().col(0).tail(realViewRows - 1) = C.realView().col(0).tail(realViewRows - 1).reverse(); VERIFY_IS_CWISE_EQUAL(B.realView().col(0).tail(realViewRows - 1), D.realView().col(0).tail(realViewRows - 1)); } template ::Vectorizable> struct test_edge_cases_impl { static void run() { using namespace internal; using RealScalar = typename NumTraits::Real; using ComplexPacket = typename packet_traits::type; using RealPacket = typename unpacket_traits::as_real; constexpr int ComplexSize = unpacket_traits::size; constexpr int RealSize = 2 * ComplexSize; VectorX a_data(2 * ComplexSize); Map> a_data_asreal(reinterpret_cast(a_data.data()), 2 * a_data.size()); VectorX b_data(RealSize); a_data.setRandom(); evaluator>> eval(a_data.realView()); for (Index offset = 0; offset < RealSize; offset++) { for (Index begin = 0; offset + begin < RealSize; begin++) { for (Index count = 0; begin + count < RealSize; count++) { b_data.setRandom(); RealPacket res = eval.template packetSegment(offset, begin, count); pstoreSegment(b_data.data(), res, begin, count); VERIFY_IS_CWISE_EQUAL(a_data_asreal.segment(offset + begin, count), b_data.segment(begin, count)); } } } } }; template struct test_edge_cases_impl { static void run() {} }; template void test_edge_cases(const ComplexScalar&) { test_edge_cases_impl::run(); } template void test_realview_readonly() { // if Rows == 1, don't test ColMajor as it is not a valid array using ColMajorMatrixType = Matrix; using ColMajorArrayType = Array; // if Cols == 1, don't test RowMajor as it is not a valid array using RowMajorMatrixType = Matrix; using RowMajorArrayType = Array; test_realview_readonly(ColMajorMatrixType()); test_realview_readonly(ColMajorArrayType()); test_realview_readonly(RowMajorMatrixType()); test_realview_readonly(RowMajorArrayType()); } template void test_realview_readwrite() { // if Rows == 1, don't test ColMajor as it is not a valid array using ColMajorMatrixType = Matrix; using ColMajorArrayType = Array; // if Cols == 1, don't test RowMajor as it is not a valid array using RowMajorMatrixType = Matrix; using RowMajorArrayType = Array; test_realview(ColMajorMatrixType()); test_realview(ColMajorArrayType()); test_realview(RowMajorMatrixType()); test_realview(RowMajorArrayType()); } template void test_realview() { test_realview_readwrite(); test_realview_readwrite, Rows, Cols, MaxRows, MaxCols>(); test_realview_readwrite(); test_realview_readwrite, Rows, Cols, MaxRows, MaxCols>(); test_realview_readwrite(); test_realview_readwrite, Rows, Cols, MaxRows, MaxCols>(); test_realview_readonly(); } EIGEN_DECLARE_TEST(realview) { for (int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1((test_realview())); CALL_SUBTEST_2((test_realview())); CALL_SUBTEST_3((test_realview())); CALL_SUBTEST_4((test_realview())); CALL_SUBTEST_5((test_realview<17, Dynamic, 17, Dynamic>())); CALL_SUBTEST_6((test_realview())); CALL_SUBTEST_7((test_realview<17, 19, 17, 19>())); CALL_SUBTEST_8((test_realview())); CALL_SUBTEST_9((test_realview<1, Dynamic>())); CALL_SUBTEST_10((test_realview<1, 1>())); CALL_SUBTEST_11(test_edge_cases(std::complex())); CALL_SUBTEST_12(test_edge_cases(std::complex())); } }