Merge pull request 'runtime: transduction decomposes a signal into components and relations, it does not convert it to a point' (#155) from fix/transduce-decomposition into dev
El SDK CI - dev / build-and-test (push) Failing after 3m46s
El SDK CI - dev / build-and-test (push) Failing after 3m46s
This commit was merged in pull request #155.
This commit is contained in:
+335
-21
@@ -6422,22 +6422,319 @@ el_val_t geometry_to_f32le_hex(el_val_t g) {
|
||||
return (el_val_t)(uintptr_t)out;
|
||||
}
|
||||
|
||||
|
||||
/* ── Manifold: a transduced signal is a SUBGRAPH, not a point ────────────────
|
||||
*
|
||||
* WHAT THIS CORRECTS. #144 gave transduction a home in the language and got
|
||||
* the DISPATCH right — realizers declared in El, resolved by name, no runtime
|
||||
* patch per modality. It got the OUTPUT TYPE wrong.
|
||||
* `transduce(signal, modality) -> Geometry` yields one vector per signal, and
|
||||
* one vector is a FINGERPRINT. A fingerprint can be matched and it can be
|
||||
* ranked; that is the whole of what it can ever do. It cannot be decomposed,
|
||||
* cannot be partially grounded, and cannot be contradicted in one part while
|
||||
* holding in another — because it has no parts.
|
||||
*
|
||||
* A song is not a point. It decomposes into pitch, interval, rhythm, harmonic
|
||||
* function, phrase structure: components, each with its own geometry, plus the
|
||||
* relations between them. THE SONG IS THE STRUCTURE OF THE RELATIONS. A
|
||||
* transducer that returns a single vector has not transduced the song, it has
|
||||
* summarised it — and the summary discards precisely the thing that made the
|
||||
* song reasonable-about.
|
||||
*
|
||||
* So transduction produces a MANIFOLD: named components, each carrying its own
|
||||
* geometry, and typed weighted relations among them. Signal in, subgraph out.
|
||||
* Conversion was never the operation.
|
||||
*
|
||||
* COMPONENTS ARE ADDRESSED BY KEY, NEVER BY INDEX. The key is what survives
|
||||
* persistence: a component becomes a node, and that node is separately
|
||||
* groundable precisely because it is separately NAMED. Index-addressing would
|
||||
* make a grounding reference positional, and a positional reference into a
|
||||
* decomposition whose arity can change is not a reference at all. Duplicate
|
||||
* keys are refused for the same reason: two components answering to one name
|
||||
* is not an addressing scheme.
|
||||
*
|
||||
* RELATION WEIGHT IS THE GROUNDING — there is no second field and no score to
|
||||
* compute. Per correspondence-and-censorship.md §1, grounding is an attribute
|
||||
* of the edge and it IS the hebbian weight; a grounding subsystem is a
|
||||
* supervisor invented for something that should be a property of the
|
||||
* substrate. A relation emitted by a realizer therefore arrives with its
|
||||
* grounding already on it and moves thereafter by use and by decay (§4: change
|
||||
* is not a consequence of use, it is use). Nothing in here computes a
|
||||
* grounding, and nothing observes one.
|
||||
*
|
||||
* A relation naming an endpoint that does not exist is REFUSED, not dropped. A
|
||||
* decomposition that silently loses edges is indistinguishable from one that
|
||||
* never had them — the same class of defect #141 exists to end.
|
||||
*
|
||||
* OWNERSHIP mirrors Geometry exactly. A Manifold is owned by the El caller and
|
||||
* released with manifold_free. manifold_add COPIES the geometry handed to it,
|
||||
* so a caller may free its own vector immediately and no component's geometry
|
||||
* is ever aliased. Keys, roles and relation strings are _persist copies, NOT
|
||||
* arena copies: a Manifold outlives the request arena that built it (a
|
||||
* realizer can be invoked from inside a handler), so an arena-tracked key
|
||||
* would dangle at el_request_end. manifold_free owns their release.
|
||||
*/
|
||||
|
||||
#define EL_MAGIC_MFLD 0xE1608E02u
|
||||
|
||||
typedef struct {
|
||||
char* key; /* addressable name, unique within the manifold */
|
||||
char* role; /* what KIND of component this is, realizer's vocabulary */
|
||||
ElGeometry* g; /* owned copy; never aliases the caller's value */
|
||||
} ElComponent;
|
||||
|
||||
typedef struct {
|
||||
char* from; /* component key */
|
||||
char* rel; /* relation name */
|
||||
char* to; /* component key */
|
||||
double weight; /* the grounding; §1 — one quantity, not two fields */
|
||||
} ElRelation;
|
||||
|
||||
typedef struct {
|
||||
ElHeader hdr;
|
||||
ElComponent* comps;
|
||||
size_t ncomp, capcomp;
|
||||
ElRelation* rels;
|
||||
size_t nrel, caprel;
|
||||
} ElManifold;
|
||||
|
||||
/* Resolve an el_val_t to a live Manifold, or NULL. Every accessor goes through
|
||||
* this, so a stale/foreign/zero value is a clean 0-return, never a deref. */
|
||||
static ElManifold* mfld_of(el_val_t m) {
|
||||
if (!looks_like_heap_obj(m)) return NULL;
|
||||
ElManifold* p = (ElManifold*)(uintptr_t)m;
|
||||
if (p->hdr.magic != EL_MAGIC_MFLD) return NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
static int mfld_find(ElManifold* p, const char* key) {
|
||||
for (size_t i = 0; i < p->ncomp; i++)
|
||||
if (strcmp(p->comps[i].key, key) == 0) return (int)i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
el_val_t manifold_new(void) {
|
||||
ElManifold* p = (ElManifold*)calloc(1, sizeof(ElManifold));
|
||||
if (!p) return (el_val_t)0;
|
||||
p->hdr.magic = EL_MAGIC_MFLD;
|
||||
p->hdr.refcount = 1;
|
||||
return (el_val_t)(uintptr_t)p;
|
||||
}
|
||||
|
||||
el_val_t manifold_is(el_val_t m) {
|
||||
return mfld_of(m) ? (el_val_t)1 : (el_val_t)0;
|
||||
}
|
||||
|
||||
/* manifold_add — add one COMPONENT: a named part with its own geometry.
|
||||
* Returns the component's index, or -1 on any refusal. Refusals are real and
|
||||
* distinct: an empty key (unaddressable), a duplicate key (ambiguous
|
||||
* addressing), a value that is not a live Geometry (a part with no geometry is
|
||||
* not a part). Each is a caller error worth surfacing at the point of the
|
||||
* mistake rather than as a missing node three layers downstream. */
|
||||
el_val_t manifold_add(el_val_t m, el_val_t key, el_val_t role, el_val_t g) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
if (!p) return (el_val_t)(int64_t)-1;
|
||||
const char* k = EL_CSTR(key);
|
||||
const char* r = EL_CSTR(role);
|
||||
if (!k || !*k) return (el_val_t)(int64_t)-1;
|
||||
if (!r) r = "";
|
||||
ElGeometry* src = geom_of(g);
|
||||
if (!src || src->dim <= 0) return (el_val_t)(int64_t)-1;
|
||||
if (mfld_find(p, k) >= 0) return (el_val_t)(int64_t)-1; /* duplicate key */
|
||||
|
||||
if (p->ncomp == p->capcomp) {
|
||||
size_t nc = p->capcomp ? p->capcomp * 2 : 8;
|
||||
ElComponent* nb = (ElComponent*)realloc(p->comps, nc * sizeof(ElComponent));
|
||||
if (!nb) return (el_val_t)(int64_t)-1;
|
||||
p->comps = nb; p->capcomp = nc;
|
||||
}
|
||||
|
||||
/* COPY the payload — a component's geometry must not alias the caller's. */
|
||||
ElGeometry* cp = (ElGeometry*)malloc(sizeof(ElGeometry));
|
||||
if (!cp) return (el_val_t)(int64_t)-1;
|
||||
cp->v = (float*)malloc(sizeof(float) * (size_t)src->dim);
|
||||
if (!cp->v) { free(cp); return (el_val_t)(int64_t)-1; }
|
||||
memcpy(cp->v, src->v, sizeof(float) * (size_t)src->dim);
|
||||
cp->hdr.magic = EL_MAGIC_GEOM;
|
||||
cp->hdr.refcount = 1;
|
||||
cp->dim = src->dim;
|
||||
|
||||
p->comps[p->ncomp].key = el_strdup_persist(k);
|
||||
p->comps[p->ncomp].role = el_strdup_persist(r);
|
||||
p->comps[p->ncomp].g = cp;
|
||||
p->ncomp++;
|
||||
return (el_val_t)(int64_t)(p->ncomp - 1);
|
||||
}
|
||||
|
||||
/* manifold_relate — state a relation BETWEEN two components. This is the part
|
||||
* that carries the meaning: the components are the parts, the relations are
|
||||
* what the thing IS.
|
||||
*
|
||||
* Both endpoints must already exist. An edge to a name that was never added is
|
||||
* refused with 0, never silently discarded — see the header note. */
|
||||
el_val_t manifold_relate(el_val_t m, el_val_t from, el_val_t rel,
|
||||
el_val_t to, el_val_t weight) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
if (!p) return (el_val_t)0;
|
||||
const char* f = EL_CSTR(from);
|
||||
const char* r = EL_CSTR(rel);
|
||||
const char* t = EL_CSTR(to);
|
||||
if (!f || !*f || !r || !*r || !t || !*t) return (el_val_t)0;
|
||||
if (mfld_find(p, f) < 0) return (el_val_t)0;
|
||||
if (mfld_find(p, t) < 0) return (el_val_t)0;
|
||||
|
||||
if (p->nrel == p->caprel) {
|
||||
size_t nc = p->caprel ? p->caprel * 2 : 8;
|
||||
ElRelation* nb = (ElRelation*)realloc(p->rels, nc * sizeof(ElRelation));
|
||||
if (!nb) return (el_val_t)0;
|
||||
p->rels = nb; p->caprel = nc;
|
||||
}
|
||||
p->rels[p->nrel].from = el_strdup_persist(f);
|
||||
p->rels[p->nrel].rel = el_strdup_persist(r);
|
||||
p->rels[p->nrel].to = el_strdup_persist(t);
|
||||
p->rels[p->nrel].weight = el_to_float(weight);
|
||||
p->nrel++;
|
||||
return (el_val_t)1;
|
||||
}
|
||||
|
||||
el_val_t manifold_size(el_val_t m) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
return p ? (el_val_t)(int64_t)p->ncomp : (el_val_t)0;
|
||||
}
|
||||
|
||||
el_val_t manifold_rel_count(el_val_t m) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
return p ? (el_val_t)(int64_t)p->nrel : (el_val_t)0;
|
||||
}
|
||||
|
||||
/* Index of a component BY KEY, or -1. This is the addressability primitive:
|
||||
* everything downstream that wants to ground, weight or contradict one part
|
||||
* finds it through here. */
|
||||
el_val_t manifold_index_of(el_val_t m, el_val_t key) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
const char* k = EL_CSTR(key);
|
||||
if (!p || !k || !*k) return (el_val_t)(int64_t)-1;
|
||||
return (el_val_t)(int64_t)mfld_find(p, k);
|
||||
}
|
||||
|
||||
el_val_t manifold_key(el_val_t m, el_val_t i) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
int64_t k = (int64_t)i;
|
||||
if (!p || k < 0 || k >= (int64_t)p->ncomp) return el_wrap_str(el_strdup(""));
|
||||
return el_wrap_str(el_strdup(p->comps[k].key));
|
||||
}
|
||||
|
||||
el_val_t manifold_role(el_val_t m, el_val_t i) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
int64_t k = (int64_t)i;
|
||||
if (!p || k < 0 || k >= (int64_t)p->ncomp) return el_wrap_str(el_strdup(""));
|
||||
return el_wrap_str(el_strdup(p->comps[k].role));
|
||||
}
|
||||
|
||||
/* manifold_geometry — the geometry OF ONE COMPONENT, as a fresh Geometry the
|
||||
* caller owns and frees. A borrowed interior pointer would let a caller's
|
||||
* geometry_free corrupt the manifold; copying is the same discipline
|
||||
* node_attach_geometry already applies in the other direction. */
|
||||
el_val_t manifold_geometry(el_val_t m, el_val_t i) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
int64_t k = (int64_t)i;
|
||||
if (!p || k < 0 || k >= (int64_t)p->ncomp) return (el_val_t)0;
|
||||
ElGeometry* src = p->comps[k].g;
|
||||
el_val_t out = geometry_new((el_val_t)(int64_t)src->dim);
|
||||
ElGeometry* dst = geom_of(out);
|
||||
if (!dst) return (el_val_t)0;
|
||||
memcpy(dst->v, src->v, sizeof(float) * (size_t)src->dim);
|
||||
return out;
|
||||
}
|
||||
|
||||
el_val_t manifold_rel_from(el_val_t m, el_val_t j) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
int64_t k = (int64_t)j;
|
||||
if (!p || k < 0 || k >= (int64_t)p->nrel) return el_wrap_str(el_strdup(""));
|
||||
return el_wrap_str(el_strdup(p->rels[k].from));
|
||||
}
|
||||
|
||||
el_val_t manifold_rel_name(el_val_t m, el_val_t j) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
int64_t k = (int64_t)j;
|
||||
if (!p || k < 0 || k >= (int64_t)p->nrel) return el_wrap_str(el_strdup(""));
|
||||
return el_wrap_str(el_strdup(p->rels[k].rel));
|
||||
}
|
||||
|
||||
el_val_t manifold_rel_to(el_val_t m, el_val_t j) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
int64_t k = (int64_t)j;
|
||||
if (!p || k < 0 || k >= (int64_t)p->nrel) return el_wrap_str(el_strdup(""));
|
||||
return el_wrap_str(el_strdup(p->rels[k].to));
|
||||
}
|
||||
|
||||
el_val_t manifold_rel_weight(el_val_t m, el_val_t j) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
int64_t k = (int64_t)j;
|
||||
if (!p || k < 0 || k >= (int64_t)p->nrel) return el_from_float(0.0);
|
||||
return el_from_float(p->rels[k].weight);
|
||||
}
|
||||
|
||||
/* manifold_single — the DEGENERATE case, expressible but visibly degenerate.
|
||||
*
|
||||
* Sometimes a modality really does have one part (a scalar sensor). That is a
|
||||
* manifold of size 1, not a different kind of thing, and writing it this way
|
||||
* keeps the fingerprint as a SPECIAL CASE of decomposition rather than a
|
||||
* parallel path back to #144's contract. Anything reading it still asks
|
||||
* manifold_size and still gets a real answer. */
|
||||
el_val_t manifold_single(el_val_t key, el_val_t role, el_val_t g) {
|
||||
el_val_t m = manifold_new();
|
||||
if (!mfld_of(m)) return (el_val_t)0;
|
||||
if ((int64_t)manifold_add(m, key, role, g) < 0) { manifold_free(m); return (el_val_t)0; }
|
||||
return m;
|
||||
}
|
||||
|
||||
el_val_t manifold_free(el_val_t m) {
|
||||
ElManifold* p = mfld_of(m);
|
||||
if (!p) return (el_val_t)0;
|
||||
for (size_t i = 0; i < p->ncomp; i++) {
|
||||
free(p->comps[i].key);
|
||||
free(p->comps[i].role);
|
||||
if (p->comps[i].g) { free(p->comps[i].g->v); p->comps[i].g->hdr.magic = 0; free(p->comps[i].g); }
|
||||
}
|
||||
for (size_t i = 0; i < p->nrel; i++) {
|
||||
free(p->rels[i].from); free(p->rels[i].rel); free(p->rels[i].to);
|
||||
}
|
||||
free(p->comps);
|
||||
free(p->rels);
|
||||
p->hdr.magic = 0; /* poison, as Geometry/List/Map do */
|
||||
free(p);
|
||||
return (el_val_t)1;
|
||||
}
|
||||
|
||||
/* ── Realizers: transduction declared in El, not patched into the runtime ────
|
||||
*
|
||||
* A REALIZER maps one modality into geometry. The whole reason transduction
|
||||
* belongs in the language is that ADDING A MODALITY MUST NOT REQUIRE A
|
||||
* RUNTIME PATCH — otherwise "the realizers are in the engram" just becomes
|
||||
* "the realizers are in the runtime" and nothing has actually moved. So
|
||||
* realizers are declared in El and registered by NAME:
|
||||
* A REALIZER DECOMPOSES one modality into components and their relations. It
|
||||
* does not encode a signal to a point — that is the operation one layer below
|
||||
* it, and it is called geometry, not transduction. A realizer for a modality
|
||||
* declares what that modality's COMPONENTS ARE: for audio, not one MFCC
|
||||
* vector, but pitch, interval, rhythm, harmonic function, and how they stand
|
||||
* to one another.
|
||||
*
|
||||
* fn tone_realizer(signal: String) -> Geometry {
|
||||
* let g: Geometry = geometry_new(8)
|
||||
* ... geometry_set(g, i, x) ...
|
||||
* g
|
||||
* The whole reason transduction belongs in the language is that ADDING A
|
||||
* MODALITY MUST NOT REQUIRE A RUNTIME PATCH — otherwise "the realizers are in
|
||||
* the engram" just becomes "the realizers are in the runtime" and nothing has
|
||||
* actually moved. So realizers are declared in El and registered by NAME:
|
||||
*
|
||||
* fn tone_realizer(signal: String) -> Manifold {
|
||||
* let m: Manifold = manifold_new()
|
||||
* let a: Int = manifold_add(m, "pitch", "spectral", pitch_geom)
|
||||
* let b: Int = manifold_add(m, "interval", "relation", interval_geom)
|
||||
* let e: Int = manifold_relate(m, "pitch", "spans", "interval", 0.9)
|
||||
* m
|
||||
* }
|
||||
*
|
||||
* realizer_register("tone", "tone_realizer")
|
||||
* let g: Geometry = transduce(sample, "tone")
|
||||
* let m: Manifold = transduce(sample, "tone")
|
||||
*
|
||||
* A realizer's DECLARED COMPONENT VOCABULARY is the interesting part of its
|
||||
* contract, and it is what a caller can then ground, weight and contradict
|
||||
* one part at a time.
|
||||
*
|
||||
* The name→symbol step rides the identical, already load-bearing mechanism
|
||||
* http_set_handler uses (see "HTTP server"): every El `fn name(...)` compiles
|
||||
@@ -6512,28 +6809,45 @@ el_val_t realizer_has(el_val_t modality) {
|
||||
return realizer_lookup(m) ? (el_val_t)1 : (el_val_t)0;
|
||||
}
|
||||
|
||||
/* transduce — THE primitive: signal in, geometry out.
|
||||
/* transduce — THE primitive: signal in, SUBGRAPH out.
|
||||
*
|
||||
* Dispatches to the realizer registered for `modality`. Returns 0 (not a
|
||||
* Geometry) when no realizer is registered, and geometry_is() on the result
|
||||
* is the check.
|
||||
* Manifold) when no realizer is registered, and manifold_is() on the result is
|
||||
* the check.
|
||||
*
|
||||
* THE RETURN TYPE IS THE CORRECTION. #144 shipped this as
|
||||
* `transduce(signal, modality) -> Geometry` — one vector out. That made
|
||||
* transduction a CONVERSION: take a thing, encode it, store a position. What
|
||||
* comes back from a conversion is a fingerprint, and a fingerprint supports
|
||||
* exactly two operations, match and rank. It cannot be decomposed, cannot have
|
||||
* one part grounded while another is not, and cannot be contradicted in a part
|
||||
* — it has no parts. Transduction is not conversion. It is DECOMPOSITION into
|
||||
* components plus the relations among them, and the relations are the content.
|
||||
* See the Manifold header above.
|
||||
*
|
||||
* There is deliberately NO built-in realizer, not even for text. A modality
|
||||
* the program has declared no organ for is one it genuinely cannot sense,
|
||||
* and returning nothing is more honest than quietly embedding a description
|
||||
* of the signal and calling that perception — which is the exact failure
|
||||
* this whole change exists to end.
|
||||
* the program has declared no organ for is one it genuinely cannot sense, and
|
||||
* returning nothing is more honest than quietly embedding a description of the
|
||||
* signal and calling that perception — the failure #144 named, and which a
|
||||
* single-vector return type quietly reintroduced one level down: a
|
||||
* one-vector-per-signal organ is a description of the signal, not a perception
|
||||
* of it.
|
||||
*
|
||||
* The result is validated to actually BE a Geometry before it is handed
|
||||
* back, so a realizer that returns something else transduced nothing rather
|
||||
* than handing a caller a value that will misbehave far from here. */
|
||||
* The result is validated to actually BE a Manifold before it is handed back.
|
||||
* A realizer still returning a bare Geometry — #144's contract — therefore
|
||||
* transduces NOTHING rather than handing back a value that decomposes to
|
||||
* nothing far from here. That is a deliberate hard failure, not an oversight:
|
||||
* "no organ" and "an organ that only fingerprints" must not look alike, which
|
||||
* is the same distinction realizer_register draws between an absent and a
|
||||
* broken organ. A realizer with genuinely one part says so with
|
||||
* manifold_single. */
|
||||
el_val_t transduce(el_val_t signal, el_val_t modality) {
|
||||
const char* m = EL_CSTR(modality);
|
||||
if (!m || !*m) return (el_val_t)0;
|
||||
el_realizer_fn fn = realizer_lookup(m);
|
||||
if (!fn) return (el_val_t)0;
|
||||
el_val_t g = fn(signal);
|
||||
return geom_of(g) ? g : (el_val_t)0;
|
||||
return mfld_of(g) ? g : (el_val_t)0;
|
||||
}
|
||||
|
||||
/* ── Batch 3: Engram in-process graph store ──────────────────────────────── */
|
||||
|
||||
+60
-10
@@ -625,20 +625,70 @@ el_val_t geometry_free(el_val_t g); /* 1 if freed, 0 if not a
|
||||
el_val_t geometry_from_f32le_hex(el_val_t hex); /* 0 on empty/odd-length/non-hex */
|
||||
el_val_t geometry_to_f32le_hex(el_val_t g); /* "" if not a Geometry */
|
||||
|
||||
/* ── Realizers + transduce ───────────────────────────────────────────────────
|
||||
* A REALIZER maps one modality into geometry. Registration is by NAME, so a
|
||||
* new modality never requires a runtime patch: every El `fn name(...)`
|
||||
* compiles to a global C symbol with that exact name, and the registry
|
||||
* resolves it with dlsym against the running binary — the same mechanism
|
||||
* http_set_handler already relies on.
|
||||
/* ── Manifold: the result of a transduction ──────────────────────────────────
|
||||
* A transduced signal is a SUBGRAPH — named components, each with its own
|
||||
* geometry, plus typed weighted relations among them — not a single vector.
|
||||
* One vector is a fingerprint: matchable, rankable, and nothing else. A song
|
||||
* decomposes into pitch, interval, rhythm, harmonic function; the song IS the
|
||||
* structure of those relations, and collapsing it to a point discards exactly
|
||||
* what made it reasonable-about. See el_runtime.c ("Manifold") for the full
|
||||
* rationale, the key-addressing rule, and the ownership contract.
|
||||
*
|
||||
* fn tone_realizer(signal: String) -> Geometry { ... }
|
||||
* Components are addressed BY KEY, never by index, because the key is what
|
||||
* survives persistence: a component becomes a node, and it is separately
|
||||
* groundable precisely because it is separately named. Relation weight IS the
|
||||
* grounding (correspondence-and-censorship.md §1) — one quantity, no separate
|
||||
* score, nothing computed on read.
|
||||
*
|
||||
* OWNERSHIP: a Manifold is owned by the El caller and released with
|
||||
* manifold_free, which also releases every component's geometry. manifold_add
|
||||
* COPIES the geometry it is given and manifold_geometry RETURNS a copy, so no
|
||||
* component's vector is ever aliased in either direction. */
|
||||
el_val_t manifold_new(void); /* empty; 0 on failure */
|
||||
el_val_t manifold_is(el_val_t m); /* 1 if a live Manifold */
|
||||
el_val_t manifold_add(el_val_t m, el_val_t key, el_val_t role, el_val_t g);
|
||||
/* component index, or -1 on empty/duplicate
|
||||
* key or a value that is not a Geometry */
|
||||
el_val_t manifold_relate(el_val_t m, el_val_t from, el_val_t rel,
|
||||
el_val_t to, el_val_t weight);
|
||||
/* 1 ok / 0 if either endpoint is unknown —
|
||||
* an unresolvable edge is REFUSED, never
|
||||
* silently dropped */
|
||||
el_val_t manifold_size(el_val_t m); /* component count */
|
||||
el_val_t manifold_rel_count(el_val_t m); /* relation count */
|
||||
el_val_t manifold_index_of(el_val_t m, el_val_t key); /* index by key, or -1 */
|
||||
el_val_t manifold_key(el_val_t m, el_val_t i); /* "" if out of range */
|
||||
el_val_t manifold_role(el_val_t m, el_val_t i); /* "" if out of range */
|
||||
el_val_t manifold_geometry(el_val_t m, el_val_t i); /* a COPY the caller frees */
|
||||
el_val_t manifold_rel_from(el_val_t m, el_val_t j); /* source component key */
|
||||
el_val_t manifold_rel_name(el_val_t m, el_val_t j); /* relation name */
|
||||
el_val_t manifold_rel_to(el_val_t m, el_val_t j); /* target component key */
|
||||
el_val_t manifold_rel_weight(el_val_t m, el_val_t j); /* Float — the grounding */
|
||||
el_val_t manifold_single(el_val_t key, el_val_t role, el_val_t g);
|
||||
/* the degenerate one-part case, expressible
|
||||
* but visibly a size-1 manifold rather than
|
||||
* a parallel path back to a bare vector */
|
||||
el_val_t manifold_free(el_val_t m); /* 1 if freed, 0 otherwise */
|
||||
|
||||
/* ── Realizers + transduce ───────────────────────────────────────────────────
|
||||
* A REALIZER DECOMPOSES one modality into components and relations. It does
|
||||
* not encode a signal to a point; that operation is one layer below and is
|
||||
* called geometry. Registration is by NAME, so a new modality never requires a
|
||||
* runtime patch: every El `fn name(...)` compiles to a global C symbol with
|
||||
* that exact name, and the registry resolves it with dlsym against the running
|
||||
* binary — the same mechanism http_set_handler already relies on.
|
||||
*
|
||||
* fn tone_realizer(signal: String) -> Manifold { ... }
|
||||
* realizer_register("tone", "tone_realizer")
|
||||
* let g: Geometry = transduce(sample, "tone")
|
||||
*/
|
||||
* let m: Manifold = transduce(sample, "tone")
|
||||
*
|
||||
* SUPERSEDES #144's `transduce -> Geometry`. A realizer that still returns a
|
||||
* bare Geometry now transduces NOTHING (transduce returns 0), deliberately: an
|
||||
* organ that only fingerprints must not be indistinguishable from a working
|
||||
* one. A modality with genuinely one part says so with manifold_single. */
|
||||
el_val_t realizer_register(el_val_t modality, el_val_t fn_name); /* 1 ok / 0 unresolved */
|
||||
el_val_t realizer_has(el_val_t modality); /* 1 if a realizer is registered */
|
||||
el_val_t transduce(el_val_t signal, el_val_t modality); /* Geometry, or 0 if no organ */
|
||||
el_val_t transduce(el_val_t signal, el_val_t modality); /* Manifold, or 0 if no organ */
|
||||
|
||||
/* ── Engram local graph primitives ───────────────────────────────────────────
|
||||
* Operate on the CGI's local Engram knowledge graph.
|
||||
|
||||
Reference in New Issue
Block a user