I looked through the Nemo.jl documentation but did not really find anything.
It does, but the functionality is documented in AbstractAlgebra.jl:
For solving with integers/rationals, LU factorization is garbage. Fraction-free LU factorization (FFLU) is much better. Solving using p-adic lifting is the best for large matrices (n > 20, say).
Solving using p-adic lifting:
julia> A = MatrixSpace(ZZ, 50, 50)(rand(Int64, 50, 50));
julia> b = MatrixSpace(ZZ, 50, 1)(rand(Int64, 50, 1));
julia> @btime solve_rational(A, b);
11.291 ms (3303 allocations: 4.51 MiB)
LU and FFLU factorization:
julia> @btime lu(MatrixSpace(QQ, 50, 50)(A));
776.146 ms (129839 allocations: 8.97 MiB)
julia> @btime fflu(A);
33.745 ms (9344 allocations: 1.77 MiB)
Oddly enough Nemo doesn’t seem to expose functions for solving giving the precomputed LU or FFLU factorizations though.
For finite fields, the story is basically the same as for floating-point numbers (except that there is no rounding error); standard LU factorization is the way to go.
julia> A = MatrixSpace(GF(19), 500, 500)(rand(Int64, 500, 500));
julia> b = MatrixSpace(GF(19), 500, 1)(rand(Int64, 500, 1));
julia> @btime solve(A, b);
16.945 ms (2759 allocations: 6.23 MiB)
julia> @btime lu(A);
18.449 ms (2761 allocations: 8.12 MiB)
I guess Nemo’s lu is slightly slower than its solve here because of some silly overhead; internally, its solve just computes the LU factorization and then solves the triangular systems here.