ipf.pas 28 KB

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