According to my benchmarks, it looks like it is much faster for the in-place shiftleft!, but still x3 faster for the out-of-place shiftleft. Also, my approach looks like is almost not affected by the percentage of non-zero values, vs. the other that do are affected.
julia> using SparseArrays, LinearAlgebra, BenchmarkTools
julia> function shiftleft!(A::SparseMatrixCSC, n)
sz = size(A)
n <= sz[2] || throw(DimensionMismatch("$(n) bigger than the number of columns $(size[2])"))
colnz = A.colptr[n+1] - 1
@view(A.colptr[begin:end-n]) .= @view(A.colptr[begin+n:end])
A.colptr[end-n+1:end] .= A.colptr[end]
A.colptr .-= colnz
deleteat!(A.rowval, 1:colnz)
deleteat!(A.nzval, 1:colnz)
A
end
shiftleft! (generic function with 1 method)
julia> shiftleft(A, n) = shiftleft!(copy(A), n)
shiftleft (generic function with 1 method)
julia> shiftleft_mul(A, n) = A * spdiagm(-n => ones(Int, size(A, 2)-n))
shiftleft_mul (generic function with 1 method)
julia> function shiftleft_slide(A::SparseMatrixCSC, n)
A[:, begin:begin+n-1] .= zero(eltype(A))
dropzeros!(A)
A[:, vcat(begin+n:end, begin:begin+n-1)]
end
shiftleft_slide (generic function with 1 method)
Results in
julia> @benchmark shiftleft!(A, 10) setup=(A=sprand(100, 100, 0.1))
BenchmarkTools.Trial: 10000 samples with 803 evaluations.
Range (min … max): 150.450 ns … 1.189 μs ┊ GC (min … max): 0.00% … 66.28%
Time (median): 164.403 ns ┊ GC (median): 0.00%
Time (mean ± σ): 193.630 ns ± 89.107 ns ┊ GC (mean ± σ): 3.87% ± 8.50%
██▆▃▃▂▁▁▁▁▂▄▃▂▃▂▁▁▁ ▁▁ ▂
██████████████████████▇▆▄▆▄▄▁▃▁▁▁▃▁▁▁▁▃▁▁▃▁▁▁▁▁▃▆▅▆▇▅▅▄▄▆▇▆▇ █
150 ns Histogram: log(frequency) by time 697 ns <
Memory estimate: 816 bytes, allocs estimate: 1.
julia> @benchmark shiftleft!(A, 10) setup=(A=sprand(100, 100, 0.9))
BenchmarkTools.Trial: 10000 samples with 800 evaluations.
Range (min … max): 145.001 ns … 2.450 μs ┊ GC (min … max): 0.00% … 84.63%
Time (median): 167.564 ns ┊ GC (median): 0.00%
Time (mean ± σ): 214.467 ns ± 130.594 ns ┊ GC (mean ± σ): 4.92% ± 8.98%
▇█▆▄▃▂▂▂▃▄▃▃▃▃▃▂▂▁▁ ▂
████████████████████▇▇▇▇▇▅▆▆▆▆▆▅▅▅▅▆▃▄▄▄▇▆▄▅▅▅▄▅▅▅▃▄▃▃▁▃▅▆▆▆▇ █
145 ns Histogram: log(frequency) by time 860 ns <
Memory estimate: 816 bytes, allocs estimate: 1.
julia> @benchmark shiftleft(A, 10) setup=(A=sprand(100, 100, 0.1))
BenchmarkTools.Trial: 10000 samples with 9 evaluations.
Range (min … max): 1.769 μs … 297.860 μs ┊ GC (min … max): 0.00% … 96.98%
Time (median): 2.857 μs ┊ GC (median): 0.00%
Time (mean ± σ): 4.596 μs ± 10.683 μs ┊ GC (mean ± σ): 11.58% ± 5.31%
▃█▆▆▆▅▄▄▃▃▂▂▂▁ ▁ ▁▁▁ ▂
████████████████▇▇▆▇▅▅▅▅▅▄▆███████▇▇▇▇▇▇▇▇▇▇▇▆▅▆▆▆▆▅▅▅▄▅▄▅▅ █
1.77 μs Histogram: log(frequency) by time 20.2 μs <
Memory estimate: 15.80 KiB, allocs estimate: 4.
julia> @benchmark shiftleft(A, 10) setup=(A=sprand(100, 100, 0.9))
BenchmarkTools.Trial: 10000 samples with 1 evaluation.
Range (min … max): 11.614 μs … 808.363 μs ┊ GC (min … max): 0.00% … 94.41%
Time (median): 14.659 μs ┊ GC (median): 0.00%
Time (mean ± σ): 18.201 μs ± 35.230 μs ┊ GC (mean ± σ): 10.51% ± 5.41%
▂▅▇██▆▄▃▂▃▂▂▁▂▁ ▁▁▁▂▂▁ ▂
▇██████████████████████▇▇▇▇▇▆▇▆▅▇▆▇▆▇▆▆▅▄▄▃▄▃▄▄▄▄▄▅▄▄▃▃▄▃▁▃▃ █
11.6 μs Histogram: log(frequency) by time 48.1 μs <
Memory estimate: 140.52 KiB, allocs estimate: 6.
julia> @benchmark shiftleft_mul(A, 10) setup=(A=sprand(100, 100, 0.1))
BenchmarkTools.Trial: 10000 samples with 1 evaluation.
Range (min … max): 17.919 μs … 1.694 ms ┊ GC (min … max): 0.00% … 95.68%
Time (median): 22.169 μs ┊ GC (median): 0.00%
Time (mean ± σ): 25.795 μs ± 36.031 μs ┊ GC (mean ± σ): 3.66% ± 2.65%
▅███▄▄▁
▁▁▂▅████████▇▅▄▃▃▃▃▃▃▃▃▃▃▂▂▃▂▂▂▃▂▂▃▃▃▄▃▃▄▃▃▃▂▂▂▂▂▁▁▁▁▁▁▁▁▁▁ ▃
17.9 μs Histogram: frequency by time 41.7 μs <
Memory estimate: 25.09 KiB, allocs estimate: 19.
julia> @benchmark shiftleft_mul(A, 10) setup=(A=sprand(100, 100, 0.9))
BenchmarkTools.Trial: 10000 samples with 1 evaluation.
Range (min … max): 51.419 μs … 938.537 μs ┊ GC (min … max): 0.00% … 86.56%
Time (median): 55.294 μs ┊ GC (median): 0.00%
Time (mean ± σ): 62.974 μs ± 43.053 μs ┊ GC (mean ± σ): 4.06% ± 5.75%
▃█▇▆▅▅▄▃▃▃▂▂▃▂▂▂▂▂▂▂▂▁▂▁▁▁▁▁▁▁ ▂
████████████████████████████████▇▇█▇▇▆▇▆▅▆▅▅▅▄▄▄▅▃▃▃▄▁▄▅▄▃▁▄ █
51.4 μs Histogram: log(frequency) by time 127 μs <
Memory estimate: 246.69 KiB, allocs estimate: 23.
julia> @benchmark shiftleft_slide(A, 10) setup=(A=sprand(100, 100, 0.1))
BenchmarkTools.Trial: 10000 samples with 7 evaluations.
Range (min … max): 4.884 μs … 230.295 μs ┊ GC (min … max): 0.00% … 88.43%
Time (median): 5.887 μs ┊ GC (median): 0.00%
Time (mean ± σ): 6.586 μs ± 8.344 μs ┊ GC (mean ± σ): 5.40% ± 4.16%
▁▁▃▄▆██▇▅▁
▁▂▃▆▇███████████▆▇▅▅▄▄▄▃▃▂▃▃▃▃▃▃▂▂▃▃▃▃▃▃▂▂▂▂▂▂▂▂▂▁▁▁▁▁▁▁▁▁▁ ▃
4.88 μs Histogram: frequency by time 9.59 μs <
Memory estimate: 14.62 KiB, allocs estimate: 4.
julia> @benchmark shiftleft_slide(A, 10) setup=(A=sprand(100, 100, 0.9))
BenchmarkTools.Trial: 10000 samples with 1 evaluation.
Range (min … max): 27.227 μs … 927.842 μs ┊ GC (min … max): 0.00% … 90.21%
Time (median): 30.218 μs ┊ GC (median): 0.00%
Time (mean ± σ): 37.314 μs ± 37.987 μs ┊ GC (mean ± σ): 4.89% ± 4.92%
▃▇█▇▅▅▅▃▃▂▁▂▃▂▁▁▁▂▂▂▃▃▃▂▂▂▂▁▁▁▁ ▁▁ ▂
████████████████████████████████████▇▇▇█▇▇▆▆▆▆▆▆▆▆▆▅▅▄▆▆▄▅▅▅ █
27.2 μs Histogram: log(frequency) by time 79 μs <
Memory estimate: 126.72 KiB, allocs estimate: 6.