# Sorting Eigensystem According to Complicated Rule

I have looked for an answer to this but the near duplicates I could find seemed slightly distinct.

I have a matrix $$A$$ which has eigenvalues in pairs $$\lambda_1,-\lambda_1,\lambda_2,-\lambda_2,\dots$$. I would like to sort the eigensystem such that the eigenvectors are in this order, with the eigenvalues having descending real parts. That is, I want to sort in descending order of the function $$f=|\Re(\cdot)|$$ and break ties by $$g=\Re(\cdot)$$.

What I was hoping for was something like:

f[z_] := Abs[Re[z]];
g[z_] := Re[z];
{eval,evec} = SortBy[Eigensystem[N[A]]\[Transpose],{f,z}]\[Transpose];



but this doesn't work. Replacing {f,g} with Abs@*Re does work but not for the tiebreak (neither does {Abs@*Re,Re}).

An example matrix that is $$8\times 8$$ is the following (although any anti-symmetric matrix has plus/minus pairs of eigenvalues):

A = {{0, 0, -1, -4*I, 0, 0, 0, 0},
{0, 0, 0, -1, 0, 0, 0, 0}, {1, 0, 0, 0, -1, -4*I,
0, 0}, {4*I, 1, 0, 0, 0, -1, 0, 0},
{0, 0, 1, 0, 0, 0, -1, -4*I}, {0, 0, 4*I, 1, 0, 0,
0, -1}, {0, 0, 0, 0, 1, 0, 0, 0},
{0, 0, 0, 0, 4*I, 1, 0, 0}}


Edit: Additionally, I have realised since writing this that for my application I probably want to organise the sorting differently than I've asked for. In particular I want to order first by f[z_] :=Abs[Re[z]], then break ties first by g[z_]:=Re[z]*Im[z] and second by h[z_]:=Re[z]. So a solution that enables me to simply list three functions f,g,h which I've defined elsewhere in my code would be preferable.

• What is your A? Nov 21, 2020 at 0:26
• A is some matrix defined elsewhere in my code. A typical small example would beA = {{0,0,1,-I},{0,0,0,1},{-1,0,0,0},{I,-1,0,0}}. Nov 21, 2020 at 12:53

New Edition

A = {{0, 0, 1, -I}, {0, 0, 0, 1}, {-1, 0, 0, 0}, {I, -1, 0, 0}};
result = Rule @@ Reverse@(A // N // Eigensystem) // Thread //
Association
SortBy[result, Re, Abs[#1] > Abs[#2] &]


Old Editon

We need a large A to test the code.

A = {{0, 0, 1, -I}, {0, 0, 0, 1}, {-1, 0, 0, 0}, {I, -1, 0, 0}};
result = Rule @@ Reverse@(A // N // Eigensystem) // Thread //
Association
ReverseSortBy[result, {Abs@*Re[#] &, Re[#] &}]


Original

What is your A?

use Association can keep the tie. Since we don't know A,here we set

eval=A//N//Eigensystem//First;
evac=A//N//Eigensystem//Last;

eval = {1 + 3 I, -(1 + 3 I), 2 - I, -(2 - I), 5 + I, -(5 + I),
3 - 8 I, -(3 - 8 I), 0.1 - 8 I, -(0.1 - 8 I)};
evac = Array[v, Length@eval];
result = ReverseSortBy[
Association[Thread[evac -> eval]], {Abs[Re[#]] &, Re[#] &}]
{neweval, newevec} = {Values[result], Keys[result]};

<|v[5] -> 5 + I, v[6] -> -5 - I, v[7] -> 3 - 8 I, v[8] -> -3 + 8 I,
v[3] -> 2 - I, v[4] -> -2 + I, v[1] -> 1 + 3 I, v[2] -> -1 - 3 I,
v[9] -> 0.1 - 8. I, v[10] -> -0.1 + 8. I|>

{{5 + I, -5 - I, 3 - 8 I, -3 + 8 I, 2 - I, -2 + I, 1 + 3 I, -1 - 3 I,
0.1 - 8. I, -0.1 + 8. I}, {v[5], v[6], v[7], v[8], v[3], v[4], v[1],
v[2], v[9], v[10]}}

• ReverseSortBy[Eigensystem[N[A]] // Transpose, {Abs[Re[#]], Re[#]} &] // Transpose should be enough Nov 21, 2020 at 19:39
• I'm having difficulty getting the first solution to work at all. The original solution seems to sort in the opposite order to the one I want - that is, for an example 4x4 matrix I might get real parts in the order (-3.7 , +3.7, -0.27, +0.27) whilst I want (+3.7,-3.7+0.27,-0.27). Nov 23, 2020 at 10:54
• @Roman does that differ substantially than what I put in the OP? I can't get that to work either. Nov 23, 2020 at 10:55
• @jacob1729 you can edit you original question and add a 10*10 matrix so that we can easy to test the method. Nov 23, 2020 at 10:58
• @cvgmt I have realised that the order I specified in the OP is not correct for my application and that I actually want order according to different functions - should I open a new question or is it easy to adapt this to ordering first by some function $f(z)$ and tie-break on a different function $g(z)$ where $f,g$ are not Mathematica built-ins like Re and Abs? Nov 23, 2020 at 16:30