Skip to content

Commit 2057316

Browse files
committed
mmread, \vee and \wedge -> | and &, fixed unpack, materialize iso on unpack
1 parent 7899296 commit 2057316

File tree

8 files changed

+186
-24
lines changed

8 files changed

+186
-24
lines changed

src/SuiteSparseGraphBLAS.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,12 @@ include("chainrules/maprules.jl")
8484
include("chainrules/reducerules.jl")
8585
include("chainrules/selectrules.jl")
8686
include("chainrules/constructorrules.jl")
87-
include("chainrules/utilityrules.jl")
87+
8888
#EXPERIMENTAL
8989
include("misc.jl")
9090
include("asjulia.jl")
9191
include("spmgb/sparsemat.jl")
92+
include("mmread.jl")
9293

9394
export SparseArrayCompat
9495
export LibGraphBLAS

src/asjulia.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function as(f::Function, type::Type{<:Union{Matrix, Vector}}, A::GBVecOrMat{T};
3232
end
3333

3434
function as(f::Function, ::Type{SparseMatrixCSC}, A::GBMatrix{T}; freeunpacked=false) where {T}
35-
colptr, rowidx, values = _unpackcscmatrix!(A)
35+
colptr, colptrsize, rowidx, rowidxsize, values, valsize = _unpackcscmatrix!(A)
3636
array = SparseMatrixCSC{T, LibGraphBLAS.GrB_Index}(size(A, 1), size(A, 2), colptr, rowidx, values)
3737
result = try
3838
f(array)
@@ -42,14 +42,14 @@ function as(f::Function, ::Type{SparseMatrixCSC}, A::GBMatrix{T}; freeunpacked=f
4242
ccall(:jl_free, Cvoid, (Ptr{LibGraphBLAS.GrB_Index},), pointer(rowidx))
4343
ccall(:jl_free, Cvoid, (Ptr{T},), pointer(values))
4444
else
45-
_packcscmatrix!(A, colptr, rowidx, values)
45+
_packcscmatrix!(A, colptr, rowidx, values; colptrsize, rowidxsize, valsize)
4646
end
4747
end
4848
return result
4949
end
5050

5151
function as(f::Function, ::Type{SparseVector}, A::GBVector{T}; freeunpacked=false) where {T}
52-
colptr, rowidx, values = _unpackcscmatrix!(A)
52+
colptr, colptrsize, rowidx, rowidxsize, values, valsize = _unpackcscmatrix!(A)
5353
vector = SparseVector{T, LibGraphBLAS.GrB_Index}(size(A, 1), rowidx, values)
5454
result = try
5555
f(vector)
@@ -59,7 +59,7 @@ function as(f::Function, ::Type{SparseVector}, A::GBVector{T}; freeunpacked=fals
5959
ccall(:jl_free, Cvoid, (Ptr{LibGraphBLAS.GrB_Index},), pointer(rowidx))
6060
ccall(:jl_free, Cvoid, (Ptr{T},), pointer(values))
6161
else
62-
_packcscmatrix!(A, colptr, rowidx, values)
62+
_packcscmatrix!(A, colptr, rowidx, values; colptrsize, rowidxsize, valsize)
6363
end
6464
end
6565
return result

src/misc.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ This is type piracy, but shouldn't be a huge deal since it's just `show`.
77
function _⛔()
88
@eval Base.show(io::IO, x::T) where {T<:Union{UInt, UInt128, UInt64,
99
UInt32, UInt16, UInt8}} = Base.print(io, x)
10-
end
10+
end

src/mmread.jl

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# mmread adapted from MatrixMarket.jl
2+
# Copyright (c) 2013: Viral B. Shah.
3+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
5+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6+
7+
8+
_parseint(x) = parse(Int, x)
9+
10+
function find_splits(s::String, num)
11+
splits = Vector{Int}(undef, num)
12+
cur = 1
13+
in_space = s[1] == '\t' || s[1] == ' '
14+
@inbounds for i in 1:length(s)
15+
if s[i] == '\t' || s[i] == ' '
16+
if !in_space
17+
in_space = true
18+
splits[cur] = i
19+
cur += 1
20+
cur > num && break
21+
end
22+
else
23+
in_space = false
24+
end
25+
end
26+
27+
splits
28+
end
29+
30+
# Hack to represent skew-symmetric matrix as an ordinary matrix with duplicated elements
31+
function skewsymmetric!(M::AbstractMatrix)
32+
m,n = size(M)
33+
m == n || throw(DimensionMismatch())
34+
return M .- transpose(tril(M, -1))
35+
end
36+
37+
function symmetric!(M::AbstractMatrix)
38+
m,n = size(M)
39+
m == n || throw(DimensionMismatch())
40+
if eltype(M) == Bool
41+
return M .| transpose(tril(M, -1))
42+
else
43+
return M .+ transpose(tril(M, -1))
44+
end
45+
end
46+
47+
function hermitian!(M::AbstractMatrix)
48+
m,n = size(M)
49+
m == n || throw(DimensionMismatch())
50+
if eltype(M) == Bool
51+
return M .| conj(transpose(tril(M, -1)))
52+
else
53+
return M .+ conj(transpose(tril(M, -1)))
54+
end
55+
end
56+
57+
58+
function mmread(filename, infoonly::Bool=false, retcoord::Bool=false)
59+
open(filename,"r") do mmfile
60+
# Read first line
61+
firstline = chomp(readline(mmfile))
62+
tokens = split(firstline)
63+
if length(tokens) != 5
64+
throw(ArgumentError(string("Not enough words on first line: ", firstline)))
65+
end
66+
if tokens[1] != "%%MatrixMarket"
67+
throw(ArgumentError(string("Expected start of header `%%MatrixMarket`, got `$(tokens[1])`")))
68+
end
69+
(head1, rep, field, symm) = map(lowercase, tokens[2:5])
70+
if head1 != "matrix"
71+
throw(ArgumentError("Unknown MatrixMarket data type: $head1 (only \"matrix\" is supported)"))
72+
end
73+
74+
eltype = field == "real" ? Float64 :
75+
field == "complex" ? ComplexF64 :
76+
field == "integer" ? Int64 :
77+
field == "pattern" ? Bool :
78+
throw(ArgumentError("Unsupported field $field (only real and complex are supported)"))
79+
80+
symlabel = symm == "general" ? identity :
81+
symm == "symmetric" ? symmetric! :
82+
symm == "hermitian" ? hermitian! :
83+
symm == "skew-symmetric" ? skewsymmetric! :
84+
throw(ArgumentError("Unknown matrix symmetry: $symm (only general, symmetric, skew-symmetric and hermitian are supported)"))
85+
86+
# Skip all comments and empty lines
87+
ll = readline(mmfile)
88+
while length(chomp(ll))==0 || (length(ll) > 0 && ll[1] == '%')
89+
ll = readline(mmfile)
90+
end
91+
# Read matrix dimensions (and number of entries) from first non-comment line
92+
dd = map(_parseint, split(ll))
93+
if length(dd) < (rep == "coordinate" ? 3 : 2)
94+
throw(ArgumentError(string("Could not read in matrix dimensions from line: ", ll)))
95+
end
96+
rows = dd[1]
97+
cols = dd[2]
98+
entries = (rep == "coordinate") ? dd[3] : (rows * cols)
99+
infoonly && return (rows, cols, entries, rep, field, symm)
100+
101+
rep == "coordinate" ||
102+
return GBMatrix(symlabel(reshape([parse(Float64, readline(mmfile)) for i in 1:entries],
103+
(rows,cols))))
104+
105+
rr = Vector{Int}(undef, entries)
106+
cc = Vector{Int}(undef, entries)
107+
xx = Vector{eltype}(undef, entries)
108+
for i in 1:entries
109+
line = readline(mmfile)
110+
splits = find_splits(line, eltype == ComplexF64 ? 3 : (eltype == Bool ? 1 : 2))
111+
rr[i] = _parseint(line[1:splits[1]])
112+
cc[i] = _parseint(eltype == Bool
113+
? line[splits[1]:end]
114+
: line[splits[1]:splits[2]])
115+
if eltype == ComplexF64
116+
real = parse(Float64, line[splits[2]:splits[3]])
117+
imag = parse(Float64, line[splits[3]:length(line)])
118+
xx[i] = ComplexF64(real, imag)
119+
elseif eltype == Bool
120+
xx[i] = true
121+
else
122+
xx[i] = parse(eltype, line[splits[2]:length(line)])
123+
end
124+
end
125+
(retcoord
126+
? (rr, cc, xx, rows, cols, entries, rep, field, symm)
127+
: symlabel(GBMatrix(rr, cc, xx, nrows=rows, ncols=cols)))
128+
end
129+
end

src/operations/broadcasts.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ defaultadd(f) = emul
99
# Default to eadd. We're limiting this to + and OR for now to enable easy graph unions.
1010
for op [
1111
:+,
12-
:,
12+
:|,
13+
:
1314
]
1415
funcquote = quote
1516
defaultadd(::typeof($op)) = eadd

src/operators/binaryops.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ end
144144
@binop new isle GxB_ISLE R=>R
145145
@binop new () GxB_LOR R=>R
146146
@binop new () GxB_LAND R=>R
147+
(::BinaryOp{typeof(|)})(::Type{Bool}, ::Type{Bool}) = LOR_BOOL
148+
(::BinaryOp{typeof(&)})(::Type{Bool}, ::Type{Bool}) = LAND_BOOL
149+
147150
@binop new lxor GxB_LXOR R=>R
148151

149152
# T/R => Bool

src/pack.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ function _packcscmatrix!(
1818
colptr::Vector{Ti},
1919
rowidx::Vector{Ti},
2020
values::Vector{T};
21-
desc = nothing
21+
desc = nothing,
22+
colptrsize = length(colptr) * sizeof(LibGraphBLAS.GrB_Index),
23+
rowidxsize = length(rowidx) * sizeof(LibGraphBLAS.GrB_Index),
24+
valsize = length(values) * sizeof(T)
2225
) where {T, Ti}
2326
colptr .-= 1
2427
rowidx .-= 1
25-
colptrsize = length(colptr) * sizeof(LibGraphBLAS.GrB_Index)
26-
rowidxsize = length(rowidx) * sizeof(LibGraphBLAS.GrB_Index)
27-
valsize = length(values) * sizeof(T)
2828
colptr = Ref{Ptr{LibGraphBLAS.GrB_Index}}(pointer(colptr))
2929
rowidx = Ref{Ptr{LibGraphBLAS.GrB_Index}}(pointer(rowidx))
3030
values = Ref{Ptr{Cvoid}}(pointer(values))
@@ -50,13 +50,13 @@ function _packcsrmatrix!(
5050
rowptr::Vector{Ti},
5151
colidx::Vector{Ti},
5252
values::Vector{T};
53-
desc = nothing
53+
desc = nothing,
54+
rowptrsize = length(rowptr) * sizeof(LibGraphBLAS.GrB_Index),
55+
colidxsize = length(colidx) * sizeof(LibGraphBLAS.GrB_Index),
56+
valsize = length(values) * sizeof(T)
5457
) where {T, Ti}
5558
rowptr .-= 1
5659
colidx .-= 1
57-
rowptrsize = length(rowptr) * sizeof(LibGraphBLAS.GrB_Index)
58-
colidxsize = length(colidx) * sizeof(LibGraphBLAS.GrB_Index)
59-
valsize = length(values) * sizeof(T)
6060
rowptr = Ref{Ptr{LibGraphBLAS.GrB_Index}}(pointer(rowptr))
6161
colidx = Ref{Ptr{LibGraphBLAS.GrB_Index}}(pointer(colidx))
6262
values = Ref{Ptr{Cvoid}}(pointer(values))

src/unpack.jl

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ function _unpackcscmatrix!(A::GBVecOrMat{T}; desc = nothing) where {T}
2222
rowidxsize = Ref{LibGraphBLAS.GrB_Index}()
2323
valsize = Ref{LibGraphBLAS.GrB_Index}()
2424
isiso = Ref{Bool}(false)
25-
isjumbled = Ref{Bool}(false)
25+
isjumbled = C_NULL
26+
nnonzeros = nnz(A)
2627
@wraperror LibGraphBLAS.GxB_Matrix_unpack_CSC(
2728
A.p,
2829
colptr,
@@ -35,16 +36,27 @@ function _unpackcscmatrix!(A::GBVecOrMat{T}; desc = nothing) where {T}
3536
isjumbled,
3637
desc
3738
)
38-
#TODO IMPROVE
39-
# colptrsize isn't always exact. Or rather it can be bigger if GrB has allocated a bigger block.
40-
# For now I'll unsafe_wrap based on size(A, 2) + 1
4139
colptr = unsafe_wrap(Array{LibGraphBLAS.GrB_Index}, colptr[], size(A, 2) + 1)
42-
rowidx = unsafe_wrap(Array{LibGraphBLAS.GrB_Index}, rowidx[], rowidxsize[] ÷ sizeof(LibGraphBLAS.GrB_Index))
40+
rowidx = unsafe_wrap(Array{LibGraphBLAS.GrB_Index}, rowidx[], nnonzeros)
41+
42+
if isiso[]
43+
val = unsafe_wrap(Array{T}, Ptr{T}(values[]), 1)[1]
44+
vals = ccall(:jl_realloc, Ptr{Cvoid}, (Ptr{T}, Int64), Ptr{T}(values[]), nnonzeros * sizeof(T))
45+
vals = unsafe_wrap(Array{T}, Ptr{T}(vals), nnonzeros)
46+
vals .= val
47+
valsize = nnonzeros * sizeof(T)
48+
else
49+
vals = unsafe_wrap(Array{T}, Ptr{T}(values[]), nnonzeros)
50+
valsize = valsize[]
51+
end
4352
colptr .+= 1
4453
rowidx .+= 1
4554
return colptr,
55+
colptrsize[],
4656
rowidx,
47-
unsafe_wrap(Array{T}, Ptr{T}(values[]), valsize[] ÷ sizeof(T))
57+
rowidxsize[],
58+
vals,
59+
valsize
4860
end
4961

5062
function _unpackcsrmatrix!(A::GBVecOrMat{T}; desc = nothing) where {T}
@@ -56,7 +68,8 @@ function _unpackcsrmatrix!(A::GBVecOrMat{T}; desc = nothing) where {T}
5668
rowptrsize = Ref{LibGraphBLAS.GrB_Index}()
5769
valsize = Ref{LibGraphBLAS.GrB_Index}()
5870
isiso = Ref{Bool}(false)
59-
isjumbled = Ref{Bool}(false)
71+
isjumbled = C_NULL
72+
nnonzeros = nnz(A)
6073
@wraperror LibGraphBLAS.GxB_Matrix_unpack_CSR(
6174
A.p,
6275
rowptr,
@@ -73,10 +86,25 @@ function _unpackcsrmatrix!(A::GBVecOrMat{T}; desc = nothing) where {T}
7386
# rowptrsize isn't always exact. Or rather it can be bigger if GrB has allocated a bigger block.
7487
# For now I'll unsafe_wrap based on size(A, 1) + 1
7588
rowptr = unsafe_wrap(Array{LibGraphBLAS.GrB_Index}, rowptr[],size(A, 1) + 1)
76-
colidx = unsafe_wrap(Array{LibGraphBLAS.GrB_Index}, colidx[], colidxsize[] ÷ sizeof(LibGraphBLAS.GrB_Index))
89+
colidx = unsafe_wrap(Array{LibGraphBLAS.GrB_Index}, colidx[], nnonzeros)
90+
91+
if isiso[]
92+
val = unsafe_wrap(Array{T}, Ptr{T}(values[]), 1)[1]
93+
vals = ccall(:jl_realloc, Ptr{Cvoid}, (Ptr{T}, Int64), Ptr{T}(values[]), nnonzeros * sizeof(T))
94+
vals = unsafe_wrap(Array{T}, Ptr{T}(vals), nnonzeros)
95+
vals .= val
96+
valsize = nnonzeros * sizeof(T)
97+
else
98+
vals = unsafe_wrap(Array{T}, Ptr{T}(values[]), nnonzeros)
99+
valsize = valsize[]
100+
end
101+
77102
rowptr .+= 1
78103
colidx .+= 1
79104
return rowptr,
105+
rowptrsize[],
80106
colidx,
81-
unsafe_wrap(Array{T}, Ptr{T}(values[]), valsize[] ÷ sizeof(T))
107+
colidxsize[],
108+
vals,
109+
valsize
82110
end

0 commit comments

Comments
 (0)