use wasm4pm_compat::event_log::EventLog as CompatEventLog;
pub const DEFAULT_SWARM_SIZE: usize = 50;
pub const DEFAULT_ITERATIONS: usize = 50;
pub fn discover_pso_real(
log: &CompatEventLog,
activity_key: &str,
) -> anyhow::Result<(wasm4pm::models::DFG, f64)> {
let native_log: wasm4pm::models::EventLog = log.clone().into();
wasm4pm::genetic_discovery::discover_pso_algorithm_from_log(
&native_log,
activity_key,
DEFAULT_SWARM_SIZE,
DEFAULT_ITERATIONS,
)
.ok_or_else(|| anyhow::anyhow!("PSO discovery found no directly-follows edges"))
}
#[cfg(test)]
mod tests {
use super::*;
use wasm4pm_compat::event_log::{Event, Trace};
fn build_small_log() -> CompatEventLog {
let trace = || {
Trace::new(
"case".to_string(),
vec![
Event::with_activity("a"),
Event::with_activity("b"),
Event::with_activity("c"),
],
)
};
CompatEventLog {
attributes: Vec::new(),
traces: vec![trace(), trace(), trace(), trace()],
extensions: None,
classifiers: None,
global_trace_attrs: None,
global_event_attrs: None,
}
}
#[test]
fn discover_pso_real_runs_on_small_log_and_converges_to_a_fit_dfg() {
let log = build_small_log();
let (dfg, fitness) = discover_pso_real(&log, "concept:name")
.expect("PSO discovery should discover a DFG without panicking");
assert!(
!dfg.nodes.is_empty(),
"expected a non-empty DFG, got {dfg:?}"
);
assert!(
fitness > 0.0,
"expected the swarm's global best to reach positive fitness on a log with \
a single strong a->b->c pattern, got fitness={fitness}"
);
let has_a_to_b = dfg.edges.iter().any(|e| e.from == "a" && e.to == "b");
assert!(
has_a_to_b,
"expected the dominant a->b edge to survive swarm convergence, got edges: {:?}",
dfg.edges
);
}
}