# How to instruct internal function to evaluate arguments only after numerical values are plugged in?

For convenience, let me start with a simple example. The following code calculates the sorted eigenvalues of a 4x4 Hermitian matrix with a parameter x

eigen[x_] :=
Sort[Eigenvalues[(1 - x^2) KroneckerProduct[PauliMatrix[3],
PauliMatrix[0]] +
Cos[x] KroneckerProduct[PauliMatrix[1], PauliMatrix[3]] +
KroneckerProduct[PauliMatrix[2], PauliMatrix[3]] +
3 Sin[x] KroneckerProduct[PauliMatrix[1], PauliMatrix[1]]]]


If I call eigen with a numerical value, say 1.0, then everything works fine. But if I call eigen as eigen[x], the Sort function won't be able to correctly sort the eigenvalues. For example, on my machine, eigen[x] /. {x -> 1.0} returns {-1.61733, 1.61733, -3.56559, 3.56559}.

I want to minimize the difference between the third smallest eigenvalue and the second smallest eigenvalue, so I write FindMinimum[eigen[x][[3]]-eigen[x][[2]], {x, 1.0}]. However, it seems that FindMinimum will try to evaluate the first argument with the symbol x such that the eigenvalues are not correctly sorted.

Is there a way that I can instruct the internal function (e.g., FindMinimum) to leave the first argument unevaluated? I notice that FindMinimum already have HoldAll attribute but still tries to manipulate the symbolic expression.

• Have you seen this already? Dec 25, 2020 at 17:20
• @J.M.'sennui I haven't, but I already played with NumericQ a bit. If I define the function as eigen[x_?NumericQ]:=..., eigen[x][[1]] will be evaluated to x, which is clearly not what I want. Dec 25, 2020 at 17:37
• With the definition eigen[x_?NumericQ]:=..., eigen[x] returns unevaluated, so eigen[x][[1]] is the argument of the unevaluated function. You use the function as before, i.e., eigen[1.] Dec 25, 2020 at 17:44

Clear["Global*"]

eigen[x_?NumericQ] :=
Sort[Eigenvalues[(1 - x^2) KroneckerProduct[PauliMatrix[3],
PauliMatrix[0]] +
Cos[x] KroneckerProduct[PauliMatrix[1], PauliMatrix[3]] +
KroneckerProduct[PauliMatrix[2], PauliMatrix[3]] +
3 Sin[x] KroneckerProduct[PauliMatrix[1], PauliMatrix[1]]]]


Use a helper function to evaluate eigen

dif[x_?NumericQ] := Module[{lst = eigen[x]}, lst[[3]] - lst[[1]]]

{min, arg} = FindMinimum[dif[x], {x, 1.0}]

(* {3.4641, {x -> -1.29913*10^-8}} *)
`