blob: 3998021e51bbc327d12ebbb8a367563b60a96f6f [file]
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2026 Rasmus Munk Larsen <rmlarsen@gmail.com>
//
// 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/.
// SPDX-License-Identifier: MPL-2.0
#include "sparse.h"
#include <Eigen/OrderingMethods>
template <typename Idx>
void verify_is_permutation(const PermutationMatrix<Dynamic, Dynamic, Idx>& perm) {
typedef Matrix<Idx, Dynamic, 1> Vec;
Vec sorted = perm.indices();
std::sort(sorted.data(), sorted.data() + sorted.size());
Vec expected = Vec::LinSpaced(perm.size(), 0, Idx(perm.size() - 1));
VERIFY_IS_EQUAL(sorted, expected);
}
template <typename Scalar>
void test_colamd_uncompressed() {
typedef int Idx;
typedef SparseMatrix<Scalar, ColMajor, Idx> SpMat;
const int n = 32;
SpMat A(n, n);
A.reserve(VectorXi::Constant(n, 5));
for (int j = 0; j < n; ++j) {
A.insert(j, j) = Scalar(2) + Scalar(j);
if (j > 0) A.insert(j - 1, j) = Scalar(-1);
if (j + 1 < n) A.insert(j + 1, j) = Scalar(-1);
}
A.insert(0, n - 1) = Scalar(0.5);
A.insert(n - 1, 0) = Scalar(0.25);
VERIFY(!A.isCompressed());
// Regression for #649: COLAMD on uncompressed input used to silently corrupt
// the permutation in release builds.
PermutationMatrix<Dynamic, Dynamic, Idx> perm_u, perm_c;
COLAMDOrdering<Idx> ord;
ord(A, perm_u);
verify_is_permutation(perm_u);
SpMat B = A;
B.makeCompressed();
ord(B, perm_c);
verify_is_permutation(perm_c);
VERIFY_IS_EQUAL(perm_u.indices(), perm_c.indices());
}
void test_colamd_mixed_index_types() {
typedef SparseMatrix<double, ColMajor, int> SpMat;
const int n = 8;
SpMat A(n, n);
A.reserve(VectorXi::Constant(n, 3));
for (int j = 0; j < n; ++j) {
A.insert(j, j) = 2.0 + j;
if (j > 0) A.insert(j - 1, j) = -1.0;
if (j + 1 < n) A.insert(j + 1, j) = -1.0;
}
A.makeCompressed();
// COLAMDOrdering<StorageIndex> is a public API choice independent of the
// source matrix's StorageIndex. Keep accepting mixed index types.
PermutationMatrix<Dynamic, Dynamic, long> perm;
COLAMDOrdering<long> ord;
ord(A, perm);
verify_is_permutation(perm);
}
template <typename Scalar>
void test_amd_uncompressed() {
typedef int Idx;
typedef SparseMatrix<Scalar, ColMajor, Idx> SpMat;
const int n = 24;
SpMat A(n, n);
A.reserve(VectorXi::Constant(n, 4));
for (int j = 0; j < n; ++j) {
A.insert(j, j) = Scalar(2) + Scalar(j);
if (j > 0) {
A.insert(j - 1, j) = Scalar(-1);
A.insert(j, j - 1) = Scalar(-1);
}
}
VERIFY(!A.isCompressed());
PermutationMatrix<Dynamic, Dynamic, Idx> perm;
AMDOrdering<Idx> ord;
ord(A, perm);
verify_is_permutation(perm);
}
EIGEN_DECLARE_TEST(sparse_ordering) {
for (int i = 0; i < g_repeat; ++i) {
CALL_SUBTEST_1(test_colamd_uncompressed<double>());
CALL_SUBTEST_2(test_colamd_uncompressed<std::complex<double> >());
CALL_SUBTEST_3(test_amd_uncompressed<double>());
CALL_SUBTEST_4(test_colamd_mixed_index_types());
}
}