# “Arnoldi” method for Eigenvalues inside FindRoot

I'm trying to implement a function which, given a matrix with one free parameter, would return the value of the parameter at which the lowest eigenvalue of the matrix is equal to a certain number.

Importantly, I'm planning to run this algorithm for extremely large sparse matrices, so I would like to use Arnoldi method.

Here's my attempt:

FitMat[matrix_, lowest_, param_, starting_, howmany_] :=
Module[{mat, fu},
mat[x_] := matrix /. {param -> x};
fu[x_] := Min[Eigenvalues[mat[x], howmany
, Method -> {"Arnoldi", "Criteria" -> "RealPart"}
]];
Return[
x /. FindRoot[fu[x] == lowest, {x, starting}
]
];
];

FitMat[( {
{1, 2, 1},
{3, 4, 1},
{x, 4, 9}
} ), -3, x, 50, 1]


This, however, results in the following error:

Eigenvalues::arm: Method -> Arnoldi can only be used for matrices of machine- or arbitrary-precision real numbers.


Please note that replacing mat[x_] and/or fu[x_] with mat[x_?NumericQ] and/or fu[x_?NumericQ] totally ruins the code, even if the Method specification is not used.

Could anyone please fix my solution or come up with a better one?

(Of course, the problem I'm trying to solve is highly non-linear; however, I typically do have a pretty good estimate for the value of starting. So, for small matrices the same code without specifying the Method works well.)

• Does defining the function give this error? Or calling it? If so, what are the arguments? – mikado Oct 21 '19 at 22:10
• Calling. Provided an example. – mavzolej Oct 21 '19 at 22:35
• What do you mean by fu[x_?NumericQ] totally ruins the code? Without it I'm getting messages about a singular Jacobian whenever I try to insert the initial condition inside the function to avoid that issue. – b3m2a1 Oct 22 '19 at 4:59
• However, if you just comment the line with Method, the code works as it should. – mavzolej Oct 22 '19 at 7:01
• I was just drawing the parallel with this question - in my case, adding _NumericQ to definitions does not seem to resolve the issue. – mavzolej Oct 22 '19 at 7:06

I think there are a few things going on.

First, as the error message says, the Arnoldi method requires machine- or arbitrary-precision real numbers. Your matrix is made of integers, hence the message.

Second, you do need fu[x_?NumericQ] to avoid FindRoot from prematurely evaluating fu without a number.

Finally, for your example, there appears to be no such root. If you insert

Print[Plot[fu[x], {x, -100, 100}, PlotRange -> All]];


into FitMat, you'll see Clearly, this never equals -3, so FindRoot fails.

If you try

FitMat[({{1., 2., 1.}, {3., 4., 1.}, {x, 4., 9.}}), 15, x, 50, 1]


instead, you get the answer 63.0769 with no errors or messages.

EDIT:

To find where the smallest (most negative) eigenvalue equals -3 you can use the -1 option for the Arnoldi method together with a Shift. No Min needed!

FitMat[matrix_, lowest_, param_, starting_] :=
Module[{mat, fu}, mat[x_] := matrix /. {param -> x};
fu[x_?NumericQ] :=
Eigenvalues[mat[x], -1,
Method -> {"Arnoldi", "Criteria" -> "RealPart",
"Shift" -> -1000}];
Print[Plot[{fu[x], lowest}, {x, -100, 100}, PlotRange -> All]];
Return[x /. FindRoot[fu[x] == lowest, {x, starting}]];];

FitMat[({{1., 2., 1.}, {3., 4., 1.}, {x, 4., 9.}}), -3, x, 50] (* 52. *)

• If you run Eigenvalues[( { {1, 2, 1}, {3, 4, 1}, {52., 4, 9} } )], you will see that the lowest eigenvalue is -3. – mavzolej Oct 22 '19 at 12:33
• Yes, but your Min is outside the Eigenvalues[{{1, 2, 1}, {3, 4, 1}, {52., 4, 9}}, 1, Method -> {"Arnoldi", "Criteria" -> "RealPart"}], which returns only one eigenvalue (the largest), so you might need to rethink you approach. – Chris K Oct 22 '19 at 12:40
• Try Eigenvalues[{{1, 2, 1}, {3, 4, 1}, {52., 4, 9}}, -1, Method -> {"Arnoldi", "Criteria" -> "RealPart", "Shift" -> -1000}] instead -- see this answer by @CarlWoll. – Chris K Oct 22 '19 at 12:43
• Thank you so much for the answer and comments! I was confused because of misunderstanding what "Criteria" -> "RealPart" does. – mavzolej Oct 22 '19 at 12:54