cholesky.red 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. module cholesky;
  2. %**********************************************************************%
  3. % %
  4. % Computation of the Cholesky decomposition of dense positive definite %
  5. % matrices containing numeric entries. %
  6. % %
  7. % Author: Matt Rebbeck, May 1994. %
  8. % %
  9. % The algorithm was taken from "Linear Algebra" - J.H.Wilkinson %
  10. % & C. Reinsch %
  11. % %
  12. % %
  13. % NB: By using the same rounded number techniques as used in svd this %
  14. % could be made a lot faster. %
  15. % %
  16. %**********************************************************************%
  17. symbolic procedure cholesky(mat1);
  18. %
  19. % A must be a positive definite symmetric matrix.
  20. %
  21. % LU decomposition of matrix A. ie: A=LU, where U is the transpose
  22. % of L. The determinant of A is also computed as a side effect but
  23. % has been commented out as it is not necessary. The procedure will
  24. % fail if A is unsymmetric. It will also fail if A, modified by
  25. % rounding errors, is not positive definite.
  26. %
  27. % The reciprocals of the diagonal elements are stored in p and the
  28. % matrix is then 'dragged' out and 'glued' back together in get_l.
  29. %
  30. %
  31. begin
  32. scalar x,p,in_mat,L,U,I_turned_rounded_on; % d1,d2;
  33. integer i,j,n;
  34. if not !*rounded then << I_turned_rounded_on := t; on rounded; >>;
  35. if not matrixp(mat1) then
  36. rederr "Error in cholesky: non matrix input.";
  37. if not symmetricp(mat1) then
  38. rederr "Error in cholesky: input matrix is not symmetric.";
  39. in_mat := copy_mat(mat1);
  40. n := first size_of_matrix(in_mat);
  41. p := mkvect(n);
  42. % d1 := 1;
  43. % d2 := 0;
  44. for i:=1:n do
  45. <<
  46. for j:=i:n do
  47. <<
  48. x := innerprod(1,1,i-1,{'minus,getmat(in_mat,i,j)},
  49. row_vec(in_mat,i,n),row_vec(in_mat,j,n));
  50. x := reval{'minus,x};
  51. if j=i then
  52. <<
  53. % d1 := reval{'times,d1,x};
  54. if get_num_part(my_reval(x))<=0 then rederr
  55. "Error in cholesky: input matrix is not positive definite.";
  56. % while abs(get_num_part(d1)) >= 1 do
  57. % <<
  58. % d1 := reval{'times,d1,0.0625};
  59. % d2 := d2+4;
  60. % >>;
  61. % while abs(get_num_part(d1)) < 0.0625 do
  62. % <<
  63. % d1 := reval{'times,d1,16};
  64. % d2 := d2-4;
  65. % >>;
  66. putv(p,i,reval{'quotient,1,{'sqrt,x}});
  67. >>
  68. else
  69. <<
  70. setmat(in_mat,j,i,reval{'times,x,getv(p,i)});
  71. >>;
  72. >>;
  73. >>;
  74. L := get_l(in_mat,p,n);
  75. U := algebraic tp(L);
  76. if I_turned_rounded_on then off rounded;
  77. return {'list,L,U};
  78. end;
  79. flag('(cholesky),'opfn); % So it can be used from algebraic mode.
  80. symbolic procedure get_l(in_mat,p,sq_size);
  81. %
  82. % Pulls out L from in_mat and p.
  83. %
  84. begin
  85. scalar L;
  86. integer i,j;
  87. L := mkmatrix(sq_size,sq_size);
  88. for i:=1:sq_size do
  89. <<
  90. setmat(L,i,i,{'quotient,1,getv(p,i)});
  91. for j:=1:i-1 do
  92. <<
  93. setmat(L,i,j,getmat(in_mat,i,j));
  94. >>;
  95. >>;
  96. return L;
  97. end;
  98. symbolic procedure symmetricp(in_mat);
  99. %
  100. % Checks input is symmetric. ie: transpose(A) = A. (boolean).
  101. %
  102. if algebraic (tp(in_mat)) neq in_mat then nil else t;
  103. flag('(symmetricp),'boolean);
  104. flag('(symmetricp),'opfn);
  105. endmodule; % cholesky.
  106. end;