1*37da2899SCharles.Forsyth# fit a polynomial to a set of points 2*37da2899SCharles.Forsyth# fit -dn [-v] 3*37da2899SCharles.Forsyth# where n is the degree of the polynomial 4*37da2899SCharles.Forsyth 5*37da2899SCharles.Forsythimplement Fit; 6*37da2899SCharles.Forsyth 7*37da2899SCharles.Forsythinclude "sys.m"; 8*37da2899SCharles.Forsyth sys: Sys; 9*37da2899SCharles.Forsythinclude "draw.m"; 10*37da2899SCharles.Forsythinclude "math.m"; 11*37da2899SCharles.Forsyth maths: Math; 12*37da2899SCharles.Forsythinclude "bufio.m"; 13*37da2899SCharles.Forsyth bufio: Bufio; 14*37da2899SCharles.Forsythinclude "arg.m"; 15*37da2899SCharles.Forsyth 16*37da2899SCharles.ForsythFit: module 17*37da2899SCharles.Forsyth{ 18*37da2899SCharles.Forsyth init: fn(nil: ref Draw->Context, argv: list of string); 19*37da2899SCharles.Forsyth}; 20*37da2899SCharles.Forsyth 21*37da2899SCharles.ForsythMAXPTS: con 512; 22*37da2899SCharles.ForsythMAXDEG: con 16; 23*37da2899SCharles.ForsythEPS: con 0.0000005; 24*37da2899SCharles.Forsyth 25*37da2899SCharles.Forsythinit(nil: ref Draw->Context, argv: list of string) 26*37da2899SCharles.Forsyth{ 27*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 28*37da2899SCharles.Forsyth maths = load Math Math->PATH; 29*37da2899SCharles.Forsyth if(maths == nil) 30*37da2899SCharles.Forsyth fatal(sys->sprint("cannot load maths library")); 31*37da2899SCharles.Forsyth bufio = load Bufio Bufio->PATH; 32*37da2899SCharles.Forsyth if(bufio == nil) 33*37da2899SCharles.Forsyth fatal(sys->sprint("cannot load bufio")); 34*37da2899SCharles.Forsyth main(argv); 35*37da2899SCharles.Forsyth} 36*37da2899SCharles.Forsyth 37*37da2899SCharles.Forsythisn(r: real, n: int): int 38*37da2899SCharles.Forsyth{ 39*37da2899SCharles.Forsyth s := r - real n; 40*37da2899SCharles.Forsyth if(s < 0.0) 41*37da2899SCharles.Forsyth s = -s; 42*37da2899SCharles.Forsyth return s < EPS; 43*37da2899SCharles.Forsyth} 44*37da2899SCharles.Forsyth 45*37da2899SCharles.Forsythfact(n: int): real 46*37da2899SCharles.Forsyth{ 47*37da2899SCharles.Forsyth f := 1.0; 48*37da2899SCharles.Forsyth for(i := 1; i <= n; i++) 49*37da2899SCharles.Forsyth f *= real i; 50*37da2899SCharles.Forsyth return f; 51*37da2899SCharles.Forsyth} 52*37da2899SCharles.Forsyth 53*37da2899SCharles.Forsythcomb(n: int, r: int): real 54*37da2899SCharles.Forsyth{ 55*37da2899SCharles.Forsyth f := 1.0; 56*37da2899SCharles.Forsyth for(i := 0; i < r; i++) 57*37da2899SCharles.Forsyth f *= real (n-i); 58*37da2899SCharles.Forsyth return f/fact(r); 59*37da2899SCharles.Forsyth} 60*37da2899SCharles.Forsyth 61*37da2899SCharles.Forsythmatalloc(n: int): array of array of real 62*37da2899SCharles.Forsyth{ 63*37da2899SCharles.Forsyth mat := array[n] of array of real; 64*37da2899SCharles.Forsyth for(i := 0; i < n; i++) 65*37da2899SCharles.Forsyth mat[i] = array[n] of real; 66*37da2899SCharles.Forsyth return mat; 67*37da2899SCharles.Forsyth} 68*37da2899SCharles.Forsyth 69*37da2899SCharles.Forsythmatsalloc(n: int): array of array of array of real 70*37da2899SCharles.Forsyth{ 71*37da2899SCharles.Forsyth mats := array[n+1] of array of array of real; 72*37da2899SCharles.Forsyth for(i := 0; i <= n; i++) 73*37da2899SCharles.Forsyth mats[i] = matalloc(i); 74*37da2899SCharles.Forsyth return mats; 75*37da2899SCharles.Forsyth} 76*37da2899SCharles.Forsyth 77*37da2899SCharles.Forsythdet(mat: array of array of real, n: int, mats: array of array of array of real): real 78*37da2899SCharles.Forsyth{ 79*37da2899SCharles.Forsyth # easy cases first 80*37da2899SCharles.Forsyth if(n == 0) 81*37da2899SCharles.Forsyth return 1.0; 82*37da2899SCharles.Forsyth if(n == 1) 83*37da2899SCharles.Forsyth return mat[0][0]; 84*37da2899SCharles.Forsyth if(n == 2) 85*37da2899SCharles.Forsyth return mat[0][0]*mat[1][1]-mat[0][1]*mat[1][0]; 86*37da2899SCharles.Forsyth d := 0.0; 87*37da2899SCharles.Forsyth s := 1; 88*37da2899SCharles.Forsyth m := mats[n-1]; 89*37da2899SCharles.Forsyth for(k := 0; k < n; k++){ 90*37da2899SCharles.Forsyth for(i := 0; i < n-1; i++){ 91*37da2899SCharles.Forsyth for(j := 0; j < n-1; j++){ 92*37da2899SCharles.Forsyth if(j < k) 93*37da2899SCharles.Forsyth m[i][j] = mat[i+1][j]; 94*37da2899SCharles.Forsyth else 95*37da2899SCharles.Forsyth m[i][j] = mat[i+1][j+1]; 96*37da2899SCharles.Forsyth } 97*37da2899SCharles.Forsyth } 98*37da2899SCharles.Forsyth d += (real s)*mat[0][k]*det(m, n-1, mats); 99*37da2899SCharles.Forsyth s = -s; 100*37da2899SCharles.Forsyth } 101*37da2899SCharles.Forsyth return d; 102*37da2899SCharles.Forsyth} 103*37da2899SCharles.Forsyth 104*37da2899SCharles.Forsythmain(argv: list of string) 105*37da2899SCharles.Forsyth{ 106*37da2899SCharles.Forsyth i, j: int; 107*37da2899SCharles.Forsyth x, y, z: real; 108*37da2899SCharles.Forsyth fb: ref Bufio->Iobuf; 109*37da2899SCharles.Forsyth 110*37da2899SCharles.Forsyth n := 0; 111*37da2899SCharles.Forsyth p := 1; 112*37da2899SCharles.Forsyth arg := load Arg Arg->PATH; 113*37da2899SCharles.Forsyth if(arg == nil) 114*37da2899SCharles.Forsyth fatal(sys->sprint("cannot load %s: %r", Arg->PATH)); 115*37da2899SCharles.Forsyth arg->init(argv); 116*37da2899SCharles.Forsyth verbose := 0; 117*37da2899SCharles.Forsyth while((o := arg->opt()) != 0) 118*37da2899SCharles.Forsyth case o{ 119*37da2899SCharles.Forsyth 'd' => 120*37da2899SCharles.Forsyth p = int arg->arg(); 121*37da2899SCharles.Forsyth 'v' => 122*37da2899SCharles.Forsyth verbose = 1; 123*37da2899SCharles.Forsyth * => 124*37da2899SCharles.Forsyth fatal(sys->sprint("bad option %c", o)); 125*37da2899SCharles.Forsyth } 126*37da2899SCharles.Forsyth args := arg->argv(); 127*37da2899SCharles.Forsyth arg = nil; 128*37da2899SCharles.Forsyth if(args != nil){ 129*37da2899SCharles.Forsyth s := hd args; 130*37da2899SCharles.Forsyth fb = bufio->open(s, bufio->OREAD); 131*37da2899SCharles.Forsyth if(fb == nil) 132*37da2899SCharles.Forsyth fatal(sys->sprint("cannot open %s", s)); 133*37da2899SCharles.Forsyth } 134*37da2899SCharles.Forsyth else{ 135*37da2899SCharles.Forsyth fb = bufio->open("/dev/cons", bufio->OREAD); 136*37da2899SCharles.Forsyth if(fb == nil) 137*37da2899SCharles.Forsyth fatal(sys->sprint("missing data file name")); 138*37da2899SCharles.Forsyth } 139*37da2899SCharles.Forsyth a := array[p+1] of real; 140*37da2899SCharles.Forsyth b := array[p+1] of real; 141*37da2899SCharles.Forsyth sx := array[2*p+1] of real; 142*37da2899SCharles.Forsyth sxy := array[p+1] of real; 143*37da2899SCharles.Forsyth xd := array[MAXPTS] of real; 144*37da2899SCharles.Forsyth yd := array[MAXPTS] of real; 145*37da2899SCharles.Forsyth while(1){ 146*37da2899SCharles.Forsyth xs := ss(bufio->fb.gett(" \t\r\n")); 147*37da2899SCharles.Forsyth if(xs == nil) 148*37da2899SCharles.Forsyth break; 149*37da2899SCharles.Forsyth ys := ss(bufio->fb.gett(" \t\r\n")); 150*37da2899SCharles.Forsyth if(ys == nil) 151*37da2899SCharles.Forsyth fatal(sys->sprint("missing value")); 152*37da2899SCharles.Forsyth if(n >= MAXPTS) 153*37da2899SCharles.Forsyth fatal(sys->sprint("too many points")); 154*37da2899SCharles.Forsyth xd[n] = real xs; 155*37da2899SCharles.Forsyth yd[n] = real ys; 156*37da2899SCharles.Forsyth n++; 157*37da2899SCharles.Forsyth } 158*37da2899SCharles.Forsyth if(p < 0) 159*37da2899SCharles.Forsyth fatal(sys->sprint("negative power")); 160*37da2899SCharles.Forsyth if(p > MAXDEG) 161*37da2899SCharles.Forsyth fatal(sys->sprint("power too large")); 162*37da2899SCharles.Forsyth if(n < p+1) 163*37da2899SCharles.Forsyth fatal(sys->sprint("not enough points")); 164*37da2899SCharles.Forsyth # use x-xbar, y-ybar to avoid overflow 165*37da2899SCharles.Forsyth for(i = 0; i <= p; i++) 166*37da2899SCharles.Forsyth sxy[i] = 0.0; 167*37da2899SCharles.Forsyth for(i = 0; i <= 2*p; i++) 168*37da2899SCharles.Forsyth sx[i] = 0.0; 169*37da2899SCharles.Forsyth xbar := ybar := 0.0; 170*37da2899SCharles.Forsyth for(i = 0; i < n; i++){ 171*37da2899SCharles.Forsyth xbar += xd[i]; 172*37da2899SCharles.Forsyth ybar += yd[i]; 173*37da2899SCharles.Forsyth } 174*37da2899SCharles.Forsyth xbar = xbar/(real n); 175*37da2899SCharles.Forsyth ybar = ybar/(real n); 176*37da2899SCharles.Forsyth for(i = 0; i < n; i++){ 177*37da2899SCharles.Forsyth x = xd[i]-xbar; 178*37da2899SCharles.Forsyth y = yd[i]-ybar; 179*37da2899SCharles.Forsyth for(j = 0; j <= p; j++) 180*37da2899SCharles.Forsyth sxy[j] += y*x**j; 181*37da2899SCharles.Forsyth for(j = 0; j <= 2*p; j++) 182*37da2899SCharles.Forsyth sx[j] += x**j; 183*37da2899SCharles.Forsyth } 184*37da2899SCharles.Forsyth mats := matsalloc(p+1); 185*37da2899SCharles.Forsyth mat := mats[p+1]; 186*37da2899SCharles.Forsyth for(i = 0; i <= p; i++) 187*37da2899SCharles.Forsyth for(j = 0; j <= p; j++) 188*37da2899SCharles.Forsyth mat[i][j] = sx[i+j]; 189*37da2899SCharles.Forsyth d := det(mat, p+1, mats); 190*37da2899SCharles.Forsyth if(isn(d, 0)) 191*37da2899SCharles.Forsyth fatal(sys->sprint("points not independent")); 192*37da2899SCharles.Forsyth for(j = 0; j <= p; j++){ 193*37da2899SCharles.Forsyth for(i = 0; i <= p; i++) 194*37da2899SCharles.Forsyth mat[i][j] = sxy[i]; 195*37da2899SCharles.Forsyth a[j] = det(mat, p+1, mats)/d; 196*37da2899SCharles.Forsyth for(i = 0; i <= p; i++) 197*37da2899SCharles.Forsyth mat[i][j] = sx[i+j]; 198*37da2899SCharles.Forsyth } 199*37da2899SCharles.Forsyth if(verbose) 200*37da2899SCharles.Forsyth sys->print("\npt actual x actual y predicted y\n"); 201*37da2899SCharles.Forsyth e := 0.0; 202*37da2899SCharles.Forsyth for(i = 0; i < n; i++){ 203*37da2899SCharles.Forsyth x = xd[i]-xbar; 204*37da2899SCharles.Forsyth y = yd[i]-ybar; 205*37da2899SCharles.Forsyth z = 0.0; 206*37da2899SCharles.Forsyth for(j = 0; j <= p; j++) 207*37da2899SCharles.Forsyth z += a[j]*x**j; 208*37da2899SCharles.Forsyth z += ybar; 209*37da2899SCharles.Forsyth e += (z-yd[i])*(z-yd[i]); 210*37da2899SCharles.Forsyth if(verbose) 211*37da2899SCharles.Forsyth sys->print("%d. %f %f %f\n", i+1, xd[i], yd[i], z); 212*37da2899SCharles.Forsyth } 213*37da2899SCharles.Forsyth if(verbose) 214*37da2899SCharles.Forsyth sys->print("root mean squared error = %f\n", maths->sqrt(e/(real n))); 215*37da2899SCharles.Forsyth for(i = 0; i <= p; i++) 216*37da2899SCharles.Forsyth b[i] = 0.0; 217*37da2899SCharles.Forsyth b[0] += ybar; 218*37da2899SCharles.Forsyth for(i = 0; i <= p; i++) 219*37da2899SCharles.Forsyth for(j = 0; j <= i; j++) 220*37da2899SCharles.Forsyth b[j] += a[i]*comb(i, j)*(-xbar)**(i-j); 221*37da2899SCharles.Forsyth pr := 0; 222*37da2899SCharles.Forsyth sys->print("y = "); 223*37da2899SCharles.Forsyth for(i = p; i >= 0; i--){ 224*37da2899SCharles.Forsyth if(!isn(b[i], 0) || (i == 0 && pr == 0)){ 225*37da2899SCharles.Forsyth if(b[i] < 0.0){ 226*37da2899SCharles.Forsyth sys->print("-"); 227*37da2899SCharles.Forsyth b[i] = -b[i]; 228*37da2899SCharles.Forsyth } 229*37da2899SCharles.Forsyth else if(pr) 230*37da2899SCharles.Forsyth sys->print("+"); 231*37da2899SCharles.Forsyth pr = 1; 232*37da2899SCharles.Forsyth if(i == 0) 233*37da2899SCharles.Forsyth sys->print("%f", b[i]); 234*37da2899SCharles.Forsyth else{ 235*37da2899SCharles.Forsyth if(!isn(b[i], 1)) 236*37da2899SCharles.Forsyth sys->print("%f*", b[i]); 237*37da2899SCharles.Forsyth sys->print("x"); 238*37da2899SCharles.Forsyth if(i > 1) 239*37da2899SCharles.Forsyth sys->print("^%d", i); 240*37da2899SCharles.Forsyth } 241*37da2899SCharles.Forsyth } 242*37da2899SCharles.Forsyth } 243*37da2899SCharles.Forsyth sys->print("\n"); 244*37da2899SCharles.Forsyth} 245*37da2899SCharles.Forsyth 246*37da2899SCharles.Forsythss(s: string): string 247*37da2899SCharles.Forsyth{ 248*37da2899SCharles.Forsyth l := len s; 249*37da2899SCharles.Forsyth while(l > 0 && (s[0] == ' ' || s[0] == '\t' || s[0] == '\r' || s[0] == '\n')){ 250*37da2899SCharles.Forsyth s = s[1: ]; 251*37da2899SCharles.Forsyth l--; 252*37da2899SCharles.Forsyth } 253*37da2899SCharles.Forsyth while(l > 0 && (s[l-1] == ' ' || s[l-1] == '\t' || s[l-1] == '\r' || s[l-1] == '\n')){ 254*37da2899SCharles.Forsyth s = s[0: l-1]; 255*37da2899SCharles.Forsyth l--; 256*37da2899SCharles.Forsyth } 257*37da2899SCharles.Forsyth return s; 258*37da2899SCharles.Forsyth} 259*37da2899SCharles.Forsyth 260*37da2899SCharles.Forsythfatal(s: string) 261*37da2899SCharles.Forsyth{ 262*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "fit: %s\n", s); 263*37da2899SCharles.Forsyth exit; 264*37da2899SCharles.Forsyth} 265