Another update from ingydotnet^djgoku

This commit is contained in:
Ingy döt Net 2015-11-18 06:14:39 +00:00
parent 91df62d461
commit 948b86eafa
7604 changed files with 108452 additions and 22726 deletions

View file

@ -1,4 +1,6 @@
Generate permutations of n items in which successive permutations differ from each other by the swapping of any two items. Also generate the sign of the permutation which is +1 when the permutation is generated from an even number of swaps from the initial state, and -1 for odd. Show the permutations and signs of three items, in order of generation ''here''.
Generate permutations of n items in which successive permutations differ from each other by the swapping of any two items.
Also generate the sign of the permutation which is +1 when the permutation is generated from an even number of swaps from the initial state, and -1 for odd.
Show the permutations and signs of three items, in order of generation ''here''.
Such data are of use in generating the [[Matrix arithmetic|determinant]] of a square matrix and any functions created should bear this in mind.
@ -7,6 +9,7 @@ Note: The SteinhausJohnsonTrotter algorithm generates successive permutati
;References:
* [[wp:SteinhausJohnsonTrotter algorithm|SteinhausJohnsonTrotter algorithm]]
* [http://www.cut-the-knot.org/Curriculum/Combinatorics/JohnsonTrotter.shtml Johnson-Trotter Algorithm Listing All Permutations]
* [http://stackoverflow.com/a/29044942/10562 Correction to] Heap's algorithm as presented in Wikipedia and widely distributed.
;Cf.:
* [[Matrix arithmetic]]

View file

@ -0,0 +1,10 @@
Permutations_By_Swapping(str, list:=""){
ch := SubStr(str, 1, 1) ; get left-most charachter of str
for i, line in StrSplit(list, "`n") ; for each line in list
loop % StrLen(line) + 1 ; loop each possible position
Newlist .= RegExReplace(line, mod(i,2) ? "(?=.{" A_Index-1 "}$)" : "^.{" A_Index-1 "}\K", ch) "`n"
list := Newlist ? Trim(Newlist, "`n") : ch ; recreate list
if !str := SubStr(str, 2) ; remove charachter from left hand side
return list ; done if str is empty
return Permutations_By_Swapping(str, list) ; else recurse
}

View file

@ -0,0 +1,4 @@
for each, line in StrSplit(Permutations_By_Swapping(1234), "`n")
result .= line "`tSign: " (mod(A_Index,2)? 1 : -1) "`n"
MsgBox, 262144, , % result
return

View file

@ -1,121 +1,62 @@
/*
The following code generates the permutations of the first 4 natural numbers.
The permutations are displayed in lexical order, smallest to largest, with appropriate signs
*/
#include <iostream>
#include <conio.h>
#include <vector>
//factorial function
long
fact(int size)
using namespace std;
vector<int> UpTo(int n, int offset = 0)
{
int i;
long tmp = 1;
if(size<=1)
return 1;
else
for(i = size;i > 0;i--)
tmp *= i;
return tmp;
vector<int> retval(n);
for (int ii = 0; ii < n; ++ii)
retval[ii] = ii + offset;
return retval;
}
//function to display the permutations.
void
Permutations(int N)
struct JohnsonTrotterState_
{
//indicates sign
short sign = 1;
vector<int> values_;
vector<int> positions_; // size is n+1, first element is not used
vector<bool> directions_;
int sign_;
//Tracks when to change sign.
unsigned short change_sign = 0;
JohnsonTrotterState_(int n) : values_(UpTo(n, 1)), positions_(UpTo(n + 1, -1)), directions_(n + 1, false), sign_(1) {}
//loop variables
short i = 0,j = 0,k = 0;
//iterations
long loops = fact(N);
//Array of pointers to hold the digits
int **Index_Nos_ptr = new int*[N];
//Repetition of each digit (Master copy)
int *Digit_Rep_Master = new int[N];
//Repetition of each digit (Local copy)
int *Digit_Rep_Local = new int[N];
//Index for Index_Nos_ptr
int *Element_Num = new int[N];
//Initialization
for(i = 0;i < N;i++){
//Allocate memory to hold the subsequent digits in the form of a LUT
//For N = N, memory required for LUT = N(N+1)/2
Index_Nos_ptr[i] = new int[N-i];
//Initialise the repetition value of each digit (Master and Local)
//Each digit repeats for (i-1)!, where 1 is the position of the digit
Digit_Rep_Local[i] = Digit_Rep_Master[i] = fact(N-i-1);
//Initialise index values to access the arrays
Element_Num[i] = N-i-1;
//Initialise the arrays with the required digits
for(j = 0;j < N-i;j++)
*(Index_Nos_ptr[i] +j) = N-j-1;
int LargestMobile() const // returns 0 if no mobile integer exists
{
for (int r = values_.size(); r > 0; --r)
{
const int loc = positions_[r] + (directions_[r] ? 1 : -1);
if (loc >= 0 && loc < values_.size() && values_[loc] < r)
return r;
}
return 0;
}
while(loops-- > 0){
std::cout << "Perm: [";
for(i = 0;i < N;i++){
//Print from MSD to LSD
std::cout << " " << *(Index_Nos_ptr[i] + Element_Num[i]);
//Decrement the repetition count for each digit
if(--Digit_Rep_Local[i] <= 0){
//Refill the repitition factor
Digit_Rep_Local[i] = Digit_Rep_Master[i];
//And the index to access the required digit is also 0...
if(Element_Num[i] <= 0 && i != 0){
//Reset the index
Element_Num[i] = N-i-1;
//Update the numbers held in Index_Nos_ptr[]
for(j = 0,k = 0;j <= N-i;j++){
//Exclude the preceeding digit (from the previous array) already printed.
if(j != Element_Num[i-1]){
*(Index_Nos_ptr[i]+k)= *(Index_Nos_ptr[i-1]+j);
k++;
}
}
}else
//Decrement the index value so as to print the appropriate digit
//in the same array
Element_Num[i]--;
}
}
std::cout<<"] Sign: "<< sign <<"\n";
if(!(change_sign-- > 0)){
//Update the sign value.
sign = -sign;
change_sign = 1;
}
bool IsComplete() const { return LargestMobile() == 0; }
void operator++() // implement Johnson-Trotter algorithm
{
const int r = LargestMobile();
const int rLoc = positions_[r];
const int lLoc = rLoc + (directions_[r] ? 1 : -1);
const int l = values_[lLoc];
// do the swap
swap(values_[lLoc], values_[rLoc]);
swap(positions_[l], positions_[r]);
sign_ = -sign_;
// change directions
for (auto pd = directions_.begin() + r + 1; pd != directions_.end(); ++pd)
*pd = !*pd;
}
};
}
int
main()
int main(void)
{
Permutations(4);
getch();
return 0;
JohnsonTrotterState_ state(4);
do
{
for (auto v : state.values_)
cout << v << " ";
cout << "\n";
++state;
} while (!state.IsComplete());
}

View file

@ -0,0 +1,5 @@
(defn permutations [a-set]
(cond (empty? a-set) '(())
(empty? (rest a-set)) (list (apply list a-set))
:else (for [x a-set y (permutations (remove #{x} a-set))]
(cons x y))))

View file

@ -0,0 +1,40 @@
defmodule Permutation do
def by_swap(n) do
p = Enum.to_list(0..-n) |> List.to_tuple
by_swap(n, p, 1)
end
defp by_swap(n, p, s) do
IO.puts "Perm: #{inspect for i <- 1..n, do: abs(elem(p,i))} Sign: #{s}"
k = 0 |> step_up(n, p) |> step_down(n, p)
if k > 0 do
pk = elem(p,k)
i = if pk>0, do: k+1, else: k-1
p = Enum.reduce(1..n, p, fn i,acc ->
if abs(elem(p,i)) > abs(pk), do: put_elem(acc, i, -elem(acc,i)), else: acc
end)
pi = elem(p,i)
p = put_elem(p,i,pk) |> put_elem(k,pi) # swap
by_swap(n, p, -s)
end
end
defp step_up(k, n, p) do
Enum.reduce(2..n, k, fn i,acc ->
if elem(p,i)<0 and abs(elem(p,i))>abs(elem(p,i-1)) and abs(elem(p,i))>abs(elem(p,acc)),
do: i, else: acc
end)
end
defp step_down(k, n, p) do
Enum.reduce(1..n-1, k, fn i,acc ->
if elem(p,i)>0 and abs(elem(p,i))>abs(elem(p,i+1)) and abs(elem(p,i))>abs(elem(p,acc)),
do: i, else: acc
end)
end
end
Enum.each(3..4, fn n ->
Permutation.by_swap(n)
IO.puts ""
end)

View file

@ -1,4 +1,4 @@
sub insert($x, @xs) { [@xs[0..$_-1], $x, @xs[$_..*]] for 0..+@xs }
sub insert($x, @xs) { ([flat @xs[0 ..^ $_], $x, @xs[$_ .. *]] for 0 .. +@xs) }
sub order($sg, @xs) { $sg > 0 ?? @xs !! @xs.reverse }
multi perms([]) {
@ -6,7 +6,7 @@ multi perms([]) {
}
multi perms([$x, *@xs]) {
perms(@xs).map({ order($_.value, insert($x, $_.key)) }) Z=> (+1,-1) xx *
perms(@xs).map({ |order($_.value, insert($x, $_.key)) }) Z=> |(+1,-1) xx *
}
.say for perms([0..2]);

View file

@ -0,0 +1,42 @@
function permutation ($array) {
function sign($A) {
$size = $A.Count
$sign = 1
for($i = 0; $i -lt $size; $i++) {
for($j = $i+1; $j -lt $size ; $j++) {
if($A[$j] -lt $A[$i]) { $sign *= -1}
}
}
$sign
}
function generate($n, $A, $i1, $i2, $cnt) {
if($n -eq 1) {
if($cnt -gt 0) {
"$A -- swapped positions: $i1 $i2 -- sign = $(sign $A)`n"
} else {
"$A -- sign = $(sign $A)`n"
}
}
else{
for( $i = 0; $i -lt ($n - 1); $i += 1) {
generate ($n - 1) $A $i1 $i2 $cnt
if($n % 2 -eq 0){
$i1, $i2 = $i, ($n-1)
$A[$i1], $A[$i2] = $A[$i2], $A[$i1]
$cnt = 1
}
else{
$i1, $i2 = 0, ($n-1)
$A[$i1], $A[$i2] = $A[$i2], $A[$i1]
$cnt = 1
}
}
generate ($n - 1) $A $i1 $i2 $cnt
}
}
$n = $array.Count
if($n -gt 0) {
(generate $n $array 0 ($n-1) 0)
} else {$array}
}
permutation @(1,2,3,4)

View file

@ -1,60 +1,53 @@
/*REXX pgm generates all permutations of N different objects by swapping*/
parse arg things bunch inbetween names /*get optional arguments from CL.*/
things=p(things 4) /*use the default for THINGS ? */
bunch =p(bunch things) /* " " " " BUNCH ? */
/*╔════════════════════════════════════════════════════════════════╗
things (optional) defaults to 4.
bunch (optional) defaults to THINGS.
inbetween (optional) defaults to a [null].
names (optional) defaults to digits (and letters).
*/
upper inbetween; if inbetween=='NONE' | inbetween="NULL" then inbetween=
call permSets things, bunch, inbetween, names
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────one─liner subrlutines───────────────*/
!: procedure; !=1; do j=2 to arg(1); !=!*j; end; return !
p: return word(arg(1), 1) /*pick the first word from a list*/
/*──────────────────────────────────GETONE subroutine───────────────────*/
getOne: if length(z)==y then return substr(z,arg(1),1)
else return sep||word(translate(z,,','), arg(1))
/*──────────────────────────────────PERMSETS subroutine─────────────────*/
permSets: procedure; parse arg x,y,between,uSyms /*X things Y at a time.*/
sep=; !.=0 /*X can't be > length(@0abcs). */
@abc = 'abcdefghijklmnopqrstuvwxyz'; parse upper var @abc @abcU
@abcS= @abcU || @abc; @0abcS=123456789 || @abcS
z= /*set Z to a null value. */
do i=1 for x /*build a list of (perm) symbols.*/
_=p(word(uSyms,i) p(substr(@0abcS,i,1) k)) /*get or gen a symbol.*/
if length(_)\==1 then sep=',' /*if not 1st char, then use SEP. */
z=z || sep || _ /*append it to the symbol list. */
/*REXX program generates all permutations of N different objects by swapping. */
parse arg things bunch . /*get optional arguments from the C.L. */
things = p(things 4) /*should use the default for THINGS ? */
bunch = p(bunch things) /* " " " " " BUNCH ? */
call permSets things, bunch /*invoke permutations by swapping sub. */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────one─liner subroutines─────────────────────*/
!: procedure; !=1; do j=2 to arg(1); !=!*j; end; return !
c: return substr(arg(1),arg(2),1) /*pick a single character from a string*/
p: return word(arg(1), 1) /*pick 1st word (or number) from a list*/
/*──────────────────────────────────PERMSETS subroutine───────────────────────*/
permSets: procedure; parse arg x,y /*take X things Y at a time. */
!.=0; pad=left('',x*y) /*Note: X can't be > length(@0abcs). */
@abc ='abcdefghijklmnopqrstuvwxyz'; @abcU=@abc; upper @abcU /*build syms.*/
@abcS=@abcU || @abc; @0abcS=123456789 || @abcS /*···and more*/
z= /*define Z to be a null value for start*/
do i=1 for x /*build list of (permutation) symbols. */
z=z || c(@0abcS,i) /*append the char to the symbol list. */
end /*i*/
#=1
if sep\=='' then z=strip(z, 'L', ",") /*strip leading commas from Z. */
!.z=1; q=z; s=1; times=!(x)%!(x-y) /*calculate TIMES using factorial*/
w=max(length(z),length('permute')) /*maximum width of Z and PERMUTE.*/
say center('permutations for ' x ' with ' y "at a time",60,'')
#=1 /*the number of permutations (so far).*/
!.z=1; q=z; s=1; times=!(x)% !(x-y) /*calculate (#) TIMES using factorial.*/
w=max(length(z), length('permute')) /*maximum width of Z and also PERMUTE.*/
say center('permutations for ' x ' things taken ' y " at a time",60,'')
say
say 'permutation' center("permute",w,'') 'sign'
say '' center("───────",w,'') ''
say center(#,11) center(z ,w) right(s,4)
say pad 'permutation' center("permute",w,'') 'sign'
say pad '' center("───────",w,'') ''
say pad center(#,11) center(z ,w) right(s, 4-1)
do step=1 until #==times
do k=1 for x-1
do m=k+1 to x /*method doesn't use adjaceny. */
?=
do n=1 for x /*build a new permutation by swap*/
if n\==k & n\==m then ?=? || getOne(n)
else if n==k then ?=? || getOne(m)
else ?=? || getOne(k)
end /*n*/
if sep\=='' then ?=strip(?,'L',sep)
z=? /*save this permute for next swap*/
if !.? then iterate m /*if defined before, try next one*/
#=#+1; s=-s; say center(#,11) center(?,w) right(s,4)
!.?=1
iterate step
end /*m*/
end /*k*/
end /*step*/
return
do $=1 until #==times /*perform permutation until # of times.*/
do k=1 for x-1 /*step thru things for things-1 times.*/
do m=k+1 to x /*this method doesn't use adjacency. */
?= /*begin this with a blank (null) slate.*/
do n=1 for x /*build the new permutation by swapping*/
if n\==k & n\==m then ? = ? || c(z, n)
else if n==k then ? = ? || c(z, m)
else ? = ? || c(z, k)
end /*n*/
z=? /*save this permutation for next swap. */
if !.? then iterate m /*if defined before, then try next 'un.*/
_=0 /* [↓] count number of swapped symbols*/
do d=1 for x while $\==1; _=_+(c(?,d)\==c(prev,d)); end /*d*/
if _>2 then do; _=z
a=$//x+1; q=q+_ /* [← ↓] this swapping tries adjacency*/
b=q//x+1; if b==a then b=a+1; if b>x then b=a-1
z=overlay(c(z,b), overlay(c(z,a), _, b), a)
iterate $ /*now, try this particular permutation.*/
end
#=#+1; s=-s; say pad center(#,11) center(?,w) right(s,4-1)
!.?=1; prev=?; iterate $ /*now, try another swapped permutation.*/
end /*m*/
end /*k*/
end /*$*/
return /*we're all finished with permutating. */