A simplified implementation of the Wolfram Model using hypergraphs,capturing key structural ideas of the Wolfram Model (hypergraph rewriting, event causality, multiway branching).
Summary
Functions
Builds the branchial graph for one step of multiway evolution.
Creates a visualization-friendly representation of the causal network. Each event (i.e., a specific hypergraph update) becomes a vertex in the causal graph. Implements the partial order of event dependencies (a DAG): if the application of event B depends on the output of event A (e.g., B’s matching pattern overlaps with hyperedges created by A), then the causal graph includes a directed edge A → B.
Checks causal invariance (confluence) for the current model state.
Applies all non-conflicting rule matches in parallel during a single step.
Evolves the universe by one step, applying one rule match selected by
opts[:ordering].
Evolves the universe for a specified number of steps.
Accepts opts forwarded to evolve_step/2 (e.g., :id_generator).
Evolves the universe by repeatedly calling evolve_step/2 until either
no rule is applicable or max_steps is reached.
Exports the causal event graph as a map of nodes and edges.
Returns true when no rule can be applied to the current hypergraph
(the system has reached a fixpoint).
Computes foliations of the causal network: layers of events where each layer contains only events whose parents all belong to earlier layers (spacelike slices of the causal partial order).
Explores the multiway graph up to a specified depth. Returns a tree of possible evolution paths.
Explores the multiway system as a directed acyclic graph (DAG) up to
depth steps. Unlike multiway_explore/2, states that are reachable via
multiple paths are represented once and converging branches share nodes.
Finds all possible rule applications in the current state (multiway evolution). Returns a deduplicated list of possible next states (unique hypergraphs).
Creates a new Wolfram Model universe with initial hypergraph and rules.
Helper function to print evolution statistics.
Types
@type rule() :: %{ pattern: [[Hypergraph.vertex()]], replacement: [[Hypergraph.vertex()]], name: String.t() }
@type t() :: %WolframModel{ causal_network: [WolframModel.Event.t()], event_index: term(), event_map: term(), evolution_history: [Hypergraph.t()], generation: non_neg_integer(), hypergraph: Hypergraph.t(), id_generator: (-> integer()), next_event_id: term(), rules: [rule()] }
Functions
Builds the branchial graph for one step of multiway evolution.
Nodes are the possible rule matches at the current state. Two matches are branchially connected when they overlap (touch at least one common hyperedge), meaning they represent conflicting/branching rewrite choices.
Returns %{nodes: [map()], edges: [map()]}.
Creates a visualization-friendly representation of the causal network. Each event (i.e., a specific hypergraph update) becomes a vertex in the causal graph. Implements the partial order of event dependencies (a DAG): if the application of event B depends on the output of event A (e.g., B’s matching pattern overlaps with hyperedges created by A), then the causal graph includes a directed edge A → B.
@spec causally_invariant?(t(), non_neg_integer()) :: boolean()
Checks causal invariance (confluence) for the current model state.
Tests all pairs of rule matches — both overlapping and non-overlapping:
- Non-overlapping pairs: applied in both orders; the results must be identical (immediate commutativity).
- Overlapping pairs: each match is applied independently; then evolution
continues for up to
depthadditional steps (default 2) on each branch. Invariance holds if the two branches reach a common state within that depth (local Church-Rosser property).
Returns true if all tested pairs satisfy the check, false otherwise.
An empty match set is trivially invariant.
Applies all non-conflicting rule matches in parallel during a single step.
Matches are processed greedily in rule/hyperedge order: once a hyperedge is consumed by a chosen match it is unavailable to subsequent matches in the same step. Returns the unchanged model when no matches exist.
Evolves the universe by one step, applying one rule match selected by
opts[:ordering].
Supported orderings:
:first(default) — first match in rule/hyperedge order:leftmost— match whose hyperedges have the smallest vertex sort key:random— uniformly random match
Accepts opts[:id_generator] to override the model's id generator for
deterministic behaviour during tests.
Returns the unchanged model when no rules are applicable (fixpoint).
@spec evolve_steps(t(), non_neg_integer(), keyword()) :: t()
Evolves the universe for a specified number of steps.
Accepts opts forwarded to evolve_step/2 (e.g., :id_generator).
@spec evolve_until_fixpoint(t(), non_neg_integer(), keyword()) :: t()
Evolves the universe by repeatedly calling evolve_step/2 until either
no rule is applicable or max_steps is reached.
Returns the final model. You can check fixpoint?/1 on the result to
distinguish a natural fixpoint from a step-limit halt.
Exports the causal event graph as a map of nodes and edges.
Nodes correspond to events in chronological order. Edges link parent events to
child events using the parent_ids recorded during evolution.
Returns true when no rule can be applied to the current hypergraph
(the system has reached a fixpoint).
@spec foliations(t()) :: [[WolframModel.Event.t()]]
Computes foliations of the causal network: layers of events where each layer contains only events whose parents all belong to earlier layers (spacelike slices of the causal partial order).
Returns a list of lists of Event.t(), ordered from earliest to latest layer.
Layer 0 contains root events (no causal parents). Layer N contains events
whose deepest ancestor is in layer N-1.
@spec multiway_explore(t(), non_neg_integer()) :: %{model: t(), children: [map()]}
Explores the multiway graph up to a specified depth. Returns a tree of possible evolution paths.
@spec multiway_explore_dag(t(), non_neg_integer()) :: %{ root: term(), nodes: map(), edges: MapSet.t() }
Explores the multiway system as a directed acyclic graph (DAG) up to
depth steps. Unlike multiway_explore/2, states that are reachable via
multiple paths are represented once and converging branches share nodes.
Returns:
%{
root: canonical_key,
nodes: %{canonical_key => %WolframModel{}},
edges: MapSet.t({from_key, to_key})
}where canonical_key is a sorted list-of-lists encoding of the hypergraph.
Finds all possible rule applications in the current state (multiway evolution). Returns a deduplicated list of possible next states (unique hypergraphs).
@spec new(Hypergraph.t(), [rule()], keyword()) :: t()
Creates a new Wolfram Model universe with initial hypergraph and rules.
@spec print_stats(t()) :: :ok
Helper function to print evolution statistics.