amachine.am_create.am_unique_isomorphic
1from collections import defaultdict 2import copy 3import random 4 5import numpy as np 6 7from ..am_hmm import HMM 8from ..am_causal_state import CausalState 9from ..am_transition import Transition 10 11from ..am_random import exp_uniform_blend, resolve_rng 12from ..am_vocabulary import Vocabulary 13 14from .am_random_machine import random_machine 15from .am_isomorphic_to import isomorphic_to 16from .am_star_join import star_join 17 18def unique_isomorphic( 19 isoclass_name : str, 20 n_machines : int, 21 n_states : int, 22 n_base_symbols : int, 23 connectedness : float, 24 randomness : float, 25 star_joined : bool, 26 mode_residency_factor : float | None = None, 27 random_seed : int | None = None ) -> HMM | list[HMM] : 28 29 if star_joined and mode_residency_factor is None : 30 raise ValueError( "star_join requires mode_residency factor" ) 31 32 base_symbol_pool = Vocabulary.digits() + Vocabulary.letters_lower() 33 enter_symbol_pool = Vocabulary.greek_lower() + Vocabulary.greek_upper() 34 exit_symbol = '*' 35 36 max_n_symbols = min( len(base_symbol_pool), len(enter_symbol_pool) ) 37 38 if n_base_symbols*n_machines > max_n_symbols : 39 raise ValueError( f"Only up to {len(base_symbol_pool)} base symbols supported" ) 40 41 alphabets = [ 42 base_symbol_pool[ start:start + n_base_symbols ] 43 for start in range( 0, n_base_symbols*n_machines, n_base_symbols ) 44 ] 45 46 enter_symbols = enter_symbol_pool[ 0:n_machines ] 47 48 m = random_machine( 49 n_states=n_states, 50 symbols=alphabets[0], 51 randomness=randomness, 52 connectedness=connectedness, 53 ensure_strongly_connected=True, 54 ensure_minimal=True, 55 random_seed=random_seed ) 56 57 m.isoclass = isoclass_name 58 59 m.collapse_to_largest_strongly_connected_subgraph() 60 m.minimize() 61 62 machines = [ m ] 63 for i in range( 1, n_machines ) : 64 65 alphabet = alphabets[ i ] 66 im = isomorphic_to( m, alphabet=alphabet, decorator=enter_symbols[ i ] ) 67 im.isoclass = isoclass_name 68 machines.append( im ) 69 70 for im in machines : 71 for state in im.states : 72 73 # get the undecorated name 74 undecorated = state.name[ 0:-1 ] 75 my_decoration = state.name[-1] 76 77 # capture decorated names of all isomorphic states 78 for a in enter_symbols : 79 80 # self not storing self as isomorph 81 if a == my_decoration : 82 continue 83 84 decorated = undecorated + a 85 state.add_isomorph( decorated ) 86 87 if star_joined : 88 89 final_machine = star_join( 90 exit_symbol=exit_symbol, 91 enter_symbols=enter_symbols, 92 machines=machines, 93 mode_residency_factor=mode_residency_factor 94 ) 95 96 return final_machine 97 98 else : 99 return machines
def
unique_isomorphic( isoclass_name: str, n_machines: int, n_states: int, n_base_symbols: int, connectedness: float, randomness: float, star_joined: bool, mode_residency_factor: float | None = None, random_seed: int | None = None) -> amachine.am_hmm.HMM | list[amachine.am_hmm.HMM]:
19def unique_isomorphic( 20 isoclass_name : str, 21 n_machines : int, 22 n_states : int, 23 n_base_symbols : int, 24 connectedness : float, 25 randomness : float, 26 star_joined : bool, 27 mode_residency_factor : float | None = None, 28 random_seed : int | None = None ) -> HMM | list[HMM] : 29 30 if star_joined and mode_residency_factor is None : 31 raise ValueError( "star_join requires mode_residency factor" ) 32 33 base_symbol_pool = Vocabulary.digits() + Vocabulary.letters_lower() 34 enter_symbol_pool = Vocabulary.greek_lower() + Vocabulary.greek_upper() 35 exit_symbol = '*' 36 37 max_n_symbols = min( len(base_symbol_pool), len(enter_symbol_pool) ) 38 39 if n_base_symbols*n_machines > max_n_symbols : 40 raise ValueError( f"Only up to {len(base_symbol_pool)} base symbols supported" ) 41 42 alphabets = [ 43 base_symbol_pool[ start:start + n_base_symbols ] 44 for start in range( 0, n_base_symbols*n_machines, n_base_symbols ) 45 ] 46 47 enter_symbols = enter_symbol_pool[ 0:n_machines ] 48 49 m = random_machine( 50 n_states=n_states, 51 symbols=alphabets[0], 52 randomness=randomness, 53 connectedness=connectedness, 54 ensure_strongly_connected=True, 55 ensure_minimal=True, 56 random_seed=random_seed ) 57 58 m.isoclass = isoclass_name 59 60 m.collapse_to_largest_strongly_connected_subgraph() 61 m.minimize() 62 63 machines = [ m ] 64 for i in range( 1, n_machines ) : 65 66 alphabet = alphabets[ i ] 67 im = isomorphic_to( m, alphabet=alphabet, decorator=enter_symbols[ i ] ) 68 im.isoclass = isoclass_name 69 machines.append( im ) 70 71 for im in machines : 72 for state in im.states : 73 74 # get the undecorated name 75 undecorated = state.name[ 0:-1 ] 76 my_decoration = state.name[-1] 77 78 # capture decorated names of all isomorphic states 79 for a in enter_symbols : 80 81 # self not storing self as isomorph 82 if a == my_decoration : 83 continue 84 85 decorated = undecorated + a 86 state.add_isomorph( decorated ) 87 88 if star_joined : 89 90 final_machine = star_join( 91 exit_symbol=exit_symbol, 92 enter_symbols=enter_symbols, 93 machines=machines, 94 mode_residency_factor=mode_residency_factor 95 ) 96 97 return final_machine 98 99 else : 100 return machines