# Trace change of one single value in a list

I have a list of eigenvalues, say:

list1 = {10., 9., 9., 8.5, 7.5, 6.5, 6.1, 5.6, 4.5, 4., 4., 3.8, 3.,
3., 1., 1., 1., 0.8, 0.5, 0.5}


After slightly modifying my matrix with a tuning parameter, I find that most of the eigenvalues change only insignificantly, but one of the elements decreases as in:

list2 = {10.1, 9.2, 8.9, 8.4, 7.6, 6.4, 6.1, 4.6, 4.1, 3.9, 3.7, 3.5, 3.1,
3., 1.1, 0.9, 0.8, 0.8, 0.3, 0.2}


where the 5.6 changed to 3.5. If I increase my parameter this value would go down even further until it eventually turns imaginary while the rest remains more or less the same.

I would like to construct a function that traces the change of this single value and plots its value as a function of my tuning parameter. I think the best way to solve this is to compare the current list with the one before the change and pick the eigenvalue that changed more than a given tolerance value.

tol = 0.3
Function[list1,list2,tol]

(* 3.5 *)


The issue here is that Mathematica orders the eigenvalues according to their magnitude so once the value that decreases the most becomes smaller than the next value in the list, they will switch positions.

Of course, any other solution would also be very helpful!

• you can try using the roots of the characteristic polynomial (instead of Eigenvalues) as, for example, in this answer. – kglr Sep 1 '19 at 23:36
• Also there is a formula for how the eigenvalues of a matrix change with a parameter here: mathematica.stackexchange.com/a/195787/23105 – SPPearce Sep 3 '19 at 9:01

This works for your example, more or less, but I'm not sure how robust it is.

listmatch reorders list2, by finding the most divergent position, then iteratively swapping that position with the next most divergent position. Iterations continue while the distance between the two lists, except for the most divergent position, is getting smaller.

listmatch[list1_, list2_] := Module[{
temp = list2,
newlist = list2,
diffs = Round[Abs[list1 - list2], .01],
dist, maxpos, maxpos2, tempdist},
dist = Total[Sort[diffs][[;; -2]]];
maxpos = Position[diffs, Max[diffs]][[1, 1]];
maxpos2 = maxpos;
While[True,
{
maxpos2 = First[Flatten[Position[diffs, Max[diffs[[maxpos2 + 1 ;;]]]]]];
temp = ReplacePart[temp, {maxpos -> temp[[maxpos2]], maxpos2 -> temp[[maxpos]]}];
diffs = Round[Abs[list1 - temp], .01];
tempdist = Total[Sort[diffs][[;; -2]]];
If[tempdist < dist, {dist = tempdist; newlist = temp},
Return[newlist, Module]];
}]]

reorderedlist = listmatch[list1, list2]
(*  {10.1, 9.2, 8.9, 8.4, 7.6, 6.4, 6.1, 3.5, 4.6, 3.9, 4.1, 3.7, 3.1, \
3., 1.1, 0.9, 0.8, 0.8, 0.3, 0.2}  *)


Comparing the original list1 and list2:

ListPlot[{list1, list2}, PlotStyle -> {Black, Red}]


And list1 with the reordered list:

ListPlot[{list1, reorderedlist}, PlotStyle -> {Black, Red}]


The changed element could then be chosen by picking the most divergent one

maxchanged[list1_, list2_] := Module[
{diffs = Round[Abs[list1 - list2], .01]},
list2[[Position[diffs, Max[diffs]][[1, 1]]]]
]

maxchanged[list1, reorderedlist]
(*  3.5  *)


Or by getting a list of all elements changed by more than a given tolerance value

tolerancechanged[list1_, list2_, tol_] := Module[
{diffs = Round[Abs[list1 - list2], .01]},
list2[[Flatten[Position[diffs, #] & /@ Select[diffs, # > tol &]]]]
]

tolerancechanged[list1, reorderedlist, .3]
(*  {3.5}   *)