josdejong / josdejong/mathjs

pinv broken on column-rank-deficient matrices.

Open
#3,373 12 comments 0 reactions 1 assignee Claimed by @KeneePatel View on GitHub
onlydust-wave
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.