sourcelibs/Matrix/src/Matrix.xtl
1⍝# Matrix: matrices -- identity, diagonal, trace, product,
2⍝# determinant, inverse, solving linear systems.
3⍝# Import it with an alias of your choice: "mx:" u_se< "Matrix".
4⍝# Put libs/Matrix/src on XETAL_PATH ("just path"); the reference is libs/Matrix/docs.
5⍝# Names with l: are exported; those under h: are private to this file.
6⍝#
7⍝# A matrix is a rank-2 array, rows first. The numerical functions
8⍝# (d_et, i_nverse, s_olve) work in Floats, by Gaussian elimination with
9⍝# partial pivoting; compare their results with Check's k:n_ear. The
10⍝# transpose is the built-in o_\.
11
12⍝## Basics
13
14⍝# i_dentity n: the n by n identity matrix (1 then n zeros, cycled).
15ˡi̲dentity ← { n → (n c̲at n) r̲eshape 1 c̲at n r̲eshape 0 }
16
17⍝# d_iag m: the items on the main diagonal.
18ˡd̲iag ← { m →
19 k ← 'm̲in r̲/ s̲hape m
20 (1 + (o̲ffsets k) × 1 + f̲irst r̲ev s̲hape m) s̲elect r̲avel m
21}
22
23⍝# t_race m: the sum of the diagonal.
24ˡt̲race ← { m → '+ r̲/ ˡd̲iag m }
25
26⍝# a m_ul b: the matrix product (a matrix and a vector work too).
27ˡm̲ul ← { a b → a '+ '× i̲nner b }
28
29⍝## Solving
30
31⍝# The permutation of 1..n that swaps i and j.
32ʰs̲wapping ← { n i j →
33 r ← r̲ange n
34 r + ((r = i) × j − i) + (r = j) × i − j
35}
36
37⍝# The row (k..n) whose item in column k is largest in size.
38ʰp̲ivot ← { k m →
39 c ← a̲bs (k − 1) d̲rop k s̲elect₂ m
40 k + (f̲irst g̲rade n̲eg c) − 1
41}
42
43⍝# Gauss-Jordan on m (Float) for columns k..n of its first n: each
44⍝# column's pivot row moved up, scaled to 1, and the column cleared
45⍝# from every other row.
46ʰg̲j ← { n k m →
47 k > n ? m
48 m ← ((n ʰs̲wapping k)_ k ʰp̲ivot m) s̲elect m
49 r ← r̲ange t̲ally m
50 v ← f̲irst k s̲elect k s̲elect₂ m ⍝ the pivot
51 0.000000000001 > a̲bs v ? @ p̲anic< "the matrix is singular: it has no inverse, and its system no unique solution"
52 row ← (k s̲elect m) ÷ v
53 c ← (k s̲elect₂ m) − f̲loat r = k
54 ((n ʰg̲j k + 1)_ m − c '× t̲able row)
55}
56
57⍝# b s_olve a: x with a m_ul x = b, for a square a; b is a vector or a
58⍝# matrix of right-hand sides (one per column). A singular a divides by
59⍝# zero (error[division-by-zero]).
60ˡs̲olve ← { b a →
61 n ← t̲ally a
62 x ← n d̲rop₂ ((n ʰg̲j 1)_ f̲loat a c̲at₂ b)
63 (s̲hape b) r̲eshape x
64}
65
66⍝# i_nverse a: the inverse of a square matrix.
67ˡi̲nverse ← { a → (ˡi̲dentity t̲ally a) ˡs̲olve a }
68
69⍝## Determinant
70
71⍝# The determinant of a Float matrix m, by elimination: the first pivot
72⍝# times the determinant of what is left, negated for a row swap.
73ʰd̲etF ← { m →
74 n ← t̲ally m
75 n = 1 ? f̲irst r̲avel m
76 p ← 1 ʰp̲ivot m
77 m ← ((n ʰs̲wapping 1)_ p) s̲elect m
78 v ← f̲irst r̲avel m
79 v = 0 ? 0.0
80 s ← f̲loat (p = 1) − p ≠ 1
81 r ← (1 d̲rop₂ 1 d̲rop m) − ((1 d̲rop f̲irst₂ m) ÷ v) '× t̲able 1 d̲rop f̲irst m
82 s × v × ʰd̲etF r
83}
84
85⍝# d_et a: the determinant of a square matrix.
86ˡd̲et ← { a → ʰd̲etF f̲loat a }
p̲anic< expands to
(⎕P̲ANIC ("the matrix is singular: it has no inverse, and its system no unique solution"))