xref: /inferno-os/appl/math/fit.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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