WolframModel (WolframModel v1.3.0)

Copy Markdown View Source

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

rule()

@type rule() :: %{
  pattern: [[Hypergraph.vertex()]],
  replacement: [[Hypergraph.vertex()]],
  name: String.t()
}

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

branchial_graph(model)

@spec branchial_graph(t()) :: %{nodes: [map()], edges: [map()]}

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()]}.

causal_network_data(model)

@spec causal_network_data(t()) :: %{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.

causally_invariant?(model, depth \\ 2)

@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 depth additional 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.

evolve_parallel(model)

@spec evolve_parallel(t()) :: t()

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.

evolve_step(model, opts \\ [])

@spec evolve_step(
  t(),
  keyword()
) :: t()

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).

evolve_steps(model, steps, opts \\ [])

@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).

evolve_until_fixpoint(model, max_steps \\ 1000, opts \\ [])

@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.

export_event_graph(model)

@spec export_event_graph(t()) :: %{nodes: [map()], edges: [map()]}

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.

fixpoint?(model)

@spec fixpoint?(t()) :: boolean()

Returns true when no rule can be applied to the current hypergraph (the system has reached a fixpoint).

foliations(model)

@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.

multiway_explore(model, depth)

@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.

multiway_explore_dag(model, depth)

@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.

multiway_step(model)

@spec multiway_step(t()) :: [t()]

Finds all possible rule applications in the current state (multiway evolution). Returns a deduplicated list of possible next states (unique hypergraphs).

new(initial_hypergraph, rules, opts \\ [])

@spec new(Hypergraph.t(), [rule()], keyword()) :: t()

Creates a new Wolfram Model universe with initial hypergraph and rules.