From ad940e40ca5d7a8821a304bb01e58d48f6b8cfbd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 28 Apr 2026 15:41:50 +0100 Subject: [PATCH] Add `linalg.matrix_pseudo_inverse` --- core/math/linalg/general.odin | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index 28ad3c393..6a7ba3937 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -1184,5 +1184,33 @@ matrix_inverse_lu_decomposition :: proc "contextless" (A: $M/matrix[$N, N]$T) -> } non_singular = true + return +} + +pseudo_inverse :: proc{ + matrix_pseudo_inverse, +} + +// Moore-Penrose Pseudo-Inverse +@(require_results) +matrix_pseudo_inverse :: proc "contextless" (A: $M/matrix[$R, $C]$T) -> (B: matrix[C, R]T, not_singular: bool) #no_bounds_check { + At := transpose(A) + + when R >= C { + // Overdetermined (tall): + // pseudo_inverse(A) = inverse(transpose(A)*A)*transpose(A) + AtA := At * A // [C, C] + AtA_inv := matrix_inverse_generic(AtA) or_return + B = AtA_inv * At + not_singular = true + } else { + // Underdetermined (wide): + // pseudo_inverse(A) = transpose(A)*inverse(A*transpose(A)) + AAt := A * At // [R, R] + AAt_inv := matrix_inverse_generic(AAt) or_return + B = At * AAt_inv + not_singular = true + } + return } \ No newline at end of file