inv.pas 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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. Calculate inverses for different kinds of matrices (different with respect
  9. to symmetry)
  10. See the file COPYING.FPC, included in this distribution,
  11. for details about the copyright.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. **********************************************************************}
  16. {$IFNDEF FPC_DOTTEDUNITS}
  17. unit inv;
  18. {$ENDIF FPC_DOTTEDUNITS}
  19. {$I DIRECT.INC}
  20. interface
  21. {$IFDEF FPC_DOTTEDUNITS}
  22. uses NumLib.Typ;
  23. {$ELSE FPC_DOTTEDUNITS}
  24. uses typ;
  25. {$ENDIF FPC_DOTTEDUNITS}
  26. {Calc inverse for a matrix with unknown symmetry. General version. }
  27. procedure invgen(n, rwidth: ArbInt; var ai: ArbFloat; var term: ArbInt);
  28. {Calc inverse for a symmetrical matrix}
  29. procedure invgsy(n, rwidth: ArbInt; var ai: ArbFloat; var term: ArbInt);
  30. {Calc inverse for a positive definite symmetrical matrix}
  31. procedure invgpd(n, rwidth: ArbInt; var ai: ArbFloat; var term: ArbInt);
  32. implementation
  33. {$IFDEF FPC_DOTTEDUNITS}
  34. uses NumLib.Mdt, NumLib.Dsl;
  35. {$ELSE FPC_DOTTEDUNITS}
  36. uses mdt, dsl;
  37. {$ENDIF FPC_DOTTEDUNITS}
  38. procedure invgen(n, rwidth: ArbInt; var ai: ArbFloat; var term: ArbInt);
  39. var
  40. success : boolean;
  41. inn, ii, i, j, k, kk, indexpivot : ArbInt;
  42. ca, h, pivot, s : ArbFloat;
  43. pa, save : ^arfloat1;
  44. p : ^arint1;
  45. begin
  46. if (n<1) or (rwidth<1) then
  47. begin
  48. term:=3; exit
  49. end; {wrong input}
  50. pa:=@ai;
  51. getmem(p, n*sizeof(ArbInt)); getmem(save, n*sizeof(ArbFloat));
  52. mdtgen(n, rwidth, pa^[1], p^[1], ca, term);
  53. if term=1 then
  54. begin
  55. inn:=(n-1)*rwidth+n; pivot:=pa^[inn];
  56. if pivot=0 then success:=false else
  57. begin
  58. success:=true; pa^[inn]:=1/pivot; k:=n;
  59. while (k>1) and success do
  60. begin
  61. k:=k-1; kk:=(k-1)*rwidth;
  62. for i:=k+1 to n do save^[i]:=-pa^[(i-1)*rwidth+k];
  63. for i:=k+1 to n do
  64. begin
  65. ii:=(i-1)*rwidth;
  66. s:=0;
  67. for j:=k+1 to n do s:=s+pa^[ii+j]*save^[j];
  68. pa^[ii+k]:=s
  69. end; {i}
  70. for j:=k+1 to n do save^[j]:=pa^[kk+j];
  71. pivot:=pa^[kk+k];
  72. if pivot=0 then success:=false else
  73. begin
  74. s:=0;
  75. for i:=k+1 to n do s:=s-save^[i]*pa^[(i-1)*rwidth+k];
  76. pa^[kk+k]:=(1+s)/pivot;
  77. for j:=k+1 to n do
  78. begin
  79. s:=0;
  80. for i:=k+1 to n do s:=s-save^[i]*pa^[(i-1)*rwidth+j];
  81. pa^[(k-1)*rwidth+j]:=s/pivot
  82. end {j}
  83. end {pivot <> 0}
  84. end; {k}
  85. if success then
  86. for k:=n downto 1 do
  87. begin
  88. indexpivot:=p^[k];
  89. if indexpivot <> k then
  90. for i:=1 to n do
  91. begin
  92. ii:=(i-1)*rwidth;
  93. h:=pa^[ii+k]; pa^[ii+k]:=pa^[ii+indexpivot];
  94. pa^[ii+indexpivot]:=h
  95. end {i}
  96. end {k}
  97. end; {pivot <> 0}
  98. if (not success) then term:=2
  99. end else term:=2;
  100. freemem(p, n*sizeof(ArbInt)); freemem(save, n*sizeof(ArbFloat));
  101. end; {invgen}
  102. procedure invgsy(n, rwidth: ArbInt; var ai: ArbFloat; var term: ArbInt);
  103. var ind, ind1, i, m, pk, j,
  104. kmin1, k, imin2, nsr,
  105. imin1, jmin1, iplus1 : ArbInt;
  106. success : boolean;
  107. di, h, ca : ArbFloat;
  108. pa, l, d, u, v, e, e1, x : ^arfloat1;
  109. p : ^arint1;
  110. q : ^arbool1;
  111. begin
  112. if (n<1) or (rwidth<1) then
  113. begin
  114. term:=3; exit
  115. end; {wrong input}
  116. pa:=@ai;
  117. getmem(p, n*sizeof(ArbInt)); getmem(q, n*sizeof(boolean));
  118. nsr:=n*sizeof(ArbFloat);
  119. getmem(l, nsr); getmem(d, nsr); getmem(u, nsr);
  120. getmem(v, nsr); getmem(e, nsr); getmem(e1, nsr);
  121. getmem(x, ((n+1)*nsr) div 2);
  122. mdtgsy(n, rwidth, pa^[1], p^[1], q^[1], ca, term);
  123. if term=1 then
  124. begin
  125. success:=true; i:=1; ind:=1;
  126. while (i<>n+1) and success do
  127. begin
  128. success:=pa^[ind]<>0; ind:=ind+rwidth+1; i:=i+1
  129. end; {i}
  130. if success then
  131. begin
  132. d^[1]:=pa^[1]; di:=d^[1]; l^[1]:=pa^[rwidth+1];
  133. d^[2]:=pa^[rwidth+2]; di:=d^[2]; u^[1]:=pa^[2];
  134. imin1:=1; i:=2;
  135. while i<n do
  136. begin
  137. imin2:=imin1; imin1:=i; i:=i+1; ind:=imin1*rwidth;
  138. l^[imin1]:=pa^[ind+imin1]; d^[i]:=pa^[ind+i]; di:=d^[i];
  139. u^[imin1]:=pa^[ind-rwidth+i]; v^[imin2]:=pa^[ind-2*rwidth+i]
  140. end; {i}
  141. m:=0; k:=0;
  142. while k<n do
  143. begin
  144. kmin1:=k; k:=k+1;
  145. for i:=1 to kmin1 do e^[i]:=0;
  146. e^[k]:=1; i:=k;
  147. while i<n do
  148. begin
  149. imin1:=i; i:=i+1; h:=0;
  150. if k=1 then j:=1 else j:=kmin1;
  151. while j<imin1 do
  152. begin
  153. jmin1:=j; j:=j+1;
  154. h:=h-pa^[(i-1)*rwidth+jmin1]*e^[j]
  155. end; {j}
  156. e^[i]:=h
  157. end; {i}
  158. dslgtr(n, l^[1], d^[1], u^[1], v^[1], q^[1],
  159. e^[1], e1^[1], term);
  160. i:=n+1; imin1:=n;
  161. while i>2 do
  162. begin
  163. iplus1:=i; i:=imin1; imin1:=imin1-1; h:=e1^[i];
  164. for j:=iplus1 to n do
  165. h:=h-pa^[(j-1)*rwidth+imin1]*e1^[j];
  166. e1^[i]:=h
  167. end; {i}
  168. for i:=k to n do
  169. begin
  170. m:=m+1; x^[m]:=e1^[i]
  171. end
  172. end; {k}
  173. m:=0;
  174. for k:=1 to n do for i:=k to n do
  175. begin
  176. m:=m+1; pa^[(i-1)*rwidth+k]:=x^[m]
  177. end; {i,k}
  178. for k:=n-1 downto 2 do
  179. begin
  180. pk:=p^[k];
  181. if pk <> k then
  182. begin
  183. kmin1:=k-1; ind:=(k-1)*rwidth; ind1:=(pk-1)*rwidth;
  184. for j:=1 to kmin1 do
  185. begin
  186. h:=pa^[ind+j];
  187. pa^[ind+j]:=pa^[ind1+j]; pa^[ind1+j]:=h
  188. end; {j}
  189. for j:=pk downto k do
  190. begin
  191. ind:=(j-1)*rwidth;
  192. h:=pa^[ind+k];
  193. pa^[ind+k]:=pa^[ind1+j]; pa^[ind1+j]:=h
  194. end; {j}
  195. for i:=pk to n do
  196. begin
  197. ind:=(i-1)*rwidth;
  198. h:=pa^[ind+k];
  199. pa^[ind+k]:=pa^[ind+pk]; pa^[ind+pk]:=h
  200. end {i}
  201. end {pk <> k}
  202. end {k}
  203. end; {success}
  204. if (not success) then term:=2 else
  205. for i:=1 to n do
  206. begin
  207. ind:=(i-1)*rwidth;
  208. for j:=i+1 to n do pa^[ind+j]:=pa^[(j-1)*rwidth+i]
  209. end {i}
  210. end else term:=2;
  211. freemem(l, nsr); freemem(d, nsr); freemem(u, nsr);
  212. freemem(v, nsr); freemem(e, nsr); freemem(e1, nsr);
  213. freemem(x, ((n+1)*nsr) div 2);
  214. end; {invgsy}
  215. procedure invgpd(n, rwidth: ArbInt; var ai: ArbFloat; var term: ArbInt);
  216. var success : boolean;
  217. i, j, k, ind : ArbInt;
  218. tk, h, ca : ArbFloat;
  219. pa, t : ^arfloat1;
  220. begin
  221. if (n<1) or (rwidth<1) then
  222. begin
  223. term:=3; exit
  224. end; {wrong input}
  225. pa:=@ai;
  226. mdtgpd(n, rwidth, pa^[1], ca, term);
  227. getmem(t, n*sizeof(ArbFloat));
  228. if term=1 then
  229. begin
  230. success:=true; ind:=1; k:=1;
  231. while (k<>n+1) and success do
  232. begin
  233. success:=pa^[ind]<>0; k:=k+1; ind:=ind+rwidth+1
  234. end; {k}
  235. if success then
  236. begin
  237. for k:=n downto 1 do
  238. begin
  239. for i:=k to n do t^[i]:=pa^[(i-1)*rwidth+k];
  240. tk:=t^[k];
  241. for i:=n downto k do
  242. begin
  243. if i=k then h:=1/tk else h:=0;
  244. ind:=(i-1)*rwidth;
  245. for j:=k+1 to i do h:=h-pa^[ind+j]*t^[j];
  246. for j:=i+1 to n do h:=h-pa^[(j-1)*rwidth+i]*t^[j];
  247. pa^[ind+k]:=h/tk
  248. end {i}
  249. end {k}
  250. end; {success}
  251. if (not success) then term:=2 else
  252. for i:=1 to n do
  253. begin
  254. ind:=(i-1)*rwidth;
  255. for j:=i+1 to n do pa^[ind+j]:=pa^[(j-1)*rwidth+i]
  256. end; {i}
  257. end; {term=1}
  258. freemem(t, n*sizeof(ArbFloat));
  259. end; {invgpd}
  260. end.