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

Improve efficiency of minors() for BinaryMatroid, TernaryMatroid, QuaternaryMatroid #18660

Closed
sagetrac-Rudi mannequin opened this issue Jun 10, 2015 · 17 comments
Closed

Comments

@sagetrac-Rudi
Copy link
Mannequin

sagetrac-Rudi mannequin commented Jun 10, 2015

The representing matrices of BinaryMatroid, TernaryMatroid, QuaternaryMatroid, are bitpacket. Taking minors, involves constructing a submatrix of such a representing matrix. Since the rows are bitpacked, the relocation of columns in particular is relatively inefficient.

By allowing a submatrix in which the columns are allowed to be permuted, it is possible to reduce the number of column relocations to at most the number of deleted columns, and this will be far more efficient than the current implementation, especially if few columns are deleted.

CC: @chaoxu @sagetrac-Stefan @sagetrac-yomcat

Component: matroid theory

Author: Rudi Pendavingh

Branch/Commit: a5fd2f5

Reviewer: Travis Scrimshaw

Issue created by migration from https://trac.sagemath.org/ticket/18660

@sagetrac-Rudi sagetrac-Rudi mannequin added this to the sage-6.8 milestone Jun 10, 2015
@sagetrac-Rudi sagetrac-Rudi mannequin self-assigned this Jun 10, 2015
@sagetrac-Rudi
Copy link
Mannequin Author

sagetrac-Rudi mannequin commented Jun 10, 2015

comment:1

Still need to try this out. Hope to do this this week.

Since a cocircuit of a binary matroid M is typically going to have size about r^*(M) /2 elements, I expect a speedup by a factor of up to r^*(M)/2/|E(M)| for the minor-taking in Chao's code in ticket #18539.

@sagetrac-Rudi
Copy link
Mannequin Author

sagetrac-Rudi mannequin commented Jun 11, 2015

@sagetrac-Rudi
Copy link
Mannequin Author

sagetrac-Rudi mannequin commented Jun 11, 2015

Commit: 7deb135

@sagetrac-Rudi
Copy link
Mannequin Author

sagetrac-Rudi mannequin commented Jun 11, 2015

comment:3

First worked on BinaryMatroid and BinaryMatrix. The new code seems to be correct:

sage: N = Matroid(MatrixSpace(GF(2), 5,12).random_element())
sage: for X in subsets(N.groundset()):
    if not BasisMatroid(N\X).equals(BasisMatroid(N)\X):
        print X

It's more efficient too. Without the patch:

sage: M = Matroid(MatrixSpace(GF(2), 500,1000).random_element())
sage: B = M.basis()
sage: timeit("for e in B: M.delete(M._fundamental_cocircuit(B,e))")
5 loops, best of 3: 3.69 s per loop

With the patch:

sage: M = Matroid(MatrixSpace(GF(2), 500,1000).random_element())
sage: B = M.basis()
sage: timeit("for e in B: M.delete(M._fundamental_cocircuit(B,e))")
5 loops, best of 3: 692 ms per loop

So, about 5 times faster on this example. This is not all due to the trick announced in the ticket. Replacing a list by a c-style array here and there did some good too. And just replacing the line

C = [c for c in range(len(self._E)) if self._E[c] not in deletions | contractions]

in _minor by something that does not compute the union deletions | contractions for each c made the code 2 times faster right there.


New commits:

7deb135Added new method for taking submatrix of a BinaryMatrix, used in BinaryMatroid._minor()

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 11, 2015

Branch pushed to git repo; I updated commit sha1. New commits:

3ea8ac5Improved Ternary and Quaternary along the same lines

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 11, 2015

Changed commit from 7deb135 to 3ea8ac5

@sagetrac-Rudi
Copy link
Mannequin Author

sagetrac-Rudi mannequin commented Jun 11, 2015

comment:5

Correctness:

sage: N = Matroid(MatrixSpace(GF(2), 5,10).random_element())
sage: for X in subsets(N.groundset()):
    for Y in subsets(N.groundset()-set(X)):
        if not BasisMatroid(N.minor(X,Y)).equals(BasisMatroid(N).minor(X,Y)):
            print X,Y
....:             
sage: N = Matroid(MatrixSpace(GF(3), 5,10).random_element())
sage: for X in subsets(N.groundset()):
    for Y in subsets(N.groundset()-set(X)):
        if not BasisMatroid(N.minor(X,Y)).equals(BasisMatroid(N).minor(X,Y)):
            print X,Y
....:             
sage: N = Matroid(MatrixSpace(GF(4,x), 5,10).random_element())
sage: for X in subsets(N.groundset()):
    for Y in subsets(N.groundset()-set(X)):
        if not BasisMatroid(N.minor(X,Y)).equals(BasisMatroid(N).minor(X,Y)):
            print X,Y

Efficiency before patch:

sage: M = Matroid(MatrixSpace(GF(2), 200,400).random_element())
sage: B = M.basis()
sage: timeit("for e in B: M.delete(M._fundamental_cocircuit(B,e))")
5 loops, best of 3: 261 ms per loop
sage: M = Matroid(MatrixSpace(GF(3), 200,400).random_element())
sage: B = M.basis()
sage: timeit("for e in B: M.delete(M._fundamental_cocircuit(B,e))")
5 loops, best of 3: 7.13 s per loop
sage: M = Matroid(MatrixSpace(GF(4,x), 200,400).random_element())
sage: B = M.basis()
sage: timeit("for e in B: M.delete(M._fundamental_cocircuit(B,e))")
5 loops, best of 3: 3.95 s per loop

Efficiency after patch:

sage: M = Matroid(MatrixSpace(GF(2), 200,400).random_element())
sage: B = M.basis()
sage: timeit("for e in B: M.delete(M._fundamental_cocircuit(B,e))")
5 loops, best of 3: 73.7 ms per loop
sage: M = Matroid(MatrixSpace(GF(3), 200,400).random_element())
sage: B = M.basis()
sage: timeit("for e in B: M.delete(M._fundamental_cocircuit(B,e))")
5 loops, best of 3: 86.7 ms per loop
sage: M = Matroid(MatrixSpace(GF(4,x), 200,400).random_element())
sage: B = M.basis()
sage: timeit("for e in B: M.delete(M._fundamental_cocircuit(B,e))")
5 loops, best of 3: 86.4 ms per loop

For TernaryMatrix and QuaternaryMatrix, there was no optimized submatrix-code to begin with, hence the 40 - 80 times speedup.
I scaled down the size of the matrix a bit, the ternary benchmark simply wouldn't finish for 500x1000.

I will remove some lingering cython profile directives, and then I'm done.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 11, 2015

Changed commit from 3ea8ac5 to 20dc896

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 11, 2015

Branch pushed to git repo; I updated commit sha1. New commits:

20dc896Cleaned up profiler directives

@sagetrac-Rudi
Copy link
Mannequin Author

sagetrac-Rudi mannequin commented Jun 11, 2015

Author: Rudi Pendavingh

@sagetrac-Rudi sagetrac-Rudi mannequin added the s: needs review label Jun 11, 2015
@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 19, 2015

Branch pushed to git repo; I updated commit sha1. New commits:

a5fd2f5removed trailing whitespace

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 19, 2015

Changed commit from 20dc896 to a5fd2f5

@sagetrac-Rudi
Copy link
Mannequin Author

sagetrac-Rudi mannequin commented Jun 19, 2015

comment:9

Before:

sage: M = Matroid(MatrixSpace(GF(3), 500,1000).random_element())
sage: timeit("M.delete([0])")
5 loops, best of 3: 333 ms per loop

After:

sage: M = Matroid(MatrixSpace(GF(3), 500,1000).random_element())
sage: timeit("M.delete([0])")
625 loops, best of 3: 655 µs per loop

@tscrim
Copy link
Collaborator

tscrim commented Jun 19, 2015

Reviewer: Travis Scrimshaw

@tscrim
Copy link
Collaborator

tscrim commented Jun 19, 2015

comment:10

LGTM. I'm slightly unhappy with the fact that it looks like a lot of logic is duplicated across the multiple matrix_from_rows_and_columns_reordered, but I don't see a way to really combine the common logic. So positive review.

@sagetrac-Rudi
Copy link
Mannequin Author

sagetrac-Rudi mannequin commented Jun 19, 2015

comment:11

Replying to @tscrim:

LGTM. I'm slightly unhappy with the fact that it looks like a lot of logic is duplicated across the multiple matrix_from_rows_and_columns_reordered, but I don't see a way to really combine the common logic. So positive review.

Thanks for the review.

@vbraun
Copy link
Member

vbraun commented Jun 20, 2015

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

No branches or pull requests

2 participants