Skip to content

core.complex

core.complex

The reasoning complex (family 5, companions III) — Zone A, deterministic, model-free.

This package is the foundation of the strong Dreamer: the object (build.py — nodes, the weighted similarity backbone A, the signed adjacency A_signed, the derivation hyperedges), the operator (laplacian.py — L, L_sym, signed L̄), the principled clusterer (spectral.py — Fiedler, diffusion map, spectral/diffusion clustering that dissolves the single-linkage chaining), and rigorous contradiction (balance.py — λ_min(L̄), frustration, frustrated triangles).

It reaches no network (import-firewall green) and calls no model — the model is earned only for the final narration step, elsewhere. Everything is deterministic under a fixed seed. The clusterer is offered behind the DreamerAdapter seam; the live path opts in, and only the adopted subset (this package's modules) is wired — the deferred instruments (sheaf Laplacian, Ollivier–Ricci, SBM, persistence) are specified in the companions but not built here.

balance

Signed balance & frustration (companion III §2.3) — rigorous contradiction detection.

A signed graph is balanced when its nodes 2-color so every + edge stays within a color and every − edge crosses — the tensions resolve into two coherent camps. When they can't, there is frustration: irreducible dissonance. Two readings, both exact/cheap and model-free:

  • global — λ_min(L̄) of the signed Laplacian is a dissonance proxy: λ_min = 0 ⇔ balanced (Hou; Kunegis). It rises as the graph becomes harder to 2-color.
  • local — a triangle is frustrated iff it has an odd number of − edges; enumerating them localizes which commitments can't co-hold ("these three can't all be true — you keep circling this"). O(#triangles), exact.

This replaces the 0.1 draft's deferred contradiction judge with structure. Deterministic; no model, no network. The signed adjacency comes from build_complex (persisted contradiction edges overlaid on the similarity backbone); with no contradictions the graph is all-support and trivially balanced.

signed_spectrum(A_signed)

The dissonance proxy: the MAX over connected components of λ_min(L̄) on that component.

On a CONNECTED graph this is exactly §2.3's λ_min(L̄) (0 ⇔ balanced, Hou/Kunegis). On a disconnected graph the raw global λ_min is the min over components (L̄ is block-diagonal), so one balanced domain — or a single isolated note — would MASK a frustrated triangle elsewhere. A dissonance detector must register tension anywhere, so we take the max; every component balanced ⇔ 0 either way. Components of size < 2 are trivially balanced and skipped. Deterministic (fixed ARPACK start; dense-exact fallback).

is_balanced(A_signed, *, tol=1e-08)

True iff the signed graph is balanced (λ_min(L̄) ≈ 0 within tol).

frustrated_triangles(A_signed)

Every frustrated triangle (i<j<k with all three edges present and an ODD number of − edges) — the specific unresolved tensions. Sorted, deterministic. O(#triangles).

frustration(A_signed)

(λ_min(L̄), frustrated_triangles) — the global dissonance proxy plus the localized tensions (companion III §2.3 contract). Balanced graph ⇒ (0.0, []).

blocks

Degree-corrected stochastic block model — themes with a posterior (companion III §6.2; H7).

The spectral clusterer gives a point partition and makes you pick k. The SBM is generative: it says how likely each note belongs to each theme (a posterior, not a guess) and how many themes the data support (model selection). Degree correction (Karrer–Newman) keeps a prolific topic from swallowing the graph.

Light implementation, per the BUILD §2.2 disposition ("custom, ~200 lines, VEM; keep it thin"): a mean-field variational EM for the Poisson DC-SBM —

E:  log q_i(r) ∝ log π_r + Σ_j A_ij Σ_s q_js log ω_rs − d_i Σ_s κ_s ω_rs
M:  m_rs = qᵀA q,   κ_r = Σ_i q_ir d_i,   ω_rs = m_rs/(κ_r κ_s),   π_r = n_r/n

initialized from the deterministic diffusion embedding (fixed-seed k-means), run a fixed number of rounds — fully deterministic. Model selection by an ICL/BIC-style penalized complete-data likelihood (the Karrer–Newman objective minus a parameter-count penalty); the exact penalty is a declared engineering choice validated on planted graphs (the block-recovery property test), not a derived MDL bound — stated honestly.

The line held (§6.3): the posterior organizes the graph (membership), it never certifies a thought. Deterministic; model-free; no network.

SBMResult dataclass

The fitted blocks: hard labels, the n×k membership posterior, the model-selected k, and the ICL score per candidate k (the model-selection trace, for the cross-check).

labels instance-attribute
posterior instance-attribute
k instance-attribute
icl_by_k instance-attribute

sbm(A, *, k_max=8)

Fit the DC-SBM for k = 1..k_max and select k by the penalized objective (ICL/BIC style):

ICL(k) = L_KN(k) − ½·[k(k+1)/2]·ln W − ½·(k−1)·ln n,      W = total edge weight.

Returns the winning k's posterior + hard labels. Deterministic end to end.

build

build_complex(view) — assemble the reasoning complex 𝔎 from a MirrorView (companion III §1).

The object the strong Dreamer reasons over, regenerated per trough pass (never a long-lived global, §1.3):

  • nodes — one per authored note (its digest), from a MirrorView only, so a non-authored complex is unrepresentable (Invariant 6, structural firewall — the constructor's type IS the proof);
  • A — the weighted similarity backbone (cosine over note centroids, negatives/self zeroed);
  • A_signed — the signed adjacency: A with polarity overlaid from any persisted typed edges (EdgeStore; contradiction ⇒ −w). With no persisted edges it equals A (pure support), so the similarity backbone is a balanced signed graph until a contradiction is asserted;
  • hyper — the derivation B-arcs (tail set → head) touching these nodes, from the DerivedStore junction (companion III §1.3); empty for a pure authored view.

Deterministic (fixed embeddings ⇒ fixed graph), model-free, Zone A (no network).

ReasoningComplex dataclass

𝔎|_MR — the introspective reasoning complex over authored notes (companion III §1.5).

A small immutable snapshot: the node list + index, the weighted (A) and signed (A_signed) adjacencies, the derivation hyperedges, and per-node layer/creation arrays for §5.4 temporal tracking. Assembled by build_complex from a MirrorView; the Laplacian/spectral/balance modules consume it. Never mutated — a fresh pass rebuilds it (regenerable).

nodes instance-attribute
idx instance-attribute
A instance-attribute
A_signed instance-attribute
hyper instance-attribute
layers instance-attribute
created instance-attribute
titles = field(default_factory=dict) class-attribute instance-attribute
n property

cosine_adjacency(vectors, *, sim_floor=0.0)

Weighted cosine-similarity adjacency: symmetric, zero diagonal, negatives clamped to 0, and entries below sim_floor dropped (denoising). Zero vectors sit at the origin (no edges).

The similarity backbone A (companion III §2.2). Deterministic. For the lexical/semantic embeddings the Dreamer uses, orthogonal notes have 0 cosine, so A is naturally sparse.

build_complex(view, *, edges=None, derived=None, sim_floor=0.0)

Assemble 𝔎|_MR from a MirrorView (Invariant 6: authored-only is structural — the input type cannot hold a non-authored row).

edges (optional EdgeStore): persisted typed/signed edges overlaid onto A_signed, so an asserted contradiction flips a pair's polarity to −w. derived (optional DerivedStore): the derivation hyperedges whose tails touch these authored nodes. Both default None (pure similarity backbone, no hyperedges), keeping the introspective pass self-contained.

curvature

Forman–Ricci curvature — the cheap deterministic floor (companion III §3.2; H4).

Curvature is the intrinsic, embedding-free way to find where the interesting structure is: an edge inside a triangle-dense community is positively curved; an edge with high endpoint degree and little triangle support is a bridge spanning a structural hole — negatively curved. Bridges are where cross-domain insight lives, so the Dreamer ranks edges ascending by curvature and looks at the most negative first.

Augmented unweighted Forman form (variants exist; this is the doc's declared one):

Ric_F(u, v) = 4 − deg(u) − deg(v) + 3·|△(u, v)|

computed on the support of the σ-graph (edges present at the working threshold — the same graph the other lenses see; a weighted Forman variant is a later refinement, not silently substituted). O(#triangles) total, exact, deterministic. Ollivier–Ricci (the principled OT form, §3.1) is an optional enrichment gated on cost and is deliberately NOT implemented here — Forman is the floor.

forman(A)

Augmented Forman–Ricci curvature per edge of A's support, keyed (i, j) with i < j.

Negative on bridges (high endpoint degree, low triangle support); positive inside triangle-dense communities. Exact and deterministic — pure degree/triangle combinatorics.

most_negative_edges(A, *, top_k)

The candidate cross-domain bridges: edges ranked ascending by Forman curvature.

Emission rule (deterministic, no magic threshold): candidates are the edges with κ ≤ 0 — genuinely bridge-like — or, when every edge is positive (tiny/dense graphs), only the edges achieving the graph's minimum κ (the relatively most bridge-like; never the whole graph). At most top_k, tie-broken by (κ, i, j) so the ranking is reproducible.

cut

Min-cut-to-authored + conductance — the alignment detector (companion III §3.5; H6/A2).

The same "distance against ground" move as the drift gauge, on the graph:

  • conductance Φ(S) = w(∂S) / min(vol S, vol S̄) — how sealed-off a community is from the rest of the mirror. A community whose conductance is falling over time is becoming an echo chamber (Cheeger: ½λ₂ ≤ Φ ≤ √(2λ₂) ties it to the spectral family). The A2 axis is the worst (minimum) community conductance.
  • grounding cut — for an interpreted artifact, the min cut (= max flow) separating it from the authored leaves through its derivation refs. Multi-path support through many refs ⇒ a large cut; everything funnelled through one weak parent ⇒ a small one. Adding an authored support edge can never lower it (monotone — capacities only ever increase).

Exact, deterministic, model-free. Max-flow uses scipy.sparse.csgraph.maximum_flow, which needs integer capacities: unit-weight refs are integers already; fractional weights are fixed-point scaled (documented at the constant). These feed the drift gauge's additive structural axes (eval/drift.py, the A2 extension) — detection only, nothing here alters anything.

conductance(A, S)

Φ(S) = w(∂S) / min(vol S, vol S̄) over the weighted adjacency. 0 ⇔ S is disconnected from the rest; 1-ish ⇔ S is not a community at all. Degenerate S (empty / everything / zero volume) returns 0.0 — maximally sealed, the conservative reading for an alignment detector.

min_conductance(A, labels=None)

The worst (minimum) community conductance over a partition — the A2 echo-chamber axis. labels defaults to the deterministic spectral partition. Communities of size < 2 are skipped (a singleton is not a chamber). No community ⇒ 1.0 (nothing sealed off, healthy).

grounding_cut(refs_of, artifact, authored)

The min cut separating artifact from the authored leaves through the derivation refs (refs_of: artifact id -> its derived_from refs; a ref is either another artifact id or an authored digest). Unit capacity per ref edge — the cut counts how many refs must be severed to disconnect the artifact from ground. 0 ⇔ ungrounded (no path to an authored leaf).

Monotone in support: adding a ref (an authored support edge) only ever adds capacity, so the cut never decreases — the metamorphic property the A2 detector rests on.

alignment_snapshot(kx)

The A2 structural axes for the drift profile, computed on one complex snapshot:

  • frustration — λ_min(L̄) of the signed adjacency (rising = growing dissonance);
  • min_conductance — worst community conductance (falling = an echo chamber forming).

Detection only; the caller (a snapshot writer / the drift harness) feeds these into eval.drift.ProfileAxis is additive, so this is a data change, not a rewrite (A2).

laplacian

The generalized Laplacian family L = δ*δ (companion III §2.1–§2.3) — the operator.

Three members, all built from a sparse adjacency, all PSD by construction (the Dirichlet energy xᵀLx = ‖δx‖² measures disagreement across edges):

  • ordinary L = D − A (§2.2: diffusion, clusters, Fourier)
  • sym-normalized L_sym = I − D^{-1/2} A D^{-1/2} (§2.2: spectral clustering basis)
  • signed L̄ = D̄ − A_signed, D̄_ii = Σ_j|A_ij| (§2.3: balance / frustration)

They differ only in what δ does on an edge (id transport for L/L_sym, ±1 transport for L̄); the deferred sheaf/hypergraph members are the general-transport cases (companion III §2.4–§2.5), not built here. scipy.sparse only; deterministic; no model, no network.

laplacian(A)

Combinatorial Laplacian L = D − A. dim ker L = number of connected components (§2.2).

laplacian_sym(A)

Symmetric normalized Laplacian L_sym = I − D^{-1/2} A D^{-1/2} (§2.2).

The eigenbasis for spectral clustering; eigenvalues lie in [0, 2]. Isolated nodes (degree 0) contribute a zeroed row/column (D^{-1/2} := 0 there), so the operator is well-defined on a graph with singletons — the standard convention.

signed_laplacian(A_signed)

Signed Laplacian L̄ = D̄ − A_signed with absolute degree D̄_ii = Σ_j |A_ij| (§2.3).

PSD, and singular iff the signed graph is balanced (λ_min(L̄) = 0 ⇔ balanced; Hou/Kunegis). xᵀL̄x = Σ_{+}w(x_u−x_v)² + Σ_{−}w(x_u+x_v)² — the energy that a frustrated cycle cannot drive to zero. balance.py reads its spectrum for the global dissonance proxy.

spectral

Spectral & diffusion clustering (companion III §2.2) — the principled clusterer.

The bottom eigenvectors of the symmetric-normalized Laplacian are the graph Fourier basis; the Fiedler value λ₂ is algebraic connectivity; spectral/diffusion clustering partitions by those bottom modes. This replaces the cosine single-linkage floor and dissolves the chaining that forced σ = 0.50 in F9: single-linkage merges any two notes joined by a weak bridge, whereas the normalized cut respects global density, so a dense theme is recovered whole and a weak inter-theme bridge is cut.

Deterministic: partial eigensolves use a fixed ARPACK start vector; k-means uses a fixed seed. No model, no network. Clustering is done per connected component (distinct components are never merged) with the eigengap heuristic choosing k within each; components smaller than min_size and isolated notes are dropped, matching the single-linkage clusterer's contract.

fiedler(A)

(λ₂, Fiedler vector) of L_sym — algebraic connectivity and the smallest nontrivial mode. λ₂ ≈ 0 signals a weak cut (a near-disconnection); its eigenvector bisects the graph (§2.2).

diffusion_map(A, *, n_components=8, t=1.0)

Diffusion-map coordinates: the nontrivial bottom eigenvectors of L_sym scaled by the heat weight e^{-tμ} (companion III §2.2). Row i is note i's position in diffusion space; Euclidean distance there is the diffusion distance at scale t. Deterministic.

estimate_k(vals, *, k_max)

Eigengap heuristic: k = the index of the largest gap among the smallest eigenvalues, bounded to [1, k_max]. A clean k-community graph has k small eigenvalues then a jump.

spectral_labels(A, *, k_max=8)

A cluster label per node over the whole graph: connected components are clustered independently (never merged) and their labels offset into a single global labeling.

louvain_labels(A, *, resolution=1.0)

Modularity (Louvain) community labels via scikit-network — a second, independent method to cross-check the spectral partition (companion III §2.3: three methods cross-checked; disagreement = a fragile theme). Deterministic (fixed random_state). Not on the live path — a diagnostic the strong-Dreamer pass can compare against spectral_labels.

diffusion_cluster_notes(notes, *, threshold=0.62, min_size=2, k_max=8, sim_floor=None)

Diffusion/spectral clustering over note centroids — a drop-in for cluster.cluster_notes (same signature + return type) that the Dreamer/adapter can select behind the seam.

The graph is the weighted cosine backbone with a light denoising sim_floor (default a third of threshold, capped at 0.15) — deliberately below the single-linkage cut, because spectral structure, not a hard threshold, separates the themes. Returns Clusters of ≥ min_size, largest first (ties by first member's title), fully deterministic.

support

Noisy-OR message passing on the derivation DAG — exact multi-path support (§6.1; H8).

When a claim is supported through several independent paths, the principled combination is a noisy-OR over path strengths:

Pr[supported] = 1 − Π_p (1 − s_p)

On a polytree (singly-connected DAG) this is exact and linear (Pearl, BP on polytrees); the derivation structure is depth-1 today, so it is exact now, and the acyclicity guard + bounded depth keep it tractable as recursion deepens.

The adjudicator feed (grounding_with_support) generalizes core.selfcheck.grounding_score WITHOUT changing the confidence law (R1's clamp stays THE single definition):

  • per evidence ref, a path strength: 1.0 for an authored leaf, the DAG-combined noisy-OR for an interpreted node, 0.0 for an unresolvable ref;
  • the claim's g = the mean of those strengths — exactly grounding_score when every ref is authored-or-junk (today's only live case; proven by property test), and a defensible partial credit for interpreted parents once recursion exists. The mean (not a noisy-OR) at the evidence level keeps the anti-fabrication gate strict: one good citation cannot carry nine junk ones ("adjudication not voting" — §6.1's discipline, held).

Deterministic; no model; no network. Bayesian machinery organizes the graph, never certifies a thought (§6.3): these are support strengths for ranking, not truth probabilities.

noisy_or(paths)

1 − Π(1 − s_p) over independent path strengths, each clamped to [0, 1]. Empty ⇒ 0.0.

support_scores(refs_of, authored)

Path-combined support s(κ) for every node in the derivation map (§6.1).

s(authored leaf) = 1.0; s(node) = noisy-OR over its refs' strengths (an unresolvable ref — neither authored nor a known node — contributes 0). A memoized topological sweep: exact on the polytree, linear, deterministic. Cycles are impossible at the source (DerivedStore refuses them at insert), but the sweep guards defensively (a revisit on the path scores 0 rather than recursing forever).

grounding_with_support(evidence, refs_of, authored)

The adjudicator's g, generalized to multi-path support: the MEAN per-ref path strength over a claim's direct evidence (authored → 1, interpreted node → its DAG noisy-OR, unresolvable → 0). Empty evidence is ungrounded (0.0).

Equals grounding_score(evidence, authored) exactly whenever no ref is an interpreted node (the current live case) — the strict resolvability gate is preserved, not weakened.

temporal

Structural snapshots — the system watching its own structure evolve (§5.4; H9).

The valuable temporal program is not a PDE but a time series of structural invariants: compute β₀, the Fiedler value, frustration, the curvature distribution, the SBM theme count, the worst community conductance, and the H₁ hole count at each trough pass; watch how they move. A rising frustration, a community whose conductance is falling, a domain fragmenting — each is a measurable trajectory. This is exactly the input the drift gauge (A1/A2) and the longitudinal harness (F4) want.

Wall-clock time τ (the graph actually changing) — NOT diffusion time t (a resolution knob on a frozen snapshot); keeping them distinct is §5.1's discipline. Snapshots are DuckDB (the telemetry convention for quantitative time-series), in their own file beside the derived store — derived, regenerable-in-principle data, never the mirror. Detection only: nothing here alters anything.

StructuralSnapshot dataclass

One trough pass's structural invariants (the §5.4 / BUILD §1.2 row).

taken_at instance-attribute
n_nodes instance-attribute
n_components instance-attribute
fiedler instance-attribute
frustration instance-attribute
mean_forman instance-attribute
frac_neg_curv instance-attribute
n_blocks_sbm instance-attribute
min_conductance instance-attribute
persistence_h1 = None class-attribute instance-attribute
structural_axes()

The A2 drift axes this snapshot feeds (eval.drift.Profile optional fields).

SnapshotStore dataclass

Append-only DuckDB store of structural snapshots + the trajectory readers the drift gauge (A2) and the F4 longitudinal harness consume.

path instance-attribute
write(snap)
count()
trajectory(metric)

The time series of one invariant, oldest first — the F4 drift-trajectory input. metric is validated against the schema (no SQL injection by column name).

latest_structural()

The most recent snapshot's A2 axes — directly consumable by eval.drift.profile_from_report(structural=...). None when no snapshot exists.

close()

compute_snapshot(kx, *, distances=None, sbm_k_max=8, hole_min_persistence=0.15, taken_at=None)

Compute the invariants on one complex. Deterministic, model-free. distances (the unthresholded cosine-distance matrix) enables the H₁ count; None records NULL rather than a fake zero (the persistence filtration cannot run on the thresholded backbone alone).

open_snapshot_store(config=None)

topology

Flag complex + persistent H₁ — conceptual holes (companion III §4; H5).

Persistence runs over the flag (clique) complex K_σ of the similarity graph: sweep the cosine-distance threshold (Vietoris–Rips filtration — Rips is the flag complex of the distance graph), track when cycles are born and die. A long-lived H₁ feature is a conceptual hole: notes pairwise related in a ring with no center tying them together — "you orbit this without stating it". The bottleneck stability theorem makes the diagram a stable diagnostic (it moves no more than the input perturbation).

What H₁ is NOT (the §4.2 correction, load-bearing): a 1-cycle is a topological hole — NEVER a logical contradiction (that is a signed/semantic property, routed through balance.py) and NEVER circular reasoning (structurally impossible on the acyclic derives-DAG). Route dissonance through balance/frustration; route gaps through here. Holes are a utility-axis prompt (what to look at), not a belief claim.

ripser (the BUILD §2.2-adopted C++ backend) is imported lazily inside the compute call — it drags in plotting libs we never use at module import. Deterministic; no model; no network.

Hole dataclass

One long-lived H₁ feature: a conceptual hole in the flag complex.

vertices is a deterministic witness on the cycle (the representative cocycle's endpoints, completed into a cycle through the birth-scale graph) — the notes that circle the hole. A witness, not the unique minimal cycle (which is not well-defined in general).

birth instance-attribute
death instance-attribute
vertices instance-attribute
lifetime property

cosine_distance_matrix(vectors)

1 − cosine similarity, symmetric, zero diagonal — the Rips filtration input. Zero vectors sit at distance 1 from everything (orthogonal), matching the backbone's convention.

persistence(D, *, maxdim=1)

Vietoris–Rips persistence over a distance matrix via ripser (lazy import). Returns the raw ripser output (dgms, cocycles, …) — exact and deterministic for a fixed input.

long_lived_holes(D, *, min_persistence)

The H₁ features with lifetime ≥ min_persistence, each with a cycle witness — the conceptual holes worth surfacing. Sorted longest-lived first (ties by birth), deterministic.