Cholesky decomposition: Difference between revisions

Content added Content deleted
(Added XPL0 example.)
(Added ATS.)
Line 357: Line 357:
12.72792 3.04604 1.64974 0.00000
12.72792 3.04604 1.64974 0.00000
9.89949 1.62455 1.84971 1.39262</pre>
9.89949 1.62455 1.84971 1.39262</pre>

=={{header|ATS}}==
<syntaxhighlight lang="ats">
%{^
#include <math.h>
#include <float.h>
%}

#include "share/atspre_staload.hats"

macdef NAN = g0f2f ($extval (float, "NAN"))
macdef Zero = g0i2f 0
macdef One = g0i2f 1
macdef Two = g0i2f 2

(* The following is often done by a single machine instruction. *)
macdef multiply_and_add (x, y, z) = (,(x) * ,(y)) + ,(z)

(* The sqrt(3) function made part of the ‘g0float’ typekind series.
(The ats2-xprelude package will do this for you, but it is easy
to do if you are not using a lot of math functions. *)
extern fn {tk : tkind} g0float_sqrt : g0float tk -<> g0float tk
overload sqrt with g0float_sqrt
implement g0float_sqrt<fltknd> x = $extfcall (float, "sqrtf", x)
implement g0float_sqrt<dblknd> x = $extfcall (double, "sqrt", x)
implement g0float_sqrt<ldblknd> x = $extfcall (ldouble, "sqrtl", x)

(*------------------------------------------------------------------*)
(* A "very little matrix library" *)

typedef Matrix_Index_Map (m1 : int, n1 : int, m0 : int, n0 : int) =
{i1, j1 : pos | i1 <= m1; j1 <= n1}
(int i1, int j1) -<cloref0>
[i0, j0 : pos | i0 <= m0; j0 <= n0]
@(int i0, int j0)

datatype Real_Matrix (tk : tkind,
m1 : int, n1 : int,
m0 : int, n0 : int) =
| Real_Matrix of (matrixref (g0float tk, m0, n0),
int m1, int n1, int m0, int n0,
Matrix_Index_Map (m1, n1, m0, n0))
typedef Real_Matrix (tk : tkind, m1 : int, n1 : int) =
[m0, n0 : pos] Real_Matrix (tk, m1, n1, m0, n0)
typedef Real_Vector (tk : tkind, m1 : int, n1 : int) =
[m1 == 1 || n1 == 1] Real_Matrix (tk, m1, n1)
typedef Real_Row (tk : tkind, n1 : int) = Real_Vector (tk, 1, n1)
typedef Real_Column (tk : tkind, m1 : int) = Real_Vector (tk, m1, 1)

extern fn {tk : tkind}
Real_Matrix_make_elt :
{m0, n0 : pos}
(int m0, int n0, g0float tk) -< !wrt >
Real_Matrix (tk, m0, n0, m0, n0)

extern fn {tk : tkind}
Real_Matrix_copy :
{m1, n1 : pos}
Real_Matrix (tk, m1, n1) -< !refwrt > Real_Matrix (tk, m1, n1)

extern fn {tk : tkind}
Real_Matrix_copy_to :
{m1, n1 : pos}
(Real_Matrix (tk, m1, n1), (* destination *)
Real_Matrix (tk, m1, n1)) -< !refwrt >
void

extern fn {}
Real_Matrix_dimension :
{tk : tkind}
{m1, n1 : pos}
Real_Matrix (tk, m1, n1) -<> @(int m1, int n1)

extern fn {tk : tkind}
Real_Matrix_get_at :
{m1, n1 : pos}
{i1, j1 : pos | i1 <= m1; j1 <= n1}
(Real_Matrix (tk, m1, n1), int i1, int j1) -< !ref > g0float tk

extern fn {tk : tkind}
Real_Matrix_set_at :
{m1, n1 : pos}
{i1, j1 : pos | i1 <= m1; j1 <= n1}
(Real_Matrix (tk, m1, n1), int i1, int j1, g0float tk) -< !refwrt >
void

extern fn {}
Real_Matrix_reflect_lower_triangle :
(* This operation makes every It is a change in how INDEXING
works. All the storage is still in the lower triangle. *)
{tk : tkind}
{n1 : pos}
{m0, n0 : pos}
Real_Matrix (tk, n1, n1, m0, n0) -<>
Real_Matrix (tk, n1, n1, m0, n0)

extern fn {tk : tkind}
Real_Matrix_fprint :
{m, n : pos}
(FILEref, Real_Matrix (tk, m, n)) -<1> void

overload copy with Real_Matrix_copy
overload copy_to with Real_Matrix_copy_to
overload dimension with Real_Matrix_dimension
overload [] with Real_Matrix_get_at
overload [] with Real_Matrix_set_at
overload reflect_lower_triangle with
Real_Matrix_reflect_lower_triangle

(*------------------------------------------------------------------*)
(* Implementation of the "very little matrix library" *)

implement {tk}
Real_Matrix_make_elt (m0, n0, elt) =
Real_Matrix (matrixref_make_elt<g0float tk> (i2sz m0, i2sz n0, elt),
m0, n0, m0, n0, lam (i1, j1) => @(i1, j1))

implement {}
Real_Matrix_dimension A =
case+ A of Real_Matrix (_, m1, n1, _, _, _) => @(m1, n1)

implement {tk}
Real_Matrix_get_at (A, i1, j1) =
let
val+ Real_Matrix (storage, _, _, _, n0, index_map) = A
val @(i0, j0) = index_map (i1, j1)
in
matrixref_get_at<g0float tk> (storage, pred i0, n0, pred j0)
end

implement {tk}
Real_Matrix_set_at (A, i1, j1, x) =
let
val+ Real_Matrix (storage, _, _, _, n0, index_map) = A
val @(i0, j0) = index_map (i1, j1)
in
matrixref_set_at<g0float tk> (storage, pred i0, n0, pred j0, x)
end

implement {}
Real_Matrix_reflect_lower_triangle {..} {n1} A =
let
typedef t = intBtwe (1, n1)
val+ Real_Matrix (storage, n1, _, m0, n0, index_map) = A
in
Real_Matrix (storage, n1, n1, m0, n0,
lam (i, j) =>
index_map ((if j <= i then i else j) : t,
(if j <= i then j else i) : t))
end

implement {tk}
Real_Matrix_copy A =
let
val @(m1, n1) = dimension A
val C = Real_Matrix_make_elt<tk> (m1, n1, A[1, 1])
val () = copy_to<tk> (C, A)
in
C
end

implement {tk}
Real_Matrix_copy_to (Dst, Src) =
let
val @(m1, n1) = dimension Src
prval [m1 : int] EQINT () = eqint_make_gint m1
prval [n1 : int] EQINT () = eqint_make_gint n1

var i : intGte 1
in
for* {i : pos | i <= m1 + 1} .<(m1 + 1) - i>.
(i : int i) =>
(i := 1; i <> succ m1; i := succ i)
let
var j : intGte 1
in
for* {j : pos | j <= n1 + 1} .<(n1 + 1) - j>.
(j : int j) =>
(j := 1; j <> succ n1; j := succ j)
Dst[i, j] := Src[i, j]
end
end

implement {tk}
Real_Matrix_fprint {m, n} (outf, A) =
let
val @(m, n) = dimension A
var i : intGte 1
in
for* {i : pos | i <= m + 1} .<(m + 1) - i>.
(i : int i) =>
(i := 1; i <> succ m; i := succ i)
let
var j : intGte 1
in
for* {j : pos | j <= n + 1} .<(n + 1) - j>.
(j : int j) =>
(j := 1; j <> succ n; j := succ j)
let
typedef FILEstar = $extype"FILE *"
extern castfn FILEref2star : FILEref -<> FILEstar
val _ = $extfcall (int, "fprintf", FILEref2star outf,
"%16.6g", A[i, j])
in
end;
fprintln! (outf)
end
end

(*------------------------------------------------------------------*)
(* Cholesky-Banachiewicz, in place. See
https://en.wikipedia.org/w/index.php?title=Cholesky_decomposition&oldid=1149960985#The_Cholesky%E2%80%93Banachiewicz_and_Cholesky%E2%80%93Crout_algorithms

I would use Cholesky-Crout if my matrices were stored in column
major order. But it makes little difference. *)

extern fn {tk : tkind}
Real_Matrix_cholesky_decomposition :
(* Only the lower triangle is considered. *)
{n : pos}
Real_Matrix (tk, n, n) -< !refwrt > void

overload cholesky_decomposition with
Real_Matrix_cholesky_decomposition

implement {tk}
Real_Matrix_cholesky_decomposition {n} A =
let
val @(n, _) = dimension A

(* I arrange the nested loops somewhat differently from how it is
done in the Wikipedia article's C snippet. *)
fun
repeat {i, j : pos | j <= i; i <= n + 1} (* <-- allowed values *)
.<(n + 1) - i, i - j>. (* <-- proof of termination *)
(i : int i, j : int j) :<!refwrt> void =
if i = n + 1 then
() (* All done. *)
else
let
fun
_sum {k : pos | k <= j} .<j - k>.
(x : g0float tk, k : int k) :<!refwrt> g0float tk =
if k = j then
x
else
_sum (x + (A[i, k] * A[j, k]), succ k)

val sum = _sum (Zero, 1)
in
if j = i then
begin
A[i, j] := sqrt (A[i, i] - sum);
repeat (succ i, 1)
end
else
begin
A[i, j] := (One / A[j, j]) * (A[i, j] - sum);
repeat (i, succ j)
end
end
in
repeat (1, 1)
end

(*------------------------------------------------------------------*)

fn {tk : tkind} (* We like Fortran, so COLUMN major here. *)
column_major_list_to_square_matrix
{n : pos}
(n : int n,
lst : list (g0float tk, n * n))
: Real_Matrix (tk, n, n) =
let
#define :: list_cons
prval () = mul_gte_gte_gte {n, n} ()
val A = Real_Matrix_make_elt (n, n, NAN)
val lstref : ref (List0 (g0float tk)) = ref lst
var j : intGte 1
in
for* {j : pos | j <= n + 1} .<(n + 1) - j>.
(j : int j) =>
(j := 1; j <> succ n; j := succ j)
let
var i : intGte 1
in
for* {i : pos | i <= n + 1} .<(n + 1) - i>.
(i : int i) =>
(i := 1; i <> succ n; i := succ i)
case- !lstref of
| hd :: tl =>
begin
A[i, j] := hd;
!lstref := tl
end
end;
A
end

implement
main0 () =
let
val _A =
column_major_list_to_square_matrix
(3, $list (25.0, 15.0, ~5.0,
0.0, 18.0, 0.0,
0.0, 0.0, 11.0))
val A = reflect_lower_triangle _A
and B = copy _A
val () =
begin
cholesky_decomposition B;
print! ("\nThe Cholesky decomposition of\n\n");
Real_Matrix_fprint (stdout_ref, A);
print! ("is\n");
Real_Matrix_fprint (stdout_ref, B)
end

val _A =
column_major_list_to_square_matrix
(4, $list (18.0, 22.0, 54.0, 42.0,
0.0, 70.0, 86.0, 62.0,
0.0, 0.0, 174.0, 134.0,
0.0, 0.0, 0.0, 106.0))
val A = reflect_lower_triangle _A
and B = copy _A
val () =
begin
cholesky_decomposition B;
print! ("\nThe Cholesky decomposition of\n\n");
Real_Matrix_fprint (stdout_ref, A);
print! ("is\n");
Real_Matrix_fprint (stdout_ref, B)
end
in
println! ()
end

(*------------------------------------------------------------------*)
</syntaxhighlight>

{{out}}
<pre>$ patscc -std=gnu2x -g -O2 -DATS_MEMALLOC_GCBDW cholesky_decomposition_task.dats -lgc -lm && ./a.out

The Cholesky decomposition of

25 15 -5
15 18 0
-5 0 11
is
5 0 0
3 3 0
-1 1 3

The Cholesky decomposition of

18 22 54 42
22 70 86 62
54 86 174 134
42 62 134 106
is
4.24264 0 0 0
5.18545 6.56591 0 0
12.7279 3.04604 1.64974 0
9.89949 1.62455 1.84971 1.39262

</pre>


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==