<s> import abc <EOL> import collections <EOL> import numbers <EOL> from python_toolbox . third_party import functools <EOL> from python_toolbox import misc_tools <EOL> from python_toolbox import nifty_collections <EOL> from python_toolbox import caching <EOL> from python_toolbox import sequence_tools <EOL> from python_toolbox import cute_iter_tools <EOL> from . . import misc <EOL> infinity = float ( '<STR_LIT>' ) <EOL> class _BasePermView ( object ) : <EOL> '''<STR_LIT>''' <EOL> __metaclass__ = abc . ABCMeta <EOL> def __init__ ( self , perm ) : <EOL> self . perm = perm <EOL> __repr__ = lambda self : '<STR_LIT>' % ( type ( self ) . __name__ , self . perm ) <EOL> @ abc . abstractmethod <EOL> def __getitem__ ( self , i ) : pass <EOL> class PermItems ( sequence_tools . CuteSequenceMixin , _BasePermView , <EOL> collections . Sequence ) : <EOL> '''<STR_LIT>''' <EOL> def __getitem__ ( self , i ) : <EOL> return ( self . perm . domain [ i ] , self . perm [ self . perm . domain [ i ] ] ) <EOL> class PermAsDictoid ( sequence_tools . CuteSequenceMixin , _BasePermView , <EOL> collections . Mapping ) : <EOL> '''<STR_LIT>''' <EOL> def __getitem__ ( self , key ) : <EOL> return self . perm [ key ] <EOL> def __iter__ ( self ) : <EOL> return iter ( self . perm . domain ) <EOL> class PermType ( abc . ABCMeta ) : <EOL> '''<STR_LIT>''' <EOL> def __call__ ( cls , item , perm_space = None ) : <EOL> if cls == Perm and isinstance ( perm_space , CombSpace ) : <EOL> cls = Comb <EOL> return super ( PermType , cls ) . __call__ ( item , perm_space ) <EOL> @ functools . total_ordering <EOL> class Perm ( sequence_tools . CuteSequenceMixin , collections . Sequence ) : <EOL> '''<STR_LIT>''' <EOL> __metaclass__ = PermType <EOL> @ classmethod <EOL> def coerce ( cls , item , perm_space = None ) : <EOL> '''<STR_LIT>''' <EOL> if isinstance ( item , Perm ) and ( perm_space is not None ) and ( item . nominal_perm_space == perm_space . _nominal_perm_space_of_perms ) : <EOL> return item <EOL> else : <EOL> return cls ( item , perm_space ) <EOL> def __init__ ( self , perm_sequence , perm_space = None ) : <EOL> '''<STR_LIT>''' <EOL> perm_space = None if perm_space is None else PermSpace . coerce ( perm_space ) <EOL> assert isinstance ( perm_sequence , collections . Iterable ) <EOL> perm_sequence = sequence_tools . ensure_iterable_is_immutable_sequence ( perm_sequence ) <EOL> if perm_space is None : <EOL> if isinstance ( perm_sequence , Perm ) : <EOL> self . nominal_perm_space = perm_sequence . nominal_perm_space <EOL> else : <EOL> self . nominal_perm_space = PermSpace ( len ( perm_sequence ) ) <EOL> else : <EOL> self . nominal_perm_space = perm_space . unsliced . undegreed . unfixed <EOL> self . is_rapplied = self . nominal_perm_space . is_rapplied <EOL> self . is_recurrent = self . nominal_perm_space . is_recurrent <EOL> self . is_partial = self . nominal_perm_space . is_partial <EOL> self . is_combination = self . nominal_perm_space . is_combination <EOL> self . is_dapplied = self . nominal_perm_space . is_dapplied <EOL> self . is_pure = not ( self . is_rapplied or self . is_dapplied <EOL> or self . is_partial or self . is_combination ) <EOL> if not self . is_rapplied : self . unrapplied = self <EOL> if not self . is_dapplied : self . undapplied = self <EOL> if not self . is_combination : self . uncombinationed = self <EOL> self . _perm_sequence = sequence_tools . ensure_iterable_is_immutable_sequence ( perm_sequence ) <EOL> assert self . is_combination == isinstance ( self , Comb ) <EOL> _reduced = property ( lambda self : ( <EOL> type ( self ) , self . _perm_sequence , self . nominal_perm_space <EOL> ) ) <EOL> __iter__ = lambda self : iter ( self . _perm_sequence ) <EOL> def __eq__ ( self , other ) : <EOL> return type ( self ) == type ( other ) and self . nominal_perm_space == other . nominal_perm_space and cute_iter_tools . are_equal ( self . _perm_sequence , other . _perm_sequence ) <EOL> __ne__ = lambda self , other : not ( self == other ) <EOL> __hash__ = lambda self : hash ( self . _reduced ) <EOL> __bool__ = lambda self : bool ( self . _perm_sequence ) <EOL> __nonzero__ = __bool__ <EOL> def __contains__ ( self , item ) : <EOL> try : <EOL> return ( item in self . _perm_sequence ) <EOL> except TypeError : <EOL> return False <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( <EOL> type ( self ) . __name__ , <EOL> ( '<STR_LIT>' % len ( self ) ) if self . is_partial else '<STR_LIT>' , <EOL> ( '<STR_LIT>' % '<STR_LIT:U+002CU+0020>' . join ( map ( repr , self . domain ) ) ) <EOL> if self . is_dapplied else '<STR_LIT>' , <EOL> '<STR_LIT:U+002CU+0020>' . join ( repr ( item ) for item in self ) , <EOL> '<STR_LIT:U+002C>' if self . length == <NUM_LIT:1> else '<STR_LIT>' <EOL> ) <EOL> def index ( self , member ) : <EOL> '''<STR_LIT>''' <EOL> numerical_index = self . _perm_sequence . index ( member ) <EOL> return self . nominal_perm_space . domain [ numerical_index ] if self . is_dapplied else numerical_index <EOL> @ caching . CachedProperty <EOL> def inverse ( self ) : <EOL> '''<STR_LIT>''' <EOL> if self . is_partial : <EOL> raise TypeError ( "<STR_LIT>" ) <EOL> if self . is_rapplied : <EOL> raise TypeError ( "<STR_LIT>" ) <EOL> if self . is_dapplied : <EOL> raise TypeError ( "<STR_LIT>" ) <EOL> if self . is_rapplied : <EOL> return self . nominal_perm_space [ <NUM_LIT:0> ] * self . unrapplied . inverse <EOL> else : <EOL> _perm = [ None ] * self . nominal_perm_space . sequence_length <EOL> for i , item in enumerate ( self ) : <EOL> _perm [ item ] = i <EOL> return type ( self ) ( _perm , self . nominal_perm_space ) <EOL> __invert__ = lambda self : self . inverse <EOL> domain = caching . CachedProperty ( <EOL> lambda self : self . nominal_perm_space . domain , <EOL> '''<STR_LIT>''' <EOL> ) <EOL> @ caching . CachedProperty <EOL> def unrapplied ( self ) : <EOL> '''<STR_LIT>''' <EOL> rapplied_sequence = list ( self . nominal_perm_space . sequence ) <EOL> new_perm_sequence = [ ] <EOL> for i in self . _perm_sequence : <EOL> i_index = rapplied_sequence . index ( i ) <EOL> rapplied_sequence [ i_index ] = misc . MISSING_ELEMENT <EOL> new_perm_sequence . append ( i_index ) <EOL> unrapplied = type ( self ) ( new_perm_sequence , <EOL> self . nominal_perm_space . unrapplied ) <EOL> assert not unrapplied . is_rapplied <EOL> return unrapplied <EOL> undapplied = caching . CachedProperty ( <EOL> lambda self : type ( self ) ( <EOL> self . _perm_sequence , <EOL> self . nominal_perm_space . undapplied <EOL> ) , <EOL> '''<STR_LIT>''' <EOL> ) <EOL> uncombinationed = caching . CachedProperty ( <EOL> lambda self : Perm ( <EOL> self . _perm_sequence , <EOL> self . nominal_perm_space . uncombinationed <EOL> ) , <EOL> '''<STR_LIT>''' <EOL> ) <EOL> def __getitem__ ( self , i ) : <EOL> if self . is_dapplied : <EOL> try : <EOL> i_to_use = self . domain . index ( i ) <EOL> except TypeError : <EOL> raise IndexError <EOL> else : <EOL> i_to_use = i <EOL> return self . _perm_sequence [ i_to_use ] <EOL> length = property ( <EOL> lambda self : self . nominal_perm_space . n_elements <EOL> ) <EOL> def apply ( self , sequence , result_type = None ) : <EOL> '''<STR_LIT>''' <EOL> sequence = sequence_tools . ensure_iterable_is_immutable_sequence ( sequence ) <EOL> if sequence_tools . get_length ( sequence ) < sequence_tools . get_length ( self ) : <EOL> raise Exception ( "<STR_LIT>" <EOL> "<STR_LIT>" ) <EOL> permed_generator = ( sequence [ i ] for i in self ) <EOL> if result_type is not None : <EOL> if result_type is str : <EOL> return '<STR_LIT>' . join ( permed_generator ) <EOL> else : <EOL> return result_type ( permed_generator ) <EOL> elif isinstance ( sequence , Perm ) : <EOL> return type ( self ) ( permed_generator , <EOL> sequence . nominal_perm_space ) <EOL> elif isinstance ( sequence , str ) : <EOL> return '<STR_LIT>' . join ( permed_generator ) <EOL> else : <EOL> return tuple ( permed_generator ) <EOL> __rmul__ = apply <EOL> __mul__ = lambda self , other : other . __rmul__ ( self ) <EOL> def __pow__ ( self , exponent ) : <EOL> '''<STR_LIT>''' <EOL> assert isinstance ( exponent , numbers . Integral ) <EOL> if exponent <= - <NUM_LIT:1> : <EOL> return self . inverse ** ( - exponent ) <EOL> elif exponent == <NUM_LIT:0> : <EOL> return self . nominal_perm_space [ <NUM_LIT:0> ] <EOL> else : <EOL> assert exponent >= <NUM_LIT:1> <EOL> return misc_tools . general_product ( ( self , ) * exponent ) <EOL> @ caching . CachedProperty <EOL> def degree ( self ) : <EOL> '''<STR_LIT>''' <EOL> if self . is_partial : <EOL> return NotImplemented <EOL> else : <EOL> return len ( self ) - self . n_cycles <EOL> @ caching . CachedProperty <EOL> def n_cycles ( self ) : <EOL> '''<STR_LIT>''' <EOL> if self . is_partial : <EOL> return NotImplemented <EOL> if self . is_rapplied : <EOL> return self . unrapplied . n_cycles <EOL> if self . is_dapplied : <EOL> return self . undapplied . n_cycles <EOL> unvisited_items = set ( self ) <EOL> n_cycles = <NUM_LIT:0> <EOL> while unvisited_items : <EOL> starting_item = current_item = next ( iter ( unvisited_items ) ) <EOL> while current_item in unvisited_items : <EOL> unvisited_items . remove ( current_item ) <EOL> current_item = self [ current_item ] <EOL> if current_item == starting_item : <EOL> n_cycles += <NUM_LIT:1> <EOL> return n_cycles <EOL> @ misc_tools . limit_positional_arguments ( <NUM_LIT:1> ) <EOL> def get_neighbors ( self , degrees = ( <NUM_LIT:1> , ) , perm_space = None ) : <EOL> '''<STR_LIT>''' <EOL> from . . map_space import MapSpace <EOL> if self . is_combination or self . is_recurrent or self . is_partial : <EOL> raise NotImplementedError <EOL> if perm_space is None : <EOL> perm_space = self . nominal_perm_space <EOL> return MapSpace ( <EOL> perm_space . coerce_perm , <EOL> nifty_collections . LazyTuple ( <EOL> tuple ( perm ) for perm in PermSpace ( <EOL> self . _perm_sequence , <EOL> degrees = degrees <EOL> ) if tuple ( perm ) in perm_space <EOL> ) <EOL> ) <EOL> def __lt__ ( self , other ) : <EOL> if isinstance ( other , Perm ) and self . nominal_perm_space == other . nominal_perm_space : <EOL> return self . _perm_sequence < other . _perm_sequence <EOL> else : <EOL> return NotImplemented <EOL> __reversed__ = lambda self : type ( self ) ( reversed ( self . _perm_sequence ) , <EOL> self . nominal_perm_space ) <EOL> items = caching . CachedProperty ( PermItems ) <EOL> as_dictoid = caching . CachedProperty ( PermAsDictoid ) <EOL> class UnrecurrentedMixin ( object ) : <EOL> '''<STR_LIT>''' <EOL> def __getitem__ ( self , i ) : <EOL> return super ( UnrecurrentedMixin , self ) . __getitem__ ( i ) [ <NUM_LIT:1> ] <EOL> def __iter__ ( self ) : <EOL> return iter ( tuple ( zip ( * super ( UnrecurrentedMixin , self ) . __iter__ ( ) ) ) [ <NUM_LIT:1> ] ) <EOL> index = lambda self , item : self . nominal_perm_space . domain [ <EOL> next ( j for j , pair in enumerate ( self . _perm_sequence ) <EOL> if pair [ <NUM_LIT:1> ] == item ) <EOL> ] <EOL> '''<STR_LIT>''' <EOL> class UnrecurrentedPerm ( UnrecurrentedMixin , Perm ) : <EOL> '''<STR_LIT>''' <EOL> from . perm_space import PermSpace <EOL> from . comb_space import CombSpace <EOL> from . comb import Comb </s>
