예제 #1
0
 def test_factoradic_iterate_permutations(self):
     for j in range3(20):
         elements = list(range3(3))
         # factoradic = Factoradic.padded_to_length_s(number_to_factoradic(j), len(elements)) # not required (visual)
         factoradic = Factoradic.number_to_factoradic(j)
         # print j, factoradic, generate_permutation_from_factoradic_inplace(factoradic, elements)
             #  this also works...
             # ... because we regenerate "elements" every loop, but generally we don't want to modify parameters
         print(j, factoradic, Factoradic.generate_permutation_from_factoradic(factoradic, elements))
예제 #2
0
 def test_factoradic_iteration(self):
     f_j = Factoradic.number_to_factoradic(0)
     for j in range3(0, 720):
         # print(j, number_to_factoradic(j), "f_j", f_j)
         assert Factoradic.number_to_factoradic(j) == f_j, "ERROR factoradics don't match"
         f_j = Factoradic.next_factoradic(f_j)
         assert Factoradic.number_to_factoradic(j) != f_j, "ERROR consecutive factoradics shouldn't match"
예제 #3
0
    def test_large_permutation(self):
        # example found online, with a big Mersenne prime
        N = (2 ** 607) - 1

        print("with a Factoradic object:")
        print("N = (2 ** 607) - 1 # =>", N)
        f_1 = Factoradic(N)
        print("factoradic(N) =>", f_1)
        print("length of factoradic(N):", f_1.length())
        perm_f1 = f_1.permutation_inplace(list(range3(f_1.length())))
        print("permutation number factoradic(N) of the ordered list from [0, 1, 2, ... 112] =>", perm_f1)

        assert f_1.length() == 113

        resL = "[2L, 77L, 30L, 88L, 71L, 102L, 97L, 70L, 4L, 12L, 75L, 71L, 27L, 9L, 91L, 43L, 75L, 58L, 30L, 73L,"
        resL+= " 10L, 11L, 68L, 33L, 77L, 79L, 50L, 80L, 41L, 77L, 48L, 5L, 32L, 78L, 25L, 74L, 0L, 9L, 49L, 3L, 43L,"
        resL+= " 14L, 6L, 20L, 2L, 6L, 61L, 14L, 29L, 7L, 37L, 41L, 5L, 15L, 30L, 54L, 26L, 0L, 41L, 19L, 29L, 50L, 6L,"
        resL+= " 6L, 2L, 25L, 6L, 8L, 44L, 10L, 26L, 13L, 16L, 0L, 14L, 4L, 5L, 24L, 24L, 30L, 22L, 6L, 6L, 29L, 10L,"
        resL+= " 24L, 12L, 23L, 3L, 20L, 15L, 20L, 16L, 11L, 12L, 7L, 2L, 15L, 10L, 5L, 5L, 8L, 6L, 7L, 2L, 0L, 0L,"
        resL+= " 1L, 0L, 1L, 0L, 1L, 0L]"

        res =  "[2, 77, 30, 88, 71, 102, 97, 70, 4, 12, 75, 71, 27, 9, 91, 43, 75, 58, 30, 73,"
        res += " 10, 11, 68, 33, 77, 79, 50, 80, 41, 77, 48, 5, 32, 78, 25, 74, 0, 9, 49, 3, 43,"
        res += " 14, 6, 20, 2, 6, 61, 14, 29, 7, 37, 41, 5, 15, 30, 54, 26, 0, 41, 19, 29, 50, 6,"
        res += " 6, 2, 25, 6, 8, 44, 10, 26, 13, 16, 0, 14, 4, 5, 24, 24, 30, 22, 6, 6, 29, 10,"
        res += " 24, 12, 23, 3, 20, 15, 20, 16, 11, 12, 7, 2, 15, 10, 5, 5, 8, 6, 7, 2, 0, 0,"
        res += " 1, 0, 1, 0, 1, 0]"

        assert str(f_1) == resL or str(f_1) == res # annoying Python2-3 compatibility glitch workaround

        perm_str  = "[2, 78, 31, 91, 73, 107, 102, 72, 5, 14, 82, 77, 30, 11, 104, 49, 87, 65, 36, 88, 13, 16, 84, 42,"
        perm_str += " 98, 101, 61, 106, 52, 103, 60, 7, 43, 111, 34, 108, 0, 17, 69, 6, 63, 24, 12, 35, 4, 18, 99, 28,"
        perm_str += " 53, 20, 67, 75, 15, 37, 58, 105, 54, 1, 85, 45, 64, 110, 22, 23, 9, 62, 26, 32, 112, 39, 74, 46,"
        perm_str += " 51, 3, 50, 25, 29, 83, 86, 96, 80, 38, 40, 109, 55, 94, 59, 95, 21, 92, 76, 97, 81, 66, 70, 47,"
        perm_str += " 19, 100, 71, 44, 48, 79, 57, 89, 27, 8, 10, 41, 33, 68, 56, 93, 90]"

        assert str(perm_f1) == perm_str

        # test the not-in-place permutation method
        assert perm_f1 == f_1.permutation(list(range3(f_1.length())))
예제 #4
0
    def test_factoradic_iteration_timed(self):
        start = (2 ** 607) - 1
        start **= 20  # we need a really large number to even get significant times in a modern computer
        end   = start + 100  # avg: 0.011 per iteration in my comp. for number_to_factoradic, 0.001 for next_factoradic
        f_j = Factoradic.number_to_factoradic(start)
        profiled_number_to_factoradic = profile_time(Factoradic.number_to_factoradic)
        profiled_next_factoradic = profile_time(Factoradic.next_factoradic)

        for j in range3(start, end):
            # print(j, number_to_factoradic(j), "f_j", f_j)
            assert profiled_number_to_factoradic(j) == f_j, "ERROR factoradics don't match"
            f_j = profiled_next_factoradic(f_j)
            assert profiled_number_to_factoradic(j) != f_j, "ERROR consecutive factoradics shouldn't match"

        calc_prof_data()
        print_prof_data()
예제 #5
0
    def cascade_factoradic_digits_inplace(
            factoradic_value):  # in-place. Makes the factoradic well-formed
        reversed_place = 1
        factoradic_value[len(factoradic_value) - 1] = 0
        for i in range3(len(factoradic_value) - 2, 0, -1):
            reversed_place += 1
            if factoradic_value[i] >= reversed_place:
                factoradic_value[i -
                                 1] += factoradic_value[i] // reversed_place
                factoradic_value[i] %= reversed_place

        reversed_place += 1
        while factoradic_value[0] >= reversed_place:
            factoradic_value.insert(0, factoradic_value[0] // reversed_place)
            factoradic_value[1] %= reversed_place
            reversed_place += 1
        return factoradic_value
예제 #6
0
    def test_padding_zeroes(self):
        f = Factoradic(5)  # [2,1,0]
        list_no_pad = Factoradic.padded_to_length_s(f.v, f.length())  # should make no change
        assert f == list_no_pad, "ERROR: padding to the same length should make no change"

        list_f = Factoradic.padded_to_length_s(f.v, 5)

        assert list_f == [0,0,2,1,0]
        assert f.v == [2,1,0]
        print("PADDING", list_f, f.v)

        for _ in range3(100):  # tests random paddings and verifies they stay consistent
            f = Factoradic(random.randint(0,100000000))
            f_padding_size = random.randint(0,50)
            list_paddedf = Factoradic.padded_to_length_s(f.v, f.length() + f_padding_size)

            assert len(list_paddedf) == f.length() + f_padding_size
            assert f.v == list_paddedf[f_padding_size:]
예제 #7
0
    def generate_permutation_from_factoradic_inplace(
            factoradic_value, elements):  # modifies 'elements' in place
        res = []

        # this bit makes the permutations cycle through:
        # permutation number [1, 0, 0, 0] <=> permutation number [0, 0, 0]
        size_diff = len(factoradic_value) - len(elements)
        if size_diff > 0:
            factoradic_value = factoradic_value[size_diff:]

        # factoradic_value needs to be padded to the length of "elements"
        if size_diff < 0:
            factoradic_value = Factoradic.padded_to_length_s(
                factoradic_value, len(elements))

        # at this point, lengths must match
        for i in range3(len(factoradic_value)):
            res.append(elements.pop(factoradic_value[i]))
        return res
예제 #8
0
    def test_increment(self):
        f = Factoradic(2)
        f.increment(5)
        f_ = Factoradic(f)  # copy constructor
        f_.increment(0)

        assert f == Factoradic(7)
        assert f == f_

        f0 = Factoradic(0)

        f0.increment(1)
        assert f0 == Factoradic([1,0])
        assert f0 == Factoradic(0).next()

        f0 = Factoradic(0)

        f0.increment(5)
        assert f0 == Factoradic(5)

        for _ in range3(100):
            x = random.randint(0,10000)
            y = random.randint(0,10000)

            f_x = Factoradic(x)
            f_inc = Factoradic(x+y)
            f_x.increment(y)
            assert f_x == f_inc, "ERROR in random increment"
            f_x_pluszero = Factoradic(f_x)
            f_x_pluszero.increment(0)
            assert f_x_pluszero == f_x
            f_x_plusone = Factoradic(f_x)
            f_x_plusone.increment(1)
            assert f_x_plusone == f_x.next()

        with self.assertRaises(FactoradicException):
            f.increment(-1)  # negatives not allowed
        with self.assertRaises(FactoradicException):
            f.increment("five")  # wrong type
        with self.assertRaises(FactoradicException):
            f.increment([1,1,0])  # would be factoradic for 3, but we don't accept this at the moment (convert to int)
예제 #9
0
    def test_large_permutation(self):
        # example found online, with a big Mersenne prime
        N = (2 ** 607) - 1
        print("N = (2 ** 607) - 1 # =>", N)
        n_f = Factoradic.number_to_factoradic(N)
        print("factoradic(N) =>", n_f)
        print("length of factoradic(N):", len(n_f))

        perm_n_f = Factoradic.generate_permutation_from_factoradic(n_f, list(range3(len(n_f))))

        print("permutation number factoradic(N) of the ordered list from [0, 1, 2, ... 112] =>", perm_n_f)
        # observation: by definition, each element of perm_n_f is >= to n_f for every position, ...
        # ... for the canonical [0...len(n_f)] list of elements

        assert len(n_f) == 113

        resL = "[2L, 77L, 30L, 88L, 71L, 102L, 97L, 70L, 4L, 12L, 75L, 71L, 27L, 9L, 91L, 43L, 75L, 58L, 30L, 73L,"
        resL+= " 10L, 11L, 68L, 33L, 77L, 79L, 50L, 80L, 41L, 77L, 48L, 5L, 32L, 78L, 25L, 74L, 0L, 9L, 49L, 3L, 43L,"
        resL+= " 14L, 6L, 20L, 2L, 6L, 61L, 14L, 29L, 7L, 37L, 41L, 5L, 15L, 30L, 54L, 26L, 0L, 41L, 19L, 29L, 50L, 6L,"
        resL+= " 6L, 2L, 25L, 6L, 8L, 44L, 10L, 26L, 13L, 16L, 0L, 14L, 4L, 5L, 24L, 24L, 30L, 22L, 6L, 6L, 29L, 10L,"
        resL+= " 24L, 12L, 23L, 3L, 20L, 15L, 20L, 16L, 11L, 12L, 7L, 2L, 15L, 10L, 5L, 5L, 8L, 6L, 7L, 2L, 0L, 0L,"
        resL+= " 1L, 0L, 1L, 0L, 1L, 0L]"

        res =  "[2, 77, 30, 88, 71, 102, 97, 70, 4, 12, 75, 71, 27, 9, 91, 43, 75, 58, 30, 73,"
        res += " 10, 11, 68, 33, 77, 79, 50, 80, 41, 77, 48, 5, 32, 78, 25, 74, 0, 9, 49, 3, 43,"
        res += " 14, 6, 20, 2, 6, 61, 14, 29, 7, 37, 41, 5, 15, 30, 54, 26, 0, 41, 19, 29, 50, 6,"
        res += " 6, 2, 25, 6, 8, 44, 10, 26, 13, 16, 0, 14, 4, 5, 24, 24, 30, 22, 6, 6, 29, 10,"
        res += " 24, 12, 23, 3, 20, 15, 20, 16, 11, 12, 7, 2, 15, 10, 5, 5, 8, 6, 7, 2, 0, 0,"
        res += " 1, 0, 1, 0, 1, 0]"

        assert str(n_f) == resL or str(n_f) == res # annoying Python2-3 compatibility glitch workaround

        perm_str  = "[2, 78, 31, 91, 73, 107, 102, 72, 5, 14, 82, 77, 30, 11, 104, 49, 87, 65, 36, 88, 13, 16, 84, 42,"
        perm_str += " 98, 101, 61, 106, 52, 103, 60, 7, 43, 111, 34, 108, 0, 17, 69, 6, 63, 24, 12, 35, 4, 18, 99, 28,"
        perm_str += " 53, 20, 67, 75, 15, 37, 58, 105, 54, 1, 85, 45, 64, 110, 22, 23, 9, 62, 26, 32, 112, 39, 74, 46,"
        perm_str += " 51, 3, 50, 25, 29, 83, 86, 96, 80, 38, 40, 109, 55, 94, 59, 95, 21, 92, 76, 97, 81, 66, 70, 47,"
        perm_str += " 19, 100, 71, 44, 48, 79, 57, 89, 27, 8, 10, 41, 33, 68, 56, 93, 90]"

        assert str(perm_n_f) == perm_str
예제 #10
0
    def factoradic_to_number(factoradic_value):
        res = 0
        for i in range3(len(factoradic_value) - 1):
            res += factoradic_value[i] * fact(len(factoradic_value) - 1 - i)

        return res
예제 #11
0
 def is_well_formed_factoradic(factoradic_value):
     for i in range3(len(factoradic_value)):
         if int(factoradic_value[i]) >= (len(factoradic_value) - i):
             return False
     return True