amachine.am_create.am_cyclic_orbit_cluster
1from amachine.am_id_generator import next_group_id 2from ..am_hmm import HMM 3from ..am_vocabulary import Vocabulary 4 5from .am_random_machine import random_machine 6from .am_isomorphic_to import isomorphic_to 7from .am_star_composition import star_composition 8 9import numpy as np 10 11def cyclic_orbit_cluster( 12 n_states : int, 13 n_base_symbols : int, 14 connectedness : float, 15 randomness : float, 16 star_joined : bool, 17 residency_factor : float = 0.75, 18 instances_per_component : int = 1, 19 np_rng : np.random.Generator | None = None ) -> HMM | list[HMM] : 20 21 base_symbol_pool = Vocabulary.digits() + Vocabulary.letters_lower() 22 enter_symbol_pool = Vocabulary.greek_lower() + Vocabulary.greek_upper() 23 exit_symbol = '*' 24 25 max_n_symbols = min( len(base_symbol_pool), len(enter_symbol_pool) ) 26 27 if n_base_symbols > max_n_symbols : 28 raise ValueError( f"Only up to {len(base_symbol_pool)} base symbols supported" ) 29 30 alphabet = base_symbol_pool[ 0:n_base_symbols ] 31 enter_symbols = enter_symbol_pool[ 0:n_base_symbols ] 32 33 m = random_machine( 34 n_states=n_states, 35 symbols=alphabet, 36 randomness=randomness, 37 connectedness=connectedness, 38 ensure_strongly_connected=True, 39 ensure_minimal=True, 40 np_rng=np_rng ) 41 42 group_id = next_group_id() 43 44 machines = [] 45 for i in range( n_base_symbols ) : 46 47 alphabet = alphabet[ -1: ] + alphabet[ 0 : n_base_symbols - 1 ] 48 im = isomorphic_to( m, alphabet=alphabet.copy(), decorator=enter_symbols[ i ] ) 49 machines.append( im ) 50 51 for im in machines : 52 53 new_states = [] 54 55 for s_idx, state in enumerate( im.states ) : 56 57 # get the undecorated name 58 undecorated = state.name[ 0:-1 ] 59 my_decoration = state.name[-1] 60 61 isomorphs = set() 62 63 # capture decorated names of all isomorphic states 64 for a in enter_symbols : 65 66 # self not storing self as isomorph 67 if a == my_decoration : 68 continue 69 70 decorated = undecorated + a 71 isomorphs.add( decorated ) 72 73 new_states.append( im.states[ s_idx ].modified_deep_copy( 74 isomorphs=isomorphs 75 ) ) 76 77 im.set_states( new_states ) 78 79 if star_joined : 80 81 final_machine = star_composition( 82 exit_symbol=exit_symbol, 83 enter_symbols=enter_symbols, 84 component_residency_factor=residency_factor, 85 component_groups={ group_id : machines }, 86 instances_per_component=instances_per_component 87 ) 88 89 if not final_machine.is_row_stochastic() : 90 raise Exception( "Cyclic cluster is not row stochastic" ) 91 92 if not final_machine.is_unifilar() : 93 raise Exception( "Cyclic cluster is not unifilar" ) 94 95 return final_machine 96 97 else : 98 return machines
def
cyclic_orbit_cluster( n_states: int, n_base_symbols: int, connectedness: float, randomness: float, star_joined: bool, residency_factor: float = 0.75, instances_per_component: int = 1, np_rng: numpy.random._generator.Generator | None = None) -> amachine.am_hmm.HMM | list[amachine.am_hmm.HMM]:
12def cyclic_orbit_cluster( 13 n_states : int, 14 n_base_symbols : int, 15 connectedness : float, 16 randomness : float, 17 star_joined : bool, 18 residency_factor : float = 0.75, 19 instances_per_component : int = 1, 20 np_rng : np.random.Generator | None = None ) -> HMM | list[HMM] : 21 22 base_symbol_pool = Vocabulary.digits() + Vocabulary.letters_lower() 23 enter_symbol_pool = Vocabulary.greek_lower() + Vocabulary.greek_upper() 24 exit_symbol = '*' 25 26 max_n_symbols = min( len(base_symbol_pool), len(enter_symbol_pool) ) 27 28 if n_base_symbols > max_n_symbols : 29 raise ValueError( f"Only up to {len(base_symbol_pool)} base symbols supported" ) 30 31 alphabet = base_symbol_pool[ 0:n_base_symbols ] 32 enter_symbols = enter_symbol_pool[ 0:n_base_symbols ] 33 34 m = random_machine( 35 n_states=n_states, 36 symbols=alphabet, 37 randomness=randomness, 38 connectedness=connectedness, 39 ensure_strongly_connected=True, 40 ensure_minimal=True, 41 np_rng=np_rng ) 42 43 group_id = next_group_id() 44 45 machines = [] 46 for i in range( n_base_symbols ) : 47 48 alphabet = alphabet[ -1: ] + alphabet[ 0 : n_base_symbols - 1 ] 49 im = isomorphic_to( m, alphabet=alphabet.copy(), decorator=enter_symbols[ i ] ) 50 machines.append( im ) 51 52 for im in machines : 53 54 new_states = [] 55 56 for s_idx, state in enumerate( im.states ) : 57 58 # get the undecorated name 59 undecorated = state.name[ 0:-1 ] 60 my_decoration = state.name[-1] 61 62 isomorphs = set() 63 64 # capture decorated names of all isomorphic states 65 for a in enter_symbols : 66 67 # self not storing self as isomorph 68 if a == my_decoration : 69 continue 70 71 decorated = undecorated + a 72 isomorphs.add( decorated ) 73 74 new_states.append( im.states[ s_idx ].modified_deep_copy( 75 isomorphs=isomorphs 76 ) ) 77 78 im.set_states( new_states ) 79 80 if star_joined : 81 82 final_machine = star_composition( 83 exit_symbol=exit_symbol, 84 enter_symbols=enter_symbols, 85 component_residency_factor=residency_factor, 86 component_groups={ group_id : machines }, 87 instances_per_component=instances_per_component 88 ) 89 90 if not final_machine.is_row_stochastic() : 91 raise Exception( "Cyclic cluster is not row stochastic" ) 92 93 if not final_machine.is_unifilar() : 94 raise Exception( "Cyclic cluster is not unifilar" ) 95 96 return final_machine 97 98 else : 99 return machines