GitLab Repo

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