What does the pinv function do in MATLAB / RunMat?
X = pinv(A) returns the Moore–Penrose pseudoinverse of A. For full-rank square matrices this
matches inv(A), while rank-deficient or rectangular inputs produce the minimum-norm solution that
satisfies the four Moore–Penrose conditions. RunMat mirrors MATLAB's tolerance logic:
tol = max(size(A)) * eps(max(s)), where s are the singular values returned by the internal SVD.
How does the pinv function behave in MATLAB / RunMat?
- Supports scalars, vectors, and higher-dimensional inputs that behave like matrices (trailing singleton dimensions are allowed; other higher ranks must be reshaped first).
- Logical and integer inputs are promoted to
doublebefore the SVD, matching MATLAB semantics. - Optional second argument
pinv(A, tol)treats values intolas the user-specified cutoff for singular values. Entries ≤tolcontribute zeros in the diagonal ofΣ⁺. - Complex matrices are handled in full complex arithmetic via
A = U * Σ * Vᴴ. - Empty matrices return the appropriately sized zero matrix (
size(pinv(A)) == fliplr(size(A))). - The result always has size
n × mif the input ism × n.
pinv Function GPU Execution Behavior
When a GPU acceleration provider is active, RunMat offers the operation through its pinv hook,
passing along any explicit tolerance. Providers may implement a native GPU kernel; otherwise, they
can gather to the host, invoke the shared SVD routine, and re-upload the result. The shipping WGPU
backend follows this gather/compute/upload pattern today, so downstream GPU work retains residency
without MATLAB-level changes.
Examples of using the pinv function in MATLAB / RunMat
Finding the pseudoinverse of a tall matrix
A = [1 0; 0 0; 0 1];
X = pinv(A);
Expected output:
X =
1 0 0
0 0 1
Solving an overdetermined least-squares problem
A = [1 1; 1 2; 1 3];
b = [1; 0; 0];
x = pinv(A) * b;
Expected output:
x =
1.1667
-0.5000
Suppressing small singular values with a custom tolerance
A = diag([1, 1e-10]);
X = pinv(A, 1e-6);
Expected output:
X =
1 0
0 0
Pseudoinverse of a rank-deficient square matrix
A = [1 2; 2 4];
X = pinv(A);
Expected output:
X =
0.0400 0.0800
0.0800 0.1600
Pseudoinverse of a complex diagonal matrix
A = diag([2+1i, 3-2i]);
X = pinv(A);
Expected output:
X =
0.4000 - 0.2000i 0
0 0.2308 + 0.1538i
GPU residency in RunMat (Do I need gpuArray?)
Explicit residency management is rarely required. When inputs already live on the GPU and the
provider implements pinv, the builtin executes entirely on the device. Providers without a native
kernel (including the current WGPU backend) transparently download the matrix, run the shared CPU
path, and re-upload the result so the caller continues working with a GPU tensor. gpuArray remains
available for MATLAB compatibility or to seed GPU residency explicitly.
FAQ
How is pinv different from inv?
inv(A) requires A to be square and full rank. pinv(A) works for any matrix shape and produces
the minimum-norm solution even when A is singular or rectangular.
What tolerance does pinv use by default?
RunMat matches MATLAB: max(size(A)) * eps(max(s)), where s are the singular values. Values below
this threshold are treated as zero when forming Σ⁺.
Can I recover the rank from the pseudoinverse?
Yes. Count the singular values greater than the effective tolerance (rank returns this directly).
The same tolerance drives both pinv and rank.
Does pinv support complex inputs?
Absolutely. Complex matrices use a full complex SVD with conjugate transposes, matching MATLAB's definition.
Will calling pinv move my data off the GPU?
Only if the active provider lacks a native implementation. In that case RunMat gathers, computes, and re-uploads for you. Providers may expose native kernels to keep the entire computation on the device.
Is pinv(A) * b equivalent to A \\ b?
For full-rank systems, yes. A \\ b is typically faster and more numerically stable, but pinv
remains useful for ill-conditioned or rank-deficient problems where the pseudoinverse is desired.
See Also
inv, linsolve, mldivide, mrdivide, svd, rank, gpuArray, gather
Source & Feedback
- The full source lives at
crates/runmat-runtime/src/builtins/math/linalg/solve/pinv.rs. - Found a behavioral difference? Open an issue with a minimal reproduction.