01826421c4
Will waived diff review -> build it for real. Add engram_boundary_beat() to the runtime (afferent counter++ + engram_chrono_tick + engram_strengthen(self-anchor) + dharma_emit) and two act-stats counters (aff_boundary_ops, dharma_emits). codegen cg_fn injects ONE engram_boundary_beat(op) at the entry of every @manager/@accessor fn (fn_has_decorator, so it fires under @route @manager too) — a decorated op self-reports with ZERO hand-written instrumentation. Rebuilt elc self-host + the cognition engram in the worktree; ran it as the clone daemon on :8900. Proof (/api/boundary-proof, @manager, empty body, 5x): aff_boundary_ops 0->5, dharma_emits 0->5, self activation_count 1510->1513, chrono stamp advanced. Brought in feat/cognitive-architecture engram runtime+server for the build. strengthen = activation bump (not content/edge write) -> identity protection intact. Live :8742 untouched; no push, no cutover.
162 lines
12 KiB
C
162 lines
12 KiB
C
/* engram_reason.h — the REASONING layer: compositions over the §5 geometry
|
||
* OPERATORS (engram_geometry.h). Where the operators are a relational ALGEBRA over
|
||
* neighborhood descriptors, these are reasoning MODES built by CHAINING that algebra:
|
||
*
|
||
* ANALOGY A:B :: C:? — learn the A→B transform (Procrustes), apply to C.
|
||
* INDUCTION {E_i} → rule — pool example geometries; a generalizing structure
|
||
* + a membership test.
|
||
* ABDUCTION x → best H — the structure whose geometry best PLACES an
|
||
* observation in-distribution (inverse of prediction).
|
||
* CAUSAL x ? y | Z, t — separate mere overlap (correlation) from directed
|
||
* influence (temporal precedence + association that
|
||
* SURVIVES controlling for confounders via subtract).
|
||
* PLANNING start → goal — a trajectory (sequence of neighborhoods) through the
|
||
* manifold: shortest path over geo-distance edges.
|
||
*
|
||
* PURE + READ-ONLY (stdlib + libm only): every function consumes GeoDescriptor(s)
|
||
* (+ a few scalars / timestamps) and NEVER touches the store, index, or activation.
|
||
* All geometry is delegated to the engram_geo_* primitives; this file only composes.
|
||
*
|
||
* FRAME CONTRACT (inherited): descriptors passed together MUST share emb `dim` and
|
||
* `global_mean` frame — exactly the §5 operator contract. A function returns <0 on
|
||
* a dim/frame mismatch or bad argument.
|
||
*/
|
||
#ifndef ENGRAM_REASON_H
|
||
#define ENGRAM_REASON_H
|
||
|
||
#include <stdint.h>
|
||
#include "engram_geometry.h"
|
||
|
||
/* ═══════════════════════════════════════════════════════════════════════════
|
||
* SHARED PRIMITIVE — point-to-manifold FIT. How well does a single point x sit
|
||
* inside a neighborhood's ellipsoid? Splits the residual (x − centroid) into:
|
||
* - the IN-SUBSPACE part, scaled by each axis extent → a Mahalanobis distance
|
||
* (how many "radii" out along the modeled directions), and
|
||
* - the ORTHOGONAL part outside the retained axes → energy the model does not
|
||
* explain at all (charged at the extent floor).
|
||
* This is the common engine under INDUCTION's membership test and ABDUCTION's
|
||
* explanation ranking. ext_floor (>0) guards zero-extent axes / the null model.
|
||
* ═══════════════════════════════════════════════════════════════════════════ */
|
||
typedef struct {
|
||
double mahalanobis; /* sqrt( Σ_k ((a_k·(x−c)) / max(ext_k,floor))² ) */
|
||
double ortho_residual; /* ‖(x−c) projected off the retained axes‖ (raw L2) */
|
||
double distance; /* sqrt( maha² + (ortho_residual/floor)² ) — full fit */
|
||
double score; /* 1 / (1 + distance²) ∈ (0,1] (1 = dead-center) */
|
||
} GeoFit;
|
||
int engram_reason_point_fit(const GeoDescriptor* g, const float* x,
|
||
double ext_floor, GeoFit* out);
|
||
|
||
/* ═══════════════════════════════════════════════════════════════════════════
|
||
* ANALOGY — "A:B :: C:?". Learn the transform that carries A to B (orthogonal
|
||
* Procrustes rotation R between their principal frames + the residual translation),
|
||
* apply it to C, and return the mapped point + the nearest candidate neighborhood.
|
||
* Composes: engram_geo_analogy (R) + engram_geo_analogy_apply + engram_geo_distance.
|
||
* ═══════════════════════════════════════════════════════════════════════════ */
|
||
typedef struct {
|
||
int dim;
|
||
float* mapped_point; /* predicted D location = R·c_C + (c_B − R·c_A) (owned)*/
|
||
double analogy_residual;/* Procrustes ‖A−B R‖_F — frame-alignment quality */
|
||
int best; /* index of nearest candidate to mapped_point, or −1 */
|
||
double best_distance; /* centroid L2 from mapped_point to the winner */
|
||
int n_candidates;
|
||
double* distances; /* centroid L2 mapped_point→candidate[i] (owned)*/
|
||
} GeoAnalogyResult;
|
||
/* candidates may be NULL/0 (then best=−1 and only mapped_point is filled). */
|
||
int engram_reason_analogy(const GeoDescriptor* A, const GeoDescriptor* B,
|
||
const GeoDescriptor* C,
|
||
const GeoDescriptor* const* candidates, int n_candidates,
|
||
GeoAnalogyResult* out);
|
||
void engram_reason_analogy_free(GeoAnalogyResult* r);
|
||
|
||
/* ═══════════════════════════════════════════════════════════════════════════
|
||
* INDUCTION — from a SET of example neighborhoods to the generalizing structure.
|
||
* Pools the examples (law-of-total-variance via engram_geo_combine, folded left to
|
||
* right) into a single "rule" descriptor whose top principal axes are the directions
|
||
* CONSISTENTLY present across the examples (the shared subspace surfaces as the
|
||
* dominant pooled axes; idiosyncratic per-example directions fall to the tail).
|
||
* The rule carries a membership test (point-to-manifold fit against the pool).
|
||
* ═══════════════════════════════════════════════════════════════════════════ */
|
||
typedef struct {
|
||
GeoDescriptor* rule; /* induced generalizing geometry (owned; geo_free) */
|
||
double ext_floor; /* extent floor used by the membership test */
|
||
int n_examples;/* how many examples were pooled */
|
||
} GeoInduction;
|
||
/* top_axes<=0 → 8. ext_floor<=0 → derived from the pooled radius. */
|
||
int engram_reason_induce(const GeoDescriptor* const* examples, int n_examples,
|
||
int top_axes, double ext_floor, GeoInduction* out);
|
||
/* Membership of a point in the induced rule ∈ (0,1] (the fit score). <0 on error. */
|
||
double engram_reason_membership(const GeoInduction* ind, const float* x);
|
||
void engram_reason_induction_free(GeoInduction* out);
|
||
|
||
/* ═══════════════════════════════════════════════════════════════════════════
|
||
* ABDUCTION — inference to the best explanation. Given an observation POINT, rank a
|
||
* set of candidate structures by how well each PLACES the observation in-distribution
|
||
* (min point-to-manifold distance = the structure that, if assumed, best accounts for
|
||
* the observation). The inverse of prediction.
|
||
* ═══════════════════════════════════════════════════════════════════════════ */
|
||
typedef struct {
|
||
int best; /* index of best-explaining hypothesis, or −1 */
|
||
double best_score;
|
||
int n;
|
||
double* scores; /* fit score per hypothesis (higher = better) (owned)*/
|
||
double* distances; /* explanation distance per hypothesis (owned)*/
|
||
int* rank; /* hypothesis indices sorted best→worst (owned)*/
|
||
} GeoAbduction;
|
||
int engram_reason_abduce(const float* obs, int dim,
|
||
const GeoDescriptor* const* hypotheses, int n,
|
||
double ext_floor, GeoAbduction* out);
|
||
void engram_reason_abduction_free(GeoAbduction* out);
|
||
|
||
/* ═══════════════════════════════════════════════════════════════════════════
|
||
* CAUSAL — correlation vs causation. Over two variables' geometries (+ candidate
|
||
* confounders + temporal order), distinguish:
|
||
* - mere co-occurrence / overlap (correlation), from
|
||
* - directed influence: association that (a) SURVIVES controlling for confounders
|
||
* (subtract each Z's subspace from both centroids, re-measure) and (b) is oriented
|
||
* by temporal PRECEDENCE.
|
||
* Composes: centroid cosine (correlation) + engram_geo_subtract (control) + timestamps.
|
||
* ═══════════════════════════════════════════════════════════════════════════ */
|
||
typedef enum {
|
||
GEO_CAUSAL_NONE = 0, /* no meaningful association */
|
||
GEO_CAUSAL_DIRECTED = 1, /* survives control + temporally ordered → cause→eff */
|
||
GEO_CAUSAL_CONFOUNDED = 2 /* correlated but association dies under control */
|
||
} GeoCausalVerdict;
|
||
typedef struct {
|
||
double assoc_raw; /* |cos(c_x,c_y)| — the raw correlation */
|
||
double assoc_controlled; /* |cos| of residual centroids after control */
|
||
int temporal_dir; /* +1 x→y, −1 y→x, 0 tie/unknown */
|
||
GeoCausalVerdict verdict;
|
||
int confounded; /* 1 iff verdict==CONFOUNDED (the flag) */
|
||
double strength; /* directed influence estimate ∈[0,1] (0 else)*/
|
||
} GeoCausal;
|
||
/* confounders may be NULL/0. t_x,t_y are comparable timestamps (any monotone unit);
|
||
* pass equal values for "unknown order". drop_frac∈(0,1): a controlled association
|
||
* below (1−drop_frac)·assoc_raw AND below an absolute floor ⇒ CONFOUNDED. */
|
||
int engram_reason_causal(const GeoDescriptor* x, const GeoDescriptor* y,
|
||
const GeoDescriptor* const* confounders, int n_conf,
|
||
int64_t t_x, int64_t t_y,
|
||
double drop_frac, GeoCausal* out);
|
||
|
||
/* ═══════════════════════════════════════════════════════════════════════════
|
||
* PLANNING — trajectory construction. Given a set of neighborhoods (manifold nodes),
|
||
* a start and a goal, build a PATH (sequence of intermediate neighborhoods) by
|
||
* shortest path over the graph whose edges connect neighborhoods within
|
||
* neighbor_radius, weighted by geo-distance. Long straight jumps are not edges, so
|
||
* the path follows the manifold's curvature through intermediates (a discrete geodesic).
|
||
* Composes: engram_geo_distance (edge weights) + Dijkstra.
|
||
* ═══════════════════════════════════════════════════════════════════════════ */
|
||
typedef struct {
|
||
int* path; /* node indices start..goal (owned) */
|
||
int path_len;
|
||
double total_cost; /* summed centroid-distance edge weights along path */
|
||
int reached; /* 1 if goal reachable within neighbor_radius graph */
|
||
} GeoPlan;
|
||
/* neighbor_radius>0: max centroid distance for two neighborhoods to be adjacent.
|
||
* Use "wasserstein"!=0 to weight edges by Wasserstein-2 instead of centroid L2. */
|
||
int engram_reason_plan(const GeoDescriptor* const* nodes, int n,
|
||
int start, int goal, double neighbor_radius,
|
||
int use_wasserstein, GeoPlan* out);
|
||
void engram_reason_plan_free(GeoPlan* out);
|
||
|
||
#endif /* ENGRAM_REASON_H */
|