bsym/colour_operation.py
from bsym import Configuration, SymmetryOperation
import numpy as np
class ColourOperation( SymmetryOperation ):
"""
This class subclasses `SymmetryOperation`.
It defines a class of object for performing a compound operation on a
configuration.
First, a matrix transform applied to the configuration
vector space, equivlant to a `SymmetryOperation`.
Second, a colour mapping, that allows objects to be replaced in the
configuration vector space.
"""
def __init__( self, matrix, colour_mapping, label=None ):
"""
Initialise a `ColourOperation` object.
A `ColourOperation` object behaves similarly to a `SymmetryOperation`, but has
an additional `colour_mapping` attribute, which is a `list` of ``dict`s,
describing a per-site mapping between objects.
Args:
matrix (numpy.matrix|numpy.ndarray|list): 1D vector as either a
`numpy.matrix`, `numpy.ndarray`, or `list` containing the site mappings
for this symmetry operation.
colour_mapping (list[dict]): A `list` of `dict`s, that describe per-site
object mappings.
label (default=None) (str): optional string label for this `SymmetryOperation` object.
Returns:
None
Example:
>>> matrix = np.array( [[1, 0], [0, 1]] )
>>> colour_mapping = [ { 0: 1, 1: 0 }, { 0: 0, 1: 1 } ]
>>> ColourOperation( matrix, colour_mapping )
"""
super().__init__( matrix, label )
self.colour_mapping = colour_mapping
@classmethod
def from_vector( cls, vector, colour_mapping, count_from_zero=False, label=None ):
"""
Initialise a ColourOperation from a vector of site mappings.
Args:
vector (list): vector of integers defining a symmetry operation mapping.
colour_mapping (list[dict]): A `list` of `dict`s, that describe per-site object mappings.
count_from_zero (default = False) (bool): set to True if the site index counts from zero.
label (default=None) (str): optional string label for this `SymmetryOperation` object.
Returns:
a new SymmetryOperation object
"""
if not count_from_zero:
vector = [ x - 1 for x in vector ]
dim = len( vector )
matrix = np.zeros( ( dim, dim ) )
for index, element in enumerate( vector ):
matrix[ element, index ] = 1
new_colour_operation = cls( matrix, colour_mapping=colour_mapping, label=label )
return new_colour_operation
def operate_on( self, configuration ):
"""
Return the Configuration generated by appliying this colour operation
Args:
configuration (Configuration): the configuration / occupation vector to operate on.
Returns:
(Configuration): the new configuration.
"""
if not isinstance( configuration, Configuration ):
raise TypeError
new_configuration = Configuration( self.matrix.dot( configuration.vector ) )
return Configuration( [ d[value] for value, d in zip( new_configuration.vector, self.colour_mapping ) ] )
def __mul__( self, other ):
"""
Operate on another object with this `ColourOperation`.
Args:
other (ColourOperation, SymmetryOperation, Configuration): the other object (colour operation, symmetry operation, configuration, or matrix).
Returns:
(ColourOperation): a new `ColourOperation` instance with the resultant matrix and colour_mapping..
(Configuration): if `other` is a `Configuration`.
"""
if isinstance( other, ColourOperation ):
new_matrix = self.matrix.dot( other.matrix )
new_mapping = [ {} for d in self.colour_mapping ]
for i, (this_mapping, other_mapping) in enumerate( zip( self.colour_mapping, other.colour_mapping ) ):
for key in this_mapping.keys():
new_mapping[i][key] = this_mapping[ other_mapping[ key ] ]
return ColourOperation( new_matrix, colour_mapping=new_mapping )
elif isinstance( other, SymmetryOperation ):
return ColourOperation( self.matrix.dot( other.matrix ), colour_mapping=self.colour_mapping )
elif isinstance( other, Configuration ):
return self.operate_on( other )
else:
print( self.__class__, other.__class__ )
raise TypeError
def invert( self, label=None ):
# TODO
raise NotImplementedError
def __repr__( self ):
label = self.label if self.label else '---'
return 'ColourOperation\nlabel(' + label + ")\n" + "\n".join( [ row.__str__() + ' ' + mapping.__repr__() for row, mapping in zip( self.matrix, self.colour_mapping ) ] )