ipf.pas 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  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. {$IFNDEF FPC_DOTTEDUNITS}
  23. unit ipf;
  24. {$ENDIF FPC_DOTTEDUNITS}
  25. {$modeswitch exceptions}
  26. {$I direct.inc}
  27. interface
  28. {$IFDEF FPC_DOTTEDUNITS}
  29. uses NumLib.Typ, NumLib.Mdt, NumLib.Dsl, NumLib.Sle, NumLib.Spe;
  30. {$ELSE FPC_DOTTEDUNITS}
  31. uses typ, mdt, dsl, sle, spe;
  32. {$ENDIF FPC_DOTTEDUNITS}
  33. type
  34. THermiteSplineType = (
  35. hstMonotone // preserves monotonicity of the interpolated function by using
  36. // a Fritsch-Carlson algorithm
  37. );
  38. { Determine natural cubic spline "s" for data set (x,y), output to (a,d2a)
  39. term=1 success,
  40. =2 failure calculating "s"
  41. =3 wrong input (e.g. x,y is not sorted increasing on x)}
  42. procedure ipffsn(n: ArbInt; var x, y, a, d2a: ArbFloat; var term: ArbInt);
  43. {calculate d2s from x,y, which can be used to calculate s}
  44. procedure ipfisn(n: ArbInt; var x, y, d2s: ArbFloat; var term: ArbInt);
  45. {Calculate function value for dataset (x,y), with n.c. spline d2s for
  46. x value t. Return (corrected) y value.
  47. s calculated from x,y, with e.g. ipfisn}
  48. function ipfspn(n: ArbInt; var x, y, d2s: ArbFloat; t: ArbFloat;
  49. var term: ArbInt): ArbFloat;
  50. {Calculate minimum and maximum values for the n.c. spline d2s.
  51. Does NOT take source points into account.}
  52. procedure ipfsmm(n: ArbInt; var x, y, d2s, minv, maxv: ArbFloat;
  53. var term: ArbInt);
  54. {Calculates tangents for each data point (d1s), for a given array of input data
  55. points (x,y), by using a selected variant of a Hermite cubic spline interpolation.
  56. Inputs:
  57. hst - algorithm selection
  58. n - highest array index
  59. x[0..n] - array of X values (one value for each data point)
  60. y[0..n] - array of Y values (one value for each data point)
  61. Outputs:
  62. d1s[0..n] - array of tangent values (one value for each data point)
  63. term - status: 1 if function succeeded, 3 if less than two data points given
  64. }
  65. procedure ipfish(hst: THermiteSplineType; n: ArbInt; var x, y, d1s: ArbFloat; var term: ArbInt);
  66. {Calculates interpolated function value for a given array of input data points
  67. (x,y) and tangents for each data point (d1s), for input value t, by using a
  68. Hermite cubic spline interpolation; d1s array can be obtained by calling the
  69. ipfish procedure.
  70. Inputs:
  71. n - highest array index
  72. x[0..n] - array of X values (one value for each data point)
  73. y[0..n] - array of Y values (one value for each data point)
  74. d1s[0..n] - array of tangent values (one value for each data point)
  75. t - input value X
  76. Outputs:
  77. term - status: 1 if function succeeded, 3 if less than two data points given
  78. result - interpolated function value Y
  79. }
  80. function ipfsph(n: ArbInt; var x, y, d1s: ArbFloat; t: ArbFloat; var term: ArbInt): ArbFloat;
  81. {Calculate n-degree polynomal b for dataset (x,y) with m elements
  82. using the least squares method.}
  83. procedure ipfpol(m, n: ArbInt; var x, y, b: ArbFloat; var term: ArbInt);
  84. {**** undocumented ****}
  85. function spline( n : ArbInt;
  86. x : complex;
  87. var ac : complex;
  88. var gammar: ArbFloat;
  89. u1 : ArbFloat;
  90. pf : complex): ArbFloat;
  91. {**** undocumented ****}
  92. procedure splineparameters
  93. ( n : ArbInt;
  94. var ac, alfadc : complex;
  95. var lambda,
  96. gammar, u1,
  97. kwsom, energie : ArbFloat;
  98. var pf : complex);
  99. implementation
  100. procedure ipffsn(n: ArbInt; var x, y, a, d2a: ArbFloat; var term: ArbInt);
  101. var i, sr, n1s, ns1, ns2: ArbInt;
  102. s, lam, lam0, lam1, lambda, ey, ca, p, q, r: ArbFloat;
  103. px, py, pd, pa, pd2a,
  104. h, z, diagb, dinv, qty, qtdinvq, c, t, tl: ^arfloat1;
  105. ub: boolean;
  106. procedure solve; {n, py, qty, h, qtdinvq, dinv, lam, t, pa, pd2a, term}
  107. var i: ArbInt;
  108. p, q, r: ArbFloat;
  109. f, c: ^arfloat1;
  110. ca: ArbFloat = 0.0;
  111. begin
  112. getmem(f, 3*ns1); getmem(c, ns1);
  113. for i:=1 to n-1 do
  114. begin
  115. f^[3*i]:=qtdinvq^[3*i]+lam*t^[2*i];
  116. if i > 1
  117. then
  118. f^[3*i-1]:=qtdinvq^[3*i-1]+lam*t^[2*i-1];
  119. if i > 2
  120. then
  121. f^[3*i-2]:=qtdinvq^[3*i-2];
  122. if lam=0
  123. then
  124. c^[i]:=qty^[i]
  125. else
  126. c^[i]:=lam*qty^[i]
  127. end;
  128. slegpb(n-1, 2,{ 3,} f^[1], c^[1], pd2a^[1], ca, term);
  129. if term=2
  130. then
  131. begin
  132. freemem(f, 3*ns1); freemem(c, ns1);
  133. exit
  134. end;
  135. p:=1/h^[1];
  136. if lam=0
  137. then
  138. r:=1
  139. else
  140. r:=1/lam;
  141. q:=1/h^[2]; pa^[1]:=py^[1]-r*dinv^[1]*p*pd2a^[1];
  142. pa^[2]:=py^[2]-r*dinv^[2]*(pd2a^[2]*q-(p+q)*pd2a^[1]); p:=q;
  143. for i:=3 to n-1 do
  144. begin
  145. q:=1/h^[i];
  146. pa^[i]:=py^[i]-r*dinv^[i]*
  147. (p*pd2a^[i-2]-(p+q)*pd2a^[i-1]+q*pd2a^[i]);
  148. p:=q
  149. end;
  150. q:=1/h^[n];
  151. pa^[n]:=py^[n]-r*dinv^[n]*(p*pd2a^[n-2]-(p+q)*pd2a^[n-1]);
  152. pa^[n+1]:=py^[n+1]-r*dinv^[n+1]*q*pd2a^[n-1];
  153. if lam=0
  154. then
  155. for i:=1 to n-1 do
  156. pd2a^[i]:=0;
  157. freemem(f, 3*ns1); freemem(c, ns1);
  158. end; {solve}
  159. function e(var c, h: ArbFloat; n:ArbInt): ArbFloat;
  160. var i:ArbInt;
  161. s:ArbFloat;
  162. pc, ph: ^arfloat1;
  163. begin
  164. ph:=@h; pc:=@c;
  165. s:=ph^[1]*pc^[1]*pc^[1];
  166. for i:=1 to n-2 do
  167. s:=s+(pc^[i]*(pc^[i]+pc^[i+1])+pc^[i+1]*pc^[i+1])*ph^[i+1];
  168. e:=(s+pc^[n-1]*pc^[n-1]*ph^[n])/3
  169. end; {e}
  170. function cr(lambda: ArbFloat): ArbFloat;
  171. var s, crs: ArbFloat;
  172. i: ArbInt;
  173. begin
  174. cr:=0; lam:=lambda;
  175. solve; { n, py, qty, h, qtdinvq, dinv, lam, t, pa, pd2a, term }
  176. if term=2
  177. then
  178. exit;
  179. crs:=ey;
  180. if lam <> 0
  181. then
  182. begin
  183. crs:=crs+e(pd2a^[1], h^[1], n);
  184. s:=0;
  185. for i:=1 to n-1 do
  186. s:=s+pd2a^[i]*qty^[i];
  187. crs:=crs-2*s
  188. end;
  189. s:=0;
  190. for i:=1 to n+1 do
  191. s:=s+sqr(pa^[i]-py^[i])*diagb^[i];
  192. cr:=crs-s
  193. end; {cr}
  194. procedure roof1r(a, b, ae, re: ArbFloat; var x: ArbFloat);
  195. var fa, fb, c, fc, m, tol, w1, w2 : ArbFloat;
  196. k : ArbInt;
  197. stop : boolean;
  198. begin
  199. fa:=cr(a);
  200. if term=2
  201. then
  202. exit;
  203. fb:=cr(b);
  204. if term=2
  205. then
  206. exit;
  207. if abs(fb)>abs(fa)
  208. then
  209. begin
  210. c:=b; fc:=fb; x:=a; b:=a; fb:=fa; a:=c; fa:=fc
  211. end
  212. else
  213. begin
  214. c:=a; fc:=fa; x:=b
  215. end;
  216. k:=0;
  217. tol:=ae+re*spemax(abs(a), abs(b));
  218. w1:=abs(b-a); stop:=false;
  219. while (abs(b-a)>tol) and (fb<>0) and (not stop) do
  220. begin
  221. m:=(a+b)/2;
  222. if (k>=2) or (fb=fc)
  223. then
  224. x:=m
  225. else
  226. begin
  227. x:=(b*fc-c*fb)/(fc-fb);
  228. if abs(b-x)<tol
  229. then
  230. x:=b-tol*spesgn(b-a);
  231. if spesgn(x-m)=spesgn(x-b)
  232. then
  233. x:=m
  234. end;
  235. c:=b; fc:=fb; b:=x; fb:=cr(x);
  236. if term=2
  237. then
  238. exit;
  239. if spesgn(fa)*spesgn(fb)>0
  240. then
  241. begin
  242. a:=c; fa:=fc; k:=0
  243. end
  244. else
  245. k:=k+1;
  246. if abs(fb)>=abs(fa)
  247. then
  248. begin
  249. c:=b; fc:=fb; x:=a; b:=a; fb:=fa; a:=c; fa:=fc; k:=0
  250. end;
  251. tol:=ae+re*spemax(abs(a), abs(b));
  252. w2:=abs(b-a);
  253. if w2>=w1
  254. then
  255. stop:=true;
  256. w1:=w2
  257. end
  258. end; {roof1r}
  259. procedure NoodGreep;
  260. var I, j: ArbInt;
  261. begin
  262. i:=1;
  263. while i <= n do
  264. begin
  265. if (pd^[i] <= 0) or (px^[i+1] <= px^[i])
  266. then
  267. begin
  268. term:=3;
  269. exit
  270. end;
  271. i:=i+1
  272. end;
  273. if pd^[n+1] <= 0
  274. then
  275. begin
  276. term:=3;
  277. exit
  278. end;
  279. for i:=1 to n+1 do
  280. dinv^[i]:=1/pd^[i];
  281. for i:=1 to n do
  282. h^[i]:=px^[i+1]-px^[i];
  283. t^[2]:=(h^[1]+h^[2])/3;
  284. for i:=2 to n-1 do
  285. begin
  286. t^[2*i]:=(h^[i]+h^[i+1])/3; t^[2*i-1]:=h^[i]/6
  287. end;
  288. move(t^[1], tl^[1], ns2);
  289. mdtgpb(n-1, 1, 2, tl^[1], ca, term);
  290. if term=2
  291. then
  292. exit;
  293. z^[1]:=1/(h^[1]*tl^[2]);
  294. for j:=2 to n-1 do
  295. z^[j]:=-(tl^[2*j-1]*z^[j-1])/tl^[2*j];
  296. s:=0;
  297. for j:=1 to n-1 do
  298. s:=s+sqr(z^[j]);
  299. diagb^[1]:=s;
  300. z^[1]:=(-1/h^[1]-1/h^[2])/tl^[2];
  301. if n>2
  302. then
  303. z^[2]:=(1/h^[2]-tl^[3]*z^[1])/tl^[4];
  304. for j:=3 to n-1 do
  305. z^[j]:=-tl^[2*j-1]*z^[j-1]/tl^[2*j];
  306. s:=0;
  307. for j:=1 to n-1 do
  308. s:=s+sqr(z^[j]);
  309. diagb^[2]:=s;
  310. for i:=2 to n-2 do
  311. begin
  312. z^[i-1]:=1/(h^[i]*tl^[2*(i-1)]);
  313. z^[i]:=(-1/h^[i]-1/h^[i+1]-tl^[2*i-1]*z^[i-1])/tl^[2*i];
  314. z^[i+1]:=(1/h^[i+1]-tl^[2*i+1]*z^[i])/tl^[2*(i+1)];
  315. for j:=i+2 to n-1 do
  316. z^[j]:=-tl^[2*j-1]*z^[j-1]/tl^[2*j];
  317. s:=0;
  318. for j:=i-1 to n-1 do
  319. s:=s+sqr(z^[j]);
  320. diagb^[i+1]:=s
  321. end;
  322. z^[n-2]:=1/(h^[n-1]*tl^[2*(n-2)]);
  323. z^[n-1]:=(-1/h^[n-1]-1/h^[n]-tl^[2*n-3]*z^[n-2])/tl^[2*(n-1)];
  324. s:=0;
  325. for j:=n-2 to n-1 do
  326. s:=s+sqr(z^[j]);
  327. diagb^[n]:=s;
  328. diagb^[n+1]:=1/sqr(h^[n]*tl^[2*(n-1)]);
  329. p:=1/h^[1];
  330. for i:=2 to n do
  331. begin
  332. q:=1/h^[i]; qty^[i-1]:=py^[i+1]*q-py^[i]*(p+q)+py^[i-1]*p;
  333. p:=q
  334. end;
  335. p:=1/h^[1]; q:=1/h^[2]; r:=1/h^[3];
  336. qtdinvq^[3]:=dinv^[1]*p*p+dinv^[2]*(p+q)*(p+q)+dinv^[3]*q*q;
  337. if n>2
  338. then
  339. begin
  340. qtdinvq^[6]:=dinv^[2]*q*q+dinv^[3]*(q+r)*(q+r)+dinv^[4]*r*r;
  341. qtdinvq^[5]:=-(dinv^[2]*(p+q)+dinv^[3]*(q+r))*q;
  342. p:=q; q:=r;
  343. for i:=3 to n-1 do
  344. begin
  345. r:=1/h^[i+1];
  346. qtdinvq^[3*i]:=dinv^[i]*q*q+dinv^[i+1]*(q+r)*(q+r)+dinv^[i+2]*r*r;
  347. qtdinvq^[3*i-1]:=-(dinv^[i]*(p+q)+dinv^[i+1]*(q+r))*q;
  348. qtdinvq^[3*i-2]:=dinv^[i]*p*q;
  349. p:=q; q:=r
  350. end
  351. end;
  352. dslgpb(n-1, 1, 2, tl^[1], qty^[1], c^[1], term);
  353. if term=2
  354. then
  355. exit;
  356. ey:=e(c^[1], h^[1], n);
  357. lam0:=0;
  358. s:=cr(lam0);
  359. if term=2
  360. then
  361. exit;
  362. if s >= 0
  363. then
  364. begin
  365. lambda:=0; term:=4
  366. end
  367. else
  368. begin
  369. lam1:=1e-8; ub:=false;
  370. while (not ub) and (lam1<=1.1e8) do
  371. begin
  372. s:=cr(lam1);
  373. if term=2
  374. then
  375. exit;
  376. if s >= 0
  377. then
  378. ub:=true
  379. else
  380. begin
  381. lam0:=lam1; lam1:=10*lam1
  382. end
  383. end;
  384. if not ub
  385. then
  386. begin
  387. term:=4; lambda:=lam0
  388. end
  389. else
  390. roof1r(lam0, lam1, 0, 1e-6, lambda);
  391. if term=2
  392. then
  393. exit
  394. end;
  395. end;
  396. begin
  397. term:=1;
  398. if n < 2
  399. then
  400. begin
  401. term:=3; exit
  402. end;
  403. sr:=sizeof(ArbFloat);
  404. n1s:=(n+1)*sr;
  405. ns2:=2*(n-1)*sr;
  406. ns1:=(n-1)*sr;
  407. getmem(dinv, n1s);
  408. getmem(h, n*sr);
  409. getmem(t, ns2);
  410. getmem(tl, ns2);
  411. getmem(z, ns1);
  412. getmem(diagb, n1s);
  413. getmem(qtdinvq, 3*ns1);
  414. getmem(c, ns1);
  415. getmem(qty, ns1);
  416. getmem(pd, n1s);
  417. { pd:=@d; }
  418. px:=@x;
  419. py:=@y;
  420. pa:=@a;
  421. pd2a:=@d2a;
  422. { de gewichten van de punten worden op 1 gezet}
  423. for i:=1 to n+1 do
  424. pd^[i]:=1;
  425. NoodGreep;
  426. freemem(dinv, n1s);
  427. freemem(h, n*sr);
  428. freemem(t, ns2);
  429. freemem(tl, ns2);
  430. freemem(z, ns1);
  431. freemem(diagb, n1s);
  432. freemem(qtdinvq, 3*ns1);
  433. freemem(c, ns1);
  434. freemem(qty, ns1);
  435. freemem(pd, n1s);
  436. end; {ipffsn}
  437. procedure ortpol(m, n: ArbInt; var x, alfa, beta: ArbFloat);
  438. // this function used to use mark/release.
  439. var
  440. i, j, ms : ArbInt;
  441. xppn1, ppn1, ppn, p, alfaj, betaj : ArbFloat;
  442. px, pal, pbe, pn, pn1 : ^arfloat1;
  443. begin
  444. px:=@x; pal:=@alfa; pbe:=@beta; ms:=m*sizeof(ArbFloat);
  445. getmem(pn, ms); getmem(pn1, ms);
  446. xppn1:=0; ppn1:=m;
  447. for i:=1 to m do
  448. begin
  449. pn^[i]:=0; pn1^[i]:=1; xppn1:=xppn1+px^[i]
  450. end;
  451. pal^[1]:=xppn1/ppn1; pbe^[1]:=0;
  452. for j:=2 to n do
  453. begin
  454. alfaj:=pal^[j-1]; betaj:=pbe^[j-1];
  455. ppn:=ppn1; ppn1:=0; xppn1:=0;
  456. for i:=1 to m do
  457. begin
  458. p:=(px^[i]-alfaj)*pn1^[i]-betaj*pn^[i];
  459. pn^[i]:=pn1^[i]; pn1^[i]:=p; p:=p*p;
  460. ppn1:=ppn1+p; xppn1:=xppn1+px^[i]*p
  461. end; {i}
  462. pal^[j]:=xppn1/ppn1; pbe^[j]:=ppn1/ppn
  463. end; {j}
  464. freemem(pn); freemem(pn1);
  465. end; {ortpol}
  466. procedure ortcoe(m, n: ArbInt; var x, y, alfa, beta, a: ArbFloat);
  467. // this function used to use mark/release.
  468. var i, j, mr : ArbInt;
  469. fpn, ppn, p, alphaj, betaj : ArbFloat;
  470. px, py, pal, pbe, pa, pn, pn1 : ^arfloat1;
  471. begin
  472. mr:=m*sizeof(ArbFloat);
  473. px:=@x; py:=@y; pal:=@alfa; pbe:=@beta; pa:=@a;
  474. getmem(pn, mr); getmem(pn1, mr);
  475. fpn:=0;
  476. for i:=1 to m do
  477. begin
  478. pn^[i]:=0; pn1^[i]:=1; fpn:=fpn+py^[i]
  479. end; {i}
  480. pa^[1]:=fpn/m;
  481. for j:=1 to n do
  482. begin
  483. fpn:=0; ppn:=0; alphaj:=pal^[j]; betaj:=pbe^[j];
  484. for i:=1 to m do
  485. begin
  486. p:=(px^[i]-alphaj)*pn1^[i]-betaj*pn^[i];
  487. pn^[i]:=pn1^[i]; pn1^[i]:=p;
  488. fpn:=fpn+py^[i]*p; ppn:=ppn+p*p
  489. end; {i}
  490. pa^[j+1]:=fpn/ppn
  491. end; {j}
  492. freemem(pn); freemem(pn1);
  493. end; {ortcoe}
  494. procedure polcoe(n:ArbInt; var alfa, beta, a, b: ArbFloat);
  495. var k, j : ArbInt;
  496. pal, pbe : ^arfloat1;
  497. pa, pb : ^arfloat0;
  498. begin
  499. pal:=@alfa; pbe:=@beta; pa:=@a; pb:=@b;
  500. move(pa^[0], pb^[0], (n+1)*sizeof(ArbFloat));
  501. for j:=0 to n-1 do
  502. for k:=n-j-1 downto 0 do
  503. begin
  504. pb^[k+j]:=pb^[k+j]-pal^[k+1]*pb^[k+j+1];
  505. if k+j<>n-1
  506. then
  507. pb^[k+j]:=pb^[k+j]-pbe^[k+2]*pb^[k+j+2]
  508. end
  509. end; {polcoe}
  510. procedure ipfpol(m, n: ArbInt; var x, y, b: ArbFloat; var term: ArbInt);
  511. var i, ns: ArbInt;
  512. fsum: ArbFloat;
  513. py, alfa, beta: ^arfloat1;
  514. pb, a: ^arfloat0;
  515. begin
  516. if (n<0) or (m<1)
  517. then
  518. begin
  519. term:=3; exit
  520. end;
  521. term:=1;
  522. if n = 0
  523. then
  524. begin
  525. py:=@y; pb:=@b;
  526. fsum:=0;
  527. for i:=1 to m do
  528. fsum:=fsum+py^[i];
  529. pb^[0]:=fsum/m
  530. end
  531. else
  532. begin
  533. if n>m-1
  534. then
  535. begin
  536. pb:=@b;
  537. fillchar(pb^[m], (n-m+1)*sizeof(ArbFloat), 0);
  538. n:=m-1
  539. end;
  540. ns:=n*sizeof(ArbFloat);
  541. getmem(alfa, ns); getmem(beta, ns);
  542. getmem(a, (n+1)*sizeof(ArbFloat));
  543. ortpol(m, n, x, alfa^[1], beta^[1]);
  544. ortcoe(m, n, x, y, alfa^[1], beta^[1], a^[0]);
  545. polcoe(n, alfa^[1], beta^[1], a^[0], b);
  546. freemem(alfa, ns); freemem(beta, ns);
  547. freemem(a, (n+1)*sizeof(ArbFloat));
  548. end
  549. end; {ipfpol}
  550. procedure ipfisn(n: ArbInt; var x, y, d2s: ArbFloat; var term: ArbInt);
  551. var
  552. s, i, L : ArbInt;
  553. p, q : ArbFloat;
  554. px, py, h, b, t : ^arfloat0;
  555. pd2s : ^arfloat1;
  556. ca : ArbFloat = 0.0;
  557. begin
  558. term:=1;
  559. if n < 1
  560. then
  561. begin
  562. term:=3; exit
  563. end; {n<1}
  564. if n = 1 then
  565. exit;
  566. px:=@x; py:=@y; pd2s:=@d2s;
  567. s:=sizeof(ArbFloat);
  568. getmem(h, n*s);
  569. getmem(b, (n-1)*s);
  570. getmem(t, 2*(n-1)*s);
  571. for i:=0 to n-1 do
  572. h^[i]:=px^[i+1]-px^[i];
  573. q:=1/6; p:=2*q;
  574. t^[1]:=p*(h^[0]+h^[1]);
  575. for i:=2 to n-1 do
  576. begin
  577. t^[2*i-1]:=p*(h^[i-1]+h^[i]); t^[2*i-2]:=q*h^[i-1]
  578. end; {i}
  579. p:=1/h^[0];
  580. for i:=2 to n do
  581. begin
  582. q:=1/h^[i-1]; b^[i-2]:=py^[i]*q-py^[i-1]*(p+q)+py^[i-2]*p; p:=q
  583. end;
  584. if n > 2 then L := 1 else L := 0;
  585. slegpb(n-1, L, {2,} t^[1], b^[0], pd2s^[1], ca, term);
  586. freemem(h, n*s);
  587. freemem(b, (n-1)*s);
  588. freemem(t, 2*(n-1)*s);
  589. end; {ipfisn}
  590. function ipfspn(n: ArbInt; var x, y, d2s: ArbFloat; t:ArbFloat;
  591. var term: ArbInt): ArbFloat;
  592. var
  593. px, py : ^arfloat0;
  594. pd2s : ^arfloat1;
  595. i, j, m : ArbInt;
  596. d, s3, h, dy : ArbFloat;
  597. begin
  598. term:=1;
  599. if n<1
  600. then
  601. begin
  602. term:=3; exit
  603. end; {n<1}
  604. px:=@x; py:=@y; pd2s:=@d2s;
  605. if n = 1
  606. then
  607. begin
  608. h:=px^[1]-px^[0];
  609. dy:=(py^[1]-py^[0])/h;
  610. ipfspn:=py^[0]+(t-px^[0])*dy
  611. end { n = 1 }
  612. else
  613. if t <= px^[0]
  614. then
  615. begin
  616. h:=px^[1]-px^[0];
  617. dy:=(py^[1]-py^[0])/h-h*pd2s^[1]/6;
  618. ipfspn:=py^[0]+(t-px^[0])*dy
  619. end { t <= x[0] }
  620. else
  621. if t >= px^[n]
  622. then
  623. begin
  624. h:=px^[n]-px^[n-1];
  625. dy:=(py^[n]-py^[n-1])/h+h*pd2s^[n-1]/6;
  626. ipfspn:=py^[n]+(t-px^[n])*dy
  627. end { t >= x[n] }
  628. else
  629. begin
  630. i:=0; j:=n;
  631. while j <> i+1 do
  632. begin
  633. m:=(i+j) div 2;
  634. if t>=px^[m]
  635. then
  636. i:=m
  637. else
  638. j:=m
  639. end; {j}
  640. h:=px^[i+1]-px^[i];
  641. d:=t-px^[i];
  642. if i=0
  643. then
  644. begin
  645. s3:=pd2s^[1]/h;
  646. dy:=(py^[1]-py^[0])/h-h*pd2s^[1]/6;
  647. ipfspn:=py^[0]+d*(dy+d*d*s3/6)
  648. end
  649. else
  650. if i=n-1
  651. then
  652. begin
  653. s3:=-pd2s^[n-1]/h;
  654. dy:=(py^[n]-py^[n-1])/h-h*pd2s^[n-1]/3;
  655. ipfspn:=py^[n-1]+d*(dy+d*(pd2s^[n-1]/2+d*s3/6))
  656. end
  657. else
  658. begin
  659. s3:=(pd2s^[i+1]-pd2s^[i])/h;
  660. dy:=(py^[i+1]-py^[i])/h-h*(2*pd2s^[i]+pd2s^[i+1])/6;
  661. ipfspn:=py^[i]+d*(dy+d*(pd2s^[i]/2+d*s3/6))
  662. end
  663. end { x[0] < t < x[n] }
  664. end; {ipfspn}
  665. procedure ipfsmm(
  666. n: ArbInt; var x, y, d2s, minv, maxv: ArbFloat; var term: ArbInt);
  667. var
  668. i: ArbInt;
  669. h: ArbFloat;
  670. px, py: ^arfloat0;
  671. pd2s: ^arfloat1;
  672. procedure UpdateMinMax(v: ArbFloat);
  673. begin
  674. if (0 >= v) or (v >= h) then exit;
  675. v := ipfspn(n, x, y, d2s, px^[i]+v, term);
  676. if v < minv then
  677. minv := v;
  678. if v > maxv then
  679. maxv := v;
  680. end;
  681. procedure MinMaxOnSegment;
  682. var
  683. a, b, c: ArbFloat;
  684. d: ArbFloat;
  685. begin
  686. h:=px^[i+1]-px^[i];
  687. if i=0
  688. then
  689. begin
  690. a:=pd2s^[1]/h/2;
  691. b:=0;
  692. c:=(py^[1]-py^[0])/h-h*pd2s^[1]/6;
  693. end
  694. else
  695. if i=n-1
  696. then
  697. begin
  698. a:=-pd2s^[n-1]/h/2;
  699. b:=pd2s^[n-1];
  700. c:=(py^[n]-py^[n-1])/h-h*pd2s^[n-1]/3;
  701. end
  702. else
  703. begin
  704. a:=(pd2s^[i+1]-pd2s^[i])/h/2;
  705. b:=pd2s^[i];
  706. c:=(py^[i+1]-py^[i])/h-h*(2*pd2s^[i]+pd2s^[i+1])/6;
  707. end;
  708. if a=0 then exit;
  709. d := b*b-4*a*c;
  710. if d<0 then exit;
  711. d:=Sqrt(d);
  712. UpdateMinMax((-b+d)/(2*a));
  713. UpdateMinMax((-b-d)/(2*a));
  714. end;
  715. begin
  716. term:=1;
  717. if n<1 then begin
  718. term:=3;
  719. exit;
  720. end;
  721. if n = 1 then
  722. exit;
  723. px:=@x; py:=@y; pd2s:=@d2s;
  724. for i:=0 to n-1 do
  725. MinMaxOnSegment;
  726. end;
  727. procedure ipfish(hst: THermiteSplineType; n: ArbInt; var x, y, d1s: ArbFloat; var term: ArbInt);
  728. var
  729. px, py, pd1s : ^arfloat0;
  730. i : ArbInt;
  731. dks : array of ArbFloat;
  732. begin
  733. term:=1;
  734. if n < 1 then
  735. begin
  736. term:=3;
  737. exit;
  738. end;
  739. px:=@x;
  740. py:=@y;
  741. pd1s:=@d1s;
  742. {Monotone cubic Hermite interpolation}
  743. {See: https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
  744. and: https://en.wikipedia.org/wiki/Cubic_Hermite_spline}
  745. {For each two adjacent data points, calculate tangent of the segment between them}
  746. SetLength(dks,n);
  747. for i:=0 to n-1 do
  748. dks[i]:=(py^[i+1]-py^[i])/(px^[i+1]-px^[i]);
  749. {As proposed by Fritsch and Carlson: For each data point - except the first and
  750. the last one - assign point's tangent (stored in a "d1s" array) as an average
  751. of tangents of the two adjacent segments (this is called 3PD, three-point
  752. difference) - but only if both tangents are either positive (segments are
  753. raising) or negative (segments are falling); in all other cases there is a local
  754. extremum at the data point, or a non-monotonic range begins/continues/ends there,
  755. so spline at this point must be flat to preserve monotonicity - so assign point's
  756. tangent as zero}
  757. for i:=0 to n-2 do
  758. if ((dks[i] > 0) and (dks[i+1] > 0)) or ((dks[i] < 0) and (dks[i+1] < 0)) then
  759. pd1s^[i+1]:=0.5*(dks[i]+dks[i+1])
  760. else
  761. pd1s^[i+1]:=0;
  762. {For the first and the last data point, assign point's tangent as a tangent of
  763. the adjacent segment (this is called one-sided difference)}
  764. pd1s^[0]:=dks[0];
  765. pd1s^[n]:=dks[n-1];
  766. {As proposed by Fritsch and Carlson: Reduce point's tangent if needed, to prevent
  767. overshoot}
  768. for i:=0 to n-1 do
  769. if dks[i] <> 0 then
  770. try
  771. if pd1s^[i]/dks[i] > 3 then
  772. pd1s^[i]:=3*dks[i];
  773. if pd1s^[i+1]/dks[i] > 3 then
  774. pd1s^[i+1]:=3*dks[i];
  775. except
  776. {There may be an exception for dks[i] values that are very close to zero}
  777. pd1s^[i]:=0;
  778. pd1s^[i+1]:=0;
  779. end;
  780. {Addition to the original algorithm: For the first and the last data point,
  781. modify point's tangent in such a way that the cubic Hermite interpolation
  782. polynomial has its inflection point exactly at the data point - so there
  783. will be a smooth transition to the extrapolated part of the graph}
  784. pd1s^[0]:=1.5*dks[0]-0.5*pd1s^[1];
  785. pd1s^[n]:=1.5*dks[n-1]-0.5*pd1s^[n-1];
  786. end; {ipfish}
  787. function ipfsph(n: ArbInt; var x, y, d1s: ArbFloat; t: ArbFloat; var term: ArbInt): ArbFloat;
  788. var
  789. px, py, pd1s : ^arfloat0;
  790. i, j, m : ArbInt;
  791. h : ArbFloat;
  792. begin
  793. term:=1;
  794. if n < 1 then
  795. begin
  796. term:=3;
  797. exit;
  798. end;
  799. px:=@x;
  800. py:=@y;
  801. pd1s:=@d1s;
  802. if t <= px^[0] then
  803. ipfsph:=py^[0]+(t-px^[0])*pd1s^[0]
  804. else
  805. if t >= px^[n] then
  806. ipfsph:=py^[n]+(t-px^[n])*pd1s^[n]
  807. else
  808. begin
  809. i:=0;
  810. j:=n;
  811. while j <> i+1 do
  812. begin
  813. m:=(i+j) div 2;
  814. if t>=px^[m] then
  815. i:=m
  816. else
  817. j:=m;
  818. end; {j}
  819. h:=px^[i+1]-px^[i];
  820. t:=(t-px^[i])/h;
  821. ipfsph:= py^[i]*(1+2*t)*Sqr(1-t) + h*pd1s^[i]*t*Sqr(1-t) + py^[i+1]*Sqr(t)*(3-2*t) + h*pd1s^[i+1]*Sqr(t)*(t-1);
  822. end;
  823. end; {ipfsph}
  824. function p(x, a, z:complex): ArbFloat;
  825. begin
  826. x.sub(a);
  827. p:=x.Inp(z)
  828. end;
  829. function e(x, y: complex): ArbFloat;
  830. const c1: ArbFloat = 0.01989436788646;
  831. var s: ArbFloat;
  832. begin x.sub(y);
  833. s := x.norm;
  834. if s=0 then e:=0 else e:=c1*s*ln(s)
  835. end;
  836. function spline( n : ArbInt;
  837. x : complex;
  838. var ac : complex;
  839. var gammar: ArbFloat;
  840. u1 : ArbFloat;
  841. pf : complex): ArbFloat;
  842. var i : ArbInt;
  843. s : ArbFloat;
  844. a : arcomp0 absolute ac;
  845. gamma : arfloat0 absolute gammar;
  846. begin
  847. s := u1 + p(x, a[n-2], pf);
  848. for i:=0 to n do s := s + gamma[i]*e(x,a[i]);
  849. spline := s
  850. end;
  851. procedure splineparameters
  852. ( n : ArbInt;
  853. var ac, alfadc : complex;
  854. var lambda,
  855. gammar, u1,
  856. kwsom, energie : ArbFloat;
  857. var pf : complex);
  858. procedure SwapC(var v, w: complex);
  859. var x: complex;
  860. begin
  861. x := v; v := w; w := x
  862. end;
  863. procedure pxpy(a, b, c: complex; var p:complex);
  864. var det: ArbFloat;
  865. begin
  866. b.sub(a); c.sub(a); det := b.xreal*c.imag-b.imag*c.xreal;
  867. b.sub(c); p.Init(b.imag/det, -b.xreal/det)
  868. end;
  869. procedure pfxpfy(a, b, c: complex; f: vector; var pf: complex);
  870. begin
  871. b.sub(a); c.sub(a);
  872. f.j := f.j-f.i; f.k := f.k-f.i;
  873. pf.init(f.j*c.imag - f.k*b.imag, -f.j*c.xreal + f.k*b.xreal);
  874. pf.scale(1/(b.xreal*c.imag - b.imag*c.xreal))
  875. end;
  876. function InpV(n: ArbInt; var v1, v2: ArbFloat): ArbFloat;
  877. var i: ArbInt;
  878. a1: arfloat0 absolute v1;
  879. a2: arfloat0 absolute v2;
  880. s : ArbFloat;
  881. begin
  882. s := 0;
  883. for i:=0 to n-1 do s := s + a1[i]*a2[i];
  884. InpV := s
  885. end;
  886. PROCEDURE SPDSOL( N : INTEGER;
  887. VAR AP : pointer;
  888. VAR B : ArbFloat);
  889. VAR I, J, K : INTEGER;
  890. H : ArbFloat;
  891. a : ^ar2dr absolute ap;
  892. bx : arfloat0 absolute b;
  893. BEGIN
  894. for k:=0 to n do
  895. BEGIN
  896. h := sqrt(a^[k]^[k]-InpV(k, a^[k]^[0], a^[k]^[0]));
  897. a^[k]^[k] := h;
  898. FOR I:=K+1 TO N do a^[i]^[k] := (a^[i]^[k] - InpV(k, a^[k]^[0], a^[i]^[0]))/h;
  899. BX[K] := (bx[k] - InpV(k, a^[k]^[0], bx[0]))/h
  900. END;
  901. FOR I:=N DOWNTO 0 do
  902. BEGIN
  903. H := BX[I];
  904. FOR J:=I+1 TO N DO H := H - A^[J]^[I]*BX[J];
  905. BX[I] := H/A^[I]^[I]
  906. END
  907. END;
  908. var i, j, i1 : ArbInt;
  909. x, h,
  910. absdet,
  911. absdetmax,
  912. s, s1, ca: ArbFloat;
  913. alfa, dv, hulp,
  914. u, v, w : vector;
  915. e22 : array[0..2] of vector;
  916. e21, b : ^arvect0;
  917. k, c : ^ar2dr;
  918. gamma : arfloat0 absolute gammar;
  919. an2, an1, an, z,
  920. vz, wz : complex;
  921. a : arcomp0 absolute ac;
  922. alfad : arcomp0 absolute alfadc;
  923. begin
  924. i1:=0;
  925. x:=a[0].xreal;
  926. for i:=1 to n do
  927. begin
  928. h:=a[i].xreal;
  929. if h<x then begin i1:=i; x:=h end
  930. end;
  931. SwapC(a[n-2], a[i1]);
  932. SwapC(alfad[n-2], alfad[i1]);
  933. x:=a[0].xreal;
  934. i1 := 0;
  935. for i:=1 to n do
  936. begin
  937. h:=a[i].xreal;
  938. if h>x then begin i1:=i; x:=h end
  939. end;
  940. SwapC(a[n-1], a[i1]);
  941. SwapC(alfad[n-1], alfad[i1]);
  942. vz := a[n-2]; vz.sub(a[n-1]);
  943. absdetmax := -1;
  944. for i:=0 to n do
  945. begin
  946. wz := a[i]; wz.sub(a[n-2]);
  947. absdet := abs(wz.imag*vz.xreal-wz.xreal*vz.imag);
  948. if absdet>absdetmax then begin i1:=i; absdetmax:=absdet end
  949. end;
  950. SwapC(a[n], a[i1]);
  951. SwapC(alfad[n], alfad[i1]);
  952. an2 := a[n-2]; an1 := a[n-1]; an := a[n];
  953. alfa.i := alfad[n-2].xreal; dv.i := alfad[n-2].imag;
  954. alfa.j := alfad[n-1].xreal; dv.j := alfad[n-1].imag;
  955. alfa.k := alfad[n ].xreal; dv.k := alfad[n ].imag;
  956. n := n - 3;
  957. GetMem(k, (n+1)*SizeOf(pointer));
  958. for j:=0 to n do GetMem(k^[j], (j+1)*SizeOf(ArbFloat));
  959. GetMem(e21, (n+1)*SizeOf(vector));
  960. GetMem(b, (n+1)*SizeOf(vector));
  961. pxpy(an2,an1,an,z); for i:=0 to n do b^[i].i:=1+p(a[i],an2,z);
  962. pxpy(an1,an,an2,z); for i:=0 to n do b^[i].j:=1+p(a[i],an1,z);
  963. pxpy(an,an2,an1,z); for i:=0 to n do b^[i].k:=1+p(a[i],an,z);
  964. e22[0].init(0,e(an1,an2),e(an,an2));
  965. e22[1].init(e(an1,an2),0,e(an,an1));
  966. e22[2].init(e(an,an2),e(an,an1),0);
  967. for j:=0 to n do e21^[j].init(e(an2,a[j]),e(an1,a[j]),e(an,a[j]));
  968. GetMem(c, (n+1)*SizeOf(pointer));
  969. for j:=0 to n do GetMem(c^[j], (j+1)*SizeOf(ArbFloat));
  970. for i:=0 to n do
  971. for j:=0 to i do
  972. begin
  973. if j=i then s:=0 else s:=e(a[i],a[j]);
  974. hulp.init(b^[j].Inprod(e22[0]), b^[j].Inprod(e22[1]), b^[j].Inprod(e22[2]));
  975. hulp.sub(e21^[j]);
  976. k^[i]^[j] := s+b^[i].InProd(hulp)-b^[j].Inprod(e21^[i]);
  977. if j=i then s:=1/alfad[i].imag else s:=0;
  978. hulp.init(b^[j].i/dv.i, b^[j].j/dv.j, b^[j].k/dv.k);
  979. c^[i]^[j] := k^[i]^[j] + (s + b^[i].Inprod(hulp))/lambda
  980. end;
  981. for i:=0 to n do gamma[i]:=alfad[i].xreal - b^[i].Inprod(alfa);
  982. SpdSol(n, pointer(c), gamma[0]);
  983. for j:=n downto 0 do FreeMem(c^[j], (j+1)*SizeOf(ArbFloat));
  984. FreeMem(c, (n+1)*SizeOf(pointer));
  985. s:=0; for j:=0 to n do s:=s+b^[j].i*gamma[j]; w.i:=s; gamma[n+1] := -s;
  986. s:=0; for j:=0 to n do s:=s+b^[j].j*gamma[j]; w.j:=s; gamma[n+2] := -s;
  987. s:=0; for j:=0 to n do s:=s+b^[j].k*gamma[j]; w.k:=s; gamma[n+3] := -s;
  988. FreeMem(b, (n+1)*SizeOf(vector));
  989. u.init(w.i/dv.i, w.j/dv.j, w.k/dv.k);
  990. u.scale(1/lambda);
  991. u.add(alfa);
  992. s:=0; for j:=0 to n do s:=s+e21^[j].i*gamma[j]; v.i := e22[0].inprod(w)-s;
  993. s:=0; for j:=0 to n do s:=s+e21^[j].j*gamma[j]; v.j := e22[1].inprod(w)-s;
  994. s:=0; for j:=0 to n do s:=s+e21^[j].k*gamma[j]; v.k := e22[2].inprod(w)-s;
  995. FreeMem(e21, (n+1)*SizeOf(vector));
  996. u.add(v);
  997. pfxpfy(an2, an1, an, u, pf); u1:=u.i;
  998. kwsom := 0; for j:=0 to n do kwsom:=kwsom+sqr(gamma[j])/alfad[j].imag;
  999. kwsom := kwsom+sqr(w.i)/dv.i+sqr(w.j)/dv.j+sqr(w.k)/dv.k;
  1000. kwsom := kwsom/sqr(lambda);
  1001. s:=0;
  1002. for i:=0 to n do
  1003. begin s1:=0;
  1004. for j:=0 to i do s1:=s1+k^[i]^[j]*gamma[j];
  1005. for j:=i+1 to n do s1:=s1+k^[j]^[i]*gamma[j];
  1006. s := gamma[i]*s1+s
  1007. end;
  1008. for j:=n downto 0 do FreeMem(k^[j], (j+1)*SizeOf(ArbFloat));
  1009. FreeMem(k, (n+1)*SizeOf(pointer));
  1010. energie := s
  1011. end {splineparameters};
  1012. end.