diff --git a/src/Numerics.Tests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs b/src/Numerics.Tests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs
index 59a6a70c0..48f4bd335 100644
--- a/src/Numerics.Tests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs
+++ b/src/Numerics.Tests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs
@@ -259,5 +259,26 @@ public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Valu
AssertHelpers.AlmostEqual(ACopy, A, 14);
AssertHelpers.AlmostEqual(BCopy, B, 14);
}
+
+ ///
+ /// Factorizing a defective matrix with a repeated eigenvalue throws
+ /// NonConvergenceException instead of looping forever (see issue #11).
+ /// This exercises the managed provider path used by DenseMatrix.Evd().
+ ///
+ [Test]
+ public void DefectiveMatrixThrowsNonConvergenceException()
+ {
+ // Lower-triangular with a single eigenvalue (0.9275488) of algebraic
+ // multiplicity 3 - a defective (non-diagonalizable) matrix that the
+ // non-symmetric complex QR iteration cannot converge on.
+ var matrix = Matrix.Build.DenseOfArray(new[,]
+ {
+ { new Complex(0.9275488, 0), Complex.Zero, Complex.Zero },
+ { new Complex(-0.9275488, 0), new Complex(0.9275488, 0), Complex.Zero },
+ { Complex.Zero, new Complex(-0.9275488, 0), new Complex(0.9275488, 0) }
+ });
+
+ Assert.Throws(() => matrix.Evd());
+ }
}
}
diff --git a/src/Numerics.Tests/LinearAlgebraTests/Complex/Factorization/UserEvdTests.cs b/src/Numerics.Tests/LinearAlgebraTests/Complex/Factorization/UserEvdTests.cs
index 5a8dadc05..41f48a862 100644
--- a/src/Numerics.Tests/LinearAlgebraTests/Complex/Factorization/UserEvdTests.cs
+++ b/src/Numerics.Tests/LinearAlgebraTests/Complex/Factorization/UserEvdTests.cs
@@ -314,5 +314,25 @@ public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Valu
AssertHelpers.AlmostEqual(ACopy, A, 14);
AssertHelpers.AlmostEqual(BCopy, B, 14);
}
+
+ ///
+ /// Factorizing a defective matrix with a repeated eigenvalue throws
+ /// NonConvergenceException instead of looping forever (see issue #11).
+ ///
+ [Test]
+ public void DefectiveMatrixThrowsNonConvergenceException()
+ {
+ // Lower-triangular with a single eigenvalue (0.9275488) of algebraic
+ // multiplicity 3 - a defective (non-diagonalizable) matrix that the
+ // non-symmetric complex QR iteration cannot converge on.
+ var matrixA = new UserDefinedMatrix(new[,]
+ {
+ { new Complex(0.9275488, 0), Complex.Zero, Complex.Zero },
+ { new Complex(-0.9275488, 0), new Complex(0.9275488, 0), Complex.Zero },
+ { Complex.Zero, new Complex(-0.9275488, 0), new Complex(0.9275488, 0) }
+ });
+
+ Assert.Throws(() => matrixA.Evd());
+ }
}
}
diff --git a/src/Numerics.Tests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs b/src/Numerics.Tests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs
index ff1cf8efd..be4747dbb 100644
--- a/src/Numerics.Tests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs
+++ b/src/Numerics.Tests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs
@@ -257,5 +257,26 @@ public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Valu
AssertHelpers.AlmostEqual(ACopy, A, 14);
AssertHelpers.AlmostEqual(BCopy, B, 14);
}
+
+ ///
+ /// Factorizing a defective matrix with a repeated eigenvalue throws
+ /// NonConvergenceException instead of looping forever (see issue #11).
+ /// This exercises the managed provider path used by DenseMatrix.Evd().
+ ///
+ [Test]
+ public void DefectiveMatrixThrowsNonConvergenceException()
+ {
+ // Lower-triangular with a single eigenvalue (0.9275488) of algebraic
+ // multiplicity 3 - a defective (non-diagonalizable) matrix that the
+ // non-symmetric complex QR iteration cannot converge on.
+ var matrix = Matrix.Build.DenseOfArray(new[,]
+ {
+ { new Complex32(0.9275488f, 0f), Complex32.Zero, Complex32.Zero },
+ { new Complex32(-0.9275488f, 0f), new Complex32(0.9275488f, 0f), Complex32.Zero },
+ { Complex32.Zero, new Complex32(-0.9275488f, 0f), new Complex32(0.9275488f, 0f) }
+ });
+
+ Assert.Throws(() => matrix.Evd());
+ }
}
}
diff --git a/src/Numerics.Tests/LinearAlgebraTests/Complex32/Factorization/UserEvdTests.cs b/src/Numerics.Tests/LinearAlgebraTests/Complex32/Factorization/UserEvdTests.cs
index d66777007..dccac157e 100644
--- a/src/Numerics.Tests/LinearAlgebraTests/Complex32/Factorization/UserEvdTests.cs
+++ b/src/Numerics.Tests/LinearAlgebraTests/Complex32/Factorization/UserEvdTests.cs
@@ -312,5 +312,25 @@ public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Valu
AssertHelpers.AlmostEqual(ACopy, A, 14);
AssertHelpers.AlmostEqual(BCopy, B, 14);
}
+
+ ///
+ /// Factorizing a defective matrix with a repeated eigenvalue throws
+ /// NonConvergenceException instead of looping forever (see issue #11).
+ ///
+ [Test]
+ public void DefectiveMatrixThrowsNonConvergenceException()
+ {
+ // Lower-triangular with a single eigenvalue (0.9275488) of algebraic
+ // multiplicity 3 - a defective (non-diagonalizable) matrix that the
+ // non-symmetric complex QR iteration cannot converge on.
+ var matrixA = new UserDefinedMatrix(new[,]
+ {
+ { new Complex32(0.9275488f, 0f), Complex32.Zero, Complex32.Zero },
+ { new Complex32(-0.9275488f, 0f), new Complex32(0.9275488f, 0f), Complex32.Zero },
+ { Complex32.Zero, new Complex32(-0.9275488f, 0f), new Complex32(0.9275488f, 0f) }
+ });
+
+ Assert.Throws(() => matrixA.Evd());
+ }
}
}
diff --git a/src/Numerics/LinearAlgebra/Complex/Factorization/UserEvd.cs b/src/Numerics/LinearAlgebra/Complex/Factorization/UserEvd.cs
index b8409882b..f0c714387 100644
--- a/src/Numerics/LinearAlgebra/Complex/Factorization/UserEvd.cs
+++ b/src/Numerics/LinearAlgebra/Complex/Factorization/UserEvd.cs
@@ -662,6 +662,10 @@ static void NonsymmetricReduceHessenberToRealSchur(Matrix eigenVectors,
exshift += s;
iter++;
+ if (iter >= 30*order)
+ {
+ throw new NonConvergenceException();
+ }
// Reduce to triangle (rows)
for (var i = l + 1; i <= n; i++)
diff --git a/src/Numerics/LinearAlgebra/Complex32/Factorization/UserEvd.cs b/src/Numerics/LinearAlgebra/Complex32/Factorization/UserEvd.cs
index d5dbca343..6fbd1366d 100644
--- a/src/Numerics/LinearAlgebra/Complex32/Factorization/UserEvd.cs
+++ b/src/Numerics/LinearAlgebra/Complex32/Factorization/UserEvd.cs
@@ -666,6 +666,10 @@ static void NonsymmetricReduceHessenberToRealSchur(Matrix eigenVector
exshift += s;
iter++;
+ if (iter >= 30*order)
+ {
+ throw new NonConvergenceException();
+ }
// Reduce to triangle (rows)
for (var i = l + 1; i <= n; i++)
diff --git a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs
index 97ca54148..db3bcb4ee 100644
--- a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs
+++ b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs
@@ -3055,6 +3055,10 @@ internal static void NonsymmetricReduceHessenberToRealSchur(Complex[] vectorV, C
exshift += s;
iter++;
+ if (iter >= 30*order)
+ {
+ throw new NonConvergenceException();
+ }
// Reduce to triangle (rows)
for (var i = l + 1; i <= n; i++)
diff --git a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs
index fbbc96f08..d5d0e3ddf 100644
--- a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs
+++ b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs
@@ -3057,6 +3057,10 @@ internal static void NonsymmetricReduceHessenberToRealSchur(Complex32[] vectorV,
exshift += s;
iter++;
+ if (iter >= 30*order)
+ {
+ throw new NonConvergenceException();
+ }
// Reduce to triangle (rows)
for (var i = l + 1; i <= n; i++)