Here's the source code. OpenGL graphics stuff is mixed in with maths stuff. The mathematical routines are findroots_inner (arguments given in findroots) and precalc (returns a set of algebraic numbers in the Point structure, x+iy is the value, o is the order of the polynomial that produced them and h is the complexity measure of the polynomial). LSet is just a container object (like Vector<Complex> or Vector<Point> in C++). I is the complex number i. frnd(x) produces a random double-precision number on the interval [0,x). Blocks with FILE *out=fopen(...)
are logfiles, can be removed if necessary.
#include <lset.c>
#include <rnd/frnd.c>
char nonconv; int fq[5001];
void findroots_inner(Complex *c,const unsigned o,LSet *pr)
{
Complex r;
if (o==1)
{
r=-c[0]/c[1];
LSet_add(pr,&r);
return;
}
int n; Complex f,d,p,or;
r=frnd(2)-1+I*(frnd(2)-1);
int i=0,j=0; // Complex h[1000];
do
{
if (j==500) {r=frnd(2)-1+I*(frnd(2)-1); j=0;} else j++;
if (i>=5000) {nonconv=1; break;}
/*{
FILE *out=fopen("5000iters.log","at");
fprintf(out,"-----\n");
//for (i=0;i<1000;i++) fprintf(out,"h[%d]=%lg+%lgi\n",i,h[i].re,h[i].im);
fclose(out);
break;
}*/
//else h[i]=r;
i++;
or=r; f=0; d=0; p=1;
for (n=0;n<o;n++,p*=r)
{
f+=p*c[n];
d+=p*c[n+1]*(n+1);
}
f+=p*c[o];
r-=f/d;
}
while (modsquared(r-or)>1e-20);
fq[i]++;
LSet_add(pr,&r);
for (n=o;n>0;n--) c[n-1]+=r*c[n];
for (n=0;n<o;n++) c[n]=c[n+1];
findroots_inner(c,o-1,pr);
}
Complex *findroots(Complex *c,const unsigned o)
{ // c[0] to c[o] are coeffs of 1 to x^o; c is destroyed, return value is created
LSet r=LSet(Complex);
findroots_inner(c,o,&r);
free(c);
return r.a;
}
#include <graphics.c>
#include <rnd/eithertime.c>
#include <rnd/sq.c>
#include <rnd/Mini.c>
GLuint othertex(const unsigned sz)
{
GLuint ret; glGenTextures(1,&ret);
glBindTexture(GL_TEXTURE_2D,ret);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
//aniso();
int n,x,y,xs=sz,ys=sz;
unsigned char *td=malloc(xs*ys*3); float f;
for (y=ys-1;y>=0;y--) for (x=xs-1;x>=0;x--)
{
n=(y*xs+x)*3;
f=sq((float)sz/2)/(1+sq((float)x-xs/2)+sq((float)y-ys/2));
td[n]=td[n+1]=td[n+2]=Mini(0xFF,f);
}
gluBuild2DMipmaps(GL_TEXTURE_2D,3,xs,ys,GL_RGB,GL_UNSIGNED_BYTE,td);
free(td);
return ret;
}
void putblob(const float x,const float y,const float r)
{
glTexCoord2f(1,1); glVertex2f(x+r*16,y+r*16);
glTexCoord2f(1,0); glVertex2f(x+r*16,y-r*16);
glTexCoord2f(0,0); glVertex2f(x-r*16,y-r*16);
glTexCoord2f(0,1); glVertex2f(x-r*16,y+r*16);
}
typedef struct {double x,y; int h,o;} Point;
LSet precalc(const int maxh)
{
LSet ret=LSet(Point); Point p;
int h,i,j,k,nz,l,sp;
for (i=0;i<=5000;i++) fq[i]=0;
int temps=0,eqns=0,roots=0;
for (h=2;h<=maxh;h++) // Complexity measure sum(|c_n|+1)
{
p.h=h;
int *t=malloc(h*sizeof(int));
for (i=(1<<(h-1))-1;i>=0;i-=2) // 2 step stops t[k-1] being zero
{
t[0]=0;
for (j=h-2,k=0;j>=0;j--)
if ((i>>j)&1) t[k]++; else {k++; t[k]=0;}
temps++;
if (k==0) continue; // k is the order
p.o=k;
//p.o=t[k];
nz=0;
for (j=k;j>=0;j--) if (t[j]!=0) nz++;
for (j=(1<<(nz-1))-1;j>=0;j--) // Signs loop
{
Complex *c=malloc((k+1)*sizeof(Complex));
for (l=k,sp=1;l>=0;l--)
if (t[l]==0 || l==k) c[l]=t[l];
else {c[l]=(j&sp?t[l]:-t[l]); sp<<=1;}
eqns++;
nonconv=0;
Complex *cc=malloc((k+1)*sizeof(Complex)); memcpy(cc,c,(k+1)*sizeof(Complex));
c=findroots(c,k);
if (!nonconv)
for (l=k-1;l>=0;l--)
{
roots++;
p.x=c[l].re; p.y=c[l].im;
LSet_add(&ret,&p);
}
else
{
FILE *out=fopen("nonconv.log","at");
for (l=k;l>=0;l--) fprintf(out,"%+lg*z^%d%s",cc[l].re,l,(l?"":"\n"));
fclose(out);
}
free(c);
free(cc);
}
}
free(t);
}
FILE *out=fopen("stats.txt","at");
fprintf(out,"temps=%d eqns=%d roots=%d\n",temps,eqns,roots);
fclose(out);
out=fopen("histoiters.csv","wt");
for (i=0;i<=5000;i++) fprintf(out,"%d,%d\n",i,fq[i]);
fclose(out);
return ret;
}
WINMAIN
{
int n; gl_ortho=1;
GRAPHICS(0,0,"Algebraic numbers [Stephen Brooks 2010]");
GLuint tex=othertex(256),list=0;
double ox=0,oy=0,zoom=yres/5,k1=0.125,k2=0.5;
SetCursorPos(xres/2,yres/2);
double ot=eithertime();
LSet ps=precalc(15);
LOOP
{
double dt=eithertime()-ot; ot=eithertime();
ox+=(mx-xres/2)/zoom; oy+=(my-yres/2)/zoom;
if (KEY(VK_O)) ox=oy=0;
SetCursorPos(xres/2,yres/2);
if (mb&1) zoom*=exp(dt*3); if (mb&2) zoom*=exp(-dt*3);
if (KHIT(VK_Z)) {k1*=1.3; glDeleteLists(list,1); list=0;}
if (KHIT(VK_X)) {k1/=1.3; glDeleteLists(list,1); list=0;}
if (KHIT(VK_C)) {k2+=0.05; glDeleteLists(list,1); list=0;}
if (KHIT(VK_V)) {k2-=0.05; glDeleteLists(list,1); list=0;}
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glScaled(zoom,zoom,zoom);
glTranslated((xres/2/zoom)-ox,(yres/2/zoom)-oy,0);
if (!list)
{
list=glGenLists(1); glNewList(list,GL_COMPILE_AND_EXECUTE);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ONE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,tex);
glBegin(GL_QUADS);
Point *p=ps.a;
for (n=ps.m-1;n>=0;n--)
{
switch (p[n].o)
{
case 1: glColor3f(1,0,0); break;
case 2: glColor3f(0,1,0); break;
case 3: glColor3f(0,0,1); break;
case 4: glColor3f(0.7,0.7,0); break;
case 5: glColor3f(1,0.6,0); break;
case 6: glColor3f(0,1,1); break;
case 7: glColor3f(1,0,1); break;
case 8: glColor3f(0.6,0.6,0.6); break;
default: glColor3f(1,1,1); break;
}
putblob(p[n].x,p[n].y,k1*pow(k2,p[n].h-3));
}
glEnd();
ot=eithertime();
glEndList();
}
else if (list) glCallList(list);
if (KEY(VK_L)) {glDeleteLists(list,1); list=0;}
if (KEY(VK_CONTROL) && KHIT(VK_S)) screenshotauto();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
ccl();
}
}