Source code for ec_gen.ehr
"""
The ehr_gen function
This code defines a function called ehr_gen that generates permutations
using Ehrlich-Hopcroft-Reingold (EHR) algorithm. A
permutation is a way of arranging a set of items in a different
order. The purpose of this code is to efficiently generate all possible
permutations of a given length.
The function takes one input: an integer n, which represents number of
elements to permute. For example, if n is 3, it will generate
permutations for elements [0, 1, 2].
The output of this function is a generator that yields integers. These
integers represent index of element that should be swapped with first
element (index 0) to create each new permutation. By following these
swap instructions, you can generate all possible permutations of n elements.
The algorithm achieves its purpose by using two lists: b and c. List b
represents current permutation, while list c keeps track of algorithm's
state. The function enters a loop where it updates these lists according
to specific rules, generating a new permutation with each iteration.
The main logic flow involves finding next element to swap by iterating
through c list. When it finds right element, it updates c, yields
index from b, and then partially reverses b to set up for next
permutation. This process continues until all permutations have been generated.
An important aspect of this algorithm is its efficiency. Instead of generating
and storing all permutations at once, it yields them one at a time. This
approach saves memory and allows for processing of permutations as they're
generated, which can be very useful when working with large sets of elements.
"""
from typing import Generator
[docs]
def ehr_gen(n: int) -> Generator[int, None, None]:
"""
The function `ehr` generates all permutations of a given length using EHR algorithm.
The `ehr_gen` function is a generator that generates all permutations
of length `n` using ehr algorithm. It yields indices of elements
to be swapped with first element (index 0) in each permutation. The
algorithm works by maintaining two lists, `perm` and `state`, where
`perm` represents the current permutation and `state` keeps track of
state of the algorithm. The algorithm iterates through elements of
`state` and updates elements of `perm` accordingly to generate all
possible permutations.
:param n: The parameter `n` represents the number of elements in the
permutation
:type n: int
Examples:
>>> for i in ehr_gen(4):
... print(f"swap 0 and {i}")
...
swap 0 and 1
swap 0 and 2
swap 0 and 1
swap 0 and 2
swap 0 and 1
swap 0 and 3
swap 0 and 2
swap 0 and 1
swap 0 and 2
swap 0 and 1
swap 0 and 2
swap 0 and 3
swap 0 and 1
swap 0 and 2
swap 0 and 1
swap 0 and 2
swap 0 and 1
swap 0 and 3
swap 0 and 2
swap 0 and 1
swap 0 and 2
swap 0 and 1
swap 0 and 2
"""
if n < 2:
return
perm = list(range(n)) # perm[0] is never used
state = [0] * (n + 1) # state[0] is never used
while True:
idx = 1
while True:
if state[idx] == idx:
state[idx] = 0
idx += 1
if state[idx] < idx:
break
if idx == n:
break
state[idx] += 1
yield perm[idx]
perm[1:idx] = perm[idx - 1 : 0 : -1]
if __name__ == "__main__":
import doctest
doctest.testmod()