Open ThibautVerron opened 1 year ago
Adding to this issue: on my side (10.0beta4),
sage: %time K2 = M.left_kernel()
CPU times: user 22.2 s, sys: 47.9 ms, total: 22.2 s
(which should correspond to the "too long" version above), whereas
sage: %time K = M.left_kernel(algorithm="generic")
CPU times: user 693 µs, sys: 2 µs, total: 695 µs
So the default is doing a rational kernel of the corresponding integer matrix (by clearing denominators) using iml. This is what takes the time. If we instead use flint, it is very quick (~7ms for _rational_kernel_flint()
versus ~42s for _rational_kernel_iml()
). So this suggests a change in the default algorithm is needed. I am not sure about other behaviors.
Indeed. Then performance becomes much better than computing the left kernel of the reduced column echelon form (a few 1ms versus a few 100ms). Well... for a fair comparison with the same left_kernel
in both cases:
N = 50
M = Matrix(QQ,6,6,lambda i,j : QQ.random_element(10^N))
M[5] = add(QQ.random_element(10^N)*M[i] for i in range(5))
t = time.perf_counter()
for _ in range(100):
Mz = M._clear_denom()[0]
KM = Mz._rational_kernel_flint()
t = time.perf_counter() - t
print(f"kernel: {t/100}")
t = time.perf_counter()
for _ in range(100):
Ez = M.transpose().echelon_form().transpose()._clear_denom()[0]
KE = Ez._rational_kernel_flint()
t = time.perf_counter() - t
print(f"cef+ker: {t/100}")
On my laptop I have
kernel: 0.00208310158690438
cef+ker: 0.000390590687748045
This means column echelon form followed by kernel would still be non-negligibly faster. Yet, this big difference is in good part an artefact of the fairly specific properties of the built matrix (the last row has larger entries, and is a linear combination of the other rows; we look at left kernel) which translate into some properties of the column echelon form.
Running the above code with a matrix having entries of similar size, but with the last column being the sum of the other column:
M = Matrix(QQ,6,6,lambda i,j : QQ.random_element(10^N))
M[5,:] = Matrix(QQ, 1, 6, lambda i, j : QQ.random_element(10^(2*N)))
M[:,5] = add(M[:,i] for i in range(5))
I get timings about 2ms (unchanged) for direct kernel, and 1ms for echelon form then kernel. The performance difference is already less critical. Making now the first column the sum of the others:
M = Matrix(QQ,6,6,lambda i,j : QQ.random_element(10^N))
M[5,:] = Matrix(QQ, 1, 6, lambda i, j : QQ.random_element(10^(2*N)))
M[:,0] = add(M[:,i] for i in range(1,6))
leads to almost 2ms for both (with a slight advantage for echelon form then kernel, still).
Furthermore, for an arguably more frequent case of left kernel computation, computing the column echelon form first is in fact a bad idea:
M = Matrix(QQ,6,3,lambda i,j : QQ.random_element(10^N))
t = time.perf_counter()
for _ in range(1000):
Mz = M._clear_denom()[0]
KM = Mz._rational_kernel_flint()
t = time.perf_counter() - t
print(f"kernel: {t/1000:.6f}")
t = time.perf_counter()
for _ in range(1000):
Ez = M.transpose().echelon_form().transpose()._clear_denom()[0]
KE = Ez._rational_kernel_flint()
t = time.perf_counter() - t
print(f"cef+ker: {t/1000:.6f}")
On my laptop: 74µs versus 286µs. And it seems that currently, calling left_kernel
directly on M
takes several seconds...
So in short, this issue has led to (at least) the following points:
algorithm='flint'
)
Is there an existing issue for this?
Did you read the documentation and troubleshoot guide?
Environment
Steps To Reproduce
Take a small singular matrix with large rational coefficients, and compute its (left) kernel. Compare with the time taken to compute the echelon form, and the kernel from the echelon form.
Do the same with the right kernel.
For example:
Expected Behavior
Computing the kernel should not be slower than computing the echelon form and the kernel of the echelon form.
Actual Behavior
The computation of the echelon form, and the computation of the kernel of the echelon form, are fast. But the computation of the kernel of the original matrix is very slow.
The same results are observed with the right kernel.
Indicative timings on my system (with the 10.0beta1 version):
Additional Information
No response