1use crate::{
2 event_log::activity_projection::EventLogActivityProjection,
3 petri_net::petri_net_struct::{PetriNet, Transition},
4};
5
6use super::full::{alphappp_discover_petri_net, AlphaPPPConfig};
7const AUTO_CONFIGS: &[AlphaPPPConfig] = &[
8 AlphaPPPConfig {
9 balance_thresh: 0.6,
10 fitness_thresh: 0.4,
11 replay_thresh: 0.0,
12 log_repair_skip_df_thresh_rel: 4.0,
13 log_repair_loop_df_thresh_rel: 4.0,
14 absolute_df_clean_thresh: 1,
15 relative_df_clean_thresh: 0.01,
16 },
17 AlphaPPPConfig {
18 balance_thresh: 0.6,
19 fitness_thresh: 0.4,
20 replay_thresh: 0.0,
21 log_repair_skip_df_thresh_rel: 2.0,
22 log_repair_loop_df_thresh_rel: 2.0,
23 absolute_df_clean_thresh: 1,
24 relative_df_clean_thresh: 0.01,
25 },
26 AlphaPPPConfig {
27 balance_thresh: 0.4,
28 fitness_thresh: 0.6,
29 replay_thresh: 0.0,
30 log_repair_skip_df_thresh_rel: 4.0,
31 log_repair_loop_df_thresh_rel: 4.0,
32 absolute_df_clean_thresh: 1,
33 relative_df_clean_thresh: 0.01,
34 },
35 AlphaPPPConfig {
36 balance_thresh: 0.4,
37 fitness_thresh: 0.6,
38 replay_thresh: 0.0,
39 log_repair_skip_df_thresh_rel: 2.0,
40 log_repair_loop_df_thresh_rel: 2.0,
41 absolute_df_clean_thresh: 1,
42 relative_df_clean_thresh: 0.01,
43 },
44 AlphaPPPConfig {
45 balance_thresh: 0.4,
46 fitness_thresh: 0.6,
47 replay_thresh: 0.0,
48 log_repair_skip_df_thresh_rel: 2.0,
49 log_repair_loop_df_thresh_rel: 2.0,
50 absolute_df_clean_thresh: 5,
51 relative_df_clean_thresh: 0.05,
52 },
53 AlphaPPPConfig {
54 balance_thresh: 0.1,
55 fitness_thresh: 0.8,
56 replay_thresh: 0.0,
57 log_repair_skip_df_thresh_rel: 2.0,
58 log_repair_loop_df_thresh_rel: 2.0,
59 absolute_df_clean_thresh: 5,
60 relative_df_clean_thresh: 0.05,
61 },
62 AlphaPPPConfig {
63 balance_thresh: 0.25,
64 fitness_thresh: 0.75,
65 replay_thresh: 0.0,
66 log_repair_skip_df_thresh_rel: 2.0,
67 log_repair_loop_df_thresh_rel: 2.0,
68 absolute_df_clean_thresh: 25,
69 relative_df_clean_thresh: 0.1,
70 },
71 AlphaPPPConfig {
72 balance_thresh: 0.1,
73 fitness_thresh: 0.8,
74 replay_thresh: 0.0,
75 log_repair_skip_df_thresh_rel: 4.0,
76 log_repair_loop_df_thresh_rel: 4.0,
77 absolute_df_clean_thresh: 1,
78 relative_df_clean_thresh: 0.01,
79 },
80 AlphaPPPConfig {
81 balance_thresh: 0.1,
82 fitness_thresh: 0.8,
83 replay_thresh: 0.0,
84 log_repair_skip_df_thresh_rel: 2.0,
85 log_repair_loop_df_thresh_rel: 2.0,
86 absolute_df_clean_thresh: 1,
87 relative_df_clean_thresh: 0.01,
88 },
89 AlphaPPPConfig {
90 balance_thresh: 0.1,
91 fitness_thresh: 0.9,
92 replay_thresh: 0.0,
93 log_repair_skip_df_thresh_rel: 4.0,
94 log_repair_loop_df_thresh_rel: 4.0,
95 absolute_df_clean_thresh: 1,
96 relative_df_clean_thresh: 0.01,
97 },
98 AlphaPPPConfig {
99 balance_thresh: 0.1,
100 fitness_thresh: 0.9,
101 replay_thresh: 0.0,
102 log_repair_skip_df_thresh_rel: 2.0,
103 log_repair_loop_df_thresh_rel: 2.0,
104 absolute_df_clean_thresh: 1,
105 relative_df_clean_thresh: 0.01,
106 },
107];
108
109pub fn alphappp_discover_with_auto_parameters(
113 log_proj: &EventLogActivityProjection,
114) -> (AlphaPPPConfig, PetriNet) {
115 let mut best: Option<(AlphaPPPConfig, f32, PetriNet)> = None;
116 for c in AUTO_CONFIGS {
117 let (pn, _) = alphappp_discover_petri_net(log_proj, *c);
118 let score = score_discovered_pn(&pn, c);
119 match best {
120 Some((_, best_score, _)) => {
121 if score > best_score {
122 best = Some((*c, score, pn));
123 }
124 }
125 None => {
126 best = Some((*c, score, pn));
127 }
128 }
129 }
130 let (best_config, best_score, best_pn) = best.unwrap();
131 println!(
132 "Best score: {:.2} with config {:?}",
133 best_score, best_config
134 );
135 println!(
136 "Resulting net has {} arcs, {} transitions and {} places",
137 best_pn.arcs.len(),
138 best_pn.transitions.len(),
139 best_pn.places.len()
140 );
141 (best_config, best_pn)
142}
143
144fn score_discovered_pn(pn: &PetriNet, config: &AlphaPPPConfig) -> f32 {
145 fn is_transition_well_connected(pn: &PetriNet, t: &Transition) -> bool {
146 if t.label.is_some() {
147 let preset_connected = pn
148 .preset_of_transition(t.into())
149 .into_iter()
150 .filter(|p| {
151 pn.is_in_initial_marking(p)
152 || pn.is_in_a_final_marking(p)
153 || pn
154 .preset_of_place(*p)
155 .into_iter()
156 .filter(|ot_id| {
157 pn.transitions
158 .get(&ot_id.get_uuid())
159 .unwrap()
160 .label
161 .is_some()
162 })
163 .count()
164 >= 1
165 })
166 .count()
167 >= 1;
168
169 let postset_connected = pn
170 .postset_of_transition(t.into())
171 .into_iter()
172 .filter(|p| {
173 pn.is_in_initial_marking(p)
174 || pn.is_in_a_final_marking(p)
175 || pn
176 .postset_of_place(*p)
177 .into_iter()
178 .filter(|ot_id| {
179 pn.transitions
180 .get(&ot_id.get_uuid())
181 .unwrap()
182 .label
183 .is_some()
184 })
185 .count()
186 >= 1
187 })
188 .count()
189 >= 1;
190
191 preset_connected && postset_connected
192 } else {
193 false
194 }
195 }
196 let num_disconnected_trans = pn
197 .transitions
198 .clone()
199 .into_iter()
200 .filter(|(_, t)| !is_transition_well_connected(pn, t))
201 .count();
202
203 return config.fitness_thresh
204 * (1.0 - config.balance_thresh)
205 * (1.0
206 - (num_disconnected_trans as f32
207 / pn.transitions
208 .iter()
209 .filter(|(_, t)| t.label.is_some())
210 .count() as f32))
211 .powf(2.0);
212}