ipf.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  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. // this function used to use mark/release.
  395. var
  396. i, j, ms : ArbInt;
  397. xppn1, ppn1, ppn, p, alfaj, betaj : ArbFloat;
  398. px, pal, pbe, pn, pn1 : ^arfloat1;
  399. begin
  400. px:=@x; pal:=@alfa; pbe:=@beta; ms:=m*sizeof(ArbFloat);
  401. getmem(pn, ms); getmem(pn1, ms);
  402. xppn1:=0; ppn1:=m;
  403. for i:=1 to m do
  404. begin
  405. pn^[i]:=0; pn1^[i]:=1; xppn1:=xppn1+px^[i]
  406. end;
  407. pal^[1]:=xppn1/ppn1; pbe^[1]:=0;
  408. for j:=2 to n do
  409. begin
  410. alfaj:=pal^[j-1]; betaj:=pbe^[j-1];
  411. ppn:=ppn1; ppn1:=0; xppn1:=0;
  412. for i:=1 to m do
  413. begin
  414. p:=(px^[i]-alfaj)*pn1^[i]-betaj*pn^[i];
  415. pn^[i]:=pn1^[i]; pn1^[i]:=p; p:=p*p;
  416. ppn1:=ppn1+p; xppn1:=xppn1+px^[i]*p
  417. end; {i}
  418. pal^[j]:=xppn1/ppn1; pbe^[j]:=ppn1/ppn
  419. end; {j}
  420. freemem(pn); freemem(pn1);
  421. end; {ortpol}
  422. procedure ortcoe(m, n: ArbInt; var x, y, alfa, beta, a: ArbFloat);
  423. // this function used to use mark/release.
  424. var i, j, mr : ArbInt;
  425. fpn, ppn, p, alphaj, betaj : ArbFloat;
  426. px, py, pal, pbe, pa, pn, pn1 : ^arfloat1;
  427. begin
  428. mr:=m*sizeof(ArbFloat);
  429. px:=@x; py:=@y; pal:=@alfa; pbe:=@beta; pa:=@a;
  430. getmem(pn, mr); getmem(pn1, mr);
  431. fpn:=0;
  432. for i:=1 to m do
  433. begin
  434. pn^[i]:=0; pn1^[i]:=1; fpn:=fpn+py^[i]
  435. end; {i}
  436. pa^[1]:=fpn/m;
  437. for j:=1 to n do
  438. begin
  439. fpn:=0; ppn:=0; alphaj:=pal^[j]; betaj:=pbe^[j];
  440. for i:=1 to m do
  441. begin
  442. p:=(px^[i]-alphaj)*pn1^[i]-betaj*pn^[i];
  443. pn^[i]:=pn1^[i]; pn1^[i]:=p;
  444. fpn:=fpn+py^[i]*p; ppn:=ppn+p*p
  445. end; {i}
  446. pa^[j+1]:=fpn/ppn
  447. end; {j}
  448. freemem(pn); freemem(pn1);
  449. end; {ortcoe}
  450. procedure polcoe(n:ArbInt; var alfa, beta, a, b: ArbFloat);
  451. var k, j : ArbInt;
  452. pal, pbe : ^arfloat1;
  453. pa, pb : ^arfloat0;
  454. begin
  455. pal:=@alfa; pbe:=@beta; pa:=@a; pb:=@b;
  456. move(pa^[0], pb^[0], (n+1)*sizeof(ArbFloat));
  457. for j:=0 to n-1 do
  458. for k:=n-j-1 downto 0 do
  459. begin
  460. pb^[k+j]:=pb^[k+j]-pal^[k+1]*pb^[k+j+1];
  461. if k+j<>n-1
  462. then
  463. pb^[k+j]:=pb^[k+j]-pbe^[k+2]*pb^[k+j+2]
  464. end
  465. end; {polcoe}
  466. procedure ipfpol(m, n: ArbInt; var x, y, b: ArbFloat; var term: ArbInt);
  467. var i, ns: ArbInt;
  468. fsum: ArbFloat;
  469. px, py, alfa, beta: ^arfloat1;
  470. pb, a: ^arfloat0;
  471. begin
  472. if (n<0) or (m<1)
  473. then
  474. begin
  475. term:=3; exit
  476. end;
  477. term:=1;
  478. if n = 0
  479. then
  480. begin
  481. py:=@y; pb:=@b;
  482. fsum:=0;
  483. for i:=1 to m do
  484. fsum:=fsum+py^[i];
  485. pb^[0]:=fsum/m
  486. end
  487. else
  488. begin
  489. if n>m-1
  490. then
  491. begin
  492. pb:=@b;
  493. fillchar(pb^[m], (n-m+1)*sizeof(ArbFloat), 0);
  494. n:=m-1
  495. end;
  496. ns:=n*sizeof(ArbFloat);
  497. getmem(alfa, ns); getmem(beta, ns);
  498. getmem(a, (n+1)*sizeof(ArbFloat));
  499. ortpol(m, n, x, alfa^[1], beta^[1]);
  500. ortcoe(m, n, x, y, alfa^[1], beta^[1], a^[0]);
  501. polcoe(n, alfa^[1], beta^[1], a^[0], b);
  502. freemem(alfa, ns); freemem(beta, ns);
  503. freemem(a, (n+1)*sizeof(ArbFloat));
  504. end
  505. end; {ipfpol}
  506. procedure ipfisn(n: ArbInt; var x, y, d2s: ArbFloat; var term: ArbInt);
  507. var
  508. s, i : ArbInt;
  509. p, q, ca : ArbFloat;
  510. px, py, h, b, t : ^arfloat0;
  511. pd2s : ^arfloat1;
  512. begin
  513. px:=@x; py:=@y; pd2s:=@d2s;
  514. term:=1;
  515. if n < 2
  516. then
  517. begin
  518. term:=3; exit
  519. end; {n<2}
  520. s:=sizeof(ArbFloat);
  521. getmem(h, n*s);
  522. getmem(b, (n-1)*s);
  523. getmem(t, 2*(n-1)*s);
  524. for i:=0 to n-1 do
  525. h^[i]:=px^[i+1]-px^[i];
  526. q:=1/6; p:=2*q;
  527. t^[1]:=p*(h^[0]+h^[1]);
  528. for i:=2 to n-1 do
  529. begin
  530. t^[2*i-1]:=p*(h^[i-1]+h^[i]); t^[2*i-2]:=q*h^[i-1]
  531. end; {i}
  532. p:=1/h^[0];
  533. for i:=2 to n do
  534. begin
  535. q:=1/h^[i-1]; b^[i-2]:=py^[i]*q-py^[i-1]*(p+q)+py^[i-2]*p; p:=q
  536. end;
  537. slegpb(n-1, 1, {2,} t^[0], b^[0], pd2s^[1], ca, term);
  538. freemem(h, n*s);
  539. freemem(b, (n-1)*s);
  540. freemem(t, 2*(n-1)*s);
  541. end; {ipfisn}
  542. function ipfspn(n: ArbInt; var x, y, d2s: ArbFloat; t:ArbFloat;
  543. var term: ArbInt): ArbFloat;
  544. var
  545. px, py : ^arfloat0;
  546. pd2s : ^arfloat1;
  547. i, j, m : ArbInt;
  548. d, s3, h, dy : ArbFloat;
  549. begin
  550. i:=1; term:=1;
  551. if n<2
  552. then
  553. begin
  554. term:=3; exit
  555. end; {n<2}
  556. px:=@x; py:=@y; pd2s:=@d2s;
  557. if t <= px^[0]
  558. then
  559. begin
  560. h:=px^[1]-px^[0];
  561. dy:=(py^[1]-py^[0])/h-h*pd2s^[1]/6;
  562. ipfspn:=py^[0]+(t-px^[0])*dy
  563. end { t <= x[0] }
  564. else
  565. if t >= px^[n]
  566. then
  567. begin
  568. h:=px^[n]-px^[n-1];
  569. dy:=(py^[n]-py^[n-1])/h+h*pd2s^[n-1]/6;
  570. ipfspn:=py^[n]+(t-px^[n])*dy
  571. end { t >= x[n] }
  572. else
  573. begin
  574. i:=0; j:=n;
  575. while j <> i+1 do
  576. begin
  577. m:=(i+j) div 2;
  578. if t>=px^[m]
  579. then
  580. i:=m
  581. else
  582. j:=m
  583. end; {j}
  584. h:=px^[i+1]-px^[i];
  585. d:=t-px^[i];
  586. if i=0
  587. then
  588. begin
  589. s3:=pd2s^[1]/h;
  590. dy:=(py^[1]-py^[0])/h-h*pd2s^[1]/6;
  591. ipfspn:=py^[0]+d*(dy+d*d*s3/6)
  592. end
  593. else
  594. if i=n-1
  595. then
  596. begin
  597. s3:=-pd2s^[n-1]/h;
  598. dy:=(py^[n]-py^[n-1])/h-h*pd2s^[n-1]/3;
  599. ipfspn:=py^[n-1]+d*(dy+d*(pd2s^[n-1]/2+d*s3/6))
  600. end
  601. else
  602. begin
  603. s3:=(pd2s^[i+1]-pd2s^[i])/h;
  604. dy:=(py^[i+1]-py^[i])/h-h*(2*pd2s^[i]+pd2s^[i+1])/6;
  605. ipfspn:=py^[i]+d*(dy+d*(pd2s^[i]/2+d*s3/6))
  606. end
  607. end { x[0] < t < x[n] }
  608. end; {ipfspn}
  609. function p(x, a, z:complex): ArbFloat;
  610. begin
  611. x.sub(a);
  612. p:=x.Inp(z)
  613. end;
  614. function e(x, y: complex): ArbFloat;
  615. const c1: ArbFloat = 0.01989436788646;
  616. var s: ArbFloat;
  617. begin x.sub(y);
  618. s := x.norm;
  619. if s=0 then e:=0 else e:=c1*s*ln(s)
  620. end;
  621. function spline( n : ArbInt;
  622. x : complex;
  623. var ac : complex;
  624. var gammar: ArbFloat;
  625. u1 : ArbFloat;
  626. pf : complex): ArbFloat;
  627. var i : ArbInt;
  628. s : ArbFloat;
  629. a : arcomp0 absolute ac;
  630. gamma : arfloat0 absolute gammar;
  631. begin
  632. s := u1 + p(x, a[n-2], pf);
  633. for i:=0 to n do s := s + gamma[i]*e(x,a[i]);
  634. spline := s
  635. end;
  636. procedure splineparameters
  637. ( n : ArbInt;
  638. var ac, alfadc : complex;
  639. var lambda,
  640. gammar, u1,
  641. kwsom, energie : ArbFloat;
  642. var pf : complex);
  643. procedure SwapC(var v, w: complex);
  644. var x: complex;
  645. begin
  646. x := v; v := w; w := x
  647. end;
  648. procedure pxpy(a, b, c: complex; var p:complex);
  649. var det: ArbFloat;
  650. begin
  651. b.sub(a); c.sub(a); det := b.xreal*c.imag-b.imag*c.xreal;
  652. b.sub(c); p.Init(b.imag/det, -b.xreal/det)
  653. end;
  654. procedure pfxpfy(a, b, c: complex; f: vector; var pf: complex);
  655. begin
  656. b.sub(a); c.sub(a);
  657. f.j := f.j-f.i; f.k := f.k-f.i;
  658. pf.init(f.j*c.imag - f.k*b.imag, -f.j*c.xreal + f.k*b.xreal);
  659. pf.scale(1/(b.xreal*c.imag - b.imag*c.xreal))
  660. end;
  661. function InpV(n: ArbInt; var v1, v2: ArbFloat): ArbFloat;
  662. var i: ArbInt;
  663. a1: arfloat0 absolute v1;
  664. a2: arfloat0 absolute v2;
  665. s : ArbFloat;
  666. begin
  667. s := 0;
  668. for i:=0 to n-1 do s := s + a1[i]*a2[i];
  669. InpV := s
  670. end;
  671. PROCEDURE SPDSOL( N : INTEGER;
  672. VAR AP : pointer;
  673. VAR B : ArbFloat);
  674. VAR I, J, K : INTEGER;
  675. H : ArbFloat;
  676. a : ^ar2dr absolute ap;
  677. bx : arfloat0 absolute b;
  678. BEGIN
  679. for k:=0 to n do
  680. BEGIN
  681. h := sqrt(a^[k]^[k]-InpV(k, a^[k]^[0], a^[k]^[0]));
  682. a^[k]^[k] := h;
  683. FOR I:=K+1 TO N do a^[i]^[k] := (a^[i]^[k] - InpV(k, a^[k]^[0], a^[i]^[0]))/h;
  684. BX[K] := (bx[k] - InpV(k, a^[k]^[0], bx[0]))/h
  685. END;
  686. FOR I:=N DOWNTO 0 do
  687. BEGIN
  688. H := BX[I];
  689. FOR J:=I+1 TO N DO H := H - A^[J]^[I]*BX[J];
  690. BX[I] := H/A^[I]^[I]
  691. END
  692. END;
  693. var i, j, i1 : ArbInt;
  694. x, h,
  695. absdet,
  696. absdetmax,
  697. s, s1, ca: ArbFloat;
  698. alfa, dv, hulp,
  699. u, v, w : vector;
  700. e22 : array[0..2] of vector;
  701. e21, b : ^arvect0;
  702. k, c : ^ar2dr;
  703. gamma : arfloat0 absolute gammar;
  704. an2, an1, an, z,
  705. vz, wz : complex;
  706. a : arcomp0 absolute ac;
  707. alfad : arcomp0 absolute alfadc;
  708. begin
  709. i1:=0;
  710. x:=a[0].xreal;
  711. for i:=1 to n do
  712. begin
  713. h:=a[i].xreal;
  714. if h<x then begin i1:=i; x:=h end
  715. end;
  716. SwapC(a[n-2], a[i1]);
  717. SwapC(alfad[n-2], alfad[i1]);
  718. x:=a[0].xreal;
  719. i1 := 0;
  720. for i:=1 to n do
  721. begin
  722. h:=a[i].xreal;
  723. if h>x then begin i1:=i; x:=h end
  724. end;
  725. SwapC(a[n-1], a[i1]);
  726. SwapC(alfad[n-1], alfad[i1]);
  727. vz := a[n-2]; vz.sub(a[n-1]);
  728. absdetmax := -1;
  729. for i:=0 to n do
  730. begin
  731. wz := a[i]; wz.sub(a[n-2]);
  732. absdet := abs(wz.imag*vz.xreal-wz.xreal*vz.imag);
  733. if absdet>absdetmax then begin i1:=i; absdetmax:=absdet end
  734. end;
  735. SwapC(a[n], a[i1]);
  736. SwapC(alfad[n], alfad[i1]);
  737. an2 := a[n-2]; an1 := a[n-1]; an := a[n];
  738. alfa.i := alfad[n-2].xreal; dv.i := alfad[n-2].imag;
  739. alfa.j := alfad[n-1].xreal; dv.j := alfad[n-1].imag;
  740. alfa.k := alfad[n ].xreal; dv.k := alfad[n ].imag;
  741. n := n - 3;
  742. GetMem(k, (n+1)*SizeOf(pointer));
  743. for j:=0 to n do GetMem(k^[j], (j+1)*SizeOf(ArbFloat));
  744. GetMem(e21, (n+1)*SizeOf(vector));
  745. GetMem(b, (n+1)*SizeOf(vector));
  746. pxpy(an2,an1,an,z); for i:=0 to n do b^[i].i:=1+p(a[i],an2,z);
  747. pxpy(an1,an,an2,z); for i:=0 to n do b^[i].j:=1+p(a[i],an1,z);
  748. pxpy(an,an2,an1,z); for i:=0 to n do b^[i].k:=1+p(a[i],an,z);
  749. e22[0].init(0,e(an1,an2),e(an,an2));
  750. e22[1].init(e(an1,an2),0,e(an,an1));
  751. e22[2].init(e(an,an2),e(an,an1),0);
  752. for j:=0 to n do e21^[j].init(e(an2,a[j]),e(an1,a[j]),e(an,a[j]));
  753. GetMem(c, (n+1)*SizeOf(pointer));
  754. for j:=0 to n do GetMem(c^[j], (j+1)*SizeOf(ArbFloat));
  755. for i:=0 to n do
  756. for j:=0 to i do
  757. begin
  758. if j=i then s:=0 else s:=e(a[i],a[j]);
  759. hulp.init(b^[j].Inprod(e22[0]), b^[j].Inprod(e22[1]), b^[j].Inprod(e22[2]));
  760. hulp.sub(e21^[j]);
  761. k^[i]^[j] := s+b^[i].InProd(hulp)-b^[j].Inprod(e21^[i]);
  762. if j=i then s:=1/alfad[i].imag else s:=0;
  763. hulp.init(b^[j].i/dv.i, b^[j].j/dv.j, b^[j].k/dv.k);
  764. c^[i]^[j] := k^[i]^[j] + (s + b^[i].Inprod(hulp))/lambda
  765. end;
  766. for i:=0 to n do gamma[i]:=alfad[i].xreal - b^[i].Inprod(alfa);
  767. SpdSol(n, pointer(c), gamma[0]);
  768. for j:=n downto 0 do FreeMem(c^[j], (j+1)*SizeOf(ArbFloat));
  769. FreeMem(c, (n+1)*SizeOf(pointer));
  770. s:=0; for j:=0 to n do s:=s+b^[j].i*gamma[j]; w.i:=s; gamma[n+1] := -s;
  771. s:=0; for j:=0 to n do s:=s+b^[j].j*gamma[j]; w.j:=s; gamma[n+2] := -s;
  772. s:=0; for j:=0 to n do s:=s+b^[j].k*gamma[j]; w.k:=s; gamma[n+3] := -s;
  773. FreeMem(b, (n+1)*SizeOf(vector));
  774. u.init(w.i/dv.i, w.j/dv.j, w.k/dv.k);
  775. u.scale(1/lambda);
  776. u.add(alfa);
  777. s:=0; for j:=0 to n do s:=s+e21^[j].i*gamma[j]; v.i := e22[0].inprod(w)-s;
  778. s:=0; for j:=0 to n do s:=s+e21^[j].j*gamma[j]; v.j := e22[1].inprod(w)-s;
  779. s:=0; for j:=0 to n do s:=s+e21^[j].k*gamma[j]; v.k := e22[2].inprod(w)-s;
  780. FreeMem(e21, (n+1)*SizeOf(vector));
  781. u.add(v);
  782. pfxpfy(an2, an1, an, u, pf); u1:=u.i;
  783. kwsom := 0; for j:=0 to n do kwsom:=kwsom+sqr(gamma[j])/alfad[j].imag;
  784. kwsom := kwsom+sqr(w.i)/dv.i+sqr(w.j)/dv.j+sqr(w.k)/dv.k;
  785. kwsom := kwsom/sqr(lambda);
  786. s:=0;
  787. for i:=0 to n do
  788. begin s1:=0;
  789. for j:=0 to i do s1:=s1+k^[i]^[j]*gamma[j];
  790. for j:=i+1 to n do s1:=s1+k^[j]^[i]*gamma[j];
  791. s := gamma[i]*s1+s
  792. end;
  793. for j:=n downto 0 do FreeMem(k^[j], (j+1)*SizeOf(ArbFloat));
  794. FreeMem(k, (n+1)*SizeOf(pointer));
  795. energie := s
  796. end {splineparameters};
  797. end.