-
-
Notifications
You must be signed in to change notification settings - Fork 595
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
Faster implementation of is_invertible() by checking full rank #39876
base: develop
Are you sure you want to change the base?
Conversation
Documentation preview for this PR (built with commit cce4350; changes) is ready! 🎉 |
Could probably be implemented for all matrix over exact fields (such as QQ) |
On another note, the check was originally added in #30161, since the bug has been fixed in m4rie the check in (actually it suffices to check if element at |
Hi so I've checked this note, totally agree on the checks part and adjusted accordingly. This should be reflected in the latest commit and should be ok if all checks pan out.
I've checked matrix_rational_dense and matrix_integer_dense, both of which integrated the "check full-rank" and "check square" in their |
This is changing behaviour: until now, for this type of matrices, one could call
(I would say that this behaviour change is actually a good thing, but this means at least checking that this is not breaking anything elsewhere in Sage.) |
@@ -963,6 +963,22 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): | |||
break | |||
return pivots | |||
|
|||
def is_invertible(self): | |||
""" | |||
Return if invertible by checking full rank. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: use the same description as the general function.
Return if invertible by checking full rank. | |
Return "True" if this matrix is invertible. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use ``True``
instead.
def is_invertible(self): | ||
""" | ||
Return if invertible by checking full rank. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an algorithm block if you want to say how this works internally:
ALGORITHM: this checks that the matrix is square and has full rank. This is to circumvent the determinant computation used by the general method :meth:`sage.matrix.matrix0.Matrix.is_invertible`, since currently there is no efficient determinant implementation in this class of matrices. |
raise ZeroDivisionError("Matrix does not have full rank.") | ||
|
||
if self._nrows: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why removing this if
?
For some exact fields it might help, but why would it help for all of them? Here it seems to help mostly because there is no determinant method for this type of matrices, so sage is calling a slow determinant to determine if the matrix is invertible (this is my understanding after a quick review, please correct me if you have better insight). For example over prime fields or the rationals, why would this approach (computing the rank) be better than computing the determinant? |
If I follow the comment of @user202729 correctly, I think that the check that can be removed is the |
Yes I'm afraid that's right. At first I thought the check in newton_john is checking for 0 row, but on 2nd look it's checking for full rank. Will revert that change.
From what I see in either rational_dense or integer_dense, it checks for invertible still via checking square + checking full rank (though integrated somehow in different functions), even both have the determinant method. I guess that was initially designed so; no class that I know of checks for det not 0. |
The general method in In fact, for matrices in rational_dense, I'm not sure to follow. I don't see an implementation of |
The naive algorithm for determinant over (exact) field is to compute the row echelon form then multiply entries on the diagonal, and for rank is to compute the row echelon form then count number of nonzero entries on the diagonal. Both are O(n^3) but you eliminate some multiplication? Or is it because there happen to have more efficient rank method for this particular class of matrix? Or some other reason? |
Ok, I see the reasoning, thanks for the explanation. Yes we can expect several types of matrices over exact fields to use this strategy: the bulk of the work is done by the computation of some echelon form or triangularization (including "non-naive" fast PLE / PLUQ decompositions), and then the rank or determinant is deduced rather directly. For the determinant this multiplication step is only O(n) multiplications, so it should not influence performance much, except possibly in rare corner cases. For matrices over finite fields the different types in Sage (based on FFLAS-FFPACK or on M4RI or on M4RIE from what I see) all use some fast triangularization, so indeed it should be a bit cleaner to rely on the rank. On the other hand, for other types of matrices especially when coefficient growth is possible, things are less clear to me. And for matrices not over a field, one should be extra careful (e.g.
In the present case of this issue (matrix over GF(2**e)), the rank method is significantly more efficient than the determinant one, but not for a good (algorithmic) reason: this only seems to be due to the absence of a dedicated determinant method. Yesterday I checked the M4RIE code and could not find a determinant procedure there (but several fast triangularization procedures, so one can expect that adding the determinant will not be difficult). |
Okay that makes sense. My complaint is that a lot of boilerplate is added, for example the docstring need to be mostly copied. I'd rather not doing that unless absolutely necessary. So… I guess you can add a timing thing and make the test fail once determinant get fast? That or add the explanation why the method need to exist (link here). If the benchmark sounds like too much work/too flaky, the latter would be good for me also. |
Yes, that is not nice. I'm not sure how to avoid this.
Maybe that would be a good option (the other one you propose looks good as well but actually doing it looks trickier). I have seen such notes sometimes in docstrings. |
Probably better to do #39912 first. Then we decide whether rank is still faster than determinant(algorithm=rref) later. (though I doubt) Then we need to benchmark whether it makes sense to switch to algorithm=rref by default on other fields. If that works, the docstring duplication etc. wouldn't be needed. |
#31274
As mentioned in the issue, a faster invertibility check for matrix in
Matrix_gf2e_dense
by checking full rank.📝 Checklist
⌛ Dependencies