# `WolframModel.Analytics`
[🔗](https://github.com/sragli/wolfram_model/blob/main/lib/wolfram_model/analytics.ex#L1)

Emergence and graph analytics helpers for the Wolfram Model.

This module provides functions to build adjacency maps, compute
clustering coefficients, estimate diameter, and other small analytics
previously living directly on `WolframModel`.

# `analyze_causality`

```elixir
@spec analyze_causality(WolframModel.t()) :: map()
```

Analyzes the causal structure of evolution events using event indices for efficiency.
Returns counts and density.

# `analyze_emergence`

```elixir
@spec analyze_emergence(WolframModel.t()) :: map()
```

Analyze emergent properties of the given `model`.

Returns a map containing basic hypergraph stats plus derived metrics:
- `:clustering_coefficient` (float)
- `:estimated_diameter` (integer)
- `:growth_rate` (float)
- `:complexity_measure` (number)
- `:evolution_generation` (integer)

This function delegates to the helper functions provided by this module and
returns a stable map suitable for reporting or tests.

# `build_adjacency_map`

```elixir
@spec build_adjacency_map(Hypergraph.t()) :: map()
```

Build an adjacency map from `hg`.

The returned map has the shape `%{vertex => MapSet.t(neighbors)}`. Isolated
vertices are included with an empty `MapSet`.

# `calculate_clustering_coefficient`

```elixir
@spec calculate_clustering_coefficient(map()) :: float()
```

Compute the average local clustering coefficient for the (projected) graph
represented by `adjacency_map`.

Uses the standard definition: average over vertices of (existing neighbor
connections) / (possible neighbor connections).

# `calculate_complexity`

```elixir
@spec calculate_complexity(Hypergraph.t()) :: number()
```

Calculate a lightweight complexity measure for a hypergraph. Currently
delegated to `Hypergraph.CorrelationLength.compute/1`. If that function is
not available or returns an error, this returns `0`.

# `calculate_growth_rate`

```elixir
@spec calculate_growth_rate(WolframModel.t()) :: float()
```

Simple growth rate between the two most recent hypergraph snapshots in the
model's `evolution_history` (recent - previous) / previous. Returns `0.0` if
there are fewer than two snapshots or the previous count is zero.

# `detect_conserved_quantities`

```elixir
@spec detect_conserved_quantities(WolframModel.t()) :: map()
```

Detects conserved quantities by scanning the full evolution history.

Checks the following candidates across all recorded hypergraph snapshots:
- `:vertex_count` — total distinct vertex count is constant
- `:edge_count` — total hyperedge count is constant
- `:vertex_count_parity` — vertex count parity (mod 2) is constant
- `:edge_count_parity` — edge count parity (mod 2) is constant
- `:total_degree` — sum of all hyperedge sizes (total degree) is constant
- `:total_degree_parity` — total degree parity is constant

Returns:
```
%{
  conserved: [:vertex_count, ...],
  vertex_count_history: [n, ...],
  edge_count_history: [n, ...],
  total_degree_history: [n, ...]
}
```

Requires at least 2 snapshots; returns `%{conserved: []}` otherwise.

# `estimate_diameter`

```elixir
@spec estimate_diameter(map()) :: non_neg_integer()
```

Estimate the graph diameter (longest shortest path) from `adjacency_map`.

For disconnected graphs, the maximum diameter among components is returned.
For a graph with a single isolated vertex the function returns `1` to remain
compatible with prior behavior in the project.

# `estimate_dimension`

```elixir
@spec estimate_dimension(Hypergraph.t()) :: float()
```

Estimates the effective spatial dimension of the hypergraph using geodesic
ball growth. Counts vertices within BFS distance r from several seed vertices
and fits V(r) ~ r^d via log-log linear regression.

Returns `1.0` for degenerate (fewer than 4 vertices) or disconnected graphs
where a meaningful estimate cannot be produced.

# `estimate_ricci_scalar`

```elixir
@spec estimate_ricci_scalar(Hypergraph.t()) :: float() | nil
```

Estimates the Ricci scalar curvature of the hypergraph from geodesic ball
growth.

For a *d*-dimensional Riemannian space the volume of a geodesic ball of
radius *r* satisfies:

    V(r) ≈ Cₐ · rᵈ · (1 − R · r² / (6(d+2)))

where R is the Ricci scalar curvature. Taking logs and grouping:

    Δ(r) = log V(r) − d · log r  ≈  const − R · r² / (6(d+2))

So a linear regression of Δ(r) against r² yields

    slope ≈ −R / (6(d+2))   ⟹   R = −slope · 6(d+2)

The estimate is averaged over up to 10 seed vertices. Returns `nil` for
graphs with fewer than 6 vertices or whenever the fit is degenerate.

- A result near `0.0` indicates flat (Euclidean-like) geometry.
- A positive result indicates positive curvature (sphere-like).
- A negative result indicates negative curvature (hyperbolic-like).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
