Sun, 27 Apr 2025 20:29:43 -0500
Fix build with stable rust.
For optimisations, build.rs now automatically sets a nightly cfg flag,
so problems with the nightly feature are avoided. It is still used for
required for additional nightly-only features.
| 5 | 1 | /*! |
| 2 | Linear equation solvers for small problems stored in Rust arrays. | |
| 3 | */ | |
| 0 | 4 | |
| 5 | use crate::types::Float; | |
| 94 | 6 | #[cfg(nightly)] |
| 0 | 7 | use std::mem::MaybeUninit; |
| 8 | ||
| 9 | /// Gaussian elimination for $AX=B$, where $A$ and $B$ are both stored in `ab`, | |
| 10 | /// $A \in \mathbb{R}^{M \times M}$ and $X, B \in \mathbb{R}^{M \times K}$. | |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
11 | pub fn linsolve0<F: Float, const M: usize, const N: usize, const K: usize>( |
|
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
12 | mut ab: [[F; N]; M], |
| 0 | 13 | ) -> [[F; K]; M] { |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
14 | assert_eq!(M + K, N); |
| 0 | 15 | |
| 16 | let mut k = 0; | |
| 17 | ||
| 18 | // Convert to row-echelon form | |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
19 | for h in 0..(M - 1) { |
| 0 | 20 | // Find pivotable column (has some non-zero entries in rows ≥ h) |
| 21 | 'find_pivot: while k < N { | |
| 22 | let (mut î, mut v) = (h, ab[h][k].abs()); | |
| 23 | // Find row ≥ h of maximum absolute value in this column | |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
24 | for i in (h + 1)..M { |
| 0 | 25 | let ṽ = ab[i][k].abs(); |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
26 | if ṽ > v { |
| 0 | 27 | î = i; |
| 28 | v = ṽ; | |
| 29 | } | |
| 30 | } | |
| 31 | if v > F::ZERO { | |
| 32 | ab.swap(h, î); | |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
33 | for i in (h + 1)..M { |
| 0 | 34 | let f = ab[i][k] / ab[h][k]; |
| 35 | ab[i][k] = F::ZERO; | |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
36 | for j in (k + 1)..N { |
|
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
37 | ab[i][j] -= ab[h][j] * f; |
| 0 | 38 | } |
| 39 | } | |
| 40 | k += 1; | |
| 41 | break 'find_pivot; | |
| 42 | } | |
| 43 | k += 1 | |
| 44 | } | |
| 45 | } | |
| 46 | ||
| 47 | // Solve UAX=UB for X where UA with U presenting the transformations above an | |
| 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 | 52 | // This use of MaybeUninit assumes F : Copy. Otherwise undefined behaviour may occur. |
| 94 | 53 | #[cfg(nightly)] |
|
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
|
54 | { |
|
92
e11986179a4b
maybe_uninit_uninit_array deprecation fix.
Tuomo Valkonen <tuomov@iki.fi>
parents:
55
diff
changeset
|
55 | let mut x: [[MaybeUninit<F>; K]; M] = [[const { MaybeUninit::uninit() }; K]; M]; |
|
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
|
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 { |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
59 | let mut tmp = ab[i][M + 𝓁]; |
|
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
60 | for j in (i + 1)..M { |
|
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
|
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 | 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 | 70 | } |
| 71 | } | |
| 94 | 72 | #[cfg(not(nightly))] |
|
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
|
73 | { |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
74 | let mut x: [[F; K]; M] = [[F::ZERO; K]; M]; |
|
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
|
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 { |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
77 | let mut tmp = ab[i][M + 𝓁]; |
|
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
78 | for j in (i + 1)..M { |
|
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
|
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 | 87 | } |
| 88 | ||
| 89 | /// Gaussian elimination for $Ax=b$, where $A$ and $b$ are both stored in `ab`, | |
| 90 | /// $A \in \mathbb{R}^{M \times M}$ and $x, b \in \mathbb{R}^M$. | |
| 91 | #[inline] | |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
92 | pub fn linsolve<F: Float, const M: usize, const N: usize>(ab: [[F; N]; M]) -> [F; M] { |
|
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
93 | let x: [[F; 1]; M] = linsolve0(ab); |
|
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
94 | unsafe { *((&x as *const [F; 1]) as *const [F; M]) } |
| 0 | 95 | } |
| 96 | ||
| 97 | #[cfg(test)] | |
| 98 | mod tests { | |
| 99 | use super::*; | |
| 100 | ||
| 101 | #[test] | |
| 102 | fn linsolve_test() { | |
| 103 | let ab1 = [[1.0, 2.0, 3.0], [2.0, 1.0, 6.0]]; | |
| 104 | assert_eq!(linsolve(ab1), [3.0, 0.0]); | |
|
93
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
105 | let ab2 = [ |
|
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
106 | [1.0, 2.0, 0.0, 1.0], |
|
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
107 | [4.0, 0.0, 0.0, 0.0], |
|
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
108 | [0.0, 0.0, 1.0, 0.0], |
|
123f7f38e161
Let Zed auto-indent modified files
Tuomo Valkonen <tuomov@iki.fi>
parents:
92
diff
changeset
|
109 | ]; |
| 0 | 110 | assert_eq!(linsolve(ab2), [0.0, 0.5, 0.0]); |
| 111 | } | |
| 112 | } |