def test_by_label( self ): s0, s1 = Mock( spec=SymmetryOperation ), Mock( spec=SymmetryOperation ) s0.label = 'A' s1.label = 'B' sg = SymmetryGroup( symmetry_operations=[ s0, s1 ] ) self.assertEqual( sg.by_label( 'A' ), s0 ) self.assertEqual( sg.by_label( 'B' ), s1 )
def test_by_label(self): s0, s1 = Mock(spec=SymmetryOperation), Mock(spec=SymmetryOperation) s0.label = 'A' s1.label = 'B' sg = SymmetryGroup(symmetry_operations=[s0, s1]) self.assertEqual(sg.by_label('A'), s0) self.assertEqual(sg.by_label('B'), s1)
def test_save_symmetry_operation_vectors_to( self ): s0, s1 = Mock( spec=SymmetryOperation ), Mock( spec=SymmetryOperation ) s0.as_vector.return_value = [ 1, 2 ] s1.as_vector.return_value = [ 2, 1 ] sg = SymmetryGroup( symmetry_operations=[ s0, s1 ] ) with patch( 'numpy.savetxt' ) as mock_savetxt: sg.save_symmetry_operation_vectors_to( 'filename' ) self.assertEqual( mock_savetxt.call_args[0][0], 'filename' ) np.testing.assert_array_equal( mock_savetxt.call_args[0][1], np.array( [ [ 1, 2 ], [ 2, 1 ] ] ) )
def test_save_symmetry_operation_vectors_to(self): s0, s1 = Mock(spec=SymmetryOperation), Mock(spec=SymmetryOperation) s0.as_vector.return_value = [1, 2] s1.as_vector.return_value = [2, 1] sg = SymmetryGroup(symmetry_operations=[s0, s1]) with patch('numpy.savetxt') as mock_savetxt: sg.save_symmetry_operation_vectors_to('filename') self.assertEqual(mock_savetxt.call_args[0][0], 'filename') np.testing.assert_array_equal(mock_savetxt.call_args[0][1], np.array([[1, 2], [2, 1]]))
def test_read_from_file( self ): s0, s1 = Mock( spec=SymmetryOperation ), Mock( spec=SymmetryOperation ) with patch( 'numpy.loadtxt' ) as mock_np_loadtxt: mock_np_loadtxt.return_value = np.array( [ [ 1, 2 ], [ 2, 1 ] ] ) with patch( 'bsym.symmetry_operation.SymmetryOperation.from_vector' ) as mock_from_vector: mock_from_vector.side_effect = [ s0, s1 ] sg = SymmetryGroup.read_from_file( 'mock_filename' ) self.assertEqual( sg.symmetry_operations[0], s0 ) self.assertEqual( sg.symmetry_operations[1], s1 ) self.assertEqual( mock_from_vector.call_args_list[0], call( [ 1, 2 ] ) ) self.assertEqual( mock_from_vector.call_args_list[1], call( [ 2, 1 ] ) )
def __init__( self, objects, symmetry_group=None ): """ Create a :any:`ConfigurationSpace` object. Args: objects (list): The set of objects that define the vector space of this configuration space. symmetry_group (:any:`SymmetryGroup`): The set of symmetry operations describing the symmetries of this configuration space. Returns: None """ # Check that all properties have compatible dimensions self.dim = len( objects ) self.objects = objects if symmetry_group: for so in symmetry_group.symmetry_operations: if so.matrix.shape[0] != self.dim: raise ValueError self.symmetry_group = symmetry_group else: self.symmetry_group = SymmetryGroup( symmetry_operations=[ SymmetryOperation( np.identity( self.dim, dtype=int ), label='E' ) ] )
def test_read_from_file_with_labels( self ): s0, s1 = Mock( spec=SymmetryOperation ), Mock( spec=SymmetryOperation ) with patch( 'numpy.genfromtxt' ) as mock_np_genfromtxt: mock_np_genfromtxt.return_value = np.array( [ [ 'E', '1', '2' ], [ 'C2', '2', '1' ] ] ) with patch( 'bsym.symmetry_operation.SymmetryOperation.from_vector' ) as mock_from_vector: mock_from_vector.side_effect = [ s0, s1 ] sg = SymmetryGroup.read_from_file_with_labels( 'mock_filename' ) self.assertEqual( sg.symmetry_operations[0], s0 ) self.assertEqual( sg.symmetry_operations[1], s1 ) self.assertEqual( mock_from_vector.call_args_list[0], call( [ 1, 2 ] ) ) self.assertEqual( mock_from_vector.call_args_list[1], call( [ 2, 1 ] ) ) self.assertEqual( s0.set_label.call_args, call( 'E' ) ) self.assertEqual( s1.set_label.call_args, call( 'C2' ) )
def test_read_from_file(self): s0, s1 = Mock(spec=SymmetryOperation), Mock(spec=SymmetryOperation) with patch('numpy.loadtxt') as mock_np_loadtxt: mock_np_loadtxt.return_value = np.array([[1, 2], [2, 1]]) with patch('bsym.symmetry_operation.SymmetryOperation.from_vector' ) as mock_from_vector: mock_from_vector.side_effect = [s0, s1] sg = SymmetryGroup.read_from_file('mock_filename') self.assertEqual(sg.symmetry_operations[0], s0) self.assertEqual(sg.symmetry_operations[1], s1) self.assertEqual(mock_from_vector.call_args_list[0], call([1, 2])) self.assertEqual(mock_from_vector.call_args_list[1], call([2, 1]))
def test_read_from_file_with_labels(self): s0, s1 = Mock(spec=SymmetryOperation), Mock(spec=SymmetryOperation) with patch('numpy.genfromtxt') as mock_np_genfromtxt: mock_np_genfromtxt.return_value = np.array([['E', '1', '2'], ['C2', '2', '1']]) with patch('bsym.symmetry_operation.SymmetryOperation.from_vector' ) as mock_from_vector: mock_from_vector.side_effect = [s0, s1] sg = SymmetryGroup.read_from_file_with_labels('mock_filename') self.assertEqual(sg.symmetry_operations[0], s0) self.assertEqual(sg.symmetry_operations[1], s1) self.assertEqual(mock_from_vector.call_args_list[0], call([1, 2])) self.assertEqual(mock_from_vector.call_args_list[1], call([2, 1])) self.assertEqual(s0.set_label.call_args, call('E')) self.assertEqual(s1.set_label.call_args, call('C2'))
class ConfigurationSpace: def __init__(self, objects, symmetry_group=None): """ Create a :any:`ConfigurationSpace` object. Args: objects (list): The set of objects that define the vector space of this configuration space. symmetry_group (:any:`SymmetryGroup`): The set of symmetry operations describing the symmetries of this configuration space. Returns: None """ # Check that all properties have compatible dimensions dim = len(objects) self.objects = objects if symmetry_group: for so in symmetry_group.symmetry_operations: if so.matrix.shape[0] != dim: raise ValueError self.symmetry_group = symmetry_group else: self.symmetry_group = SymmetryGroup(symmetry_operations=[ SymmetryOperation(np.identity(dim, dtype=int), label='E') ]) def __repr__(self): to_return = "ConfigurationSpace\n" to_return += self.objects.__repr__() + "\n" to_return += "\n".join(self.symmetry_group.__repr__().split("\n")[1:]) return to_return def unique_configurations(self, site_distribution, verbose=False): """ Find the symmetry inequivalent configurations for a given population of objects. Args: site_distribution (dict): A dictionary that defines the number of each object to be arranged in this system. e.g. for a system with four sites, with two occupied (denoted `1`) and two unoccupied (denoted `0`):: { 1 : 2, 2 : 1 } verbose (opt:default=False): Print verbose output. Returns: unique_configurations (list): A list of :any:`Configuration` objects, for each symmetry inequivalent configuration. """ if verbose: print('total number of sites: ' + str(sum(site_distribution.values()))) print('using {:d} symmetry operations: '.format( len(self.symmetry_group.symmetry_operations))) permutations = [] working = True seen = set() unique_configurations = [] s = flatten_list([[key] * site_distribution[key] for key in site_distribution]) for new_permutation in unique_permutations(s): if permutation_as_config_number(new_permutation) not in seen: config = Configuration.from_tuple(new_permutation) numeric_equivalents = set( config.numeric_equivalents( self.symmetry_group.symmetry_operations)) config.count = len(numeric_equivalents) [seen.add(i) for i in numeric_equivalents] unique_configurations.append(config) if verbose: print("found {:d}, screened {:d}".format( len(unique_configurations), len(seen))) if verbose: print('unique configurations: ' + str(len(unique_configurations))) return (unique_configurations)
class ConfigurationSpace: def __init__( self, objects, symmetry_group=None ): """ Create a :any:`ConfigurationSpace` object. Args: objects (list): The set of objects that define the vector space of this configuration space. symmetry_group (:any:`SymmetryGroup`): The set of symmetry operations describing the symmetries of this configuration space. Returns: None """ # Check that all properties have compatible dimensions self.dim = len( objects ) self.objects = objects if symmetry_group: for so in symmetry_group.symmetry_operations: if so.matrix.shape[0] != self.dim: raise ValueError self.symmetry_group = symmetry_group else: self.symmetry_group = SymmetryGroup( symmetry_operations=[ SymmetryOperation( np.identity( self.dim, dtype=int ), label='E' ) ] ) def __repr__( self ): to_return = "ConfigurationSpace\n" to_return += self.objects.__repr__() + "\n" to_return += "\n".join( self.symmetry_group.__repr__().split("\n")[1:] ) return to_return def enumerate_configurations( self, generator, verbose=False ): """ Find all symmetry inequivalent configurations within the set produced by `generator`. Args: generator (:obj:`generator`): Generator object, that yields the configurations to search through. verbose (opt:default=False): Print verbose output. Returns: unique_configurations (list): A list of :any:`Configuration` objects, for each symmetry inequivalent configuration. """ working = True seen = set() unique_configurations = [] using_tqdm = hasattr( generator, 'postfix' ) for new_permutation in generator: if permutation_as_config_number( new_permutation ) not in seen: config = Configuration.from_tuple( new_permutation ) numeric_equivalents = set( config.numeric_equivalents( self.symmetry_group.symmetry_operations ) ) config.count = len( numeric_equivalents ) [ seen.add( i ) for i in numeric_equivalents ] unique_configurations.append( config ) if using_tqdm: generator.set_postfix( found=len(unique_configurations) ) if verbose: print( 'unique configurations: {} / {}'.format( len( unique_configurations ), len( seen ) ) ) return( unique_configurations ) def unique_configurations( self, site_distribution, verbose=False, show_progress=False ): """ Find the symmetry inequivalent configurations for a given population of objects. Args: site_distribution (dict): A dictionary that defines the number of each object to be arranged in this system. e.g. for a system with four sites, with two occupied (denoted `1`) and two unoccupied (denoted `0`):: { 1: 2, 0: 2 } verbose (opt:default=False): Print verbose output. show_progress (opt:default=False): Show a progress bar. Setting to `True` gives a simple progress bar. Setting to `"notebook"` gives a Jupyter notebook compatible progress bar. Returns: unique_configurations (list): A list of :any:`Configuration` objects, for each symmetry inequivalent configuration. """ s = flatten_list( [ [ key ] * site_distribution[ key ] for key in site_distribution ] ) total_permutations = number_of_unique_permutations( s ) if verbose: print( 'total number of sites: ' + str( sum( site_distribution.values() ) ) ) print( 'using {:d} symmetry operations.'.format( len( self.symmetry_group.symmetry_operations ) ) ) print( 'evaluating {:d} unique permutations.'.format( total_permutations ) ) generator = unique_permutations( s ) if show_progress: if show_progress=='notebook': generator = tqdm_notebook( generator, total=total_permutations, unit=' permutations' ) else: generator = tqdm( generator, total=total_permutations, unit=' permutations' ) return self.enumerate_configurations( generator, verbose=verbose ) def unique_colourings( self, colours, verbose=False ): """ Find the symmetry inequivalent colourings for a given number of 'colours'. Args: colours (list): A list of each object that may be arranged zero or more times in this system. verbose (opt:default=False): Print verbose output. Returns: unique_colours (list): A list of :any:`Configuration` objects, for each symmetry inequivalent colouring. """ generator = colourings_generator( colours, self.dim ) return self.enumerate_configurations( generator, verbose=verbose )
def test_append( self ): s0, s1 = Mock( spec=SymmetryOperation ), Mock( spec=SymmetryOperation ) sg = SymmetryGroup( symmetry_operations=[ s0, s1 ] ) s2 = Mock( spec=SymmetryOperation) sg.append( s2 ) self.assertEqual( sg.symmetry_operations, [ s0, s1, s2 ] )
def test_labels(self): s0, s1 = Mock(spec=SymmetryOperation), Mock(spec=SymmetryOperation) s0.label = 'A' s1.label = 'B' sg = SymmetryGroup(symmetry_operations=[s0, s1]) self.assertEqual(sg.labels, ['A', 'B'])
def test_symmetry_group_is_initialised(self): s0, s1 = Mock(spec=SymmetryOperation), Mock(spec=SymmetryOperation) sg = SymmetryGroup(symmetry_operations=[s0, s1]) self.assertEqual(sg.symmetry_operations[0], s0) self.assertEqual(sg.symmetry_operations[1], s1)
def test_append(self): s0, s1 = Mock(spec=SymmetryOperation), Mock(spec=SymmetryOperation) sg = SymmetryGroup(symmetry_operations=[s0, s1]) s2 = Mock(spec=SymmetryOperation) sg.append(s2) self.assertEqual(sg.symmetry_operations, [s0, s1, s2])