in reply to sort function and parity of the permutation.
Assume this input.
my @x = qw"q s t l y a p c f v i r d w k o j b";
First, sort in such a way that you get the permutation too, not only the sorted array. We'll use perl's builtin sort for this, though there are certainly other ways.
my @p = sort { $x[$a] cmp $x[$b] } 0 .. @x-1;
Now @p contains the permutation, eg. it contains (5, 17, 7, ...) because the first element of the sorted array would be $x[5] (that is, "a"), the second would be $x[17] etc. If you need it, @x[@p] gives the sorted list.
Now you just have to determine the parity of this permutation. As hinted in Knuth exercises 5.2.2/2 and 5.3.1/29, a way to do this is to determine the number of cycles in the permutation (by traversing them), and then subtracting this number from the number of elements. The following may or may not work, be sure to verify it's correct before using it.
my $d = 0; my @s; for my $s (0 .. @p - 1) { if ($s[$s]) { $d++; } for (my $t = $s; !$s[$t]++; $t = $p[$t]) {} } if (0 != $d%2) { say "odd" } else { say "even" }
Alternately, you could try to use some module, such as Math::GSL, but it doesn't seem like it gets much easier that way.
Update: or you could interface some external computer algebra software that has a library function for this. Here's a hilariously bad example.
use File::Temp "tempfile"; my($T, $N) = tempfile("perm-XXXXXXXX", UNLINK => 1); say $T "SignPerm(PermList(1+[", join(",", @p), "]));\n"; close $T or die; my $s = qx"gap -q <$N"; if (1 == $s) { say "even" } elsif (-1 == $s) { say "odd" } else { die +}
|
|---|