diff --git a/test/adjoint.cpp b/test/adjoint.cpp index 636647694..28562b7f8 100644 --- a/test/adjoint.cpp +++ b/test/adjoint.cpp @@ -207,6 +207,48 @@ void adjoint_extra() { a = a.transpose(); } +template +void inner_product_boundary_sizes() { + const Index PS = internal::packet_traits::size; + // Sizes that exercise every branch in the 4-way unrolled vectorized inner product: + // scalar fallback (< PS), 1-3 packets, quad loop entry/exit, remainder packets, scalar cleanup + const Index sizes[] = {0, + 1, + PS - 1, + PS, + PS + 1, + 2 * PS - 1, + 2 * PS, + 2 * PS + 1, + 3 * PS - 1, + 3 * PS, + 3 * PS + 1, + 4 * PS - 1, + 4 * PS, + 4 * PS + 1, + 8 * PS, + 8 * PS + 1, + 8 * PS + PS, + 8 * PS + 2 * PS, + 8 * PS + 3 * PS, + 8 * PS + 3 * PS + 1}; + for (int si = 0; si < 20; ++si) { + const Index n = sizes[si]; + if (n <= 0) continue; + typedef Matrix Vec; + Vec v1 = Vec::Random(n); + Vec v2 = Vec::Random(n); + // Reference: scalar loop + Scalar expected(0); + for (Index k = 0; k < n; ++k) expected += numext::conj(v1(k)) * v2(k); + VERIFY_IS_APPROX(v1.dot(v2), expected); + // Also test squaredNorm + Scalar sq_expected(0); + for (Index k = 0; k < n; ++k) sq_expected += numext::conj(v1(k)) * v1(k); + VERIFY_IS_APPROX(v1.squaredNorm(), numext::real(sq_expected)); + } +} + EIGEN_DECLARE_TEST(adjoint) { for (int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1(adjoint(Matrix())); @@ -233,4 +275,10 @@ EIGEN_DECLARE_TEST(adjoint) { CALL_SUBTEST_7(adjoint(Matrix())); CALL_SUBTEST_13(adjoint_extra<0>()); + + // Inner product vectorization boundary tests (deterministic, outside g_repeat) + CALL_SUBTEST_14(inner_product_boundary_sizes()); + CALL_SUBTEST_15(inner_product_boundary_sizes()); + CALL_SUBTEST_16(inner_product_boundary_sizes>()); + CALL_SUBTEST_17(inner_product_boundary_sizes>()); } diff --git a/test/block.cpp b/test/block.cpp index 8f7c8de68..5f48bfd1f 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -87,6 +87,32 @@ void block(const MatrixType& m) { m1.col(c1).setZero(); VERIFY_IS_CWISE_EQUAL(m1.col(c1), DynamicVectorType::Zero(rows)); m1 = m1_copy; + // test setZero/setConstant/setOnes on non-contiguous multi-row/multi-col blocks + // This exercises the non-fill_n path in Fill.h and verifies no data corruption + if (r2 > r1 && c2 > c1) { + Index br = r2 - r1, bc = c2 - c1; + m1 = m1_copy; + m1.block(r1, c1, br, bc).setZero(); + VERIFY_IS_CWISE_EQUAL(m1.block(r1, c1, br, bc), DynamicMatrixType::Zero(br, bc)); + for (Index j = 0; j < cols; ++j) + for (Index i = 0; i < rows; ++i) + if (i < r1 || i >= r2 || j < c1 || j >= c2) VERIFY_IS_EQUAL(m1(i, j), m1_copy(i, j)); + + m1 = m1_copy; + m1.block(r1, c1, br, bc).setConstant(s1); + VERIFY_IS_CWISE_EQUAL(m1.block(r1, c1, br, bc), DynamicMatrixType::Constant(br, bc, s1)); + for (Index j = 0; j < cols; ++j) + for (Index i = 0; i < rows; ++i) + if (i < r1 || i >= r2 || j < c1 || j >= c2) VERIFY_IS_EQUAL(m1(i, j), m1_copy(i, j)); + + m1 = m1_copy; + m1.block(r1, c1, br, bc).setOnes(); + VERIFY_IS_CWISE_EQUAL(m1.block(r1, c1, br, bc), DynamicMatrixType::Ones(br, bc)); + for (Index j = 0; j < cols; ++j) + for (Index i = 0; i < rows; ++i) + if (i < r1 || i >= r2 || j < c1 || j >= c2) VERIFY_IS_EQUAL(m1(i, j), m1_copy(i, j)); + } + m1 = m1_copy; // check row() and col() VERIFY_IS_EQUAL(m1.col(c1).transpose(), m1.transpose().row(c1)); diff --git a/test/io.cpp b/test/io.cpp index 219e1cbfb..637f02d9c 100644 --- a/test/io.cpp +++ b/test/io.cpp @@ -48,7 +48,7 @@ static void check_ostream() { check_ostream_impl::run(); } -EIGEN_DECLARE_TEST(rand) { +EIGEN_DECLARE_TEST(io) { CALL_SUBTEST(check_ostream()); CALL_SUBTEST(check_ostream()); CALL_SUBTEST(check_ostream()); diff --git a/test/redux.cpp b/test/redux.cpp index 71ef535ef..af5c11d69 100644 --- a/test/redux.cpp +++ b/test/redux.cpp @@ -152,6 +152,47 @@ void vectorRedux(const VectorType& w) { VERIFY_RAISES_ASSERT(v.head(0).maxCoeff()); } +void boolRedux(Index rows, Index cols) { + // Test boolean reductions: all(), any(), count() + typedef Array BoolArray; + + // All-true + BoolArray all_true = BoolArray::Constant(rows, cols, true); + VERIFY(all_true.all()); + VERIFY(all_true.any()); + VERIFY_IS_EQUAL(all_true.count(), rows * cols); + + // All-false + BoolArray all_false = BoolArray::Constant(rows, cols, false); + if (rows > 0 && cols > 0) { + VERIFY(!all_false.all()); + VERIFY(!all_false.any()); + } + VERIFY_IS_EQUAL(all_false.count(), Index(0)); + + // Mixed: set a checkerboard pattern + BoolArray mixed(rows, cols); + Index expected_count = 0; + for (Index j = 0; j < cols; ++j) + for (Index i = 0; i < rows; ++i) { + mixed(i, j) = ((i + j) % 2 == 0); + if (mixed(i, j)) expected_count++; + } + VERIFY_IS_EQUAL(mixed.count(), expected_count); + if (rows > 0 && cols > 0) { + VERIFY(mixed.any()); + VERIFY(mixed.all() == (expected_count == rows * cols)); + } + + // Partial reductions + if (rows > 0 && cols > 0) { + auto col_counts = mixed.colwise().count(); + for (Index k = 0; k < cols; ++k) VERIFY_IS_EQUAL(col_counts(k), mixed.col(k).count()); + auto row_counts = mixed.rowwise().count(); + for (Index k = 0; k < rows; ++k) VERIFY_IS_EQUAL(row_counts(k), mixed.row(k).count()); + } +} + EIGEN_DECLARE_TEST(redux) { // the max size cannot be too large, otherwise reduxion operations obviously generate large errors. int maxsize = (std::min)(100, EIGEN_TEST_MAX_SIZE); @@ -202,4 +243,9 @@ EIGEN_DECLARE_TEST(redux) { CALL_SUBTEST_10(vectorRedux(VectorX(size))); CALL_SUBTEST_10(vectorRedux(ArrayX(size))); } + // Bool reductions (deterministic, outside g_repeat) + CALL_SUBTEST_11(boolRedux(1, 1)); + CALL_SUBTEST_11(boolRedux(4, 4)); + CALL_SUBTEST_11(boolRedux(7, 13)); + CALL_SUBTEST_11(boolRedux(63, 63)); } diff --git a/test/vectorwiseop.cpp b/test/vectorwiseop.cpp index d037bb49b..bccfe70cd 100644 --- a/test/vectorwiseop.cpp +++ b/test/vectorwiseop.cpp @@ -91,6 +91,16 @@ void vectorwiseop_array(const ArrayType& m) { VERIFY((mb.col(c) == (m1.real().col(c) >= 0.7).any()).all()); mb = (m1.real() >= 0.7).rowwise().any(); VERIFY((mb.row(r) == (m1.real().row(r) >= 0.7).any()).all()); + + // test count() + { + Array colcounts(cols); + Array rowcounts(rows); + colcounts = (m1.real() >= 0).colwise().count(); + for (Index k = 0; k < cols; ++k) VERIFY_IS_EQUAL(colcounts(k), (m1.real().col(k) >= 0).count()); + rowcounts = (m1.real() >= 0).rowwise().count(); + for (Index k = 0; k < rows; ++k) VERIFY_IS_EQUAL(rowcounts(k), (m1.real().row(k) >= 0).count()); + } } template @@ -206,6 +216,15 @@ void vectorwiseop_matrix(const MatrixType& m) { VERIFY_EVALUATION_COUNT(m2 = (m1.rowwise() - m1.colwise().sum() / RealScalar(m1.rows())), (MatrixType::RowsAtCompileTime != 1 ? 1 : 0)); + // test colwise/rowwise reverse + { + MatrixType m_rev(rows, cols); + m_rev = m1.colwise().reverse(); + for (Index k = 0; k < cols; ++k) VERIFY_IS_APPROX(m_rev.col(k), m1.col(k).reverse()); + m_rev = m1.rowwise().reverse(); + for (Index k = 0; k < rows; ++k) VERIFY_IS_APPROX(m_rev.row(k), m1.row(k).reverse()); + } + // test empty expressions VERIFY_IS_APPROX(m1.matrix().middleCols(0, 0).rowwise().sum().eval(), MatrixX::Zero(rows, 1)); VERIFY_IS_APPROX(m1.matrix().middleRows(0, 0).colwise().sum().eval(), MatrixX::Zero(1, cols)); @@ -224,6 +243,73 @@ void vectorwiseop_matrix(const MatrixType& m) { VERIFY_IS_EQUAL(m1.real().middleCols(0, fix<0>).colwise().maxCoeff().eval().cols(), 0); } +// Integer-safe subset of vectorwiseop_array: tests +, -, all/any, count only. +// Skips *, / which cause integer overflow or division-by-zero with full-range random ints. +template +void vectorwiseop_array_integer(const ArrayType& m) { + typedef typename ArrayType::Scalar Scalar; + typedef Array ColVectorType; + typedef Array RowVectorType; + + Index rows = m.rows(); + Index cols = m.cols(); + Index r = internal::random(0, rows - 1), c = internal::random(0, cols - 1); + + ArrayType m1 = ArrayType::Random(rows, cols), m2(rows, cols); + // Clamp to avoid overflow even in addition/subtraction. + for (Index j = 0; j < cols; ++j) + for (Index i = 0; i < rows; ++i) m1(i, j) = m1(i, j) % Scalar(10000); + + ColVectorType colvec = ColVectorType::Random(rows); + for (Index i = 0; i < rows; ++i) colvec(i) = colvec(i) % Scalar(10000); + RowVectorType rowvec = RowVectorType::Random(cols); + for (Index j = 0; j < cols; ++j) rowvec(j) = rowvec(j) % Scalar(10000); + + // test addition + m2 = m1; + m2.colwise() += colvec; + VERIFY_IS_APPROX(m2, m1.colwise() + colvec); + VERIFY_IS_APPROX(m2.col(c), m1.col(c) + colvec); + + m2 = m1; + m2.rowwise() += rowvec; + VERIFY_IS_APPROX(m2, m1.rowwise() + rowvec); + VERIFY_IS_APPROX(m2.row(r), m1.row(r) + rowvec); + + // test subtraction + m2 = m1; + m2.colwise() -= colvec; + VERIFY_IS_APPROX(m2, m1.colwise() - colvec); + VERIFY_IS_APPROX(m2.col(c), m1.col(c) - colvec); + + m2 = m1; + m2.rowwise() -= rowvec; + VERIFY_IS_APPROX(m2, m1.rowwise() - rowvec); + VERIFY_IS_APPROX(m2.row(r), m1.row(r) - rowvec); + + // all/any + Array mb(rows, cols); + mb = (m1 <= Scalar(0)).colwise().all(); + VERIFY((mb.col(c) == (m1.col(c) <= Scalar(0)).all()).all()); + mb = (m1 <= Scalar(0)).rowwise().all(); + VERIFY((mb.row(r) == (m1.row(r) <= Scalar(0)).all()).all()); + + mb = (m1 >= Scalar(0)).colwise().any(); + VERIFY((mb.col(c) == (m1.col(c) >= Scalar(0)).any()).all()); + mb = (m1 >= Scalar(0)).rowwise().any(); + VERIFY((mb.row(r) == (m1.row(r) >= Scalar(0)).any()).all()); + + // test count() + { + Array colcounts(cols); + Array rowcounts(rows); + colcounts = (m1 >= Scalar(0)).colwise().count(); + for (Index k = 0; k < cols; ++k) VERIFY_IS_EQUAL(colcounts(k), (m1.col(k) >= Scalar(0)).count()); + rowcounts = (m1 >= Scalar(0)).rowwise().count(); + for (Index k = 0; k < rows; ++k) VERIFY_IS_EQUAL(rowcounts(k), (m1.row(k) >= Scalar(0)).count()); + } +} + void vectorwiseop_mixedscalar() { Matrix4cd a = Matrix4cd::Random(); Vector4cd b = Vector4cd::Random(); @@ -248,4 +334,6 @@ EIGEN_DECLARE_TEST(vectorwiseop) { CALL_SUBTEST_7(vectorwiseop_matrix(VectorXd(internal::random(1, EIGEN_TEST_MAX_SIZE)))); CALL_SUBTEST_7(vectorwiseop_matrix(RowVectorXd(internal::random(1, EIGEN_TEST_MAX_SIZE)))); CALL_SUBTEST_8(vectorwiseop_mixedscalar()); + CALL_SUBTEST_9(vectorwiseop_array_integer( + ArrayXXi(internal::random(1, EIGEN_TEST_MAX_SIZE), internal::random(1, EIGEN_TEST_MAX_SIZE)))); }