use wasm4pm_compat::event_log::EventLog as CompatEventLog;
pub const DEFAULT_ANT_COUNT: usize = 50;
pub const DEFAULT_ITERATIONS: usize = 50;
pub fn discover_aco_real(
log: &CompatEventLog,
activity_key: &str,
) -> anyhow::Result<(wasm4pm::models::DFG, f64)> {
let native_log: wasm4pm::models::EventLog = log.clone().into();
let has_nontrivial_input = native_log.traces.iter().any(|t| t.events.len() >= 2);
let (dfg, fitness) = wasm4pm::genetic_discovery::discover_aco_algorithm_from_log(
&native_log,
activity_key,
DEFAULT_ANT_COUNT,
DEFAULT_ITERATIONS,
)
.ok_or_else(|| anyhow::anyhow!("ACO discovery found no directly-follows edges"))?;
if has_nontrivial_input && dfg.edges.is_empty() {
return Err(anyhow::anyhow!(
"DEGENERATE_RESULT: ACO discovery returned an empty DFG (fitness={fitness}) on a \
log with directly-follows pairs present — the pheromone-trail search collapsed \
to nothing rather than genuinely finding no structure. Not treated as success."
));
}
Ok((dfg, fitness))
}
#[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_aco_real_runs_on_small_log_and_finds_dominant_edges() {
let log = build_small_log();
let (dfg, fitness) = discover_aco_real(&log, "concept:name")
.expect("ACO 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 best ant's edge set 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 pheromone reinforcement, got edges: {:?}",
dfg.edges
);
}
}