src/linsolve.rs

Fri, 14 Feb 2025 23:31:24 -0500

author
Tuomo Valkonen <tuomov@iki.fi>
date
Fri, 14 Feb 2025 23:31:24 -0500
changeset 91
db870f2a2cde
parent 55
7b2ee3e84c5f
permissions
-rw-r--r--

slice_assume_init_mut deprecation workaround

5
59dc4c5883f4 Improve documentation
Tuomo Valkonen <tuomov@iki.fi>
parents: 0
diff changeset
1 /*!
59dc4c5883f4 Improve documentation
Tuomo Valkonen <tuomov@iki.fi>
parents: 0
diff changeset
2 Linear equation solvers for small problems stored in Rust arrays.
59dc4c5883f4 Improve documentation
Tuomo Valkonen <tuomov@iki.fi>
parents: 0
diff changeset
3 */
0
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
4
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
5 use crate::types::Float;
55
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
6 #[cfg(feature = "nightly")]
0
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
7 use std::mem::MaybeUninit;
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
8
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
9 /// Gaussian elimination for $AX=B$, where $A$ and $B$ are both stored in `ab`,
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
10 /// $A \in \mathbb{R}^{M \times M}$ and $X, B \in \mathbb{R}^{M \times K}$.
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
11 pub fn linsolve0<F : Float, const M : usize, const N : usize, const K : usize>(
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
12 mut ab : [[F; N]; M]
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
13 ) -> [[F; K]; M] {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
14 assert_eq!(M + K , N);
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
15
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
16 let mut k = 0;
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
17
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
18 // Convert to row-echelon form
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
19 for h in 0..(M-1) {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
20 // Find pivotable column (has some non-zero entries in rows ≥ h)
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
21 'find_pivot: while k < N {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
22 let (mut î, mut v) = (h, ab[h][k].abs());
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
23 // Find row ≥ h of maximum absolute value in this column
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
24 for i in (h+1)..M {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
25 let ṽ = ab[i][k].abs();
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
26 if ṽ > v {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
27 î = i;
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
28 v = ṽ;
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
29 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
30 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
31 if v > F::ZERO {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
32 ab.swap(h, î);
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
33 for i in (h+1)..M {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
34 let f = ab[i][k] / ab[h][k];
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
35 ab[i][k] = F::ZERO;
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
36 for j in (k+1)..N {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
37 ab[i][j] -= ab[h][j]*f;
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
38 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
39 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
40 k += 1;
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
41 break 'find_pivot;
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
42 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
43 k += 1
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
44 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
45 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
46
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
47 // Solve UAX=UB for X where UA with U presenting the transformations above an
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
48 // upper triangular matrix.
55
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
49 //
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
50 // If the "nightly" feature is enabled, we will use an uninitialised array for a
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
51 // little bit of efficiency.
0
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
52 // This use of MaybeUninit assumes F : Copy. Otherwise undefined behaviour may occur.
55
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
53 #[cfg(feature = "nightly")]
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
54 {
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
55 let mut x : [[MaybeUninit<F>; K]; M] = core::array::from_fn(|_| MaybeUninit::uninit_array::<K>() );
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
56 //unsafe { std::mem::MaybeUninit::uninit().assume_init() };
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
57 for i in (0..M).rev() {
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
58 for 𝓁 in 0..K {
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
59 let mut tmp = ab[i][M+𝓁];
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
60 for j in (i+1)..M {
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
61 tmp -= ab[i][j] * unsafe { *(x[j][𝓁].assume_init_ref()) };
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
62 }
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
63 tmp /= ab[i][i];
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
64 x[i][𝓁].write(tmp);
0
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
65 }
55
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
66 }
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
67 unsafe {
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
68 //core::intrinsics::assert_inhabited::<[[F; K]; M]>();
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
69 (&x as *const _ as *const [[F; K]; M]).read()
0
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
70 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
71 }
55
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
72 #[cfg(not(feature = "nightly"))]
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
73 {
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
74 let mut x : [[F; K]; M] = [[F::ZERO; K]; M];
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
75 for i in (0..M).rev() {
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
76 for 𝓁 in 0..K {
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
77 let mut tmp = ab[i][M+𝓁];
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
78 for j in (i+1)..M {
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
79 tmp -= ab[i][j] * x[j][𝓁];
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
80 }
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
81 tmp /= ab[i][i];
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
82 x[i][𝓁] = tmp;
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
83 }
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
84 }
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
85 x
7b2ee3e84c5f Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Tuomo Valkonen <tuomov@iki.fi>
parents: 24
diff changeset
86 }
0
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
87 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
88
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
89 /// Gaussian elimination for $Ax=b$, where $A$ and $b$ are both stored in `ab`,
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
90 /// $A \in \mathbb{R}^{M \times M}$ and $x, b \in \mathbb{R}^M$.
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
91 #[inline]
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
92 pub fn linsolve<F : Float, const M : usize, const N : usize>(ab : [[F; N]; M]) -> [F; M] {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
93 let x : [[F; 1]; M] = linsolve0(ab);
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
94 unsafe { *((&x as *const [F; 1]) as *const [F; M] ) }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
95 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
96
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
97
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
98 #[cfg(test)]
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
99 mod tests {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
100 use super::*;
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
101
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
102 #[test]
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
103 fn linsolve_test() {
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
104 let ab1 = [[1.0, 2.0, 3.0], [2.0, 1.0, 6.0]];
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
105 assert_eq!(linsolve(ab1), [3.0, 0.0]);
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
106 let ab2 = [[1.0, 2.0, 0.0, 1.0], [4.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0]];
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
107 assert_eq!(linsolve(ab2), [0.0, 0.5, 0.0]);
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
108 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
109 }
9f27689eb130 Initialise new clean repository
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
110

mercurial