/* test_geometry.c — build + RUN gate for the M9 FOUNDATION geometry descriptor * (engram_geometry.{c,h}). Self-contained: synthesizes a store with two KNOWN * embedding clusters + intra-cluster hebb edges, then verifies the descriptor * recovers the shape — centroid near the seeded cluster, skeleton = the strong * intra-cluster edges, membership gradient, radius, positive co-registration. * * Pure C11; links engram_geometry.c + engram_store.c + engram_vindex.c; -lm. * ASan/UBSan clean. Needs no live data. */ #include "engram_geometry.h" #include "engram_store.h" #include "engram_vindex.h" #include #include #include #include #include #include #define DIM 64 static int g_fail=0; #define CHECK(c,m) do{ if(!(c)){printf(" FAIL: %s\n",m); g_fail=1;} else printf(" ok: %s\n",m);}while(0) static uint64_t rs=0x1234abcdULL; static uint64_t xr(void){ uint64_t z=(rs+=0x9E3779B97F4A7C15ULL); z=(z^(z>>30))*0xBF58476D1CE4E5B9ULL; z=(z^(z>>27))*0x94D049BB133111EBULL; return z^(z>>31); } static float jitter(void){ return (float)(((double)(xr()>>11)*(1.0/9007199254740992.0))-0.5)*0.15f; } /* two clusters: A centered on axis 0, B centered on axis 1. NA+NB nodes. */ #define NA 40 #define NB 40 int main(void){ printf("=== engram_geometry (M9 foundation) test suite ===\n"); char path[256]; snprintf(path,sizeof path,"/tmp/geo_test_store_%d.egm",(int)getpid()); unlink(path); EngramPagedStore* st=store_create(path); if(!st){ printf("FAIL: store_create\n"); return 1; } char aids[NA][16], bids[NB][16]; /* cluster A: near +e0 ; cluster B: near +e1 */ for(int i=0;iB0 */ int ei=0; for(int i=1;i expect an A-dominated neighborhood */ st=store_open(path); const char* seeds[1]={aids[0]}; GeoDescriptor* g=engram_geometry_descriptor(st, ix, ids, nids, seeds, 1, &P); CHECK(g!=NULL, "descriptor computed"); if(g){ printf(" members=%d embedded=%d edges=%d k_core=%d radius=%.4f co_reg=%.3f n_axes=%d\n", g->n_members,g->n_embedded,g->n_edges,g->k_core,g->radius,g->co_registration,g->n_axes); /* centroid near cluster-A center (+e0): centroid[0] should dominate */ int argmax=0; for(int d=1;ddim;d++) if(fabsf(g->centroid[d])>fabsf(g->centroid[argmax])) argmax=d; printf(" centroid dominant axis = %d (expect 0), centroid[0]=%.3f centroid[1]=%.3f\n", argmax, g->centroid[0], g->centroid[1]); CHECK(argmax==0, "centroid sits on cluster-A's axis (near members)"); /* hub should be A0 (the intra-A hub with NA-1 strong edges) */ CHECK(g->hub_id && strcmp(g->hub_id,"A0")==0, "hub = the relational center A0"); /* membership: seed A0 == 1.0; A-members strong, B-members (if any) weaker */ double seedw=-1, minA=2, maxB=-1; int na=0,nb=0; for(int i=0;in_members;i++){ const char* id=g->members[i].id; double w=g->members[i].membership; if(strcmp(id,"A0")==0) seedw=w; if(id[0]=='A'){ na++; if(wmaxB)maxB=w; } } printf(" A-members=%d B-members=%d seedw=%.3f\n", na,nb,seedw); CHECK(fabs(seedw-1.0)<1e-9, "seed membership == 1.0"); CHECK(na>=NA-1, "neighborhood recovers cluster A"); /* skeleton = the strong intra-A edges: every edge eff_weight>=threshold, * and edges connect A-nodes (co-registration should be positive: wired * pairs are semantically near). */ int allstrong=1, allA=1; for(int e=0;en_edges;e++){ if(g->edges[e].eff_weight < P.edge_min_weight) allstrong=0; const char* a=g->members[g->edges[e].a].id, *b=g->members[g->edges[e].b].id; if(!(a[0]=='A'&&b[0]=='A')) { /* the lone eX cross edge is allowed */ if(!((strcmp(a,"A0")==0&&strcmp(b,"B0")==0)||(strcmp(a,"B0")==0&&strcmp(b,"A0")==0))) allA=0; } } CHECK(allstrong, "skeleton holds only above-threshold (strong) edges"); CHECK(allA, "skeleton backbone is the intra-cluster wiring"); CHECK(g->co_registration>0.0, "co-registration positive (wired pairs are semantically near)"); /* principal axes: extents strictly non-increasing */ int mono=1; for(int i=1;in_axes;i++) if(g->axes[i].extent>g->axes[i-1].extent+1e-9) mono=0; CHECK(g->n_axes>0 && mono, "principal axes sorted by descending extent"); CHECK(g->radius>0, "radius positive"); } engram_geo_free(g); /* edge cases: NULL store, no seeds, relational-only (NULL vindex) */ CHECK(engram_geometry_descriptor(NULL,ix,ids,nids,seeds,1,&P)==NULL, "NULL store -> NULL"); CHECK(engram_geometry_descriptor(st,ix,ids,nids,seeds,0,&P)==NULL, "zero seeds -> NULL"); GeoDescriptor* g2=engram_geometry_descriptor(st, NULL, NULL, 0, seeds, 1, &P); CHECK(g2!=NULL && g2->n_members>=NA-1, "relational-only path (no vindex) works"); engram_geo_free(g2); for(int i=0;i