pinv broken on column-rank-deficient matrices.
- Dominant language
- JavaScript
- Stars
- 15.1k
- Forks
- 1.3k
- PR merge metrics
- No merged PRs in 30d
Description
Applies to mathjs 14.1.0, installed via npm.
May be related to #3012, but that bug does not provide a test case.
According to [wikipedia's summary](https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse), the pseudo-inverse of a column-rank-deficient matrix `mat` exists, and acts as a right inverse `mat * pinv(mat) = I`.
This does not appear to be the case when using `mathjs.pinv` on matricies with columns that are not linearly independent.
In some cases, the returned matrix is not a right inverse:
```
const mat = [
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 ],
[ 0, 0, 1, 1, 0, 0, 0, 0, 0, 1 ],
[ 0, 0, 2, 0, 1, 0, 0, 1, 0, 0 ],
[ 1, 0, 1, 0, 0, 0, 0, 0, 1, 0 ],
[ 0, 1, 1, 0, 1, 1, 2, 0, 0, 1 ]
];
const pinv = math.pinv(mat);
console.table(math.multiply(mat, pinv));
```
The output here has its first column as all zeros -- quite far from the identity matrix (expected result).
In comparison, computing with [wikipedia's summary of how to compute the pseudoinverse](https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse#Definition) works just fine:
```
const mat = /* same as above */;
//right-inverse recipe, works for matrices with linearly-independent rows:
const pinv = math.multiply(
math.transpose( mat ),
math.inv(
math.multiply(
mat,
math.transpose( mat )
)
)
);
console.table(math.multiply(mat, pinv));
```
Here, the output is very close to the identity matrix.
----
Further, `pinv` just fails on some matrices:
```
const mat = [
[ 0, 0, 0, 0, 0, 0, 0, 1, 0 ],
[ 0, 0, 1, 1, 0, 0, 0, 0, 1 ],
[ 0, 0, 0, 0, 1, 0, 1, 0, 0 ],
[ 1, 0, 1, 0, 0, 0, 0, 1, 0 ],
[ 0, 1, 1, 0, 1, 2, 0, 0, 1 ]
];
const pinv = math.pinv(mat);
```
Results in an `Error: Cannot calculate inverse, determinant is zero` exception being thrown. (The right inverse recipe above still works on this matrix.)
----
My suspicion is that the `pinv` implementation here was only tested on matrices with linearly-independent *columns* (the rank-surplus case), not linearly-independent *rows* (the rank-deficient case). It's a useful tool in both situations so it would make sense to patch to deal with both.
Contributor guide
Assessment
This issue has not been assessed yet.