From 905fb69d33261ffdbe05cac3f1924919ed33221f Mon Sep 17 00:00:00 2001 From: Eirik Keilegavlen Date: Mon, 9 Jan 2017 11:31:48 +0100 Subject: [PATCH] Generator for multinary numbers of given base and length. Also unit tests. --- permutations.py | 46 ++++++++++++++++++++++++++++++++++++++ tests/test_permutations.py | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 permutations.py create mode 100644 tests/test_permutations.py diff --git a/permutations.py b/permutations.py new file mode 100644 index 0000000000..48aec5b164 --- /dev/null +++ b/permutations.py @@ -0,0 +1,46 @@ + +def multinary_permutations(base, length): + """ + Define a generator over all numbers of a certain length for a number system + with a specified base. + + For details on the decomposition into an arbitrary base see + http://math.stackexchange.com/questions/111150/changing-a-number-between-arbitrary-bases + + Note that the generator will loop over base**length combinations. + + Examples: + + Construct the numbers [00] to [11] in binary numbers + >>> multinary_permutations(2, 2) + [array([ 0., 0.]), array([ 1., 0.]), array([ 0., 1.]), array([ 1., 1.])] + + Construct the numbers from 0 to 99 (permuted) in the decimal number + system. + >>> it = multinary_permutation(10, 2) + + Parameters: + base (int): Base of the number system + length (int): Number of digits in the numbers + + Yields: + array, size length: Array describing the next number combination. + + """ + + # There are in total base ** length numbers to be covered, these need to be + # rewritten into the base number system + for iter1 in range(base ** length): + + # Array to store the multi-d index of the current index + bit_val = [0] * length + # Number to be decomposed + v = iter1 + + # Loop over all digits, find the expression of v in that system + for iter2 in range(length): + bit_val[iter2] = v % base + v = v // base + # Yield the next value + yield bit_val + diff --git a/tests/test_permutations.py b/tests/test_permutations.py new file mode 100644 index 0000000000..67359d5f46 --- /dev/null +++ b/tests/test_permutations.py @@ -0,0 +1,46 @@ +import unittest +import numpy as np + +from utils import permutations + +class TestPermutations(unittest.TestCase): + + def compare_lists(self, base, length, lst): + # Compare a pre-defined list with the result of multinary_permutations + # Define a generator, and check that all values produced are contained within lst + # Also count the number of iterations + iter_cnt = 0 + for a in permutations.multinary_permutations(base, length): + found = False + for b in lst: + if np.array_equal(np.array(a), np.array(b)): + found = True + break + assert found + iter_cnt += 1 + assert iter_cnt == len(lst) + + + def test_length_2(self): + # Explicitly construct a 2D array of all combination of base 3 + base = 3 + length = 2 + lst = [] + for i in range(base): + for j in range(base): + lst.append([i, j]) + self.compare_lists(base, length, lst) + + def test_base_4(self): + # Check with a manually constructed list of length 3 + base = 4 + length = 3 + lst = [] + for i in range(base): + for j in range(base): + for k in range(base): + lst.append([i, j, k]) + self.compare_lists(base, length, lst) + + if __name__ == '__main__': + unittest.main()