The function Ops.permutation() passes binary arithmetic
operators (“+”, “*”, “/”,
“^”, and “==”) to the appropriate
specialist function.
Multiplication, as in a*b, is effectively
word_prod(a,b); it coerces its arguments to word form (because
a*b = b[a]).
Raising permutations to integer powers, as in a^n, is
cycle_power(a,n); it coerces a to cycle form and returns
a cycle. Negative and zero values of n operate as expected.
Function cycle_power() is vectorized; it calls
cycle_power_single(), which is not. This calls vps()
(“Vector Power Single”), which checks for simple cases such as
pow=0 or the identity permutation; and function vps()
calls function ccps() which performs the actual
number-theoretic manipulation to raise a cycle to a power.
Raising a permutation to the power of another permutation, as in
a^b, is idiom for inverse(b)*a*b, sometimes known as
group action; the notation is motivated by the identities
x^(yz)=(x^y)^z and (xy)^z=x^z*y^z.
Permutation addition, as in a+b, is defined if the cycle
representations of the addends are disjoint. The sum is defined as
the permutation given by juxtaposing the cycles of a with those
of b. Note that this operation is commutative. If a
and b do not have disjoint cycle representations, an error is
returned. This is useful if you want to guarantee that two
permutations commute (NB: permutation a commutes with
a^i for i any integer, and in particular a
commutes with itself. But a+a returns an error: the operation
checks for disjointness, not commutativity).
Permutation “division”, as in a/b, is
a*inverse(b). Note that a/b*c is evaluated left to
right so is equivalent to a*inverse(b)*c. See note.
Function helper() sorts out recycling for binary functions, the
behaviour of which is inherited from cbind(), which also
handles the names of the returned permutation.