use warnings; use strict; sub perm_decode { my(@perm) = @_; my($n, $k, $b, $v, $e); ($n, $k, $b, $v) = (0, 0, 0, 0); for $e (@perm) { #$b == choose($n, $k - 1) or die "assertion failed"; $e or $v += $b; $n++; $e and $k++; $b = $k <= 1 ? ($k < 1 ? 0 : 1) : ($b * $n / ($e ? $k - 1 : $n - $k + 1)); } $b = $k <= 0 ? 1 : ($b * ($n - $k + 1)) / $k; #$b == choose($n, $k) or die "assertion failed"; $n, $k, $v, $b; } sub perm_encode { my($n, $k, $v) = @_; my(@r, $bi); while (0 < $n) { $n--; $bi = choose($n, $k - 1); if ($v < $bi) { unshift @r, 1; $k--; } else { $v -= $bi; unshift @r, 0; } } @r; }