wasm4pm 26.6.13

High-performance process mining algorithms in WebAssembly for JavaScript/TypeScript
Documentation
# Architecture of wasm4pm

Design, structure, and internals of the wasm4pm module.

## Overview

wasm4pm is a self-contained Rust crate compiled to WebAssembly. It implements all process mining algorithms natively — there is no dependency on an external Rust library. JavaScript receives opaque string handles; all data lives in WASM linear memory.

## Architecture Diagram

```
┌─────────────────────────────────────┐
│   JavaScript/TypeScript Application │
│  (Browser or Node.js)               │
└──────────────┬──────────────────────┘
               │ JavaScript API (handles + JSON strings)
┌──────────────▼──────────────────────┐
│   wasm4pm.js  (WASM glue code)        │
│   Auto-generated by wasm-bindgen    │
└──────────────┬──────────────────────┘
               │ wasm-bindgen (type marshalling)
┌──────────────▼──────────────────────┐
│   wasm4pm_bg.wasm                     │
│   (WebAssembly binary, ~2MB)        │
└──────────────┬──────────────────────┘
               │ Rust internals
┌──────────────▼──────────────────────┐
│   wasm4pm Rust Core                   │
│   src/{discovery, conformance, ...} │
└─────────────────────────────────────┘
```

## Source Modules

| File                     | Responsibility                                                                                                         |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `lib.rs`                 | Module registrations, `init()`, `get_version()`                                                                        |
| `models.rs`              | Data structures: `EventLog`, `Trace`, `Event`, `DFG`, `PetriNet`, `DeclareModel`, `StreamingDfgBuilder`, `ColumnarLog` |
| `state.rs`               | `AppState` — global handle store, `with_object` / `with_object_mut`                                                    |
| `io.rs`                  | Load/export: XES, JSON, OCEL                                                                                           |
| `xes_format.rs`          | XES XML parser (SIMD-accelerated byte scan)                                                                            |
| `discovery.rs`           | DFG, DECLARE (columnar single-pass)                                                                                    |
| `advanced_algorithms.rs` | Heuristic Miner, Inductive Miner, rework/bottleneck detection                                                          |
| `ilp_discovery.rs`       | ILP Petri net, Optimized DFG                                                                                           |
| `genetic_discovery.rs`   | Genetic Algorithm, PSO                                                                                                 |
| `fast_discovery.rs`      | A\*, Hill Climbing, variants, patterns, drift, clustering                                                              |
| `more_discovery.rs`      | ACO, Simulated Annealing, Process Skeleton                                                                             |
| `streaming.rs`           | Streaming DFG builder for IoT/chunked ingestion                                                                        |
| `conformance.rs`         | Token-based replay                                                                                                     |
| `analysis.rs`            | Statistics, activities, case duration                                                                                  |
| `final_analytics.rs`     | Variant entropy, transition matrix, trace similarity                                                                   |
| `utilities.rs`           | Shared helpers                                                                                                         |
| `types.rs`               | Type aliases                                                                                                           |

## Memory Management

### Handle-Based Architecture

```
JavaScript                    WASM Runtime (AppState)
┌──────────────────┐        ┌────────────────────────┐
│ "obj_0" (string) │───────→│ EventLog               │
│ "obj_1" (string) │───────→│ DirectlyFollowsGraph   │
│ "obj_2" (string) │───────→│ PetriNet               │
│ "obj_3" (string) │───────→│ StreamingDfgBuilder    │
└──────────────────┘        └────────────────────────┘
```

Handles are opaque string IDs. Objects live in Rust-managed heap memory until `delete_object(handle)` is called.

### Memory Lifecycle

```
1. Load / create
   load_eventlog_from_xes(content) → "obj_0"

2. Compute (zero-copy via with_object)
   discover_dfg("obj_0", "concept:name") → JSON string

3. Cleanup
   delete_object("obj_0")
```

### Streaming Memory Model

The `StreamingDfgBuilder` stores only running count tables plus per-case buffers for open (in-progress) traces. Once `streaming_dfg_close_trace` is called, the trace buffer is freed and its data exists only in the O(A²) count tables. This keeps memory independent of total event count.

```
Memory ≈ A² × 16 bytes (edge counts)
       + open_traces × avg_trace_len × 4 bytes (u32 buffers)
```

Where A = number of unique activities.

## Columnar Event Log

`EventLog::to_columnar(activity_key)` builds a zero-copy view:

```rust
pub struct ColumnarLog<'a> {
    pub events: Vec<u32>,         // flat array of activity ids
    pub trace_offsets: Vec<usize>, // boundary sentinel per trace
    pub vocab: Vec<&'a str>,      // borrowed activity names
}
```

Integer-keyed `FxHashMap<(u32,u32), usize>` edge counting is ~6× more memory-efficient than `HashMap<(String,String), usize>` and hashes in O(1) vs O(len).

## Build System

Three WASM targets via `wasm-pack`:

| Target            | Command                | Use case              |
| ----------------- | ---------------------- | --------------------- |
| Bundler (default) | `npm run build`        | Webpack, Vite, Rollup |
| Node.js           | `npm run build:nodejs` | Server, CLI           |
| Web               | `npm run build:web`    | Direct `<script>` tag |

Release profile: `opt-level = 3`, `lto = true`, `codegen-units = 1` — generates the smallest, fastest binary.

## Performance Characteristics

| Algorithm         | Complexity   | Notes                                       |
| ----------------- | ------------ | ------------------------------------------- |
| DFG               | O(E)         | Single columnar scan                        |
| Hill Climbing     | O(iter × E)  | Marginal-gain rewrite (was O(iter × A × E)) |
| DECLARE           | O(T × E × A) | Flat-array single pass                      |
| Heuristic Miner   | O(E)         | Columnar follows/precedes                   |
| Genetic Algorithm | O(G × P × E) | G=generations, P=population                 |

## API Contract

All `#[wasm_bindgen]` functions follow one of two shapes:

**Query** — returns JSON, no side effects:

```rust
pub fn discover_dfg(handle: &str, activity_key: &str) -> Result<String, JsValue>
```

**Mutating** — returns handle or stats JSON, stores result in `AppState`:

```rust
pub fn discover_heuristic_miner(handle: &str, ...) -> Result<String, JsValue>
// returns: {"handle": "obj_N", "nodes": N, "edges": N, ...}
```

**Streaming** — mutates `StreamingDfgBuilder` via `with_object_mut`:

```rust
pub fn streaming_dfg_add_event(handle: &str, case_id: &str, activity: &str) -> Result<String, JsValue>
// returns: {"ok": true, "event_count": N, "open_traces": N, ...}
```

## Compatibility Matrix

| Runtime     | Support               |
| ----------- | --------------------- |
| Chrome 57+  | Yes                   |
| Firefox 52+ | Yes                   |
| Safari 11+  | Yes                   |
| Edge 79+    | Yes                   |
| Node.js 16+ | Yes (18+ recommended) |

## Security

- All inputs validated in Rust before use
- WASM sandbox prevents arbitrary code execution
- No filesystem or network access from WASM
- Handle system prevents use-after-free at the JavaScript boundary