Class Permutation
- All Implemented Interfaces:
Serializable
A permutation is a one-to-one (bijective) mapping of a set to itself. For
finite sets, the elements are not represented concretely, but by an abstract
numbering. This implementation uses the primitive type int for
numbers.
Zero/One Indexing
Objects of this class generally represent permutations that are zero-indexed: A finite set of n elements is represented by the integers 0, …, n−1. This convention is very prominent in computer science; but much less so in mathematics, where one-indexing is the norm.
In order to have a finite set of n elements represented by the
integers 1, …, n instead, use permutations where 0 is mapped to
0. This property is preserved by all the usual algebraic operations on
permutations (unless index 0 is passed explicitly), and can be
checked with the isOneBased() method. Use shift(int) to convert
between the two views.
Size
Objects of this class encode one-to-one mappings on integers. The size of
the set they are applied to is not part of their defining
properties. Instead, the following rules apply (and are enforced by the
get(int) method):
- A permutation is always undefined on the negative integers.
- A permutation is always defined on the non-negative integers. Their
definition, however, may only mention a bounded subset of numbers. For all
numbers that exceed the bound, permutations act as the identical function,
mapping each such number to itself. Compare the behavior of class
BitSet.
Immutability
Like all mathematical entities, permutations are represented accurately by immutable data structures. Instead of modifying an existing permutation object after its creation, a new derived one is created using a variety of algebraic operations.
Hence objects of this class are always created by means of static factory methods, and interacted with solely by calling stateless (getter) methods.
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classCanonical form of a permutation. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionaction()Returns an operator that maps every index to the value assigned by this permutation.andThen(Permutation other) Returns a permutation that applies the mapping of this permutation before that of a given other permutation.Represents this permutation in canonical form.compose(Permutation other) Returns a permutation that applies the mapping of this permutation after that of a given other permutation.static Permutationcycle(int... members) Returns a permutation that rotates the given positions cyclically.booleanChecks whether some object is equal to this permutation.intget(int index) Returns the value assigned to the given index by this permutation.inthashCode()Computes a hash code for this permutation.(package private) booleanChecks whether this permutation has the correct parity bit.static Permutationidentity()Returns the identity permutation.inverse()Returns a permutation that inverts the mapping of this permutation.booleanisEven()Checks whether this permutation is of even parity.(package private) booleanChecks whether all entries of this permutation are unique.(package private) booleanChecks whether all entries of this permutation are in the valid range.(package private) booleanChecks whether all entries of this permutation are necessary.booleanChecks whether this permutation can represent a set with one-based indexing.(package private) booleanisValid()Checks whether the representation of this permutation is valid.static Permutationmirror(int from, int to) Returns a permutation that mirrors the positions in a given interval.static Permutationof(Permutation.CanonicalForm canonicalForm) Creates a permutation from its canonical form.power(long exponent) Returns a repeated composition of this permutation with itself.static Permutationrotate(int from, int to) Returns a permutation that rotates the positions in a given interval one step up.shift(int offset) Returns a copy of this permutation where all entries are shifted by a given offset.shiftDown(int offset) Returns a copy of this permutation where all entries are shifted downwards by a given offset.shiftUp(int offset) Returns a copy of this permutation where all entries are shifted upwards by a given offset.voidshuffle(int[] seq) Permutes the elements of a sequence according to this permutation.voidPermutes the elements of a sequence according to this permutation.voidPermutes the elements of a sequence according to this permutation.intsign()Returns the parity sign of this permutation.static Permutationsorting(int[] seq) Returns the permutation that sorts the given sequence in ascending numerical ordering.static <E extends Comparable<? super E>>
Permutationsorting(E[] seq) Returns the permutation that sorts the given sequence in natural ordering.static <E> Permutationsorting(E[] seq, Comparator<? super E> comp) Returns the permutation that sorts the given sequence in the given ordering.static <E extends Comparable<? super E>>
PermutationReturns the permutation that sorts the given sequence in natural ordering.static <E> Permutationsorting(List<? extends E> seq, Comparator<? super E> comp) Returns the permutation that sorts the given sequence in the given ordering.sqrt()Finds some permutation that composed with itself is equivalent to this permutation.substitute(String text) Substitute each Unicode code point in the given string according to this permutation.static Permutationswap(int a, int b) Returns a permutation that swaps two positions.toString()Returns a human-readable presentation of this permutation.static Permutationunsorting(int... seq) Returns the permutation that reproduces the given sequence from its sorted elements.
-
Constructor Details
-
Permutation
Permutation(int[] elems, boolean even) Creates a new instance. Do not call this constructor directly!- Parameters:
elems- the minimal mappingeven- the parity- Throws:
NullPointerException- if elems is null
-
-
Method Details
-
identity
Returns the identity permutation.- Returns:
- the permutation that assigns each index to itself
-
get
public int get(int index) Returns the value assigned to the given index by this permutation.- Parameters:
index- the nonnegative index- Returns:
- the value mapped to the given index
- Throws:
IllegalArgumentException- ifindex < 0
-
action
Returns an operator that maps every index to the value assigned by this permutation.- Returns:
- an operator that maps every
itothis.get(i) - See Also:
-
isEven
public boolean isEven()Checks whether this permutation is of even parity.A permutation is of even (odd) parity, if and only if it can be decomposed into an even (odd) number of proper swaps, respectively.
- Returns:
trueif this permutation is of even parity;falseif it is of odd parity- See Also:
-
sign
public int sign()Returns the parity sign of this permutation.- Returns:
1if this permutation is of even parity;-1if it is of odd parity- See Also:
-
isOneBased
public boolean isOneBased()Checks whether this permutation can represent a set with one-based indexing.- Returns:
trueif0is assigned to0;falseotherwise
-
isInRange
boolean isInRange()Checks whether all entries of this permutation are in the valid range.- Returns:
trueif all entries are also valid indices;falseotherwise
-
isInjective
boolean isInjective()Checks whether all entries of this permutation are unique.- Returns:
falseif there are two entries with identical values;trueotherwise
-
isMinimal
boolean isMinimal()Checks whether all entries of this permutation are necessary.- Returns:
falseif equivalent behavior can be specified by a shorter mapping array;trueotherwise
-
hasParity
boolean hasParity()Checks whether this permutation has the correct parity bit.This method uses a quadratic algorithm, and should not be called too often.
- Returns:
trueifevenis equal to the computed parity;falseotherwise
-
isValid
boolean isValid()Checks whether the representation of this permutation is valid.A permutations created by the static factory methods in this class are valid by construction. Hence this method should only be called for the purpose of testing extensions.
- Returns:
trueif all invariants are satisfied;falseotherwise
-
compose
Returns a permutation that applies the mapping of this permutation after that of a given other permutation.p.compose(q).get(i) == p.get(q.get(i))- Parameters:
other- the permutation to apply before this one- Returns:
- a permutation that applies
thisafterother
-
andThen
Returns a permutation that applies the mapping of this permutation before that of a given other permutation.p.andThen(q).get(i) == q.get(p.get(i))- Parameters:
other- the permutation to apply after this one- Returns:
- a permutation that applies
thisbeforeother
-
inverse
Returns a permutation that inverts the mapping of this permutation.p.inverse().get(p.get(i)) == i, as well asp.get(p.inverse().get(i)) == i- Returns:
- the inverse permutation
-
equals
Checks whether some object is equal to this permutation. -
hashCode
public int hashCode()Computes a hash code for this permutation. -
toString
Returns a human-readable presentation of this permutation. -
swap
Returns a permutation that swaps two positions.The resulting permutation behaves as follows (and like the identity elsewhere):
swap(a, b).get(a) == b, andswap(a, b).get(b) == aIt is implied that the result is the identity permutation if
a == b.- Parameters:
a- the position to swap withbb- the position to swap witha- Returns:
- a permutation that assigns value
ato indexband vice versa, and is the identity otherwise - Throws:
IllegalArgumentException- ifa < 0orb < 0
-
rotate
Returns a permutation that rotates the positions in a given interval one step up.The resulting permutation behaves as follows (and like the identity elsewhere):
p.rotate(from, to).get(i) == i + 1ifi >= from && i < to, andp.rotate(from, to).get(to) == fromIt is implied that the result is the identity permutation if
from >= to.To rotate an arbitrary number of steps up or down, use
power(long)on the result.- Parameters:
from- the lower end of the position interval to rotate, inclusivelyto- the upper end of the position interval to rotate, inclusively- Returns:
- a permutation that rotates the positions in the interval
from–toone step up - See Also:
-
mirror
Returns a permutation that mirrors the positions in a given interval.The resulting permutation behaves as follows (and like the identity elsewhere):
p.mirror(from, to).get(i) == from + to - iifi >= from && i <= toIt is implied that the result is the identity permutation if
from >= to.- Parameters:
from- the lower end of the position interval to mirror, inclusivelyto- the upper end of the position interval to mirror, inclusively- Returns:
- a permutation that mirrors the positions in the interval
from–to
-
cycle
Returns a permutation that rotates the given positions cyclically.The resulting permutation behaves as follows (and like the identity elsewhere):
p.cycle(members).get(members[i]) == members[(i + 1) % members.length]It is implied that the result is the identity permutation if
members.length <= 1.- Parameters:
members- an injective sequence of cycle members- Returns:
- a permutation that rotates the given positions cyclically
- Throws:
NullPointerException- ifmembersis nullIllegalArgumentException- ifmemberscontains a negative value, or contains the same value more than once
-
canonicalForm
Represents this permutation in canonical form.The result is stable, and may be cached to speed up subsequent calls of this method.
- Returns:
- a representation of this permutation in canonical form
- See Also:
-
of
Creates a permutation from its canonical form.Behavior is undefined if the given array does not represent a canonical form.
- Parameters:
canonicalForm- a canonical form- Returns:
- a permutation with the given canonical form
- See Also:
-
power
Returns a repeated composition of this permutation with itself.If the given number of repetitions is negative, inversion is implied.
The number of algebraic operations on permutations invoked by this algorithm grows only logarithmically with the exponent; even very large powers are feasible to compute.
- Parameters:
exponent- the number of repetitions- Returns:
- the
exponent-fold composition of this permutation with itself
-
shuffle
Permutes the elements of a sequence according to this permutation.The element at each index
iis moved to indexget(i).This method implements a two-phase algorithm:
- The first phase calculates the canonical form of this permutation.
- The second phase moves elements in cycles, using a single temporary variable.
- Parameters:
seq- the sequence to permute- Throws:
NullPointerException- ifseqis null- See Also:
-
shuffle
public void shuffle(int[] seq) Permutes the elements of a sequence according to this permutation.The element at each index
iis moved to indexget(i).This method implements a two-phase algorithm:
- The first phase calculates the canonical form of this permutation.
- The second phase moves elements in cycles, using a single temporary variable.
- Parameters:
seq- the sequence to permute- Throws:
NullPointerException- ifseqis null- See Also:
-
shuffle
Permutes the elements of a sequence according to this permutation.The element at each index
iis moved to indexget(i).This method implements a two-phase algorithm:
- The first phase calculates the canonical form of this permutation.
- The second phase moves elements in cycles, using a single temporary variable.
- Parameters:
seq- the sequence to permute- Throws:
NullPointerException- ifseqis null- See Also:
-
sqrt
Finds some permutation that composed with itself is equivalent to this permutation.The implemented algorithm is stable; for equivalent permutations, equivalent results are obtained always. It is also complete; if there are any solutions, one will be found. It is not unique; if there are several solutions, only a single, arbitrary one is found.
- Returns:
- some permutation that composed with itself is equivalent to this
permutation; or
Optional.empty()if none exists.
-
shift
Returns a copy of this permutation where all entries are shifted by a given offset.If this construction succeeds, the result behaves as follows:
p.shift(k).get(i) = p.get(i - k) + k, ifiandi-kare both nonnegativeThe effect of shifting depends on the sign of the offset:
- If
offsetis positive, then all existing entries are shifted upwards, padded with identical entries at the lower end. - If
offsetis zero, then the result is equivalent to this permutation. - If
offsetis negative, then all existing entries are shifted downwards. Entries below the offset threshold are deleted. If any of the remaining entries is left dangling (points to a deleted one), the result would be inconsistent; the construction fails in this case.
- Parameters:
offset- the offset- Returns:
- a copy of this permutation shifted by
offset; orOptional.empty()ifoffsetis negative and the result would be inconsistent - See Also:
- If
-
shiftUp
Returns a copy of this permutation where all entries are shifted upwards by a given offset.If this construction succeeds, the result behaves as follows:
p.shift(k).get(i) = p.get(i - k) + k, ifiandi-kare both nonnegative- Parameters:
offset- the nonnegative offset- Returns:
- a copy of this permutation shifted upwards by
offset - Throws:
IllegalArgumentException- ifoffset < 0- See Also:
-
shiftDown
Returns a copy of this permutation where all entries are shifted downwards by a given offset.If this construction succeeds, the result behaves as follows:
p.shift(k).get(i) = p.get(i - k) + k, ifiandi-kare both nonnegativeIf the right-hand side is found be negative in a valid case, the resulting permutation would be inconsistent, and the construction fails.
- Parameters:
offset- the nonnegative offset- Returns:
- a copy of this permutation shifted downwards by
offset; orOptional.empty()if the result would be inconsistent - Throws:
IllegalArgumentException- ifoffset < 0- See Also:
-
sorting
Returns the permutation that sorts the given sequence in natural ordering.sorting(s).shuffle(s)has the same effect asArrays.sort(s).The result corresponds to a stable sorting algorithm; equal elements are never transposed. This also makes the result uniquely specified.
- Type Parameters:
E- the type of sequence elements- Parameters:
seq- the sequence- Returns:
- the permutation that sorts
seq - Throws:
NullPointerException- ifseqis or contains null
-
sorting
Returns the permutation that sorts the given sequence in the given ordering.sorting(c, s).shuffle(s)has the same effect asArrays.sort(s, c).The result corresponds to a stable sorting algorithm; equal elements are never transposed. This also makes the result uniquely specified.
- Type Parameters:
E- the type of sequence elements- Parameters:
seq- the sequencecomp- the comparator that specifies the ordering- Returns:
- the permutation that sorts
seqaccording tocomp - Throws:
NullPointerException- ifcompis null, or ifseqis or contains null
-
sorting
Returns the permutation that sorts the given sequence in ascending numerical ordering.sorting(s).shuffle(s)has the same effect asArrays.sort(s).The result corresponds to a stable sorting algorithm; equal elements are never transposed. This also makes the result uniquely specified.
- Parameters:
seq- the sequence- Returns:
- the permutation that sorts
seq - Throws:
NullPointerException- ifseqis or contains null- See Also:
-
sorting
Returns the permutation that sorts the given sequence in natural ordering.sorting(s).shuffle(s)has the same effect asCollections.sort(s).The result corresponds to a stable sorting algorithm; equal elements are never transposed. This also makes the result uniquely specified.
- Type Parameters:
E- the type of sequence elements- Parameters:
seq- the sequence- Returns:
- the permutation that sorts
seq - Throws:
NullPointerException- ifseqis or contains null
-
sorting
Returns the permutation that sorts the given sequence in the given ordering.sorting(c, s).shuffle(s)has the same effect asCollections.sort(s, c).The result corresponds to a stable sorting algorithm; equal elements are never transposed. This also makes the result uniquely specified.
- Type Parameters:
E- the type of sequence elements- Parameters:
seq- the sequencecomp- the comparator that specifies the ordering- Returns:
- the permutation that sorts
seqaccording tocomp - Throws:
NullPointerException- ifcompis null, or ifseqis or contains null
-
unsorting
Returns the permutation that reproduces the given sequence from its sorted elements.The following sequence of operations effectively restores the sequence
seqto its original content:final Permutation p = unsorting(seq); Arrays.sort(seq); p.shuffle(seq);This method is a convenient robust tool for notating a permutation ad-hoc. The given elements are not constrained in the way that permutation entries are: Negative values, non-contiguous range and duplicates are all allowed here. The hypothetical underlying sorting is by ascending numerical value.
The result corresponds to a stable sorting algorithm; equal elements are never transposed. This also makes the result uniquely specified.
If the given sequence literally specifies entries of a permutation, i.e., if its elements cover the range 0, …, n−1 without duplicates, then the result is that permutation. Conversely, if the given sequence is sorted in ascending numerical order, then the result is the identical permutation.
- Parameters:
seq- a sequence of arbitrary integer values- Returns:
- a permutation that reproduces
seqfrom its sorted elements - Throws:
NullPointerException- ifseqis null- See Also:
-
substitute
Substitute each Unicode code point in the given string according to this permutation.p.substitute(s).codePoints()ands.codePoints().map(p::get)produce equivalent streamsNote that there is no general simple index-based expression of this specification, since a code point that fits in a single
charmay be substituted for one that requires a surrogate pair, and/or vice versa.- Parameters:
text- a cleartext string- Returns:
- the cyphertext resulting from substituting each code point using
this.get - Throws:
NullPointerException- iftextis null
-