-
-
Notifications
You must be signed in to change notification settings - Fork 481
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
Improve Matrix_mod2_dense solve_right performance #38843
base: develop
Are you sure you want to change the base?
Conversation
Use M4RI builtin `mzd_solve_left` function to solve equation.
Documentation preview for this PR (built with commit 9c532c5; changes) is ready! 🎉 |
# although it is called mzd_solve_left, it does the same thing as solve_right | ||
ret = mzd_solve_left(lhs, rhs, 0, check) | ||
sig_off() | ||
mzd_free(lhs) |
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.
Wouldn't this leak the lhs
and rhs
if user press ctrl+C?
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.
You are right, should I wrap it with a try...finally block or just disable the ability to Ctrl-C?
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.
Similarity, while _right_kernel_matrix
does not enable signal but it can still leak the resulting kernel matrix when Ctrl-C (triggered during self.new_matrix
).
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.
Certainly handling it properly is preferable. (But no memory leak is a hard thing to test for…)
cysignals is a bit complicated…
https://cysignals.readthedocs.io/en/latest/interrupt.html#using-sig-on-and-sig-off
So far I don't exactly understand what's the difference between try: sig_on() except KeyboardInterrupt:
versus if not sig_on_no_except():
either.
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.
for what it's worth, the part I don't understand is sagemath/cysignals#205 .
In any case, I think the following will work:
data = malloc(...)
if not sig_on_no_except():
mzd_free(lhs)
mzd_free(rhs)
cython_check_exception()
ret = mzd_solve_left(...)
sig_off()
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.
Okay, I have pushed a version where try...finally are used to ensure allocated matrices get freed.
if self._entries.ncols == 0 or B_entries.ncols == 0: | ||
# special case: empty matrix | ||
if B != 0: | ||
raise ValueError("matrix equation has no solutions") |
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.
Surely this is redundant (?) if B has no entries then every entries are 0?
(also even if it can happen you forget to free X here)
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.
There are cases where A have zero cols but B have non zero cols, so it would have a different result depends on whether B is zero. And without this, some sage tests will fail.
As for X, I think it is a Python object so it would be handled by Python's refcount?
Maybe add a few tests?
(note that the old code returns empty matrix for the third case, while the new code raises error. Apparently it doesn't break any existing test case, but anyway.) Strange that m4ri doesn't automatically handle the empty matrix case correctly (mathematically) though. Any idea why? |
Tests for special case added.
TBH, zero size matrix is pretty weird by itself I think, so it is not unusual to not consider that I think. It would probably be better handled by the |
|
My argument: just as zero is not a weird integer, zero-dimensional vector space (which is just a point) is not a weird space. So a zero-sized matrix is just a linear map from (or to) a zero-dimensional vector space. The math checks out. (Of course, programming-wise it is still a corner case.) The failed test case (commit 9c532c5) is
looks completely unrelated to this change. And the only difference is in the ordering of the keys so… probably it's fine. On the other hand Python dict is ordered by insertion time, and it looks weird that a dict can have two keys that is exactly equal…? (they're probably not equal but have same representation or something. Worth opening a new issue for that.) |
Looks like the failing test is #38940 . Should be unrelated to this change then. |
sage: matrix(GF(2), 2, 0).solve_right(matrix(GF(2), 2, 2) + 1, check=False) == matrix(GF(2), 0, 2) | ||
True | ||
sage: matrix(GF(2), 2, 2).solve_right(matrix(GF(2), 2, 0)) == matrix(GF(2), 2, 0) | ||
True |
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.
True | |
True | |
Check that it can be interrupted:: | |
sage: set_random_seed(12345) | |
sage: n, m = 20000, 19968 | |
sage: A = random_matrix(GF(2), n, m) | |
sage: x = random_vector(GF(2), m) | |
sage: B = A*x | |
sage: alarm(0.5); sol = A.solve_right(B) | |
Traceback (most recent call last): | |
... | |
AlarmInterrupt |
Use M4RI builtin
mzd_solve_left
function to solve equation.Currently, using
solve_right
on largeGF(2)
matrix is pretty slow because it use a generic solving function in matrix2.pyx, but M4RI provides amzd_solve_left
function that does the same thing.For example, try running this in sage's IPython REPL:
without this PR, it took
with this PR, it becomes
📝 Checklist
⌛ Dependencies