Composition of permutations – the group product
Haskell, 157 148 bytes
EDIT:
- -9 bytes: That could indeed be golfed more. Removed redundant parentheses around
p++q
. Swapped argument order ofg
. Got rid ofd
by startingiterate
withp x
, after whichtakeWhile
no longer tied withfst
+span
. Madeiterate
infix.
Doing this while I'm late... probably can golf some more.
It was simpler, and seemed to be allowed, so the output includes single-element cycles.
q#p=g(p++q>>=id)$f q.f p
f p a=last$a:[y|c<-p,(x,y)<-zip(0:c)(c++c),x==a]
g(x:l)p|c<-x:fst(span(/=x)$p`iterate`p x)=c:g[x|x<-l,x`notElem`c]p
g[]p=[]
Try it online!
How it works:
#
is the main function.q#p
takes two lists of lists of numbers, and returns a similar list. The tests seem to have Q before P so I used the same order.f p
converts the permutationp
from disjoint cycle form to a function, after whichf q
andf p
can be composed with the usual composition operator.
.- The list comprehension iterates through the cycles
c
, searching fora
and finding its successor. If the comprehension finds nothing,a
is just returned. zip(0:c)(c++c)
is a list of pairs of elements ofc
and their successors. Since the question lets us "start at one" we can use0
as a dummy value; it's cheaper to prepend that tozip
's first argument than to usetail
on the second.
- The list comprehension iterates through the cycles
g l p
takes a listl
of elements, and a permutation functionp
, and returns the list of cycles touching the elements.- Here
c
is the cycle containing the first elementx
of the list, the other elements ofc
are found by iterating fromp x
untilx
is found again. When recursing to find the remaining cycles, all elements ofc
are first removed with a list comprehension.
- Here
Mathematica, 15 bytes
##⊙Cycles@{}&
Yes Virginia, there is a builtin.... Mathematica supports a permutation data type already in disjoint cycle notation: this pure function takes as input any number of arguments in the form Cycles[{{1, 5}, {2, 4}}]
and outputs the product permutation, again in Cycles[]
form. It uses the opposite ordering convention as the OP, so for example,
##⊙Cycles@{}&[Cycles[{{1, 2, 4, 3}}], Cycles[{{1, 5}, {2, 4}}]]
returns Cycles[{{1, 4, 3, 5}}]
. The ⊙
symbol I used above should really be the 3-byte private-use Unicode symbol U+F3DE to work in Mathematica. Note that Mathematica has a named builtin for this operation, PermutationProduct
, but that's three bytes longer.
J, 7 bytes
C.@C.@,
Try it online!