\datethis @*Intro. This program, hacked from {\mc ACHAIN4}, finds all canonical addition chains of minimum length for a given integer. There are two command-line parameters. First is a file that contains values of $l(n)$, as output by the previous program. Then comes the desired integer $n$. @d nmax 10000000 /* should be less than $2^{24}$ on a 32-bit machine */ @c #include #include unsigned char l[nmax]; int a[128],b[128]; unsigned int undo[128*128]; int ptr; /* this many items of the |undo| stack are in use */ struct { int lbp,ubp,lbq,ubq,r,ptrp,ptrq; } stack[128]; int tail[128],outdeg[128],outsum[128],limit[128]; int down[nmax]; /* a navigation aid discussed below */ FILE *infile; main(int argc, char* argv[]) { register int i,j,n,p,q,r,s,ubp,ubq=0,lbp,lbq,ptrp,ptrq; int lb,nn; @; @; for (n=1;n<=nn;n++) { @; @; } @; } @ @= if (argc!=3) { fprintf(stderr,"Usage: %s infile n\n",argv[0]); exit(-1); } infile=fopen(argv[1],"r"); if (!infile) { fprintf(stderr,"I couldn't open `%s' for reading!\n",argv[1]); exit(-2); } if (sscanf(argv[2],"%d",&nn)!=1 || nn<3 || nn>=nmax) { fprintf(stderr,"The number `%s' was supposed to be between 3 and %d!\n", argv[2],nmax-1); exit(-3); } @ @= lb=fgetc(infile)-' '; /* |fgetc| will return a negative value after EOF */ if (lb<0 || (n>1 && lb>l[n-1]+1)) { fprintf(stderr,"Input file has the wrong value (%d) for l[%d]!\n",lb,n); exit(-4); } l[n]=lb; @*The interesting part. @= a[0]=b[0]=1, a[1]=b[1]=2; n=nn, lb=l[n]; for (i=0;i<=lb;i++) outdeg[i]=outsum[i]=0; a[lb]=b[lb]=n; for (i=2;i=2;i--) { if ((a[i]<<1)>1; if (b[i]>=b[i+1]) b[i]=b[i+1]-1; } @; @ One of the key operations we need is to increase |p| to the smallest element $p'>p$ that has $l[p']p$ that has $l[p']= { p++; if (l[p]==s) p=(down[p]>p? down[p]: nmax); } @ @=s|, increase |p| to the next element with |l[p]= do { if (down[p]>p) p=down[p]; else { p=nmax;@+break; } }@+while (l[p]>=s); @ @= for (n=1;n<=nn;n++) down[n]=n-1; @ I can't help exclaiming that this little algorithm is quite pretty. @= if (l[n]l[n];p=q) q=down[p], down[p]=n; down[n]=p; } @ @= ptr=0; /* clear the |undo| stack */ for (r=s=lb;s>2;s--) { if (outdeg[s]==1) limit[s]=a[s]-tail[outsum[s]];@+ else limit[s]=a[s]-1; /* the max feasible |p| */ if (limit[s]>b[s-1]) limit[s]=b[s-1]; @; while (p<=limit[s]) { @; ptrp=ptr; for (; ubp>=lbp; ubp--) { @; if (p==q) goto happiness; if (ubq>=ubp) ubq=ubp-1; ptrq=ptr; for (; ubq>=lbq; ubq--) { @; happiness: @; goto onward; /* now |a[s]| is covered; try to cover |a[s-1]| */ backup: s++; if (s>lb) goto impossible; @; if (p==q) goto failp; failq:@+ while (ptr>ptrq) @; } /* end loop on |ubq| */ failp:@+ while (ptr>ptrp) @; } /* end loop on |ubp| */ failpq: @; } /* end loop on |p| */ goto backup; onward: continue; } /* end loop on |s| */ @; goto backup; impossible:@; @ At this point we have |a[k]=b[k]| for all $r\le k\le|lb|$. @= if (a[s]&1) { /* necessarily |p!=q| */ unequal:@+if (outdeg[s-1]==0) q=a[s]/3;@+else q=a[s]>>1; if (q>b[s-2]) q=b[s-2]; p=a[s]-q; if (l[p]>=s) { @=s|,...@>; q=a[s]-p; } }@+else { p=q=a[s]>>1; if (l[p]>=s) goto unequal; /* a rare case like |l[191]=l[382]| */ } if (p>limit[s]) goto backup; for (;r>2&&a[r-1]==b[r-1];r--); if (p>b[r-1]) { /* now |ra[r]) r++; /* this step keeps |rb[r-2]) { if (a[r]<=a[s]-b[r-2]) p=a[r],q=b[s]-p; else q=b[r-2],p=a[s]-q; } @ @= if (p==q) { if (outdeg[s-1]==0) q=(a[s]/3)+1; /* will be decreased momentarily */ if (q>b[s-2]) q=b[s-2];@+ else q--; p=a[s]-q; if (l[p]>=s) { @=s|,...@>; q=a[s]-p; } }@+else { @; q=a[s]-p; } if (q>2) { if (a[s-1]==b[s-1]) { /* maybe |p| has to be present already */ doublecheck:@+while (pb[r-1]) { while (p>a[r]) r++; p=a[r],q=a[s]-p; /* possibly |r=s| now */ }@+else if (q>b[r-2]) { if (a[r]<=a[s]-b[r-2]) p=a[r],q=b[s]-p; else q=b[r-2],p=a[s]-q; } } if (ubq>=s) ubq=s-1; while (q>=a[ubq+1]) ubq++; while (qb[ubq]) { q=b[ubq],p=a[s]-q; if (a[s-1]==b[s-1]) goto doublecheck; } } @ @= tail[s]=q, stack[s].r=r; outdeg[ubp]++, outsum[ubp]+=s; outdeg[ubq]++, outsum[ubq]+=s; stack[s].lbp=lbp,stack[s].ubp=ubp; stack[s].lbq=lbq,stack[s].ubq=ubq; stack[s].ptrp=ptrp,stack[s].ptrq=ptrq; @ @= ptrq=stack[s].ptrq,ptrp=stack[s].ptrp; lbq=stack[s].lbq,ubq=stack[s].ubq; lbp=stack[s].lbp,ubp=stack[s].ubp; outdeg[ubq]--, outsum[ubq]-=s; outdeg[ubp]--, outsum[ubp]-=s; q=tail[s], p=a[s]-q, r=stack[s].r; @ After the test in this step is passed, we'll have |ubp>ubq| and |lbp>lbq|. @= if (l[p]>=s) goto failpq; lbp=l[p]; while (b[lbp]b[lbp-2]+b[lbp-1]) { if (++lbp>=s) goto failpq; } if (a[lbp]>p) goto failpq; for (ubp=lbp;a[ubp+1]<=p;ubp++); if (ubp==s-1) lbp=ubp; if (p==q) lbq=lbp,ubq=ubp; else { lbq=l[q]; if (lbq>=ubp) goto failpq; while (b[lbq]b[lbq-2]+b[lbq-1]) lbq++; if (lbq>=ubp) goto failpq; if (a[lbq]>q) goto failpq; if (lbp<=lbq) lbp=lbq+1; while ((q<<(lbp-lbq))ubp) goto failpq; } for (ubq=lbq;a[ubq+1]<=q && (q<<(ubp-ubq-1))>=p;ubq++); } @ The undoing mechanism is very simple: When changing |a[j]|, we put |(j<<24)+x| on the |undo| stack, where |x| was the former value. Similarly, when changing |b[j]|, we stack the value |(1<<31)+(j<<24)+x|. @d newa(j,y) undo[ptr++]=(j<<24)+a[j], a[j]=y @d newb(j,y) undo[ptr++]=(1<<31)+(j<<24)+b[j], b[j]=y @= { i=undo[--ptr]; if (i>=0) a[i>>24]=i&0xffffff; else b[(i&0x3fffffff)>>24]=i&0xffffff; } @ At this point we know that $a[ubp]\le p\le b[ubp]$. @= if (a[ubp]!=p) { newa(ubp,p); for (j=ubp-1;(a[j]<<1)>1; if (i>b[j]) goto failp; newa(j,i); } for (j=ubp+1;a[j]<=a[j-1];j++) { i=a[j-1]+1; if (i>b[j]) goto failp; newa(j,i); } } if (b[ubp]!=p) { newb(ubp,p); for (j=ubp-1;b[j]>=b[j+1];j--) { i=b[j+1]-1; if (ib[j-1]<<1;j++) { i=b[j-1]<<1; if (i; @ If, say, we've just set |a[8]=b[8]=132|, special considerations apply, because the only addition chains of length~8 for 132 are $$\eqalign{ &1,2,4,8,16,32,64,128,132;\cr &1,2,4,8,16,32,64,68,132;\cr &1,2,4,8,16,32,64,66,132;\cr &1,2,4,8,16,32,34,66,132;\cr &1,2,4,8,16,32,33,66,132;\cr &1,2,4,8,16,17,33,66,132.\cr}$$ The values of |a[4]| and |b[4]| must therefore be 16; and then, of course, we also must have |a[3]=b[3]=8|, etc. Similar reasoning applies whenever we set $a[j]=b[j]=2^j+2^k$ for $k\le j-4$. Such cases may seem extremely special. But my hunch is that they are important, because efficient chains need such values. When we try to prove that no efficient chain exists, we want to show that such values can't be present. Numbers with small |l[p]| are harder to rule out, so it should be helpful to penalize them. @= i=p-(1<<(ubp-1)); if (i && ((i&(i-1))==0) && (i<<4)>=1,j--); if (b[j]<(1<= if (a[ubq]!=q) { if (a[ubq]>q) goto failq; newa(ubq,q); for (j=ubq-1;(a[j]<<1)>1; if (i>b[j]) goto failq; newa(j,i); } for (j=ubq+1;a[j]<=a[j-1];j++) { i=a[j-1]+1; if (i>b[j]) goto failq; newa(j,i); } } if (b[ubq]!=q) { if (b[ubq]=b[j+1];j--) { i=b[j+1]-1; if (ib[j-1]<<1;j++) { i=b[j-1]<<1; if (i; @ @= i=q-(1<<(ubq-1)); if (i && ((i&(i-1))==0) && (i<<4)>=1,j--); if (b[j]<(1<= for (j=0;j<=lb;j++) printf(" %d",a[j]); printf("\n"); @*Index.