GitLab Repo

amachine.am_create.am_isomorphic_to_with_category_rotation

 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
14def isomorphic_to_with_category_rotation(
15    m : HMM,
16    symbol_categories : dict[ str, int ],
17    categories_shifts : int | dict[ int, int ],
18    decorator : str ) -> HMM :
19
20    if ( not isinstance( categories_shifts, int ) and 
21        set( categories_shifts.keys() ) != set( symbol_categories.values() )
22    ) :
23        raise ValueError(  "set( categories_shifts.keys() ) != set( symbol_categories.values() )" )
24
25    alphabet = m.alphabet.copy()
26
27    states = [ 
28        CausalState( 
29            name=f"{s.name}{decorator}",
30            classes=s.classes.copy()
31        )
32        for s in m.states
33    ]
34
35    s_cats = {}
36    for c in set( symbol_categories.values() ) :
37        s_cats[ c ] = sorted( [ 
38            y for y in alphabet 
39            if y in symbol_categories and symbol_categories[y] == c 
40        ] )
41
42    transitions = []
43    for tr in m.transitions :
44        
45        s = alphabet[ tr.symbol_idx ]
46        c = symbol_categories[ s ]
47
48        should_shift = (
49            s in symbol_categories and ( 
50                ( isinstance( categories_shifts, int ) and categories_shifts > 0 )
51                or 
52                ( not isinstance( categories_shifts, int ) 
53                 and categories_shifts[ symbol_categories[ s ] ] > 0 )
54            )
55        )
56        
57        # if the symbol has a category and we should rotate it
58        if should_shift :
59            
60            # get the sorted list of symbols in the same category
61            category = symbol_categories[ s ]
62            s_cat = s_cats[ category ]
63            shift = ( 
64                categories_shifts if isinstance( categories_shifts, int ) 
65                else categories_shifts[ category ] 
66            )
67
68            # shift the symbol witin the category
69            sc_idx = ( s_cat.index( s ) + shift ) % len( s_cat )
70            new_s = s_cat[ sc_idx ]
71            new_symbol_idx = m.symbol_idx_map[ new_s ]
72
73            # same transition but with different symbol
74            transitions.append(
75                Transition(
76                    origin_state_idx=tr.origin_state_idx,
77                    target_state_idx=tr.target_state_idx,
78                    prob=tr.prob,
79                    symbol_idx=new_symbol_idx,
80                    pq=tr.pq,
81                    cross_component=tr.cross_component
82                )
83            )
84
85        else :
86            transitions.append( copy.deepcopy( tr ) )
87
88    return HMM(
89        states=states,
90        transitions=transitions,
91        start_state=0,
92        alphabet=alphabet
93    )
def isomorphic_to_with_category_rotation( m: amachine.am_hmm.HMM, symbol_categories: dict[str, int], categories_shifts: int | dict[int, int], decorator: str) -> amachine.am_hmm.HMM:
15def isomorphic_to_with_category_rotation(
16    m : HMM,
17    symbol_categories : dict[ str, int ],
18    categories_shifts : int | dict[ int, int ],
19    decorator : str ) -> HMM :
20
21    if ( not isinstance( categories_shifts, int ) and 
22        set( categories_shifts.keys() ) != set( symbol_categories.values() )
23    ) :
24        raise ValueError(  "set( categories_shifts.keys() ) != set( symbol_categories.values() )" )
25
26    alphabet = m.alphabet.copy()
27
28    states = [ 
29        CausalState( 
30            name=f"{s.name}{decorator}",
31            classes=s.classes.copy()
32        )
33        for s in m.states
34    ]
35
36    s_cats = {}
37    for c in set( symbol_categories.values() ) :
38        s_cats[ c ] = sorted( [ 
39            y for y in alphabet 
40            if y in symbol_categories and symbol_categories[y] == c 
41        ] )
42
43    transitions = []
44    for tr in m.transitions :
45        
46        s = alphabet[ tr.symbol_idx ]
47        c = symbol_categories[ s ]
48
49        should_shift = (
50            s in symbol_categories and ( 
51                ( isinstance( categories_shifts, int ) and categories_shifts > 0 )
52                or 
53                ( not isinstance( categories_shifts, int ) 
54                 and categories_shifts[ symbol_categories[ s ] ] > 0 )
55            )
56        )
57        
58        # if the symbol has a category and we should rotate it
59        if should_shift :
60            
61            # get the sorted list of symbols in the same category
62            category = symbol_categories[ s ]
63            s_cat = s_cats[ category ]
64            shift = ( 
65                categories_shifts if isinstance( categories_shifts, int ) 
66                else categories_shifts[ category ] 
67            )
68
69            # shift the symbol witin the category
70            sc_idx = ( s_cat.index( s ) + shift ) % len( s_cat )
71            new_s = s_cat[ sc_idx ]
72            new_symbol_idx = m.symbol_idx_map[ new_s ]
73
74            # same transition but with different symbol
75            transitions.append(
76                Transition(
77                    origin_state_idx=tr.origin_state_idx,
78                    target_state_idx=tr.target_state_idx,
79                    prob=tr.prob,
80                    symbol_idx=new_symbol_idx,
81                    pq=tr.pq,
82                    cross_component=tr.cross_component
83                )
84            )
85
86        else :
87            transitions.append( copy.deepcopy( tr ) )
88
89    return HMM(
90        states=states,
91        transitions=transitions,
92        start_state=0,
93        alphabet=alphabet
94    )