ipf.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. {
  2. This file is part of the Numlib package.
  3. Copyright (c) 1986-2000 by
  4. Kees van Ginneken, Wil Kortsmit and Loek van Reij of the
  5. Computational centre of the Eindhoven University of Technology
  6. FPC port Code by Marco van de Voort ([email protected])
  7. documentation by Michael van Canneyt ([email protected])
  8. Interpolate and (curve) fitting.
  9. Slegpb in this unit patched parameters slightly. Units IPF and sle
  10. were not in the same revision in this numlib copy (which was a
  11. copy of the work directory of the author) .
  12. Contains two undocumented functions. If you recognize the algoritm,
  13. mail us.
  14. See the file COPYING.FPC, included in this distribution,
  15. for details about the copyright.
  16. This program is distributed in the hope that it will be useful,
  17. but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  19. **********************************************************************}
  20. {
  21. }
  22. unit ipf;
  23. {$I direct.inc}
  24. interface
  25. uses typ, mdt, dsl, sle, spe;
  26. { Determine natural cubic spline "s" for data set (x,y), output to (a,d2a)
  27. term=1 success,
  28. =2 failure calculating "s"
  29. =3 wrong input (e.g. x,y is not sorted increasing on x)}
  30. procedure ipffsn(n: ArbInt; var x, y, a, d2a: ArbFloat; var term: ArbInt);
  31. {calculate d2s from x,y, which can be used to calculate s}
  32. procedure ipfisn(n: ArbInt; var x, y, d2s: ArbFloat; var term: ArbInt);
  33. {Calculate function value for dataset (x,y), with n.c. spline d2s for
  34. x value t. Return (corrected) y value.
  35. s calculated from x,y, with e.g. ipfisn}
  36. function ipfspn(n: ArbInt; var x, y, d2s: ArbFloat; t: ArbFloat;
  37. var term: ArbInt): ArbFloat;
  38. {Calculate n-degree polynomal b for dataset (x,y) with n elements
  39. using the least squares method.}
  40. procedure ipfpol(m, n: ArbInt; var x, y, b: ArbFloat; var term: ArbInt);
  41. {**** undocumented ****}
  42. function spline( n : ArbInt;
  43. x : complex;
  44. var ac : complex;
  45. var gammar: ArbFloat;
  46. u1 : ArbFloat;
  47. pf : complex): ArbFloat;
  48. {**** undocumented ****}
  49. procedure splineparameters
  50. ( n : ArbInt;
  51. var ac, alfadc : complex;
  52. var lambda,
  53. gammar, u1,
  54. kwsom, energie : ArbFloat;
  55. var pf : complex);
  56. implementation
  57. procedure ipffsn(n: ArbInt; var x, y, a, d2a: ArbFloat; var term: ArbInt);
  58. var i, j, sr, n1s, ns1, ns2: ArbInt;
  59. s, lam, lam0, lam1, lambda, ey, ca, p, q, r: ArbFloat;
  60. px, py, pd, pa, pd2a,
  61. h, z, diagb, dinv, qty, qtdinvq, c, t, tl: ^arfloat1;
  62. ub: boolean;
  63. procedure solve; {n, py, qty, h, qtdinvq, dinv, lam, t, pa, pd2a, term}
  64. var i: ArbInt;
  65. p, q, r, ca: ArbFloat;
  66. f, c: ^arfloat1;
  67. begin
  68. getmem(f, 3*ns1); getmem(c, ns1);
  69. for i:=1 to n-1 do
  70. begin
  71. f^[3*i]:=qtdinvq^[3*i]+lam*t^[2*i];
  72. if i > 1
  73. then
  74. f^[3*i-1]:=qtdinvq^[3*i-1]+lam*t^[2*i-1];
  75. if i > 2
  76. then
  77. f^[3*i-2]:=qtdinvq^[3*i-2];
  78. if lam=0
  79. then
  80. c^[i]:=qty^[i]
  81. else
  82. c^[i]:=lam*qty^[i]
  83. end;
  84. slegpb(n-1, 2,{ 3,} f^[1], c^[1], pd2a^[1], ca, term);
  85. if term=2
  86. then
  87. begin
  88. freemem(f, 3*ns1); freemem(c, ns1);
  89. exit
  90. end;
  91. p:=1/h^[1];
  92. if lam=0
  93. then
  94. r:=1
  95. else
  96. r:=1/lam;
  97. q:=1/h^[2]; pa^[1]:=py^[1]-r*dinv^[1]*p*pd2a^[1];
  98. pa^[2]:=py^[2]-r*dinv^[2]*(pd2a^[2]*q-(p+q)*pd2a^[1]); p:=q;
  99. for i:=3 to n-1 do
  100. begin
  101. q:=1/h^[i];
  102. pa^[i]:=py^[i]-r*dinv^[i]*
  103. (p*pd2a^[i-2]-(p+q)*pd2a^[i-1]+q*pd2a^[i]);
  104. p:=q
  105. end;
  106. q:=1/h^[n];
  107. pa^[n]:=py^[n]-r*dinv^[n]*(p*pd2a^[n-2]-(p+q)*pd2a^[n-1]);
  108. pa^[n+1]:=py^[n+1]-r*dinv^[n+1]*q*pd2a^[n-1];
  109. if lam=0
  110. then
  111. for i:=1 to n-1 do
  112. pd2a^[i]:=0;
  113. freemem(f, 3*ns1); freemem(c, ns1);
  114. end; {solve}
  115. function e(var c, h: ArbFloat; n:ArbInt): ArbFloat;
  116. var i:ArbInt;
  117. s:ArbFloat;
  118. pc, ph: ^arfloat1;
  119. begin
  120. ph:=@h; pc:=@c;
  121. s:=ph^[1]*pc^[1]*pc^[1];
  122. for i:=1 to n-2 do
  123. s:=s+(pc^[i]*(pc^[i]+pc^[i+1])+pc^[i+1]*pc^[i+1])*ph^[i+1];
  124. e:=(s+pc^[n-1]*pc^[n-1]*ph^[n])/3
  125. end; {e}
  126. function cr(lambda: ArbFloat): ArbFloat;
  127. var s, crs: ArbFloat;
  128. i: ArbInt;
  129. begin
  130. cr:=0; lam:=lambda;
  131. solve; { n, py, qty, h, qtdinvq, dinv, lam, t, pa, pd2a, term }
  132. if term=2
  133. then
  134. exit;
  135. crs:=ey;
  136. if lam <> 0
  137. then
  138. begin
  139. crs:=crs+e(pd2a^[1], h^[1], n);
  140. s:=0;
  141. for i:=1 to n-1 do
  142. s:=s+pd2a^[i]*qty^[i];
  143. crs:=crs-2*s
  144. end;
  145. s:=0;
  146. for i:=1 to n+1 do
  147. s:=s+sqr(pa^[i]-py^[i])*diagb^[i];
  148. cr:=crs-s
  149. end; {cr}
  150. procedure roof1r(a, b, ae, re: ArbFloat; var x: ArbFloat);
  151. var fa, fb, c, fc, m, tol, w1, w2 : ArbFloat;
  152. k : ArbInt;
  153. stop : boolean;
  154. begin
  155. fa:=cr(a);
  156. if term=2
  157. then
  158. exit;
  159. fb:=cr(b);
  160. if term=2
  161. then
  162. exit;
  163. if abs(fb)>abs(fa)
  164. then
  165. begin
  166. c:=b; fc:=fb; x:=a; b:=a; fb:=fa; a:=c; fa:=fc
  167. end
  168. else
  169. begin
  170. c:=a; fc:=fa; x:=b
  171. end;
  172. k:=0;
  173. tol:=ae+re*spemax(abs(a), abs(b));
  174. w1:=abs(b-a); stop:=false;
  175. while (abs(b-a)>tol) and (fb<>0) and (not stop) do
  176. begin
  177. m:=(a+b)/2;
  178. if (k>=2) or (fb=fc)
  179. then
  180. x:=m
  181. else
  182. begin
  183. x:=(b*fc-c*fb)/(fc-fb);
  184. if abs(b-x)<tol
  185. then
  186. x:=b-tol*spesgn(b-a);
  187. if spesgn(x-m)=spesgn(x-b)
  188. then
  189. x:=m
  190. end;
  191. c:=b; fc:=fb; b:=x; fb:=cr(x);
  192. if term=2
  193. then
  194. exit;
  195. if spesgn(fa)*spesgn(fb)>0
  196. then
  197. begin
  198. a:=c; fa:=fc; k:=0
  199. end
  200. else
  201. k:=k+1;
  202. if abs(fb)>=abs(fa)
  203. then
  204. begin
  205. c:=b; fc:=fb; x:=a; b:=a; fb:=fa; a:=c; fa:=fc; k:=0
  206. end;
  207. tol:=ae+re*spemax(abs(a), abs(b));
  208. w2:=abs(b-a);
  209. if w2>=w1
  210. then
  211. stop:=true;
  212. w1:=w2
  213. end
  214. end; {roof1r}
  215. procedure NoodGreep;
  216. var I, j: ArbInt;
  217. begin
  218. i:=1;
  219. while i <= n do
  220. begin
  221. if (pd^[i] <= 0) or (px^[i+1] <= px^[i])
  222. then
  223. begin
  224. term:=3;
  225. exit
  226. end;
  227. i:=i+1
  228. end;
  229. if pd^[n+1] <= 0
  230. then
  231. begin
  232. term:=3;
  233. exit
  234. end;
  235. for i:=1 to n+1 do
  236. dinv^[i]:=1/pd^[i];
  237. for i:=1 to n do
  238. h^[i]:=px^[i+1]-px^[i];
  239. t^[2]:=(h^[1]+h^[2])/3;
  240. for i:=2 to n-1 do
  241. begin
  242. t^[2*i]:=(h^[i]+h^[i+1])/3; t^[2*i-1]:=h^[i]/6
  243. end;
  244. move(t^[1], tl^[1], ns2);
  245. mdtgpb(n-1, 1, 2, tl^[1], ca, term);
  246. if term=2
  247. then
  248. exit;
  249. z^[1]:=1/(h^[1]*tl^[2]);
  250. for j:=2 to n-1 do
  251. z^[j]:=-(tl^[2*j-1]*z^[j-1])/tl^[2*j];
  252. s:=0;
  253. for j:=1 to n-1 do
  254. s:=s+sqr(z^[j]);
  255. diagb^[1]:=s;
  256. z^[1]:=(-1/h^[1]-1/h^[2])/tl^[2];
  257. if n>2
  258. then
  259. z^[2]:=(1/h^[2]-tl^[3]*z^[1])/tl^[4];
  260. for j:=3 to n-1 do
  261. z^[j]:=-tl^[2*j-1]*z^[j-1]/tl^[2*j];
  262. s:=0;
  263. for j:=1 to n-1 do
  264. s:=s+sqr(z^[j]);
  265. diagb^[2]:=s;
  266. for i:=2 to n-2 do
  267. begin
  268. z^[i-1]:=1/(h^[i]*tl^[2*(i-1)]);
  269. z^[i]:=(-1/h^[i]-1/h^[i+1]-tl^[2*i-1]*z^[i-1])/tl^[2*i];
  270. z^[i+1]:=(1/h^[i+1]-tl^[2*i+1]*z^[i])/tl^[2*(i+1)];
  271. for j:=i+2 to n-1 do
  272. z^[j]:=-tl^[2*j-1]*z^[j-1]/tl^[2*j];
  273. s:=0;
  274. for j:=i-1 to n-1 do
  275. s:=s+sqr(z^[j]);
  276. diagb^[i+1]:=s
  277. end;
  278. z^[n-2]:=1/(h^[n-1]*tl^[2*(n-2)]);
  279. z^[n-1]:=(-1/h^[n-1]-1/h^[n]-tl^[2*n-3]*z^[n-2])/tl^[2*(n-1)];
  280. s:=0;
  281. for j:=n-2 to n-1 do
  282. s:=s+sqr(z^[j]);
  283. diagb^[n]:=s;
  284. diagb^[n+1]:=1/sqr(h^[n]*tl^[2*(n-1)]);
  285. p:=1/h^[1];
  286. for i:=2 to n do
  287. begin
  288. q:=1/h^[i]; qty^[i-1]:=py^[i+1]*q-py^[i]*(p+q)+py^[i-1]*p;
  289. p:=q
  290. end;
  291. p:=1/h^[1]; q:=1/h^[2]; r:=1/h^[3];
  292. qtdinvq^[3]:=dinv^[1]*p*p+dinv^[2]*(p+q)*(p+q)+dinv^[3]*q*q;
  293. if n>2
  294. then
  295. begin
  296. qtdinvq^[6]:=dinv^[2]*q*q+dinv^[3]*(q+r)*(q+r)+dinv^[4]*r*r;
  297. qtdinvq^[5]:=-(dinv^[2]*(p+q)+dinv^[3]*(q+r))*q;
  298. p:=q; q:=r;
  299. for i:=3 to n-1 do
  300. begin
  301. r:=1/h^[i+1];
  302. qtdinvq^[3*i]:=dinv^[i]*q*q+dinv^[i+1]*(q+r)*(q+r)+dinv^[i+2]*r*r;
  303. qtdinvq^[3*i-1]:=-(dinv^[i]*(p+q)+dinv^[i+1]*(q+r))*q;
  304. qtdinvq^[3*i-2]:=dinv^[i]*p*q;
  305. p:=q; q:=r
  306. end
  307. end;
  308. dslgpb(n-1, 1, 2, tl^[1], qty^[1], c^[1], term);
  309. if term=2
  310. then
  311. exit;
  312. ey:=e(c^[1], h^[1], n);
  313. lam0:=0;
  314. s:=cr(lam0);
  315. if term=2
  316. then
  317. exit;
  318. if s >= 0
  319. then
  320. begin
  321. lambda:=0; term:=4
  322. end
  323. else
  324. begin
  325. lam1:=1e-8; ub:=false;
  326. while (not ub) and (lam1<=1.1e8) do
  327. begin
  328. s:=cr(lam1);
  329. if term=2
  330. then
  331. exit;
  332. if s >= 0
  333. then
  334. ub:=true
  335. else
  336. begin
  337. lam0:=lam1; lam1:=10*lam1
  338. end
  339. end;
  340. if not ub
  341. then
  342. begin
  343. term:=4; lambda:=lam0
  344. end
  345. else
  346. roof1r(lam0, lam1, 0, 1e-6, lambda);
  347. if term=2
  348. then
  349. exit
  350. end;
  351. end;
  352. begin
  353. term:=1;
  354. if n < 2
  355. then
  356. begin
  357. term:=3; exit
  358. end;
  359. sr:=sizeof(ArbFloat);
  360. n1s:=(n+1)*sr;
  361. ns2:=2*(n-1)*sr;
  362. ns1:=(n-1)*sr;
  363. getmem(dinv, n1s);
  364. getmem(h, n*sr);
  365. getmem(t, ns2);
  366. getmem(tl, ns2);
  367. getmem(z, ns1);
  368. getmem(diagb, n1s);
  369. getmem(qtdinvq, 3*ns1);
  370. getmem(c, ns1);
  371. getmem(qty, ns1);
  372. getmem(pd, n1s);
  373. { pd:=@d; }
  374. px:=@x;
  375. py:=@y;
  376. pa:=@a;
  377. pd2a:=@d2a;
  378. { de gewichten van de punten worden op 1 gezet}
  379. for i:=1 to n+1 do
  380. pd^[i]:=1;
  381. NoodGreep;
  382. freemem(dinv, n1s);
  383. freemem(h, n*sr);
  384. freemem(t, ns2);
  385. freemem(tl, ns2);
  386. freemem(z, ns1);
  387. freemem(diagb, n1s);
  388. freemem(qtdinvq, 3*ns1);
  389. freemem(c, ns1);
  390. freemem(qty, ns1);
  391. freemem(pd, n1s);
  392. end; {ipffsn}
  393. procedure ortpol(m, n: ArbInt; var x, alfa, beta: ArbFloat);
  394. var
  395. i, j, ms : ArbInt;
  396. xppn1, ppn1, ppn, p, alfaj, betaj : ArbFloat;
  397. px, pal, pbe, pn, pn1 : ^arfloat1;
  398. temp : pointer;
  399. begin
  400. mark(temp);
  401. px:=@x; pal:=@alfa; pbe:=@beta; ms:=m*sizeof(ArbFloat);
  402. getmem(pn, ms); getmem(pn1, ms);
  403. xppn1:=0; ppn1:=m;
  404. for i:=1 to m do
  405. begin
  406. pn^[i]:=0; pn1^[i]:=1; xppn1:=xppn1+px^[i]
  407. end;
  408. pal^[1]:=xppn1/ppn1; pbe^[1]:=0;
  409. for j:=2 to n do
  410. begin
  411. alfaj:=pal^[j-1]; betaj:=pbe^[j-1];
  412. ppn:=ppn1; ppn1:=0; xppn1:=0;
  413. for i:=1 to m do
  414. begin
  415. p:=(px^[i]-alfaj)*pn1^[i]-betaj*pn^[i];
  416. pn^[i]:=pn1^[i]; pn1^[i]:=p; p:=p*p;
  417. ppn1:=ppn1+p; xppn1:=xppn1+px^[i]*p
  418. end; {i}
  419. pal^[j]:=xppn1/ppn1; pbe^[j]:=ppn1/ppn
  420. end; {j}
  421. release(temp)
  422. end; {ortpol}
  423. procedure ortcoe(m, n: ArbInt; var x, y, alfa, beta, a: ArbFloat);
  424. var i, j, mr : ArbInt;
  425. fpn, ppn, p, alphaj, betaj : ArbFloat;
  426. px, py, pal, pbe, pa, pn, pn1 : ^arfloat1;
  427. temp : pointer;
  428. begin
  429. mark(temp); mr:=m*sizeof(ArbFloat);
  430. px:=@x; py:=@y; pal:=@alfa; pbe:=@beta; pa:=@a;
  431. getmem(pn, mr); getmem(pn1, mr);
  432. fpn:=0;
  433. for i:=1 to m do
  434. begin
  435. pn^[i]:=0; pn1^[i]:=1; fpn:=fpn+py^[i]
  436. end; {i}
  437. pa^[1]:=fpn/m;
  438. for j:=1 to n do
  439. begin
  440. fpn:=0; ppn:=0; alphaj:=pal^[j]; betaj:=pbe^[j];
  441. for i:=1 to m do
  442. begin
  443. p:=(px^[i]-alphaj)*pn1^[i]-betaj*pn^[i];
  444. pn^[i]:=pn1^[i]; pn1^[i]:=p;
  445. fpn:=fpn+py^[i]*p; ppn:=ppn+p*p
  446. end; {i}
  447. pa^[j+1]:=fpn/ppn
  448. end; {j}
  449. release(temp)
  450. end; {ortcoe}
  451. procedure polcoe(n:ArbInt; var alfa, beta, a, b: ArbFloat);
  452. var k, j : ArbInt;
  453. pal, pbe : ^arfloat1;
  454. pa, pb : ^arfloat0;
  455. begin
  456. pal:=@alfa; pbe:=@beta; pa:=@a; pb:=@b;
  457. move(pa^[0], pb^[0], (n+1)*sizeof(ArbFloat));
  458. for j:=0 to n-1 do
  459. for k:=n-j-1 downto 0 do
  460. begin
  461. pb^[k+j]:=pb^[k+j]-pal^[k+1]*pb^[k+j+1];
  462. if k+j<>n-1
  463. then
  464. pb^[k+j]:=pb^[k+j]-pbe^[k+2]*pb^[k+j+2]
  465. end
  466. end; {polcoe}
  467. procedure ipfpol(m, n: ArbInt; var x, y, b: ArbFloat; var term: ArbInt);
  468. var i, ns: ArbInt;
  469. fsum: ArbFloat;
  470. px, py, alfa, beta: ^arfloat1;
  471. pb, a: ^arfloat0;
  472. begin
  473. if (n<0) or (m<1)
  474. then
  475. begin
  476. term:=3; exit
  477. end;
  478. term:=1;
  479. if n = 0
  480. then
  481. begin
  482. py:=@y; pb:=@b;
  483. fsum:=0;
  484. for i:=1 to m do
  485. fsum:=fsum+py^[i];
  486. pb^[0]:=fsum/m
  487. end
  488. else
  489. begin
  490. if n>m-1
  491. then
  492. begin
  493. pb:=@b;
  494. fillchar(pb^[m], (n-m+1)*sizeof(ArbFloat), 0);
  495. n:=m-1
  496. end;
  497. ns:=n*sizeof(ArbFloat);
  498. getmem(alfa, ns); getmem(beta, ns);
  499. getmem(a, (n+1)*sizeof(ArbFloat));
  500. ortpol(m, n, x, alfa^[1], beta^[1]);
  501. ortcoe(m, n, x, y, alfa^[1], beta^[1], a^[0]);
  502. polcoe(n, alfa^[1], beta^[1], a^[0], b);
  503. freemem(alfa, ns); freemem(beta, ns);
  504. freemem(a, (n+1)*sizeof(ArbFloat));
  505. end
  506. end; {ipfpol}
  507. procedure ipfisn(n: ArbInt; var x, y, d2s: ArbFloat; var term: ArbInt);
  508. var
  509. s, i : ArbInt;
  510. p, q, ca : ArbFloat;
  511. px, py, h, b, t : ^arfloat0;
  512. pd2s : ^arfloat1;
  513. begin
  514. px:=@x; py:=@y; pd2s:=@d2s;
  515. term:=1;
  516. if n < 2
  517. then
  518. begin
  519. term:=3; exit
  520. end; {n<2}
  521. s:=sizeof(ArbFloat);
  522. getmem(h, n*s);
  523. getmem(b, (n-1)*s);
  524. getmem(t, 2*(n-1)*s);
  525. for i:=0 to n-1 do
  526. h^[i]:=px^[i+1]-px^[i];
  527. q:=1/6; p:=2*q;
  528. t^[1]:=p*(h^[0]+h^[1]);
  529. for i:=2 to n-1 do
  530. begin
  531. t^[2*i-1]:=p*(h^[i-1]+h^[i]); t^[2*i-2]:=q*h^[i-1]
  532. end; {i}
  533. p:=1/h^[0];
  534. for i:=2 to n do
  535. begin
  536. q:=1/h^[i-1]; b^[i-2]:=py^[i]*q-py^[i-1]*(p+q)+py^[i-2]*p; p:=q
  537. end;
  538. slegpb(n-1, 1, {2,} t^[0], b^[0], pd2s^[1], ca, term);
  539. freemem(h, n*s);
  540. freemem(b, (n-1)*s);
  541. freemem(t, 2*(n-1)*s);
  542. end; {ipfisn}
  543. function ipfspn(n: ArbInt; var x, y, d2s: ArbFloat; t:ArbFloat;
  544. var term: ArbInt): ArbFloat;
  545. var
  546. px, py : ^arfloat0;
  547. pd2s : ^arfloat1;
  548. i, j, m : ArbInt;
  549. d, s3, h, dy : ArbFloat;
  550. begin
  551. i:=1; term:=1;
  552. if n<2
  553. then
  554. begin
  555. term:=3; exit
  556. end; {n<2}
  557. px:=@x; py:=@y; pd2s:=@d2s;
  558. if t <= px^[0]
  559. then
  560. begin
  561. h:=px^[1]-px^[0];
  562. dy:=(py^[1]-py^[0])/h-h*pd2s^[1]/6;
  563. ipfspn:=py^[0]+(t-px^[0])*dy
  564. end { t <= x[0] }
  565. else
  566. if t >= px^[n]
  567. then
  568. begin
  569. h:=px^[n]-px^[n-1];
  570. dy:=(py^[n]-py^[n-1])/h+h*pd2s^[n-1]/6;
  571. ipfspn:=py^[n]+(t-px^[n])*dy
  572. end { t >= x[n] }
  573. else
  574. begin
  575. i:=0; j:=n;
  576. while j <> i+1 do
  577. begin
  578. m:=(i+j) div 2;
  579. if t>=px^[m]
  580. then
  581. i:=m
  582. else
  583. j:=m
  584. end; {j}
  585. h:=px^[i+1]-px^[i];
  586. d:=t-px^[i];
  587. if i=0
  588. then
  589. begin
  590. s3:=pd2s^[1]/h;
  591. dy:=(py^[1]-py^[0])/h-h*pd2s^[1]/6;
  592. ipfspn:=py^[0]+d*(dy+d*d*s3/6)
  593. end
  594. else
  595. if i=n-1
  596. then
  597. begin
  598. s3:=-pd2s^[n-1]/h;
  599. dy:=(py^[n]-py^[n-1])/h-h*pd2s^[n-1]/3;
  600. ipfspn:=py^[n-1]+d*(dy+d*(pd2s^[n-1]/2+d*s3/6))
  601. end
  602. else
  603. begin
  604. s3:=(pd2s^[i+1]-pd2s^[i])/h;
  605. dy:=(py^[i+1]-py^[i])/h-h*(2*pd2s^[i]+pd2s^[i+1])/6;
  606. ipfspn:=py^[i]+d*(dy+d*(pd2s^[i]/2+d*s3/6))
  607. end
  608. end { x[0] < t < x[n] }
  609. end; {ipfspn}
  610. function p(x, a, z:complex): ArbFloat;
  611. begin
  612. x.sub(a);
  613. p:=x.Inp(z)
  614. end;
  615. function e(x, y: complex): ArbFloat;
  616. const c1: ArbFloat = 0.01989436788646;
  617. var s: ArbFloat;
  618. begin x.sub(y);
  619. s := x.norm;
  620. if s=0 then e:=0 else e:=c1*s*ln(s)
  621. end;
  622. function spline( n : ArbInt;
  623. x : complex;
  624. var ac : complex;
  625. var gammar: ArbFloat;
  626. u1 : ArbFloat;
  627. pf : complex): ArbFloat;
  628. var i : ArbInt;
  629. s : ArbFloat;
  630. a : arcomp0 absolute ac;
  631. gamma : arfloat0 absolute gammar;
  632. begin
  633. s := u1 + p(x, a[n-2], pf);
  634. for i:=0 to n do s := s + gamma[i]*e(x,a[i]);
  635. spline := s
  636. end;
  637. procedure splineparameters
  638. ( n : ArbInt;
  639. var ac, alfadc : complex;
  640. var lambda,
  641. gammar, u1,
  642. kwsom, energie : ArbFloat;
  643. var pf : complex);
  644. procedure SwapC(var v, w: complex);
  645. var x: complex;
  646. begin
  647. x := v; v := w; w := x
  648. end;
  649. procedure pxpy(a, b, c: complex; var p:complex);
  650. var det: ArbFloat;
  651. begin
  652. b.sub(a); c.sub(a); det := b.xreal*c.imag-b.imag*c.xreal;
  653. b.sub(c); p.Init(b.imag/det, -b.xreal/det)
  654. end;
  655. procedure pfxpfy(a, b, c: complex; f: vector; var pf: complex);
  656. begin
  657. b.sub(a); c.sub(a);
  658. f.j := f.j-f.i; f.k := f.k-f.i;
  659. pf.init(f.j*c.imag - f.k*b.imag, -f.j*c.xreal + f.k*b.xreal);
  660. pf.scale(1/(b.xreal*c.imag - b.imag*c.xreal))
  661. end;
  662. function InpV(n: ArbInt; var v1, v2: ArbFloat): ArbFloat;
  663. var i: ArbInt;
  664. a1: arfloat0 absolute v1;
  665. a2: arfloat0 absolute v2;
  666. s : ArbFloat;
  667. begin
  668. s := 0;
  669. for i:=0 to n-1 do s := s + a1[i]*a2[i];
  670. InpV := s
  671. end;
  672. PROCEDURE SPDSOL( N : INTEGER;
  673. VAR AP : pointer;
  674. VAR B : ArbFloat);
  675. VAR I, J, K : INTEGER;
  676. H : ArbFloat;
  677. a : ^ar2dr absolute ap;
  678. bx : arfloat0 absolute b;
  679. BEGIN
  680. for k:=0 to n do
  681. BEGIN
  682. h := sqrt(a^[k]^[k]-InpV(k, a^[k]^[0], a^[k]^[0]));
  683. a^[k]^[k] := h;
  684. FOR I:=K+1 TO N do a^[i]^[k] := (a^[i]^[k] - InpV(k, a^[k]^[0], a^[i]^[0]))/h;
  685. BX[K] := (bx[k] - InpV(k, a^[k]^[0], bx[0]))/h
  686. END;
  687. FOR I:=N DOWNTO 0 do
  688. BEGIN
  689. H := BX[I];
  690. FOR J:=I+1 TO N DO H := H - A^[J]^[I]*BX[J];
  691. BX[I] := H/A^[I]^[I]
  692. END
  693. END;
  694. var i, j, i1 : ArbInt;
  695. x, h,
  696. absdet,
  697. absdetmax,
  698. s, s1, ca: ArbFloat;
  699. alfa, dv, hulp,
  700. u, v, w : vector;
  701. e22 : array[0..2] of vector;
  702. e21, b : ^arvect0;
  703. k, c : ^ar2dr;
  704. gamma : arfloat0 absolute gammar;
  705. an2, an1, an, z,
  706. vz, wz : complex;
  707. a : arcomp0 absolute ac;
  708. alfad : arcomp0 absolute alfadc;
  709. begin
  710. i1:=0;
  711. x:=a[0].xreal;
  712. for i:=1 to n do
  713. begin
  714. h:=a[i].xreal;
  715. if h<x then begin i1:=i; x:=h end
  716. end;
  717. SwapC(a[n-2], a[i1]);
  718. SwapC(alfad[n-2], alfad[i1]);
  719. x:=a[0].xreal;
  720. i1 := 0;
  721. for i:=1 to n do
  722. begin
  723. h:=a[i].xreal;
  724. if h>x then begin i1:=i; x:=h end
  725. end;
  726. SwapC(a[n-1], a[i1]);
  727. SwapC(alfad[n-1], alfad[i1]);
  728. vz := a[n-2]; vz.sub(a[n-1]);
  729. absdetmax := -1;
  730. for i:=0 to n do
  731. begin
  732. wz := a[i]; wz.sub(a[n-2]);
  733. absdet := abs(wz.imag*vz.xreal-wz.xreal*vz.imag);
  734. if absdet>absdetmax then begin i1:=i; absdetmax:=absdet end
  735. end;
  736. SwapC(a[n], a[i1]);
  737. SwapC(alfad[n], alfad[i1]);
  738. an2 := a[n-2]; an1 := a[n-1]; an := a[n];
  739. alfa.i := alfad[n-2].xreal; dv.i := alfad[n-2].imag;
  740. alfa.j := alfad[n-1].xreal; dv.j := alfad[n-1].imag;
  741. alfa.k := alfad[n ].xreal; dv.k := alfad[n ].imag;
  742. n := n - 3;
  743. GetMem(k, (n+1)*SizeOf(pointer));
  744. for j:=0 to n do GetMem(k^[j], (j+1)*SizeOf(ArbFloat));
  745. GetMem(e21, (n+1)*SizeOf(vector));
  746. GetMem(b, (n+1)*SizeOf(vector));
  747. pxpy(an2,an1,an,z); for i:=0 to n do b^[i].i:=1+p(a[i],an2,z);
  748. pxpy(an1,an,an2,z); for i:=0 to n do b^[i].j:=1+p(a[i],an1,z);
  749. pxpy(an,an2,an1,z); for i:=0 to n do b^[i].k:=1+p(a[i],an,z);
  750. e22[0].init(0,e(an1,an2),e(an,an2));
  751. e22[1].init(e(an1,an2),0,e(an,an1));
  752. e22[2].init(e(an,an2),e(an,an1),0);
  753. for j:=0 to n do e21^[j].init(e(an2,a[j]),e(an1,a[j]),e(an,a[j]));
  754. GetMem(c, (n+1)*SizeOf(pointer));
  755. for j:=0 to n do GetMem(c^[j], (j+1)*SizeOf(ArbFloat));
  756. for i:=0 to n do
  757. for j:=0 to i do
  758. begin
  759. if j=i then s:=0 else s:=e(a[i],a[j]);
  760. hulp.init(b^[j].Inprod(e22[0]), b^[j].Inprod(e22[1]), b^[j].Inprod(e22[2]));
  761. hulp.sub(e21^[j]);
  762. k^[i]^[j] := s+b^[i].InProd(hulp)-b^[j].Inprod(e21^[i]);
  763. if j=i then s:=1/alfad[i].imag else s:=0;
  764. hulp.init(b^[j].i/dv.i, b^[j].j/dv.j, b^[j].k/dv.k);
  765. c^[i]^[j] := k^[i]^[j] + (s + b^[i].Inprod(hulp))/lambda
  766. end;
  767. for i:=0 to n do gamma[i]:=alfad[i].xreal - b^[i].Inprod(alfa);
  768. SpdSol(n, pointer(c), gamma[0]);
  769. for j:=n downto 0 do FreeMem(c^[j], (j+1)*SizeOf(ArbFloat));
  770. FreeMem(c, (n+1)*SizeOf(pointer));
  771. s:=0; for j:=0 to n do s:=s+b^[j].i*gamma[j]; w.i:=s; gamma[n+1] := -s;
  772. s:=0; for j:=0 to n do s:=s+b^[j].j*gamma[j]; w.j:=s; gamma[n+2] := -s;
  773. s:=0; for j:=0 to n do s:=s+b^[j].k*gamma[j]; w.k:=s; gamma[n+3] := -s;
  774. FreeMem(b, (n+1)*SizeOf(vector));
  775. u.init(w.i/dv.i, w.j/dv.j, w.k/dv.k);
  776. u.scale(1/lambda);
  777. u.add(alfa);
  778. s:=0; for j:=0 to n do s:=s+e21^[j].i*gamma[j]; v.i := e22[0].inprod(w)-s;
  779. s:=0; for j:=0 to n do s:=s+e21^[j].j*gamma[j]; v.j := e22[1].inprod(w)-s;
  780. s:=0; for j:=0 to n do s:=s+e21^[j].k*gamma[j]; v.k := e22[2].inprod(w)-s;
  781. FreeMem(e21, (n+1)*SizeOf(vector));
  782. u.add(v);
  783. pfxpfy(an2, an1, an, u, pf); u1:=u.i;
  784. kwsom := 0; for j:=0 to n do kwsom:=kwsom+sqr(gamma[j])/alfad[j].imag;
  785. kwsom := kwsom+sqr(w.i)/dv.i+sqr(w.j)/dv.j+sqr(w.k)/dv.k;
  786. kwsom := kwsom/sqr(lambda);
  787. s:=0;
  788. for i:=0 to n do
  789. begin s1:=0;
  790. for j:=0 to i do s1:=s1+k^[i]^[j]*gamma[j];
  791. for j:=i+1 to n do s1:=s1+k^[j]^[i]*gamma[j];
  792. s := gamma[i]*s1+s
  793. end;
  794. for j:=n downto 0 do FreeMem(k^[j], (j+1)*SizeOf(ArbFloat));
  795. FreeMem(k, (n+1)*SizeOf(pointer));
  796. energie := s
  797. end {splineparameters};
  798. end.