Cycle Decomposition#
To use the class CycleDecomposition, just import it from symmetria in the following way
from symmetria import CycleDecomposition
- class symmetria.CycleDecomposition(*cycles: Cycle)[source]#
The
CycleDecompositionclass represents the cycle decomposition of a permutation of the symmetric group.Recall that every permutation of the symmetric group can be represented uniquely as the composition of a finite number of cycles thanks to the Cycle Decomposition Theorem for Permutations.
To define a permutation as a cycle decomposition, you need to provide its cycles.
For example, to define the permutation given by the cycles:
Cycle(2, 1)andCycle(4, 3), you should writeCycleDecomposition(Cycle(2, 1), Cycle(4, 3)).Note
By convention, a cycle decomposition starts always with the smaller cycle, i.e., the cycle with the smallest element, and is increasing.
This is because a cycle decomposition can have different representations. Don’t panic, you can write the cycle decomposition in the way you like the most, but then it will be stored following the above convention.
- Parameters:
cycle (Cycle) – Cycle factors of the permutation.
- Raises:
ValueError – If there are two or more cycles with non-disjoint support.
ValueError – If there are missing cycles in the decomposition.
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> cycle = CycleDecomposition(Cycle(2, 1), Cycle(4, 3)) >>> cycle = CycleDecomposition(*[Cycle(2, 1), Cycle(4, 3)]) >>> cycle = CycleDecomposition(*(Cycle(2, 1), Cycle(4, 3)))
- __bool__() bool[source]#
Check if the cycle decomposition is non-empty, i.e., it is different from the identity cycle decomposition.
- Returns:
True if the cycle decomposition is different from the identity cycle decomposition, False otherwise.
- Return type:
bool
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> bool(CycleDecomposition(Cycle(1))) False >>> bool(CycleDecomposition(Cycle(1), Cycle(2))) False >>> bool(CycleDecomposition(Cycle(2, 1, 3))) True
- Note:
Every cycle of the form
CycleDecomposition(Cycle(n))is considered empty for every \(n \in \mathbb{N}\), i.e.,bool(CycleDecomposition(Cycle(n))) = False. Same for cycle decomposition of identity cycle, e.g.,CycleDecomposition(Cycle(1), Cycle(2), Cycle(3)).
- __call__(item: Any) Any[source]#
Call the cycle decomposition on the item object, i.e., mimic a cycle decomposition action on the element item.
If item is an integer, it applies the cycle decomposition to the integer.
If item is a string, a list or a tuple, it applies the cycle decomposition permuting the values by indexes.
If item is a permutation, it returns the composition of the cycle decomposition with the permutation.
If item is a cycle or a cycle decomposition, it returns the composition in cycle decomposition.
- Parameters:
item (Any) – The object on which the cycle acts.
- Returns:
The permuted object.
- Return type:
Any
- Raises:
ValueError – If there are not enough elements in the item to perform the permutation.
ValueError – If attempting to compose the cycle decomposition with a permutation, cycle, or cycle decomposition from a different symmetric group.
TypeError – If the item type is not supported.
- __eq__(other: Any) bool[source]#
Check if the cycle decomposition is equal to the other object.
- Parameters:
other (Any) – The object to compare with.
- Returns:
True if the cycle decomposition is equal to other, i.e., they define the same map. Otherwise, False.
- Return type:
bool
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1, 2)) == CycleDecomposition(Cycle(1, 2)) True >>> CycleDecomposition(Cycle(1), Cycle(2)) == CycleDecomposition(Cycle(1), Cycle(2)) True >>> CycleDecomposition(Cycle(1), Cycle(2, 3)) == CycleDecomposition(Cycle(1)) False
- __getitem__(idx: int) Cycle[source]#
Return the cycle of the cycle decomposition at the given index item.
The index corresponds to the position in the cycle decomposition, starting from 0.
- Parameters:
idx (int) – The index of the cycle.
- Returns:
The cycle of the cycle decomposition at the specified index.
- Return type:
int
- Raises:
IndexError – If the index is out of range.
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1, 2), Cycle(3, 4))[0] Cycle(1, 2)
- __int__() int[source]#
- Raises:
NotImplementedError – The method is not implemented for the class
CycleDecomposition, because it is not possible to uniquely represent a cycle decomposition of a permutation using just an integer.
- __iter__() Iterable[Cycle][source]#
Return an iterator over the cycles in the cycle decomposition.
- Returns:
An iterator over the cycles in the cycle decomposition.
- Return type:
Iterable[Cycle]
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> for cycle in CycleDecomposition(Cycle(1, 2), Cycle(3, 4)): ... print(cycle) (1 2) (3 4)
- __len__() int[source]#
Return the length of the cycle decomposition, which is the number of cycles present in the decomposition.
- Returns:
The length of the cycle decomposition.
- Return type:
int
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> len(CycleDecomposition(Cycle(1))) 1 >>> len(CycleDecomposition(Cycle(1, 3), Cycle(2))) 2 >>> len(CycleDecomposition(Cycle(1, 3), Cycle(4, 5), Cycle(2, 6))) 3
- __mul__(other: CycleDecomposition) CycleDecomposition[source]#
Multiply the cycle decomposition with another cycle decomposition, resulting in a new cycle decomposition that represents the composition of the two cycle decompositions.
- Parameters:
other (CycleDecomposition) – The other cycle decomposition to multiply with.
- Returns:
The composition of the two cycle decompositions.
- Return type:
- Raises:
ValueError – If the cycle decompositions don’t live in the same Symmetric group.
TypeError – If the other object is not a CycleDecomposition.
- __pow__(power: int) CycleDecomposition[source]#
Return the permutation object to the chosen power.
- Parameters:
power (int) – the exponent for the power operation.
- Returns:
the power of the cycle decomposition.
- Return type:
- Raises:
TypeError – If power is not an integer.
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(3), Cycle(1), Cycle(2)) ** 0 CycleDecomposition(Cycle(1), Cycle(2), Cycle(3)) >>> CycleDecomposition(Cycle(1, 2), Cycle(3)) ** 1 CycleDecomposition(Cycle(1, 2), Cycle(3)) >>> CycleDecomposition(Cycle(1, 2), Cycle(3)) ** -1 CycleDecomposition(Cycle(1, 2), Cycle(3)) >>> CycleDecomposition(Cycle(1, 3), Cycle(2, 4))**2 CycleDecomposition(Cycle(1), Cycle(2), Cycle(3), Cycle(4))
- __repr__() str[source]#
Return a string representation of the cycle decomposition.
The string representation is in the following format:
\['CycleDecomposition(Cycle(x, ...), Cycle(y, ...), ...)',\]where \(x, y, ... \in \mathbb{N}\) are the elements of the cycles.
- Returns:
A string representation of the cycle decomposition.
- Return type:
str
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).__repr__() 'CycleDecomposition(Cycle(1))' >>> CycleDecomposition(Cycle(1, 3), Cycle(2)).__repr__() 'CycleDecomposition(Cycle(1, 3), Cycle(2))' >>> CycleDecomposition(Cycle(1, 3), Cycle(4, 5, 2, 6)).__repr__() 'CycleDecomposition(Cycle(1, 3), Cycle(2, 6, 4, 5))'
- __str__() str[source]#
Return a string representation of the cycle decomposition in the cycle notation.
- Returns:
A string representation of the cycle decomposition.
- Return type:
str
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> str(CycleDecomposition(Cycle(1))) '(1)' >>> str(CycleDecomposition(Cycle(1, 3), Cycle(2))) '(1 3)(2)' >>> str(CycleDecomposition(Cycle(1, 3), Cycle(4, 5, 2, 6))) '(1 3)(2 6 4 5)'
- cycle_decomposition() CycleDecomposition[source]#
Return the cycle decomposition of the permutation.
As a cycle decomposition is already in the cycle decomposition, the method return the cycle decomposition itself.
- Returns:
The cycle decomposition of the permutation.
- Return type:
- cycle_notation() str[source]#
Return a string representing the cycle notation of the cycle decomposition.
- Returns:
The cycle notation of the permutation.
- Return type:
str
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).cycle_notation() '(1)' >>> CycleDecomposition(Cycle(1, 3, 2)).cycle_notation() '(1 3 2)' >>> CycleDecomposition(Cycle(1, 3, 2), Cycle(4)).cycle_notation() '(1 3 2)(4)'
- cycle_type() Tuple[int][source]#
Return the cycle type of the cycle decomposition.
Recall that the cycle type of the permutation \(\sigma\) is a sequence of integer, where There is a 1 for every fixed point of \(\sigma\), a 2 for every transposition, and so on.
Note
Note that the resulting tuple is sorted in ascending order.
- Returns:
The cycle type of the cycle decomposition.
- Return type:
Tuple[int]
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).cycle_type() (1,) >>> CycleDecomposition(Cycle(3, 1, 2)).cycle_type() (3,) >>> CycleDecomposition(Cycle(1, 3, 2), Cycle(4)).cycle_type() (1, 3) >>> CycleDecomposition(Cycle(1, 2), Cycle(3, 4)).cycle_type() (2, 2)
- property domain: Iterable[int]#
Return an iterable containing the elements of the domain of the cycle decomposition.
The domain of a cycle decomposition is the set of indices for which the cycle decomposition is defined.
- Returns:
The domain of the cycle decomposition.
- Return type:
Iterable[int]
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).domain range(1, 2) >>> CycleDecomposition(Cycle(3, 1, 2)).domain range(1, 4) >>> CycleDecomposition(Cycle(1), Cycle(3, 4, 5, 2, 6)).domain range(1, 7)
- equivalent(other: Any) bool[source]#
Check if the cycle decomposition is equivalent to another object.
This method is introduced because we can have different representation of the same cycle decomposition, e.g., as a cycle, or as permutation.
- Parameters:
other (Any) – The object to compare with.
- Returns:
True if the cycle decomposition is equivalent to the other object, False otherwise.
- Return type:
bool
- Example:
>>> from symmetria import Cycle, CycleDecomposition, Permutation ... >>> cycle_decomposition = CycleDecomposition(Cycle(1, 2, 3)) >>> cycle_decomposition.equivalent(cycle_decomposition) True >>> cycle = Cycle(1, 2, 3) >>> cycle_decomposition.equivalent(cycle) True >>> permutation = Permutation(2, 3, 1) >>> cycle_decomposition.equivalent(permutation) True
- inverse() CycleDecomposition[source]#
Return the inverse of the cycle decomposition.
Recall that the inverse of a permutation \(\sigma \in S_n\), for some \(n \in \mathbb{N}\), is the the only permutation \(\tau \in S_n\) such that \(\sigma * \tau = \tau * \sigma = id\), where \(id\) is the identity permutation.
- Returns:
The inverse of the cycle decomposition.
- Return type:
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1, 2, 3)).inverse() CycleDecomposition(Cycle(1, 3, 2)) >>> CycleDecomposition(Cycle(1, 2), Cycle(3, 4)).inverse() CycleDecomposition(Cycle(1, 2), Cycle(3, 4))
- inversions() List[Tuple[int, int]][source]#
Return the inversions of the cycle decomposition.
Recall that an inversion of a permutation \(\sigma \in S_n\), for \(n \in \mathbb{N}\), is a pair \((i, j)\) of positions (indexes), where the entries of the permutation are in the opposite order, i.e., \(i<j\) but \(\sigma(i)>\sigma(j)\).
- Returns:
The inversions of the ycle decomposition.
- Return type:
List[Tuple[int, int]]
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1), Cycle(2), Cycle(3)).inversions() [] >>> CycleDecomposition(Cycle(1, 2, 3)).inversions() [(1, 3), (2, 3)]
- is_conjugate(other: CycleDecomposition) bool[source]#
Check if two cycle decompositions are conjugated.
Recall that two permutations \(\sigma, \quad \tau \in S_n\), for some \(n \in \mathbb{N}\), are said to be conjugated if there is \(\gamma \in S_n\) such that \(\gamma\sigma\gamma^{-1} = \tau\).
- Parameters:
other (CycleDecomposition) – a cycle decomposition
- Returns:
True if self and other are conjugated, False otherwise.
- Return type:
bool
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> cycle_dec = CycleDecomposition(Cycle(1, 2, 3)) >>> cycle_dec.is_conjugate(cycle_dec) True >>> cycle_dec_a = CycleDecomposition(Cycle(1, 3, 2, 5, 4)) >>> cycle_dec_b = CycleDecomposition(Cycle(1, 4, 3, 5, 2)) >>> cycle_dec_a.is_conjugate(cycle_dec_b) True >>> cycle_dec_a = CycleDecomposition(Cycle(1, 2), Cycle(3, 4)) >>> cycle_dec_b = CycleDecomposition(Cycle(1), Cycle(3, 2, 4)) >>> cycle_dec_a.is_conjugate(cycle_dec_b) False
- is_derangement() bool[source]#
Check if the cycle decomposition is a derangement.
Recall that a permutation \(\sigma\) is called a derangement if it has no fixed points, i.e., \(\sigma(x) \neq x\) for every \(x\) in the permutation domain.
- Returns:
True if the permutation is a derangement, False otherwise.
- Return type:
bool
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).is_derangement() False >>> CycleDecomposition(Cycle(1, 2, 3)).is_derangement() True >>> CycleDecomposition(Cycle(1), Cycle(2, 3)).is_derangement() False
- is_even() bool[source]#
Check if the cycle decomposition is even.
Recall that a permutation is said to be even if it can be expressed as the product of an even number of transpositions.
- Returns:
True if the cycle decomposition is even, False otherwise.
- Return type:
bool
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).is_even() True >>> CycleDecomposition(Cycle(1, 2), Cycle(3)).is_even() False >>> CycleDecomposition(Cycle(1), Cycle(2, 4, 7, 6), Cycle(3, 5)).is_even() True
- is_odd() bool[source]#
Check if the cycle decomposition is odd.
Recall that a permutation is said to be odd if it can be expressed as the product of an odd number of transpositions.
- Returns:
True if the cycle decomposition is odd, False otherwise.
- Return type:
bool
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).is_odd() False >>> CycleDecomposition(Cycle(1, 2), Cycle(3)).is_odd() True >>> CycleDecomposition(Cycle(1), Cycle(2, 4, 7, 6), Cycle(3, 5)).is_odd() False
- is_regular() bool[source]#
Check if the cycle decomposition is regular.
Recall that a permutation is said regular if all cycles in its cycle decomposition have the same length.
- Returns:
True if the cycle decomposition is regular, False otherwise.
- Return type:
bool
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).is_regular() True >>> CycleDecomposition(Cycle(2, 1)).is_regular() True >>> CycleDecomposition(Cycle(2, 1), Cycle(3)).is_regular() False
- property map: Dict[int, int]#
Return a dictionary representing the mapping of the cycle decomposition, where keys are indices and values are the corresponding elements after permutation.
- Returns:
The mapping of the cycle decompostiion.
- Return type:
Dict[int, int]
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).map {1: 1} >>> CycleDecomposition(Cycle(1, 2), Cycle(3, 4)).map {1: 2, 2: 1, 3: 4, 4: 3}
- orbit(item: Any) List[Any][source]#
Compute the orbit of item object under the action of the cycle decomposition.
Recall that the orbit of the action of a cycle decomposition \(\sigma\) on an element x is given by the set
..math:: { sigma^n(x): n in mathbb{N}}.
- Parameters:
item (Any) – The initial element or iterable to compute the orbit for.
- Returns:
The orbit of the specified element under the permutation.
- Return type:
List[Any]
- order() int[source]#
Return the order of the cycle permutation.
Recall that the order of a cycle decompostion is the least common multiple of lengths (order) of its cycles.
- Returns:
The order of the cycle permutation.
- Return type:
int
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).order() 1 >>> CycleDecomposition(Cycle(1, 3, 2)).order() 3 >>> CycleDecomposition(Cycle(1, 3, 2), Cycle(4, 5)).order() 6
- sgn() int[source]#
Return the sign of the cycle decomposition.
Recall that the sign, signature, or signum of a permutation \(\sigma\) is defined as +1 if \(\sigma\) is even, and -1 if \(\sigma\) is odd.
To compute the sign of a cycle decomposition, we use the fact that the sign is a homomorphism of groups, i.e., the sign of the cycle decomposition is just the product of the signs of the cycle componing it.
- Returns:
1 if the cycle decomposition is even, -1 if the cycle decomposition is odd.
- Return type:
int
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).sgn() 1 >>> CycleDecomposition(Cycle(1, 2), Cycle(3)).sgn() -1 >>> CycleDecomposition(Cycle(1), Cycle(2, 4, 7, 6), Cycle(3, 5)).sgn() 1
- support() Set[int][source]#
Return a set containing the indices in the domain of the permutation whose images are different from their respective indices, i.e., the set of \(n \in \mathbb{N}\) in the permutation domain which are not mapped to itself.
- Returns:
The support set of the cycle decomposition.
- Return type:
Set[int]
- Example:
>>> from symmetria import Cycle, CycleDecomposition ... >>> CycleDecomposition(Cycle(1)).support() set() >>> CycleDecomposition(Cycle(1), Cycle(2, 3)).support() {2, 3} >>> CycleDecomposition(Cycle(3, 4, 5, 6), Cycle(2, 1)).support() {1, 2, 3, 4, 5, 6}