@@ -1140,15 +1140,12 @@ def passive_vpa_learning_arithmetics():
11401140
11411141def passive_vpa_learning_on_all_benchmark_models ():
11421142 from aalpy .learning_algs import run_PAPNI
1143- from aalpy .utils .BenchmarkVpaModels import get_all_VPAs
1143+ from aalpy .utils .BenchmarkVpaModels import vpa_L1 , vpa_L12 , vpa_for_odd_parentheses
11441144 from aalpy .utils import generate_input_output_data_from_vpa , convert_i_o_traces_for_RPNI
11451145
1146- for gt in get_all_VPAs ():
1147-
1146+ for gt in [vpa_L1 (), vpa_L12 (), vpa_for_odd_parentheses ()]:
11481147 vpa_alphabet = gt .input_alphabet
1149- data = generate_input_output_data_from_vpa (gt , num_sequances = 2000 , min_seq_len = 1 , max_seq_len = 16 )
1150-
1151- data = convert_i_o_traces_for_RPNI (data )
1148+ data = generate_input_output_data_from_vpa (gt , num_sequances = 2000 , max_seq_len = 16 )
11521149
11531150 papni = run_PAPNI (data , vpa_alphabet , algorithm = 'gsm' , print_info = True )
11541151
@@ -1160,3 +1157,147 @@ def passive_vpa_learning_on_all_benchmark_models():
11601157 assert False , 'Papni Learned Model not consistent with data.'
11611158
11621159 print ('PAPNI model conforms to data.' )
1160+
1161+
1162+ def gsm_rpni ():
1163+ from aalpy import load_automaton_from_file
1164+ from aalpy .utils .Sampling import get_io_traces , sample_with_length_limits
1165+ from aalpy .learning_algs .general_passive .GeneralizedStateMerging import run_GSM
1166+
1167+ automaton = load_automaton_from_file ("DotModels/car_alarm.dot" , "moore" )
1168+ input_traces = sample_with_length_limits (automaton .get_input_alphabet (), 100 , 20 , 30 )
1169+ traces = get_io_traces (automaton , input_traces )
1170+
1171+ learned_model = run_GSM (traces , output_behavior = "moore" , transition_behavior = "deterministic" )
1172+ learned_model .visualize ()
1173+
1174+
1175+ def gsm_edsm ():
1176+ from typing import Dict
1177+ from aalpy import load_automaton_from_file
1178+ from aalpy .utils .Sampling import get_io_traces , sample_with_length_limits
1179+ from aalpy .learning_algs .general_passive .GeneralizedStateMerging import run_GSM
1180+ from aalpy .learning_algs .general_passive .ScoreFunctionsGSM import ScoreCalculation
1181+ from aalpy .learning_algs .general_passive .Node import Node
1182+
1183+ automaton = load_automaton_from_file ("DotModels/car_alarm.dot" , "moore" )
1184+ input_traces = sample_with_length_limits (automaton .get_input_alphabet (), 100 , 20 , 30 )
1185+ traces = get_io_traces (automaton , input_traces )
1186+
1187+ def EDSM_score (part : Dict [Node , Node ]):
1188+ nr_partitions = len (set (part .values ()))
1189+ nr_merged = len (part )
1190+ return nr_merged - nr_partitions
1191+
1192+ score = ScoreCalculation (score_function = EDSM_score )
1193+ learned_model = run_GSM (traces , output_behavior = "moore" , transition_behavior = "deterministic" , score_calc = score )
1194+ learned_model .visualize ()
1195+
1196+
1197+ def gsm_likelihood_ratio ():
1198+ from typing import Dict
1199+ from scipy .stats import chi2
1200+ from aalpy .learning_algs .general_passive .GeneralizedStateMerging import run_GSM
1201+ from aalpy .learning_algs .general_passive .ScoreFunctionsGSM import ScoreFunction , differential_info , ScoreCalculation
1202+ from aalpy .learning_algs .general_passive .Node import Node
1203+ from aalpy .utils .Sampling import get_io_traces , sample_with_length_limits
1204+ from aalpy import load_automaton_from_file
1205+
1206+ automaton = load_automaton_from_file ("DotModels/MDPs/faulty_car_alarm.dot" , "mdp" )
1207+ input_traces = sample_with_length_limits (automaton .get_input_alphabet (), 2000 , 20 , 30 )
1208+ traces = get_io_traces (automaton , input_traces )
1209+
1210+ def likelihood_ratio_score (alpha = 0.05 ) -> ScoreFunction :
1211+ if not 0 < alpha <= 1 :
1212+ raise ValueError (f"Confidence { alpha } not between 0 and 1" )
1213+
1214+ def score_fun (part : Dict [Node , Node ]):
1215+ llh_diff , param_diff = differential_info (part )
1216+ if param_diff == 0 :
1217+ # This should cover the corner case when the partition merges only states with no outgoing transitions.
1218+ return - 1 # Let them be very bad merges.
1219+ score = 1 - chi2 .cdf (2 * llh_diff , param_diff )
1220+ if score < alpha :
1221+ return False
1222+ return score
1223+
1224+ return score_fun
1225+
1226+ score = ScoreCalculation (score_function = likelihood_ratio_score ())
1227+ learned_model = run_GSM (traces , output_behavior = "moore" , transition_behavior = "stochastic" , score_calc = score )
1228+ learned_model .visualize ()
1229+
1230+
1231+ def gsm_IOAlergia_EDSM ():
1232+ from aalpy .learning_algs .general_passive .GeneralizedStateMerging import run_GSM
1233+ from aalpy .learning_algs .general_passive .ScoreFunctionsGSM import hoeffding_compatibility , ScoreCalculation
1234+ from aalpy .learning_algs .general_passive .Node import Node
1235+ from aalpy .utils .Sampling import get_io_traces , sample_with_length_limits
1236+ from aalpy import load_automaton_from_file
1237+
1238+ automaton = load_automaton_from_file ("DotModels/MDPs/faulty_car_alarm.dot" , "mdp" )
1239+ input_traces = sample_with_length_limits (automaton .get_input_alphabet (), 2000 , 20 , 30 )
1240+ traces = get_io_traces (automaton , input_traces )
1241+
1242+ class IOAlergiaWithEDSM (ScoreCalculation ):
1243+ def __init__ (self , epsilon ):
1244+ super ().__init__ ()
1245+ self .ioa_compatibility = hoeffding_compatibility (epsilon )
1246+ self .evidence = 0
1247+
1248+ def reset (self ):
1249+ self .evidence = 0
1250+
1251+ def local_compatibility (self , a : Node , b : Node ):
1252+ self .evidence += 1
1253+ return self .ioa_compatibility (a , b )
1254+
1255+ def score_function (self , part : dict [Node , Node ]):
1256+ return self .evidence
1257+
1258+ epsilon = 0.05
1259+ scores = {
1260+ "IOA" : ScoreCalculation (hoeffding_compatibility (epsilon )),
1261+ "IOA+EDSM" : IOAlergiaWithEDSM (epsilon ),
1262+ }
1263+ for name , score in scores .items ():
1264+ learned_model = run_GSM (traces , output_behavior = "moore" , transition_behavior = "stochastic" , score_calc = score ,
1265+ compatibility_on_pta = True , compatibility_on_futures = True )
1266+ learned_model .visualize (name )
1267+
1268+
1269+ def gsm_IOAlergia_domain_knowldege ():
1270+ from aalpy .learning_algs .general_passive .GeneralizedStateMerging import run_GSM
1271+ from aalpy .learning_algs .general_passive .ScoreFunctionsGSM import hoeffding_compatibility , ScoreCalculation
1272+ from aalpy .learning_algs .general_passive .Node import Node
1273+ from aalpy .utils .Sampling import get_io_traces , sample_with_length_limits
1274+ from aalpy import load_automaton_from_file
1275+
1276+ automaton = load_automaton_from_file ("DotModels/MDPs/faulty_car_alarm.dot" , "mdp" )
1277+ input_traces = sample_with_length_limits (automaton .get_input_alphabet (), 2000 , 20 , 30 )
1278+ traces = get_io_traces (automaton , input_traces )
1279+
1280+ ioa_compat = hoeffding_compatibility (0.05 )
1281+
1282+ def get_parity (node : Node ):
1283+ pref = node .get_prefix ()
1284+ return [sum (in_s == key for in_s , out_s in pref ) % 2 for key in ["l" , "d" ]]
1285+
1286+ # The car has 4 physical states arising from the combination of locked/unlocked and open/closed.
1287+ # Each input toggles a transition between these four states. While the car alarm system has richer behavior than that,
1288+ # it still needs to discern the physical states. Thus, in every sane implementation of a car alarm system, every state
1289+ # is associated with exactly one physical state. This additional assumption can be enforced by checking the parity of
1290+ # all input symbols during merging.
1291+ def ioa_compat_domain_knowledge (a : Node , b : Node ):
1292+ parity = get_parity (a ) == get_parity (b )
1293+ ioa = ioa_compat (a , b )
1294+ return parity and ioa
1295+
1296+ scores = {
1297+ "IOA" : ScoreCalculation (ioa_compat ),
1298+ "IOA+DK" : ScoreCalculation (ioa_compat_domain_knowledge ),
1299+ }
1300+ for name , score in scores .items ():
1301+ learned_model = run_GSM (traces , output_behavior = "moore" , transition_behavior = "stochastic" , score_calc = score ,
1302+ compatibility_on_pta = True , compatibility_on_futures = True )
1303+ learned_model .visualize (name )
0 commit comments