Source code for bsym.configuration_space

from bsym.permutations import flatten_list, unique_permutations, number_of_unique_permutations
from bsym import Configuration, SymmetryGroup, SymmetryOperation
import numpy as np
from itertools import combinations_with_replacement
from collections import Counter
from tqdm import tqdm, tqdm_notebook

[docs]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
[docs] 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 )
[docs] 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 )
[docs] 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 )
[docs]def colourings_generator( colours, dim ): for s in combinations_with_replacement( colours, dim ): for new_permutation in unique_permutations( s ): yield new_permutation
[docs]def permutation_as_config_number( p ): """ A numeric representation of a numeric list. Example: >>> permutation_as_config_number( [ 1, 1, 0, 0, 1 ] ) 11001 """ tot = 0 for num in p: tot *= 10 tot += num return tot