Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Develop structure to generate random permutations #109

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ FEATURE:
- `symmetria.Permutation`: add `degree` method
- `symmetria.CyclePermutation`: add `degree` method
- `symmetria.Cycle`: add `degree` method
- `symmetria.random`: add random module to create random permutations

ENHANCEMENT:
- `symmetria.Permutation`: change how the sign is computed
Expand Down
32 changes: 32 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,38 @@ with the symmetric group and its elements.

API reference

.. grid-item-card:: :octicon:`iterations` Generators
:text-align: center
:class-title: sd-fs-5
:class-card: sd-p-3

Generating permutations

.. button-ref:: pages/API_reference/generators/index
:ref-type: doc
:color: primary
:outline:
:click-parent:
:expand:

API Reference

.. grid-item-card:: :octicon:`file-code` CLI
:text-align: center
:class-title: sd-fs-5
:class-card: sd-p-3

Command Line Interface

.. button-ref:: pages/cli/command_line_interface
:ref-type: doc
:color: primary
:outline:
:click-parent:
:expand:

API reference



.. warning:: The documentations is still a working in progress.
Expand Down
44 changes: 44 additions & 0 deletions docs/source/pages/API_reference/generators/deterministic.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
Deterministic Generation
========================

`Symmetria` provides a way to generate all the permutations of a given degree. The generation follows different
algorithms which can be specified.

You can use the generator of permutations in the following way

.. code-block:: python

import symmetria

permutations = symmetria.generate(algorithm="lexicographic", degree=3)

A list of implemented algorithms to generate permutations:

.. list-table:: overview
:widths: 35 50 15
:header-rows: 1

* - Algorithm
- Description
- Reference
* - ``lexicographic``
- The permutations are generate following the **lexicographic order**.
- `[1]`_
* - ``heap``
- The permutations are generate following the **Heap's algorithm**.
- `[2]`_
* - ``steinhaus-johnson-trotter``
- The permutations are generate following the **Steinhaus-Johnson-Trotter algorithm**.
- `[3]`_

.. _[1]: https://en.wikipedia.org/wiki/Lexicographic_order
.. _[2]: https://academic.oup.com/comjnl/article/6/3/293/360213
.. _[3]: https://en.wikipedia.org/wiki/Steinhaus–Johnson–Trotter_algorithm

====

The API of the method is given as following:

.. automodule:: symmetria.generators.algorithm.api
:members: generate
:exclude-members: random, random_generator
18 changes: 0 additions & 18 deletions docs/source/pages/API_reference/generators/generate.rst

This file was deleted.

31 changes: 5 additions & 26 deletions docs/source/pages/API_reference/generators/index.rst
Original file line number Diff line number Diff line change
@@ -1,36 +1,15 @@
Generators
==========

`Symmetria` provides a way to generate all the permutations of a given degree. The generation follows different
algorithms which can be specified.
`Symmetria` provides a way to generate permutations of a given degree in two way:

.. note:: The permutation are generated following a well-defined pattern, i.e., they are not random.
- algorithmically, i.e., the permutations are generated following a given algorithm;
- randomly, i.e., the permutations are generate randomly.

A list of implemented algorithms to generate permutations:

.. list-table:: overview
:widths: 35 50 15
:header-rows: 1

* - Algorithm
- Description
- Reference
* - ``lexicographic``
- The permutations are generate following the **lexicographic order**.
- `[1]`_
* - ``heap``
- The permutations are generate following the **Heap's algorithm**.
- `[2]`_
* - ``steinhaus-johnson-trotter``
- The permutations are generate following the **Steinhaus-Johnson-Trotter algorithm**.
- `[3]`_

.. _[1]: https://en.wikipedia.org/wiki/Lexicographic_order
.. _[2]: https://academic.oup.com/comjnl/article/6/3/293/360213
.. _[3]: https://en.wikipedia.org/wiki/Steinhaus–Johnson–Trotter_algorithm

.. toctree::
:maxdepth: 1
:hidden:

generate
deterministic
random
48 changes: 48 additions & 0 deletions docs/source/pages/API_reference/generators/random.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Random Generation
=================

`Symmetria` provides a way to generate random permutation.

You can use the random generation of permutations in the following way

.. code-block:: python

import symmetria

permutations = symmetria.random_generator(algorithm="lexicographic", degree=3)

If you don't want to have a generator and you want to just have a singular random permutation
you can use write

.. code-block:: python

import symmetria

permutation = symmetria.random(algorithm="lexicographic", degree=3)


A list of implemented algorithms to generate permutations:

.. list-table:: overview
:widths: 35 50 15
:header-rows: 1

* - Algorithm
- Description
- Reference
* - ``random``
- A permutation is generated by choosing the integer uniformly.
-
* - ``fisher-yates``
- The permutations are generate following the **Steinhaus-Johnson-Trotter algorithm**.
- `[1]`_

.. _[1]: https://en.wikipedia.org/wiki/Lexicographic_order

====

The API of the method is given as following:

.. automodule:: symmetria.generators.random.api
:members: random_generator
:exclude-members: random
13 changes: 11 additions & 2 deletions symmetria/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
from symmetria.elements.cycle import Cycle
from symmetria.generators.api import generate
from symmetria.elements.permutation import Permutation
from symmetria.generators.random.api import random, random_generator
from symmetria.generators.algorithm.api import generate
from symmetria.elements.cycle_decomposition import CycleDecomposition

__version__ = "0.2.0"
__all__ = ["__version__", "generate", "Permutation", "Cycle", "CycleDecomposition"]
__all__ = [
"__version__",
"generate",
"random",
"random_generator",
"Permutation",
"Cycle",
"CycleDecomposition",
]
26 changes: 26 additions & 0 deletions symmetria/generators/_validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typing import List


def _check_algorithm_parameter(value: str, supported: List[str]) -> None:
"""Private method to check the value provided for the parameter `algorithm`.

Recall that the parameter `algorithm` must be a string present in the list `supported`.
"""
if isinstance(value, str) is False:
raise TypeError(f"The parameter `algorithm` must be of type string, but {type(value)} was provided.")
if value not in supported:
raise ValueError(
f"The given algorithm ({value}) is not supported. \n "
f"Here, a list of supported algorithm for generations of permutations {supported}."
)


def _check_degree_parameter(value: int) -> None:
"""Private method to check the value provided for the parameter `degree`.

Recall that the parameter `degree` must be a non-negative integer different from zero.
"""
if isinstance(value, int) is False:
raise TypeError(f"The parameter `degree` must be of type int, but {type(value)} was provided.")
if value < 1:
raise ValueError(f"The parameter `degree` must be a non-zero positive integer, but {value} was provided.")
Empty file.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import List, Generator

import symmetria.elements.permutation
from symmetria import Permutation


def _lexicographic(degree: int, start: List[int]) -> Generator["Permutation", None, None]:
def _lexicographic(degree: int, start: List[int]) -> Generator[Permutation, None, None]:
"""Private method to generate all the permutations of degree `degree` in lexicographic order.

The algorithm is described as follows:
Expand Down Expand Up @@ -38,7 +39,7 @@ def _lexicographic(degree: int, start: List[int]) -> Generator["Permutation", No
permutation[k + 1 :] = reversed(permutation[k + 1 :])


def _heap(degree: int, start: List[int]) -> Generator["Permutation", None, None]:
def _heap(degree: int, start: List[int]) -> Generator[Permutation, None, None]:
"""Private method to generate all the permutations of degree `degree` using the Heap's algorithm.

A description of the algorithm can be founded in the article:
Expand All @@ -63,7 +64,7 @@ def _heap(degree: int, start: List[int]) -> Generator["Permutation", None, None]
yield from _heap(k - 1, permutation)


def _steinhaus_johnson_trotter(degree: int, start: List[int]) -> Generator["Permutation", None, None]:
def _steinhaus_johnson_trotter(degree: int, start: List[int]) -> Generator[Permutation, None, None]:
"""Private method to generate all the permutations of degree `degree` using the Steinhaus-Johnson-Trotter algorithm.

A description of the algorithm is given at:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from typing import List, Generator

from symmetria.generators._algorithms import (
from symmetria import Permutation
from symmetria.generators._validators import _check_degree_parameter, _check_algorithm_parameter
from symmetria.generators.algorithm._algorithms import (
_heap,
_lexicographic,
_steinhaus_johnson_trotter,
Expand All @@ -15,7 +17,7 @@
]


def generate(degree: int, algorithm: str = "lexicographic") -> Generator["Permutation", None, None]:
def generate(degree: int, algorithm: str = "lexicographic") -> Generator[Permutation, None, None]:
"""Generate all the permutations of the given degree based on the chosen algorithm.

The method generates all the permutations of the given degree using the specified algorithm.
Expand Down Expand Up @@ -45,37 +47,12 @@ def generate(degree: int, algorithm: str = "lexicographic") -> Generator["Permut
Permutation(3, 1, 2)
Permutation(3, 2, 1)
"""
_check_algorithm_parameter(value=algorithm)
_check_algorithm_parameter(value=algorithm, supported=_SUPPORTED_ALGORITHM)
_check_degree_parameter(value=degree)
return _relevant_generator(algorithm=algorithm, degree=degree)


def _check_algorithm_parameter(value: str) -> None:
"""Private method to check the value provided for the parameter `algorithm`.

Recall that the parameter `algorithm` must be a string present in the list _SUPPORTED_ALGORITHM
"""
if isinstance(value, str) is False:
raise TypeError(f"The parameter `algorithm` must be of type string, but {type(value)} was provided.")
if value not in _SUPPORTED_ALGORITHM:
raise ValueError(
f"The given algorithm ({value}) is not supported. \n "
f"Here, a list of supported algorithm for generations of permutations {_SUPPORTED_ALGORITHM}."
)


def _check_degree_parameter(value: int) -> None:
"""Private method to check the value provided for the parameter `degree`.

Recall that the parameter `degree` must be a non-negative integer different from zero.
"""
if isinstance(value, int) is False:
raise TypeError(f"The parameter `degree` must be of type int, but {type(value)} was provided.")
if value < 1:
raise ValueError(f"The parameter `degree` must be a non-zero positive integer, but {value} was provided.")


def _relevant_generator(algorithm: str, degree: int) -> Generator["Permutation", None, None]:
def _relevant_generator(algorithm: str, degree: int) -> Generator[Permutation, None, None]:
"""Private method to pick the correct algorithm for generating permutations."""
if algorithm == "lexicographic":
return _lexicographic(degree=degree, start=list(range(1, degree + 1)))
Expand Down
Empty file.
33 changes: 33 additions & 0 deletions symmetria/generators/random/_algorithms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from random import randint, shuffle
from typing import List, Generator

from symmetria import Permutation


def _random_shuffle(permutation: List[int]) -> Permutation:
"""Private method to generate a random permutation using the random module of Python."""
shuffle(permutation)
return Permutation(*permutation)


def _random_shuffle_generator(degree: int) -> Generator[Permutation, None, None]:
"""Private method to generate random permutations using the random module of Python."""
permutation = list(range(1, degree + 1))
while True:
yield _random_shuffle(permutation=permutation)


def _fisher_yates_shuffle(permutation: List[int]) -> Permutation:
"""Private method to generate a random permutation using the Fisher-Yates shuffle."""
n = len(permutation)
for i in range(n - 1, 0, -1):
j = randint(0, i)
permutation[i], permutation[j] = permutation[j], permutation[i]
return Permutation(*permutation)


def _fisher_yates_shuffle_generator(degree: int) -> Generator[Permutation, None, None]:
"""Private method to generate random permutations using the Fisher-Yates shuffle."""
permutation = list(range(1, degree + 1))
while True:
yield _fisher_yates_shuffle(permutation=permutation)
Loading
Loading