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 (even if \(n=1\)). 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.
Group-theoretic conjugation is implemented: in package idiom,
a^b gives inverse(b)*a*b. The notation is motivated by
the identities x^(yz)=(x^y)^z and (xy)^z=x^z*y^z [or
\(x^{yz}=(x^y)^z\) and \((xy)^z=x^zy^z\)].
Internally, conjugation() is called. The concept of conjugate
permutations [that is, permutations with the same
shape()] is discussed at conjugate.
The caret “^” also indicates group action [there is some
discussion at as.function.permutation.Rd]. Given an integer
n and a permutation g, idiom n^g returns the
group action of g acting on n. The notation is
motivated by the identity n^(ab) == (n^a)^b.
The sum of two permutations a and b, 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. If a+b
is defined we have
a^n + b^n == (a+b)^n == a^n * b^n == (a*b)^n
for any \(n\in\mathbb{Z}\). Using “+” in
this way 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.
Experimental functionality is provided to define the “sum” of a
permutation and an integer. If \(x\) is a permutation in cycle
form with \(x=(abc)\), say, and \(n\) an integer, then
\(x+n=(a+n,b+n,c+n)\): each element of each cycle of \(x\)
is increased by \(n\). Note that this has associativity
consequences. For example, x+(x+n) might be defined but not
(x+x)+n, as the two “+” operators have different
interpretations. Distributivity is similarly broken (see the
examples). Package idiom includes x-n [defined as x +
(-n)] and n+x but not n-x as inverses are defined
multiplicatively. The implementation is vectorized.