Arithmetic Ops Group Methods for permutations
Allows arithmetic operators to be used for manipulation of permutation objects such as addition, multiplication, division, integer powers, etc.
## S3 method for class 'permutation' Ops(e1, e2) cycle_power(x,pow) cycle_power_single(x,pow) cycle_sum(e1,e2) cycle_sum_single(c1,c2) group_action(e1,e2) word_equal(e1,e2) word_prod(e1,e2) word_prod_single(e1,e2) permprod(x) vps(vec,pow) ccps(n,pow) helper(e1,e2)
x,e1,e2 |
Objects of class “ |
c1,c2 |
Objects of class |
pow |
Integer vector of powers |
vec |
In function |
n |
In function |
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.
None of these functions are really intended for the end user: use the ops as shown in the examples section.
The class of the returned object is the appropriate one.
It would be nice to define a unary operator which inverted a
permutation. I do not like “id/x
” to represent a
permutation inverse: the idiom introduces an utterly redundant object
(“id
”), and forces the use of a binary operator where a
unary operator is needed.
The natural unary operator would be the exclamation mark, !x
.
However, redefining the exclamation mark to give permutation inverses,
while possible, is not desirable because its precedence is too low.
One would like !x*y
to return inverse(x)*y
but instead
standard precendence rules means that it returns inverse(x*y)
.
This caused such severe cognitive dissonance that I removed it.
There does not appear to be a way to define a new unary operator due to the construction of the parser.
Robin K. S. Hankin
x <- rperm(20,9) # word form y <- rperm(20,9) # word form x*y # word form x^5 # coerced to cycle form x^as.cycle(1:5) # group action; coerced to word. x*inverse(x) == id # all TRUE # the 'sum' of two permutations is defined if their cycles are disjoint: as.cycle(1:4) + as.cycle(7:9) data(megaminx) megaminx[1] + megaminx[7:12]
Please choose more modern alternatives, such as Google Chrome or Mozilla Firefox.