Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pinv broken on column-rank-deficient matrices. #3373

Open
ixchow opened this issue Jan 30, 2025 · 1 comment
Open

pinv broken on column-rank-deficient matrices. #3373

ixchow opened this issue Jan 30, 2025 · 1 comment

Comments

@ixchow
Copy link

ixchow commented Jan 30, 2025

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, 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 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.

@gwhitney
Copy link
Collaborator

Thanks! This is a good addition to #3012. Having specific examples is very helpful. You don't happen to have an intuition as how we might find even smaller examples, do you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants