added depend label
[unix-history] / usr / src / usr.bin / spline / spline.c
CommitLineData
ef461b9e 1#ifndef lint
907f31c6 2static char *sccsid = "@(#)spline.c 4.4 (Berkeley) %G%";
ef461b9e
SL
3#endif
4
365384c2 5#include <stdio.h>
762ee6b6 6#include <math.h>
365384c2
BJ
7
8#define NP 1000
762ee6b6 9#define INF HUGE
365384c2
BJ
10
11struct proj { int lbf,ubf; float a,b,lb,ub,quant,mult,val[NP]; } x,y;
12float *diag, *r;
13float dx = 1.;
14float ni = 100.;
15int n;
16int auta;
17int periodic;
18float konst = 0.0;
19float zero = 0.;
20
21/* Spline fit technique
22let x,y be vectors of abscissas and ordinates
ef461b9e 23 h be vector of differences hi=xi-xi-1
365384c2
BJ
24 y" be vector of 2nd derivs of approx function
25If the points are numbered 0,1,2,...,n+1 then y" satisfies
26(R W Hamming, Numerical Methods for Engineers and Scientists,
272nd Ed, p349ff)
ef461b9e 28 hiy"i-1+2(hi+hi+1)y"i+hi+1y"i+1
365384c2 29
ef461b9e 30 = 6[(yi+1-yi)/hi+1-(yi-yi-1)/hi] i=1,2,...,n
365384c2 31
ef461b9e 32where y"0 = y"n+1 = 0
365384c2
BJ
33This is a symmetric tridiagonal system of the form
34
ef461b9e
SL
35 | a1 h2 | |y"1| |b1|
36 | h2 a2 h3 | |y"2| |b2|
37 | h3 a3 h4 | |y"3| = |b3|
365384c2
BJ
38 | . | | .| | .|
39 | . | | .| | .|
40It can be triangularized into
ef461b9e
SL
41 | d1 h2 | |y"1| |r1|
42 | d2 h3 | |y"2| |r2|
43 | d3 h4 | |y"3| = |r3|
365384c2
BJ
44 | . | | .| | .|
45 | . | | .| | .|
46where
ef461b9e 47 d1 = a1
365384c2 48
ef461b9e 49 r0 = 0
365384c2 50
ef461b9e 51 di = ai - hi2/di-1 1<i<_n
365384c2 52
907f31c6 53 ri = bi - hiri-1/di-1i 1<_i<_n
365384c2
BJ
54
55the back solution is
ef461b9e 56 y"n = rn/dn
365384c2 57
ef461b9e 58 y"i = (ri-hi+1y"i+1)/di 1<_i<n
365384c2 59
ef461b9e 60superficially, di and ri don't have to be stored for they can be
365384c2
BJ
61recalculated backward by the formulas
62
ef461b9e 63 di-1 = hi2/(ai-di) 1<i<_n
365384c2 64
ef461b9e 65 ri-1 = (bi-ri)di-1/hi 1<i<_n
365384c2
BJ
66
67unhappily it turns out that the recursion forward for d
68is quite strongly geometrically convergent--and is wildly
69unstable going backward.
70There's similar trouble with r, so the intermediate
71results must be kept.
72
73Note that n-1 in the program below plays the role of n+1 in the theory
74
ef461b9e 75Other boundary conditions_________________________
365384c2
BJ
76
77The boundary conditions are easily generalized to handle
78
ef461b9e 79 y0" = ky1", yn+1" = kyn"
365384c2
BJ
80
81for some constant k. The above analysis was for k = 0;
82k = 1 fits parabolas perfectly as well as stright lines;
83k = 1/2 has been recommended as somehow pleasant.
84
ef461b9e 85All that is necessary is to add h1 to a1 and hn+1 to an.
365384c2
BJ
86
87
ef461b9e 88Periodic case_____________
365384c2
BJ
89
90To do this, add 1 more row and column thus
91
ef461b9e
SL
92 | a1 h2 h1 | |y1"| |b1|
93 | h2 a2 h3 | |y2"| |b2|
94 | h3 a4 h4 | |y3"| |b3|
365384c2
BJ
95 | | | .| = | .|
96 | . | | .| | .|
ef461b9e 97 | h1 h0 a0 | | .| | .|
365384c2 98
ef461b9e 99where h0=_ hn+1
365384c2
BJ
100
101The same diagonalization procedure works, except for
ef461b9e
SL
102the effect of the 2 corner elements. Let si be the part
103of the last element in the ith "diagonalized" row that
365384c2
BJ
104arises from the extra top corner element.
105
ef461b9e 106 s1 = h1
365384c2 107
ef461b9e 108 si = -si-1hi/di-1 2<_i<_n+1
365384c2
BJ
109
110After "diagonalizing", the lower corner element remains.
ef461b9e 111Call ti the bottom element that appears in the ith colomn
365384c2
BJ
112as the bottom element to its left is eliminated
113
ef461b9e 114 t1 = h1
365384c2 115
ef461b9e 116 ti = -ti-1hi/di-1
365384c2 117
ef461b9e 118Evidently ti = si.
365384c2
BJ
119Elimination along the bottom row
120introduces further corrections to the bottom right element
121and to the last element of the right hand side.
122Call these corrections u and v.
123
ef461b9e 124 u1 = v1 = 0
365384c2 125
ef461b9e 126 ui = ui-1-si-1*ti-1/di-1
365384c2 127
ef461b9e 128 vi = vi-1-ri-1*ti-1/di-1 2<_i<_n+1
365384c2
BJ
129
130The back solution is now obtained as follows
131
ef461b9e 132 y"n+1 = (rn+1+vn+1)/(dn+1+sn+1+tn+1+un+1)
365384c2 133
ef461b9e 134 y"i = (ri-hi+1*yi+1-si*yn+1)/di 1<_i<_n
365384c2 135
ef461b9e 136Interpolation in the interval xi<_x<_xi+1 is by the formula
365384c2 137
ef461b9e 138 y = yix+ + yi+1x- -(h2i+1/6)[y"i(x+-x+3)+y"i+1(x--x-3)]
365384c2 139where
ef461b9e 140 x+ = xi+1-x
365384c2 141
ef461b9e 142 x- = x-xi
365384c2
BJ
143*/
144
145float
146rhs(i){
147 int i_;
148 double zz;
149 i_ = i==n-1?0:i;
150 zz = (y.val[i]-y.val[i-1])/(x.val[i]-x.val[i-1]);
151 return(6*((y.val[i_+1]-y.val[i_])/(x.val[i+1]-x.val[i]) - zz));
152}
153
154spline(){
155 float d,s,u,v,hi,hi1;
156 float h;
157 float D2yi,D2yi1,D2yn1,x0,x1,yy,a;
158 int end;
159 float corr;
160 int i,j,m;
161 if(n<3) return(0);
162 if(periodic) konst = 0;
163 d = 1;
164 r[0] = 0;
165 s = periodic?-1:0;
166 for(i=0;++i<n-!periodic;){ /* triangularize */
167 hi = x.val[i]-x.val[i-1];
168 hi1 = i==n-1?x.val[1]-x.val[0]:
169 x.val[i+1]-x.val[i];
170 if(hi1*hi<=0) return(0);
171 u = i==1?zero:u-s*s/d;
172 v = i==1?zero:v-s*r[i-1]/d;
173 r[i] = rhs(i)-hi*r[i-1]/d;
174 s = -hi*s/d;
175 a = 2*(hi+hi1);
176 if(i==1) a += konst*hi;
177 if(i==n-2) a += konst*hi1;
178 diag[i] = d = i==1? a:
179 a - hi*hi/d;
180 }
181 D2yi = D2yn1 = 0;
182 for(i=n-!periodic;--i>=0;){ /* back substitute */
183 end = i==n-1;
184 hi1 = end?x.val[1]-x.val[0]:
185 x.val[i+1]-x.val[i];
186 D2yi1 = D2yi;
187 if(i>0){
188 hi = x.val[i]-x.val[i-1];
189 corr = end?2*s+u:zero;
190 D2yi = (end*v+r[i]-hi1*D2yi1-s*D2yn1)/
191 (diag[i]+corr);
192 if(end) D2yn1 = D2yi;
193 if(i>1){
194 a = 2*(hi+hi1);
195 if(i==1) a += konst*hi;
196 if(i==n-2) a += konst*hi1;
197 d = diag[i-1];
198 s = -s*d/hi;
199 }}
200 else D2yi = D2yn1;
201 if(!periodic) {
202 if(i==0) D2yi = konst*D2yi1;
203 if(i==n-2) D2yi1 = konst*D2yi;
204 }
205 if(end) continue;
206 m = hi1>0?ni:-ni;
207 m = 1.001*m*hi1/(x.ub-x.lb);
208 if(m<=0) m = 1;
209 h = hi1/m;
210 for(j=m;j>0||i==0&&j==0;j--){ /* interpolate */
211 x0 = (m-j)*h/hi1;
212 x1 = j*h/hi1;
213 yy = D2yi*(x0-x0*x0*x0)+D2yi1*(x1-x1*x1*x1);
214 yy = y.val[i]*x0+y.val[i+1]*x1 -hi1*hi1*yy/6;
215 printf("%f ",x.val[i]+j*h);
216 printf("%f\n",yy);
217 }
218 }
219 return(1);
220 }
221readin() {
222 for(n=0;n<NP;n++){
223 if(auta) x.val[n] = n*dx+x.lb;
224 else if(!getfloat(&x.val[n])) break;
225 if(!getfloat(&y.val[n])) break; } }
226
227getfloat(p)
228 float *p;{
229 char buf[30];
230 register c;
231 int i;
232 extern double atof();
233 for(;;){
234 c = getchar();
235 if (c==EOF) {
236 *buf = '\0';
237 return(0);
238 }
239 *buf = c;
240 switch(*buf){
241 case ' ':
242 case '\t':
243 case '\n':
244 continue;}
245 break;}
246 for(i=1;i<30;i++){
247 c = getchar();
248 if (c==EOF) {
249 buf[i] = '\0';
250 break;
251 }
252 buf[i] = c;
253 if('0'<=c && c<='9') continue;
254 switch(c) {
255 case '.':
256 case '+':
257 case '-':
258 case 'E':
259 case 'e':
260 continue;}
261 break; }
262 buf[i] = ' ';
263 *p = atof(buf);
264 return(1); }
265
266getlim(p)
267 struct proj *p; {
268 int i;
269 for(i=0;i<n;i++) {
270 if(!p->lbf && p->lb>(p->val[i])) p->lb = p->val[i];
271 if(!p->ubf && p->ub<(p->val[i])) p->ub = p->val[i]; }
272 }
273
274
275main(argc,argv)
276 char *argv[];{
277 extern char *malloc();
278 int i;
279 x.lbf = x.ubf = y.lbf = y.ubf = 0;
280 x.lb = INF;
281 x.ub = -INF;
282 y.lb = INF;
283 y.ub = -INF;
284 while(--argc > 0) {
285 argv++;
286again: switch(argv[0][0]) {
287 case '-':
288 argv[0]++;
289 goto again;
290 case 'a':
291 auta = 1;
292 numb(&dx,&argc,&argv);
293 break;
294 case 'k':
295 numb(&konst,&argc,&argv);
296 break;
297 case 'n':
298 numb(&ni,&argc,&argv);
299 break;
300 case 'p':
301 periodic = 1;
302 break;
303 case 'x':
304 if(!numb(&x.lb,&argc,&argv)) break;
305 x.lbf = 1;
306 if(!numb(&x.ub,&argc,&argv)) break;
307 x.ubf = 1;
308 break;
309 default:
310 fprintf(stderr, "Bad agrument\n");
311 exit(1);
312 }
313 }
314 if(auta&&!x.lbf) x.lb = 0;
315 readin();
316 getlim(&x);
317 getlim(&y);
318 i = (n+1)*sizeof(dx);
319 diag = (float *)malloc((unsigned)i);
320 r = (float *)malloc((unsigned)i);
321 if(r==NULL||!spline()) for(i=0;i<n;i++){
322 printf("%f ",x.val[i]);
323 printf("%f\n",y.val[i]); }
324}
325numb(np,argcp,argvp)
326 int *argcp;
327 float *np;
328 char ***argvp;{
329 double atof();
330 char c;
331 if(*argcp<=1) return(0);
332 c = (*argvp)[1][0];
333 if(!('0'<=c&&c<='9' || c=='-' || c== '.' )) return(0);
334 *np = atof((*argvp)[1]);
335 (*argcp)--;
336 (*argvp)++;
337 return(1); }