예제 #1
0
 def test_subgroup_family(self):
     cf = Permutation.read_cycle_form
     a = cf([[2,3],[4,6],[5,8],[9,11]], 13)
     b = cf([[1,2,4,7,9,3,5,6,8,10,11,12,13]], 13)
     fam = SubgroupFamily(PermGroup([a,b]))
     stack = PartitionStack([0]*13,[-1]*13)
     stack.extend(0,[1,3,5,7,9,11])
     stack.extend(1,[1])
     stack.extend(1,[3])
     func1 = fam.extension_functions(stack)[1]
     extend = lambda x:fam.extension_functions(x)[0](x)
     extend(stack)
     after = Partition([[4,6,8,10,13],[5,7,9,11],[1],[3],[2,12]])
     self.assertEqual(stack[-1],after)
     stack.extend(1,[5])
     extend(stack)
     extend(stack)
     extend(stack)
     extend(stack)
     extend(stack)
     extend(stack)
     self.assertFalse(stack.discrete())
     extend(stack)
     self.assertTrue(stack.discrete())
     
     right_before = PartitionStack.single_partition_stack([[2,4,6,8,10,12,13],[1,5,7,11],[9],[3]])
     func1(right_before)
     right_after = Partition([[2,6,8,12,13],[1,5,7,11],[9],[3],[4,10]])
     self.assertEqual(right_before[-1],right_after)        
예제 #2
0
 def test_discrete(self):
     base = PartitionStack([0,0,0,0,0],[-1,-1,-1,-1,-1])
     base.extend(0,[3,4,5])
     base.extend(1,[4])
     base.extend(0,[2])
     self.assertFalse(base.discrete())
     base.extend(1,[5])
     self.assertTrue(base.discrete())
예제 #3
0
 def __init__(self, group_property, refinement_family, size):
     self.size = size
     self.refinement_family = refinement_family
     self.group_property = group_property
     self.left = PartitionStack([0]*size,[-1]*size)
     self.right = PartitionStack([0]*size,[-1]*size)
     self._cur_height = 0
     self._cur_position = None
     self._special_lookup = None
     self._left_split_index = None
     self.printing = False
     self.multi_backtrack = True
     self.double_coset_check = False
예제 #4
0
 def test_can_extend(self):
     base = PartitionStack([0,0,0,0,0],[-1,-1,-1,-1,-1]) 
     base.extend(0, [1,3,5])
     self.assertEqual(base[-1], Partition([[2,4],[1,3,5]]))
     self.assertFalse(base.can_extend(0,[2,4]))
     self.assertFalse(base.can_extend(0,[2,4,1,3]))
     self.assertFalse(base.can_extend(0,[]))
     self.assertFalse(base.can_extend(0,[5]))
     self.assertTrue(base.can_extend(0,[1,2,3]))
     self.assertTrue(base.can_extend(0,[4]))
예제 #5
0
 def test_pop(self):
     stack = PartitionStack([6,2,4,7,0,0,3,5,1,4],[1,1,0,2,-1,-1,0,4,0,0])
     self.assertEqual(stack[-1], Partition([[5,6],[9],[2],[7],[3,10],[8],[1],[4]]))
     stack.pop()
     self.assertEqual(stack[-1], Partition([[5,6],[9],[2,4],[7],[3,10],[8],[1]]))
     self.assertEqual(stack, PartitionStack([6,2,4,2,0,0,3,5,1,4],[1,1,0,1,-1,-1,0,4,0,0]))
     stack.pop()
     self.assertEqual(stack[-1], Partition([[5,6],[1,9],[2,4],[7],[3,10],[8]]))
     stack.pop()
     self.assertEqual(stack[-1], Partition([[5,6],[1,9],[2,4],[7],[3,8,10]]))
     stack.pop()
     self.assertEqual(stack[-1], Partition([[3,5,6,8,10],[1,9],[2,4],[7]]))    
예제 #6
0
 def __init__(self, group_property, refinement_family, size):
     self.size = size
     self.refinement_family = refinement_family
     self.group_property = group_property
     self.left = PartitionStack([0]*size,[-1]*size)
     self.right = PartitionStack([0]*size,[-1]*size)
     self._cur_height = 0
     self._cur_position = None
     self._special_lookup = None
     self._left_split_index = None
예제 #7
0
 def extension_functions(self,left,*args):
     #Only works for r_base construction or equivelent procedure.
     base = left.fix()
     self._group.change_base(base)
     orbits = self._group.orbits(len(base), key = self._key_single)
     orbits.sort(key = self._key_orbit)
     #should be left.height if we can gaureentee complete part. stack.
     for i in range(left.degree):
         for orbit in orbits:
             if left.can_extend(i, orbit):
                 base_stack = PartitionStack.deep_copy(left)
                 func = lambda stack: self._full_extension(stack,base,i,orbit)
                 func._info = [self.__class__,base, i,orbit]
                 return func, func
     return None
예제 #8
0
 def extension_functions(self,left):
     base = left.fix()
     self._group.change_base(base)
     orbits = self._group.orbits(len(base), key = self._key_single)
     orbits.sort(key = self._key_orbit)
     left_copy = PartitionStack.deep_copy(left)
     for i in range(left.base_size):
         for orbit in orbits:
             before = len(stack)
             self.full_extention(left, right,base_stack,i,orbit)
             if len(stack) > before:
                 func = lambda l=None, r=None : self.full_extention(l,r,base_stack,i,orbit)
                 func._info = [self.__class__,base, i,orbit ]
                 return left, right, func
     return left, right, None   
예제 #9
0
    def test_non_trivial_modifiers(self):
        cf = lambda x: Permutation.read_cycle_form(x,13)
        a = cf([[2,3],[4,6],[5,8],[9,11]])
        b = cf([[1,2,4,7,9,3,5,6,8,10,11,12,13]])
        G = PermGroup([a,b])
        part_stab = Partition([[3,2],[6,4],[5,1,7,8,9,10,11,12,13]])
        
        fam = RefinementUnion([PartitionStabaliserFamily(part_stab), SubgroupFamily(G)])
        
        prop = CosetPropertyUnion([PartitionStabaliserProperty(part_stab), SubgroupProperty(G)])
        
        log = LeonLoggerUnion([LeonCounter()])
        
        cons = ModifierUnion([PartitionStackConstraint()])
        
        union = ModifierUnion([fam,prop,log,cons])
        
        left = PartitionStack([0]*13,[-1]*13)         
        right = PartitionStack.deep_copy(left)
        
        funcs = union.extension_functions(left)
        self.assertFalse(funcs is None)
        funcs[0](left)
        funcs[1](right)
        
        index = union.exclude_backtrack_index(left,right, None, 1)
        self.assertEqual(index,None)

        index = union.exclude_backtrack_index(left,right, None, 2)
        self.assertEqual(index,1)
        
        self.assertTrue(union.property_check(a))
        self.assertFalse(union.property_check(b))
        
        pos_leaf = union.leaf_fail_backtrack_index(a,b,None)
        neg_leaf = union.leaf_pass_backtrack_index(a,b,None)
        self.assertEqual(pos_leaf, None)
        self.assertEqual(neg_leaf, None)
예제 #10
0
class PartitionBacktrackWorkhorse():
    def __init__(self, group_property, refinement_family, size):
        self.size = size
        self.refinement_family = refinement_family
        self.group_property = group_property
        self.left = PartitionStack([0]*size,[-1]*size)
        self.right = PartitionStack([0]*size,[-1]*size)
        self._cur_height = 0
        self._cur_position = None
        self._special_lookup = None
        self._left_split_index = None
        self.printing = False
        self.multi_backtrack = True
        self.double_coset_check = False
    
    def find_partition_backtrack_subgroup(self):
        #Assume the refinement families are symmetric.
        generators = []
        r_base = self._r_base()
        count = 0
        leaf_count = 0
        

        if self.printing:
            print("-----------------------------------")
            print("Traversing tree:")
        
        while self._cur_height > -1:
            count += 1
            if self.printing:
                a = self._cur_position
                b = self.right[self._cur_height]
                c = self.left[self._cur_height]
                
                print("\n{}: {}\n{} -> {}".format(self._cur_height,a,c,b)) 
            #Alternatice 1: premature rule out.
            if self.alt1():
                if self.printing:
                    print("Alternative 1: partition violation")
                #print("alt_1")
                self.backtrack(self._cur_height - 1)
            
            #Alternative 2: discrete check.
            elif self.right.discrete():
                leaf_count += 1
                #print("alt_2")
                perm = Permutation.read_partitions(self.left[self._cur_height], self.right[self._cur_height])
                if self.double_coset_check and self.printing:
                    G=PermGroup(generators)
                    Dco = G*perm*G
                    perm_key = ordering.ordering_to_perm_key(self.left.fix())
                    if Dco.mid_minimal(key = perm_key):
                        print("Actually minimal in own double coset: {}".format(Dco._list_elements(Perm_key)))
                    
                added = False                
                if not perm.trivial() and self.group_property.check(perm):
                    generators.append(perm)
                    added = True
                    #self.backtrack()
                if self.printing:
                    print("Alternative 2 found permutation: {} ({})".format(perm, added))
                if self.multi_backtrack and added:
                    self.backtrack(self._cur_position.min_changed_index())
                else:
                    self.backtrack()
            
            #Alternative 3: not a special level
            elif r_base[self._cur_height] is not None:
                #print("alt_3")
                r_base[self._cur_height](None, self.right)
                if self.printing:
                    print("Alternative 3 applying function: {}".format(r_base[self._cur_height]._info))  
                self._cur_height += 1                
            
            #Alternative 4: is a special level
            else:
                if self.printing:
                    print("Alternative 4 special level")                  
                #print("alt_4")
                self.extend_right()
        
        if self.printing:
            print("\nFinished tree traversal.")
            print("Visited {} vertices ({} of which were terminal).".format(count, leaf_count))

        return generators
    
    def _r_base(self):
        if self.printing:
            print("Constructing r-base:")
        r_base = []
        special_cell_sizes = []
        special_lookup = dict()
        height = 0
        while height < self.size -1:
            if self.printing:
                print("\n{}".format(self.left[-1]))
            _,_,func = self.refinement_family.extend(self.left, None)
            r_base.append(func)            
            if func is not None:
                if self.printing:
                    print(func._info)
                special_cell_sizes.append(0)
            else:
                if self.printing:
                    print("Special level:")
                cell, cell_size, point = self._split_left_cell()
                special_cell_sizes.append(cell_size)
                special_lookup[height] = (cell, point)
            height += 1
        if self.printing:
            print("\n{}".format(self.left[-1]))      
        self._cur_position = PositionTracker(special_cell_sizes)
        self._special_lookup = special_lookup
        if self.printing:
            print("\nFinished R-base construction.")
            _temp_levels = sorted([level for level in special_lookup])
            print("Special levels: {}".format(_temp_levels))
            special_cells = [special_lookup[level][0] for level in _temp_levels]
            special_vals = [special_lookup[level][1] for level in _temp_levels]
            print("Basis of group: {}".format(special_vals))
            print("Ordering from rbase: {}".format(self.left.fix()))            
        return r_base

    def _split_left_cell(self):
        #Overwrite this with a clever function that queries the refinements for
        #clues as to which cell and element to split.
        top = self.left[-1]
        if self._left_split_index is None or len(top[self._left_split_index]) < 2:
            _, self._left_split_index = min([(len(cell),index) for index, cell in enumerate(top) if len(cell) > 1])
        cell = top[self._left_split_index]
        point = cell[0]
        cell_size = len(cell)
        #Turn checks off.
        self.left.extend(self._left_split_index, [point])
        return self._left_split_index, cell_size, point
    
    def find_partition_backtrack_coset(self):        
        #Assume the refinement families are LR-symmetric.
        r_base = self._r_base()
        count = 0
        
        while self._cur_height > -1:
            count += 1
            #a = self._cur_position
            #b = self.right[self._cur_height]
            #c = self.left[self._cur_height]
            #if self.size == 13:
            #print("\n{}:{}\n{} -> {}".format(self._cur_height,a,c,b)) 
            #Alternatice 1: premature rule out.
            if self.alt1():
                #print("alt_1")
                self.backtrack(self._cur_height - 1)
            
            #Alternative 2: discrete check.
            elif self.right.discrete():
                #print("alt_2")
                perm = Permutation.read_partitions(self.left[self._cur_height], self.right[self._cur_height])
                if self.group_property.check(perm):
                    return perm
                #self.backtrack()
                self.backtrack(self._cur_position.min_changed_index())
            
            #Alternative 3: not a special level
            elif r_base[self._cur_height] is not None:
                #print("alt_3")
                r_base[self._cur_height](None, self.right)
                self._cur_height += 1
            
            #Alternative 4: is a special level
            else:
                #print("alt_4")
                self.extend_right()
        
        print(count)
        return generators
    
    def backtrack(self, new_height = None):
        if new_height is None:
            new_height = self._cur_height
        self._cur_height = self._cur_position.increment(new_height)    
        if self._cur_height > -1:
            while len(self.right) > self._cur_height + 1:
                self.right.pop()
            self.extend_right()
        
                  
    def alt1(self):
        #Size violation
        if len(self.right) != self._cur_height + 1:
            return True
        elif len(self.right[-1][-1]) != len(self.left[self._cur_height][-1]):
            return True
        #Contained group violation.
        #Minimal in double coset violation.    
        #Property dependant violation.
        return False
    
    def extend_right(self):
        index = self._cur_height
        split_index, _ = self._special_lookup[index]
        cell = self.right[index][split_index]
        try:    
            split_val = cell[self._cur_position[index]]            
        except IndexError:
            for i in range(index + 1):
                a = self._cur_position
                b = self.right[i]
                c = self.left[i]
                print("\n{} -> {}\n{}".format(c,b,a))
            #this is where it screws
            raise IndexError("DIFFERENT")
        self.right.extend(split_index, [split_val])
        self._cur_height += 1
예제 #11
0
 def test_fix(self):
     stack = PartitionStack([6,2,4,7,0,0,3,5,1,4],[1,1,0,2,-1,-1,0,4,0,0])
     self.assertEqual(stack.fix(), [7,8,1,9,4,2])
예제 #12
0
 def initialise_partition_stacks(self):
     size = self.degree
     self.left = PartitionStack([0]*size,[-1]*size)
     self.right = PartitionStack([0]*size,[-1]*size)
예제 #13
0
    def test_extend(self):
        base = PartitionStack([0,0,0,0,0],[-1,-1,-1,-1,-1])
        self.assertEqual(base[-1], Partition([[1,2,3,4,5]]))
        base.extend(0,[3,4,5])
        self.assertEqual(base[-1], Partition([[1,2],[3,4,5]]))
        base.extend(1,[4])
        self.assertEqual(base[-1], Partition([[1,2],[3,5],[4]]))
        base.extend(0,[2])
        self.assertEqual(base[-1], Partition([[1],[3,5],[4],[2]]))
        extention = base.extend(1,[5])
        self.assertEqual(extention[-1], Partition([[1],[3],[4],[2],[5]]))
        self.assertEqual(base[-1], Partition([[1],[3],[4],[2],[5]]))
        
        self.assertEqual(extention[0], Partition([[1,2,3,4,5]]))
        self.assertEqual(extention[1], Partition([[1,2],[3,4,5]]))
        self.assertEqual(extention[2], Partition([[1,2],[3,5],[4]]))
        self.assertEqual(extention[3], Partition([[1],[3,5],[4],[2]]))
        self.assertEqual(extention[4], Partition([[1],[3],[4],[2],[5]]))

        base = PartitionStack([0,0,0,0,0],[-1,-1,-1,-1,-1]) 
        base.extend(0, [])
        self.assertEqual(len(base[1]), 1)
        base = PartitionStack([0,0,0,0,0],[-1,-1,-1,-1,-1]) 
        base.extend(0, [1,2,3,4,5])
        self.assertEqual(len(base[1]), 1)
예제 #14
0
 def test_single_partition_stack(self):
     stack = PartitionStack([0,0,1,1,2,2],[-1,-1,0,0,0,0])
     part = Partition([[1,2],[3,4],[5,6]])
     self.assertEqual(stack[-1], part)
     self.assertEqual(stack, PartitionStack.single_partition_stack(part))
예제 #15
0
class LeonSearch():
    def __init__(self, leon_modifiers, degree):
        self.degree = degree
        self.tree_modifiers = leon_modifiers
        self.left = None
        self.right = None
        self._left_split_index = None
        self._cur_height = None        
        self._r_base = None
        self._special_level_sizes = None
        #Tree position tracker to store traversal information.
        self._cur_position = None
        #Dictionary with heights as keys and split index and point pairs as values.
        self._special_lookup = None
    
    def initialise_partition_stacks(self):
        size = self.degree
        self.left = PartitionStack([0]*size,[-1]*size)
        self.right = PartitionStack([0]*size,[-1]*size)
    
    def initialise_r_base(self):
        r_base = []
        special_cell_sizes = []
        special_lookup = dict()
        height = 0
        while height < self.degree -1:
            funcs = self.tree_modifiers.extension_functions(self.left)
            if funcs is not None:
                left_func, right_func = funcs
                left_func(self.left)
                r_base.append(right_func)                
                special_cell_sizes.append(0)
            else:
                r_base.append(None)
                cell, cell_size, point = self._split_left_cell()
                special_cell_sizes.append(cell_size)
                special_lookup[height] = (cell, point)
            height += 1
        self._r_base = r_base
        self._special_level_sizes = special_cell_sizes
        self._special_lookup = special_lookup        
    
    def initialise_search_tree(self):
        self._cur_height = 0
        self._cur_position = PositionTracker(self._special_level_sizes)        
        
    def subgroup(self):
        #Needs to be done in this order.
        self.initialise_partition_stacks()
        self.initialise_r_base()
        self.initialise_search_tree()
                        
        gens = []
        
        while self._cur_height > -1:
            #alt_1 rule out.
            backtrack_index = self.tree_modifiers.exclude_backtrack_index(self.left, self.right, self._cur_position, self._cur_height)
            if backtrack_index is not None:
                self.backtrack(backtrack_index)
            
            #alt_2 discrete check.
            elif self.right.discrete():
                perm = Permutation.read_partitions(self.left[self._cur_height], self.right[self._cur_height])            
                if not perm.trivial() and self.tree_modifiers.property_check(perm):
                    gens.append(perm)
                    backtrack_index = self.tree_modifiers.leaf_pass_backtrack_index(self.left,self.right,self._cur_position)            
                else:
                    backtrack_index = self.tree_modifiers.leaf_fail_backtrack_index(self.left,self.right,self._cur_position)
                self.backtrack(backtrack_index)
            
            #alt_3 function to extend.
            elif self._r_base[self._cur_height] is not None:
                func = self._r_base[self._cur_height]
                func(self.right)
                self._cur_height += 1
            
            #alt_4 special level.    
            else:
                self._extend_right()
            
        return gens
    
    def backtrack(self, new_height = None):
        if new_height is None:
            new_height = self._cur_height
        self._cur_height = self._cur_position.increment(new_height)    
        if self._cur_height > -1:
            while len(self.right) > self._cur_height + 1:
                self.right.pop()
            self._extend_right()

    def _extend_right(self):
        index = self._cur_height
        split_index, _ = self._special_lookup[index]
        cell = self.right[index][split_index]
        try:    
            split_val = cell[self._cur_position[index]]            
        except IndexError:
            for i in range(index + 1):
                a = self._cur_position
                b = self.right[i]
                c = self.left[i]
                print("\n{} -> {}\n{}".format(c,b,a))
            #this is where it screws
            raise IndexError("DIFFERENT")
        self.right.extend(split_index, [split_val])
        self._cur_height += 1      
        
    def _split_left_cell(self):
        #Overwrite this with a clever function that queries the refinements for
        #clues as to which cell and element to split.
        top = self.left[-1]
        if self._left_split_index is None or len(top[self._left_split_index]) < 2:
            _, self._left_split_index = min([(len(cell),index) for index, cell in enumerate(top) if len(cell) > 1])
        cell = top[self._left_split_index]
        point = cell[0]
        cell_size = len(cell)
        #Turn checks off.
        self.left.extend(self._left_split_index, [point])
        return self._left_split_index, cell_size, point
예제 #16
0
 def test_pop(self):
     stack = PartitionStack([6,2,4,7,0,0,3,5,1,4],[1,1,0,2,-1,-1,0,4,0,0])
     self.assertEqual(stack[-1], Partition([[5,6],[9],[2],[7],[3,10],[8],[1],[4]]))
     stack.pop()
     self.assertEqual(stack[-1], Partition([[5,6],[9],[2,4],[7],[3,10],[8],[1]]))
     self.assertEqual(stack, PartitionStack([6,2,4,2,0,0,3,5,1,4],[1,1,0,1,-1,-1,0,4,0,0]))
     stack.pop()
     self.assertEqual(stack[-1], Partition([[5,6],[1,9],[2,4],[7],[3,10],[8]]))
     stack.pop()
     self.assertEqual(stack[-1], Partition([[5,6],[1,9],[2,4],[7],[3,8,10]]))
     stack.pop()
     self.assertEqual(stack[-1], Partition([[3,5,6,8,10],[1,9],[2,4],[7]]))   
     stack.pop()
     self.assertEqual(stack[-1], Partition([[3,5,6,7,8,10],[1,9],[2,4]]))   
     stack.pop()
     self.assertEqual(stack[-1], Partition([[3,5,6,8,10,7],[1,9,2,4]]))   
     stack.pop()
     self.assertEqual(stack[-1], Partition([[1,2,3,4,5,6,7,8,9,10]]))   
     
     raised_error = False
     try:
         stack.pop()
     except IndexError:
         raised_error = True
     self.assertTrue(raised_error)
     
     self.assertEqual(stack[-1], Partition([[1,2,3,4,5,6,7,8,9,10]]))
     self.assertEqual(len(stack), 1)
예제 #17
0
 def test_valid_intersection(self):
     base = PartitionStack([0,0,0,0,0],[-1,-1,-1,-1,-1]) 
     base.extend(0, [1,3,5])
     self.assertEqual(base[-1], Partition([[2,4],[1,3,5]]))
     self.assertTrue(base._valid_intersection(1,[2,4]) is None)
     self.assertEqual(base._valid_intersection(1,[1,2,4,5]), [1,5])