I solved this by writing separate digits to io.
using SparseArrays, MatrixMarket
const _digit_chars ::String = "0123456789";
@inline function _mat_p_ex(io::IO, p::Int) ::Nothing
#= Export the position/index of a matrix entry. =#
@inbounds begin n=ndigits(p); D=10^(n-1);
for _ = 1:n
d = (p Ă· D) % 10;
print(io,_digit_chars[d+1]);
D Ă·= 10 end end end;
@inline function _mat_w_ex(io::IO, w::tw) where {tw}
#= Export the weight/value of a matrix entry. =#
print(io,w) end; # inefficient default
@inline function _mat_w_ex(io::IO, w::tw) where {tw<:Integer}
w<0 && print(io,'-');
_mat_p_ex(io, abs(w)) end; # more efficient specialization
@inline function _entry_write(io::IO, i::Int, j::Int, w::tw, sep::Char) ::Nothing where {tw}
_mat_p_ex(io,i); write(io,sep);
_mat_p_ex(io,j); write(io,sep);
_mat_w_ex(io,w); write(io,'\n');
nothing end;
function _mat_export(X::SparseMatrixCSC{tw,tp}, m::Int, n::Int, sep::Char, io::IO, buf::IOBuffer, n_bytes::Int) where {tw, tp}
I = X.colptr; pp = X.rowval; ww = X.nzval;
for j = 1:n
for k = I[j] : I[j+1]-1
i = pp[k]
w = ww[k]
_entry_write(buf,i,j,w,sep);
if position(buf) ≥ n_bytes write(io,take!(buf)) end end end;
write(io,take!(buf));
nothing end;
function mat_ex(X::SparseMatrixCSC{tw,tp}, file::String, n_bytes::Int=100_000_000, sep::Char=' ', buf::IO=IOBuffer(sizehint=ceil(Int,n_bytes*1.1))) ::Nothing where {tw,tp}
#= Export a sparse matrix to the MatrixMarket.jl format, which is cross-language/platform (can be used in Python, MatLab, Mathematica, C++, C, Fortran, ...). =#
m,n = size(X); r = nnz(X);
open(file, "w") do io
println(io, "%%MatrixMarket matrix coordinate integer general")
println(io, "$m $n $r")
_mat_export(X,m,n,sep,io,buf,n_bytes) end
end;
This is 2x faster than built-in method (for Int weights), since Chars don’t allocate:
n=10^6; X = sprand(n, n, 1e-4, r-> rand(-1000:1000,r));
@time mat_ex(X, "/path/to/my/file.mtx")
22.077753 seconds (866 allocations: 6.417 GiB, 1.83% gc time)
julia> @time MatrixMarket.mmwrite("/path/to/my/file.mtx", X);
50.613167 seconds (1.15 G allocations: 32.051 GiB, 2.46% gc time)
Please let me know if there are any possible performance improvements.