amachine.am_create.am_disjoint_isomorphic
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 disjoint_isomorphic( 12 n_components : int, 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*n_components > max_n_symbols : 29 raise ValueError( f"Only up to {len(base_symbol_pool)} base symbols supported" ) 30 31 alphabets = [ 32 base_symbol_pool[ start:start + n_base_symbols ] 33 for start in range( 0, n_base_symbols*n_components, n_base_symbols ) 34 ] 35 36 enter_symbols = enter_symbol_pool[ 0:n_components ] 37 38 m = random_machine( 39 n_states=n_states, 40 symbols=alphabets[0], 41 randomness=randomness, 42 connectedness=connectedness, 43 ensure_strongly_connected=True, 44 ensure_minimal=True, 45 np_rng=np_rng ) 46 47 group_id = next_group_id() 48 49 machines = [ m ] 50 for i in range( 1, n_components ) : 51 52 alphabet = alphabets[ i ] 53 im = isomorphic_to( m, alphabet=alphabet.copy(), decorator=enter_symbols[ i ] ) 54 machines.append( im ) 55 56 for im in machines : 57 for state in im.states : 58 59 # get the undecorated name 60 undecorated = state.name[ 0:-1 ] 61 my_decoration = state.name[-1] 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 state.add_isomorph( decorated ) 72 73 if star_joined : 74 75 final_machine = star_composition( 76 exit_symbol=exit_symbol, 77 enter_symbols=enter_symbols, 78 component_residency_factor=residency_factor, 79 component_groups={ group_id : machines }, 80 instances_per_component=instances_per_component 81 ) 82 83 if not final_machine.is_row_stochastic() : 84 raise Exception( "Disjoint isomorphic is not row stochastic" ) 85 86 if not final_machine.is_unifilar() : 87 raise Exception( "Disjoint isomorphic is not unifilar" ) 88 89 return final_machine 90 91 else : 92 return machines
def
disjoint_isomorphic( n_components: int, 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 disjoint_isomorphic( 13 n_components : int, 14 n_states : int, 15 n_base_symbols : int, 16 connectedness : float, 17 randomness : float, 18 star_joined : bool, 19 residency_factor : float = 0.75, 20 instances_per_component : int = 1, 21 np_rng : np.random.Generator | None = None ) -> HMM | list[HMM] : 22 23 base_symbol_pool = Vocabulary.digits() + Vocabulary.letters_lower() 24 enter_symbol_pool = Vocabulary.greek_lower() + Vocabulary.greek_upper() 25 exit_symbol = '*' 26 27 max_n_symbols = min( len(base_symbol_pool), len(enter_symbol_pool) ) 28 29 if n_base_symbols*n_components > max_n_symbols : 30 raise ValueError( f"Only up to {len(base_symbol_pool)} base symbols supported" ) 31 32 alphabets = [ 33 base_symbol_pool[ start:start + n_base_symbols ] 34 for start in range( 0, n_base_symbols*n_components, n_base_symbols ) 35 ] 36 37 enter_symbols = enter_symbol_pool[ 0:n_components ] 38 39 m = random_machine( 40 n_states=n_states, 41 symbols=alphabets[0], 42 randomness=randomness, 43 connectedness=connectedness, 44 ensure_strongly_connected=True, 45 ensure_minimal=True, 46 np_rng=np_rng ) 47 48 group_id = next_group_id() 49 50 machines = [ m ] 51 for i in range( 1, n_components ) : 52 53 alphabet = alphabets[ i ] 54 im = isomorphic_to( m, alphabet=alphabet.copy(), decorator=enter_symbols[ i ] ) 55 machines.append( im ) 56 57 for im in machines : 58 for state in im.states : 59 60 # get the undecorated name 61 undecorated = state.name[ 0:-1 ] 62 my_decoration = state.name[-1] 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 state.add_isomorph( decorated ) 73 74 if star_joined : 75 76 final_machine = star_composition( 77 exit_symbol=exit_symbol, 78 enter_symbols=enter_symbols, 79 component_residency_factor=residency_factor, 80 component_groups={ group_id : machines }, 81 instances_per_component=instances_per_component 82 ) 83 84 if not final_machine.is_row_stochastic() : 85 raise Exception( "Disjoint isomorphic is not row stochastic" ) 86 87 if not final_machine.is_unifilar() : 88 raise Exception( "Disjoint isomorphic is not unifilar" ) 89 90 return final_machine 91 92 else : 93 return machines