Skip to content

Commit 421e267

Browse files
committed
new index, setfill, one=>pair
1 parent 9cb9e55 commit 421e267

File tree

5 files changed

+79
-47
lines changed

5 files changed

+79
-47
lines changed

docs/src/index.md

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# SuiteSparseGraphBLAS.jl
22

3-
SuiteSparseGraphBLAS.jl is a package for sparse linear algebra on arbitrary semirings, with a particular focus on graph computations.
4-
It aims to provide a Julian wrapper over Tim Davis' SuiteSparse:GraphBLAS reference implementation of the GraphBLAS C specification.
3+
Fast sparse linear algebra is an essential part of the scientific computing toolkit. Outside of the usual applications, like differential equations, sparse linear algebra provides an elegant way to express graph algorithms on adjacency and incidence matrices. The GraphBLAS standard specifies a set of operations for computing sparse matrix graph algorithm in a vein similar to the BLAS or LAPACK standards.
4+
5+
SuiteSparseGraphBLAS.jl is a blazing fast package for shared memory sparse matrix operations which wraps Tim Davis' SuiteSparse:GraphBLAS implementation of the GraphBLAS C specification.
56

67
# Installation
78

@@ -18,26 +19,27 @@ using Pkg
1819
Pkg.add("SuiteSparseGraphBLAS")
1920
```
2021

21-
The SuiteSparse:GraphBLAS binary is installed automatically as `SSGraphBLAS_jll`.
22+
The SuiteSparse:GraphBLAS binary, SSGraphBLAS_jll.jl, is installed automatically.
2223

23-
Then in the REPL or script `using SuiteSparseGraphBLAS` will import the package.
24+
Then in the REPL or script `using SuiteSparseGraphBLAS` will make the package available for use.
2425

2526
# Introduction
2627

2728
GraphBLAS harnesses the well-understood duality between graphs and matrices.
2829
Specifically a graph can be represented by the [adjacency matrix](https://en.wikipedia.org/wiki/Adjacency_matrix) and/or [incidence matrix](https://en.wikipedia.org/wiki/Incidence_matrix), or one of the many variations on those formats.
2930
With this matrix representation in hand we have a method to operate on the graph with linear algebra.
3031

31-
Below is an example of the adjacency matrix of a directed graph, and finding the neighbors of a single vertex using basic matrix-vector multiplication on the arithemtic semiring.
32+
One important algorithm that maps well to linear algebra is Breadth First Search (BFS).
33+
A simple BFS is just a matrix-vector multiplication, where `A` is the adjacency matrix and `v` is the set of source nodes, as illustrated below.
3234

3335
![BFS and Adjacency Matrix](./assets/AdjacencyBFS.png)
3436

3537
## GBArrays
3638

37-
The core SuiteSparseGraphBLAS.jl array types are `GBVector` and `GBMatrix` which are subtypes `SparseArrays.AbstractSparseVector` and `SparseArrays.AbstractSparseMatrix` respectively.
39+
The core SuiteSparseGraphBLAS.jl array types are `GBVector` and `GBMatrix` which are subtypes `SparseArrays.AbstractSparseVector` and `SparseArrays.AbstractSparseMatrix` respectively. There are also several auxiliary array types that restrict one or more behaviors, like row or column orientation. More info on those types can be found ### HERE ###
3840

3941
!!! note "GBArray"
40-
These docs will often refer to the `GBArray` type, which is the union of `GBVector`, `GBMatrix` and their lazy Transpose objects.
42+
These docs will often refer to the `GBArray` type, which is the union of `AbstractGBVector`, `AbstractGBMatrix` and their lazy Transpose objects.
4143

4244
```@setup intro
4345
using SuiteSparseGraphBLAS
@@ -59,7 +61,8 @@ Here we can already see several differences compared to `SparseArrays.SparseMatr
5961
The first is that `A` is stored in `hypersparse` format, and by row.
6062

6163
`GBArrays` are (technically) opaque to the user in order to allow the library author to choose the best storage format.\
62-
GraphBLAS takes advantage of this by storing matrices in one of four formats: `dense`, `bitmap`, `sparse-compressed`, or `hypersparse-compressed`; and in either `row` or `column` major orientation.
64+
GraphBLAS takes advantage of this by storing matrices in one of four formats: `dense`, `bitmap`, `sparse-compressed`, or `hypersparse-compressed`; and in either `row` or `column` major orientation.\
65+
Different matrices may be better suited to storage in one of those formats, and certain operations may perform differently on `row` or `column` major matrices.
6366

6467
!!! warning "Default Orientation"
6568
The default orientation of a `GBMatrix` is by-row, the opposite of Julia arrays. However, a `GBMatrix` constructed from a `SparseMatrixCSC` or
@@ -72,31 +75,38 @@ Information about storage formats, orientation, conversion, construction and mor
7275
The second difference is that a `GBArray` doesn't assume the fill-in value of a sparse array.\
7376
Since `A[1,5]` isn't stored in the matrix (it's been "compressed" out), we return `nothing`.\
7477

75-
This matches the GraphBLAS spec, where `NO_VALUE` is returned, rather than `zero(eltype(A))`.
78+
This better matches the GraphBLAS spec, where `NO_VALUE` is returned, rather than `zero(eltype(A))`. This is better suited to graph algorithms where returning `zero(eltype(A))` might imply the presence of an edge with weight `zero`.\
79+
However this behavior can be changed with the [`setfill!`](@ref) and [`setfill`](@ref) functions.
80+
81+
```@repl intro
82+
A[1, 1] === nothing
83+
84+
B = setfill(A, 0) # no-copy alias
85+
B[1, 1]
86+
```
7687

7788
An empty matrix and vector won't do us much good, so let's see how to construct the matrix and vector from the graphic above. Both `A` and `v` below are constructed from coordinate format or COO.
7889

7990
```@repl intro
80-
#GBMatrix(I::Vector{<:Integer}, J::Vector{<:Integer}, V::Vector{T})
8191
A = GBMatrix([1,1,2,2,3,4,4,5,6,7,7,7], [2,4,5,7,6,1,3,6,3,3,4,5], [1:12...])
8292
83-
#GBVector(I::Vector{<:Integer}, V::Vector{T})
8493
v = GBVector([4], [10])
8594
```
95+
8696
## GraphBLAS Operations
8797

8898
The complete documentation of supported operations can be found in [Operations](@ref).
89-
GraphBLAS operations are, where possible, methods of existing Julia functions listed in the third column.
99+
GraphBLAS operations are, where possible, methods of existing Julia functions listed in the third column.
90100

91101
| GraphBLAS | Operation | Julia |
92102
|:--------------------|:----------------------------------------: |----------: |
93103
|`mxm`, `mxv`, `vxm` |``\bf C \langle M \rangle = C \odot AB`` |`mul[!]` or `*` |
94104
|`eWiseMult` |``\bf C \langle M \rangle = C \odot (A \otimes B)`` |`emul[!]` or `.` broadcasting |
95105
|`eWiseAdd` |``\bf C \langle M \rangle = C \odot (A \oplus B)`` |`eadd[!]` |
96-
|`extract` |``\bf C \langle M \rangle = C \odot A(I,J)`` |`extract[!]`, `getindex` or `A[i...]` |
97-
|`subassign` |``\bf C (I,J) \langle M \rangle = C(I,J) \odot A`` |`subassign[!]`, `setindex!` or `A[i...]=3.5`|
106+
|`extract` |``\bf C \langle M \rangle = C \odot A(I,J)`` |`extract[!]`, `getindex` |
107+
|`subassign` |``\bf C (I,J) \langle M \rangle = C(I,J) \odot A`` |`subassign[!]` or `setindex!`|
98108
|`assign` |``\bf C \langle M \rangle (I,J) = C(I,J) \odot A`` |`assign[!]` |
99-
|`apply` |``{\bf C \langle M \rangle = C \odot} f{\bf (A)}`` |`map[!]` or `.` broadcasting |
109+
|`apply` |``{\bf C \langle M \rangle = C \odot} f{\bf (A)}`` |`apply[!]`, `map[!]` or `.` broadcasting |
100110
| |``{\bf C \langle M \rangle = C \odot} f({\bf A},y)`` | |
101111
| |``{\bf C \langle M \rangle = C \odot} f(x,{\bf A})`` | |
102112
|`select` |``{\bf C \langle M \rangle = C \odot} f({\bf A},k)`` |`select[!]` |
@@ -105,41 +115,53 @@ GraphBLAS operations are, where possible, methods of existing Julia functions l
105115
|`transpose` |``\bf C \langle M \rangle = C \odot A^{\sf T}`` |`gbtranspose[!]`, lazy: `transpose`, `'` |
106116
|`kronecker` |``\bf C \langle M \rangle = C \odot \text{kron}(A, B)`` |`kron[!]` |
107117

108-
where ``\bf M`` is a `GBArray` mask, ``\odot`` is a binary operator for accumulating into ``\bf C``, and ``\otimes`` and ``\oplus`` are a binary operation and commutative monoid respectively.
118+
where ``\bf M`` is a `GBArray` mask, ``\odot`` is a binary operator for accumulating into ``\bf C``, and ``\otimes`` and ``\oplus`` are a binary operation and commutative monoid respectively. ``f`` is either a unary or binary operator.
109119

110120
## GraphBLAS Operators
111121

122+
Many GraphBLAS operations take additional arguments called *operators*. In the table above operators are denoted by ``\odot``, ``\otimes``, and ``\oplus`` and ``f``, and they behave similar to the function argument of `map`. A closer look at operators can be found in [Operators](@ref)
123+
112124
A GraphBLAS operator is a unary or binary function, the commutative monoid form of a binary function,
113125
or a semiring, made up of a binary op and a commutative monoid.
114126
SuiteSparse:GraphBLAS ships with many of the common unary and binary operators as built-ins,
115127
along with monoids and semirings built commonly used in graph algorithms.
116-
In most cases these operators can be used with familiar Julia syntax and functions, which then map to
117-
objects found in the submodules below:
128+
These built-in operators are *fast*, and should be used where possible. However, users are also free to provide their own functions as operators when necessary.
118129

119-
- `UnaryOps` such as `SIN`, `SQRT`, `ABS`
120-
- `BinaryOps` such as `GE`, `MAX`, `POW`, `FIRSTJ`
121-
- `Monoids` such as `PLUS_MONOID`, `LXOR_MONOID`
122-
- `Semirings` such as `PLUS_TIMES` (the arithmetic semiring), `MAX_PLUS` (a tropical semiring), `PLUS_PLUS`, ...
130+
SuiteSparseGraphBLAS.jl will *mostly* take care of operators behind the scenes, and in most cases users should pass in normal functions like `+` and `sin`. For example:
123131

124-
The above objects should, in almost all cases, be used by instead passing the equivalent functions, `sin` for `SIN`, `+` for `PLUS_MONOID` etc.
132+
```@repl intro
133+
emul(A, A, ^) # elementwise exponent
125134
126-
A user may choose to call a function in multiple different forms: `A .+ B`, `eadd(A, B, +)`,
127-
or `eadd(A, B, BinaryOps.PLUS)`.
135+
map(sin, A)
136+
```
137+
138+
Broadcasting functionality is also supported, `A .^ A` will lower to `emul(A, A, ^)`, and `sin.(A)` will lower to `map(sin, A)`.
139+
140+
Matrix multiplication, which accepts a semiring, can be called with either `*(max, +)(A, B)` or
141+
`mul(A, B, (max, +))`.
142+
143+
We can also use functions that are not already built into SuiteSparseGraphBLAS.jl:
144+
145+
```@repl intro
146+
M = GBMatrix([[1,2] [3,4]])
147+
increment(x) = x + 1
148+
map(increment, M)
149+
```
128150

129-
Functions which only accept monoids like `reduce` will automatically find the correct monoid,
130-
so a call to `reduce(+, A)`, will lower to `reduce(Monoids.PLUS_MONOID, A)`.
151+
Unfortunately this has a couple problems. The first is that it's slow.\
152+
Compared to `A .+ 1` which lowers to `apply(+, A, 1)` the `map` call above is ~2.5x slower due to function pointer overhead.
131153

132-
Matrix multiplication, which accepts a semiring, can be called with either `*(max, +)(A, B)`,
133-
`mul(A, B, (max, +))`, or `mul(A, B, Semirings.MAX_PLUS)`.
154+
The second is that everytime we call `map(increment, M)` we will be re-creating the function pointer for `increment` matched to the type of `M`.\
155+
To avoid this there's a convenience macro [`@unop`](@ref) which will provide a permanent constant which is used every time `increment` is called with a GraphBLAS operation. See [Operators](@ref) for more information.
134156

135157
!!! warning "Performance of User Defined Functions"
136158
Operators which are not already built-in are automatically constructed using function pointers when called.
137159
Note, however, that their performance is significantly degraded compared to built-in operators,
138-
and where possible user code should avoid this capability.
160+
and where possible user code should avoid this capability. See [Operators](@ref).
139161

140162
## Example
141163

142-
Here is an example of two different methods of triangle counting with GraphBLAS.
164+
Here is a quick example of two different methods of triangle counting with GraphBLAS.
143165
The methods are drawn from the LAGraph [repo](https://github.com/GraphBLAS/LAGraph).
144166

145167
Input `A` must be a square, symmetric matrix with any element type.

src/SuiteSparseGraphBLAS.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export clear!, extract, extract!, subassign!, assign!, hvcat! #array functions
121121

122122
#operations
123123
export mul, select, select!, eadd, eadd!, emul, emul!, map, map!, gbtranspose, gbtranspose!,
124-
gbrand, eunion, eunion!, mask, mask!, apply, apply!
124+
gbrand, eunion, eunion!, mask, mask!, apply, apply!, setfill, setfill!
125125
# Reexports from LinAlg
126126
export diag, diagm, mul!, kron, kron!, transpose, reduce, tril, triu
127127

src/abstractgbarray.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,4 +548,14 @@ function Base.getindex(
548548
mask = nothing, accum = nothing, desc = nothing
549549
)
550550
return extract(A, i, j; mask, accum, desc)
551+
end
552+
553+
function setfill!(A::AbstractGBArray, x)
554+
A.fill = x
555+
end
556+
557+
function setfill(A::AbstractGBArray, x) # aliasing form.
558+
B = similar(A; fill=x)
559+
B.p = A.p
560+
return B
551561
end

src/operators/binaryops.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ end
124124
@binop first GrB_FIRST T=>T
125125
@binop new second GrB_SECOND T=>T
126126
@binop any GxB_ANY T=>T # this doesn't match the semantics of Julia's any, but that may be ok...
127-
@binop one GrB_ONEB T=>T # I prefer pair, but to keep up with the spec I'll match...
127+
@binop new pair GrB_ONEB T=>T # I prefer pair, but to keep up with the spec I'll match...
128128
@binop (+) GrB_PLUS T=>T
129129
@binop (-) GrB_MINUS T=>T
130130
@binop new rminus GxB_RMINUS T=>T

src/operators/semirings.jl

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Semirings
22
import ..SuiteSparseGraphBLAS
33
using ..SuiteSparseGraphBLAS: isGxB, isGrB, TypedSemiring, AbstractSemiring, GBType,
44
valid_vec, juliaop, gbtype, symtotype, Itypes, Ftypes, Ztypes, FZtypes,
5-
Rtypes, Ntypes, Ttypes, suffix, BinaryOps.BinaryOp, Monoids.Monoid, BinaryOps.second, BinaryOps.rminus,
5+
Rtypes, Ntypes, Ttypes, suffix, BinaryOps.BinaryOp, Monoids.Monoid, BinaryOps.second, BinaryOps.rminus, BinaryOps.pair,
66
BinaryOps.iseq, BinaryOps.isne, BinaryOps.isgt, BinaryOps.islt, BinaryOps.isge, BinaryOps.isle, BinaryOps.∨,
77
BinaryOps.∧, BinaryOps.lxor, BinaryOps.xnor, BinaryOps.fmod, BinaryOps.bxnor, BinaryOps.bget, BinaryOps.bset,
88
BinaryOps.bclr, BinaryOps.firsti0, BinaryOps.firsti, BinaryOps.firstj0, BinaryOps.firstj, BinaryOps.secondi0,
@@ -112,7 +112,7 @@ end
112112
# (I..., F...)
113113
@rig (min, first) GxB_MIN_FIRST IF=>IF
114114
@rig (min, second) GxB_MIN_SECOND IF=>IF
115-
@rig (min, one) GxB_MIN_PAIR IF=>IF
115+
@rig (min, pair) GxB_MIN_PAIR IF=>IF
116116
@rig (min, min) GxB_MIN_MIN IF=>IF
117117
@rig (min, max) GxB_MIN_MAX IF=>IF
118118
@rig (min, +) GxB_MIN_PLUS IF=>IF
@@ -133,7 +133,7 @@ end
133133

134134
@rig (max, first) GxB_MAX_FIRST IF=>IF
135135
@rig (max, second) GxB_MAX_SECOND IF=>IF
136-
@rig (max, one) GxB_MAX_PAIR IF=>IF
136+
@rig (max, pair) GxB_MAX_PAIR IF=>IF
137137
@rig (max, min) GxB_MAX_MIN IF=>IF
138138
@rig (max, max) GxB_MAX_MAX IF=>IF
139139
@rig (max, +) GxB_MAX_PLUS IF=>IF
@@ -154,7 +154,7 @@ end
154154

155155
@rig (+, first) GxB_PLUS_FIRST IF=>IF
156156
@rig (+, second) GxB_PLUS_SECOND IF=>IF
157-
@rig (+, one) GxB_PLUS_PAIR IF=>IF
157+
@rig (+, pair) GxB_PLUS_PAIR IF=>IF
158158
@rig (+, min) GxB_PLUS_MIN IF=>IF
159159
@rig (+, max) GxB_PLUS_MAX IF=>IF
160160
@rig (+, +) GxB_PLUS_PLUS IF=>IF
@@ -175,7 +175,7 @@ end
175175

176176
@rig (*, first) GxB_TIMES_FIRST IF=>IF
177177
@rig (*, second) GxB_TIMES_SECOND IF=>IF
178-
@rig (*, one) GxB_TIMES_PAIR IF=>IF
178+
@rig (*, pair) GxB_TIMES_PAIR IF=>IF
179179
@rig (*, min) GxB_TIMES_MIN IF=>IF
180180
@rig (*, max) GxB_TIMES_MAX IF=>IF
181181
@rig (*, +) GxB_TIMES_PLUS IF=>IF
@@ -196,7 +196,7 @@ end
196196

197197
@rig (any, first) GxB_ANY_FIRST IF=>IF
198198
@rig (any, second) GxB_ANY_SECOND IF=>IF
199-
@rig (any, one) GxB_ANY_PAIR IF=>IF
199+
@rig (any, pair) GxB_ANY_PAIR IF=>IF
200200
@rig (any, min) GxB_ANY_MIN IF=>IF
201201
@rig (any, max) GxB_ANY_MAX IF=>IF
202202
@rig (any, +) GxB_ANY_PLUS IF=>IF
@@ -255,7 +255,7 @@ end
255255

256256
@rig (, first) GxB_LAND_FIRST Bool=>Bool
257257
@rig (, second) GxB_LAND_SECOND Bool=>Bool
258-
@rig (, one) GxB_LAND_PAIR Bool=>Bool
258+
@rig (, pair) GxB_LAND_PAIR Bool=>Bool
259259
@rig (, ) GxB_LAND_LOR Bool=>Bool
260260
@rig (, ) GxB_LAND_LAND Bool=>Bool
261261
@rig (, lxor) GxB_LAND_LXOR Bool=>Bool
@@ -267,7 +267,7 @@ end
267267

268268
@rig (, first) GxB_LOR_FIRST Bool=>Bool
269269
@rig (, second) GxB_LOR_SECOND Bool=>Bool
270-
@rig (, one) GxB_LOR_PAIR Bool=>Bool
270+
@rig (, pair) GxB_LOR_PAIR Bool=>Bool
271271
@rig (, ) GxB_LOR_LOR Bool=>Bool
272272
@rig (, ) GxB_LOR_LAND Bool=>Bool
273273
@rig (, lxor) GxB_LOR_LXOR Bool=>Bool
@@ -279,7 +279,7 @@ end
279279

280280
@rig (lxor, first) GxB_LXOR_FIRST Bool=>Bool
281281
@rig (lxor, second) GxB_LXOR_SECOND Bool=>Bool
282-
@rig (lxor, one) GxB_LXOR_PAIR Bool=>Bool
282+
@rig (lxor, pair) GxB_LXOR_PAIR Bool=>Bool
283283
@rig (lxor, ) GxB_LXOR_LOR Bool=>Bool
284284
@rig (lxor, ) GxB_LXOR_LAND Bool=>Bool
285285
@rig (lxor, lxor) GxB_LXOR_LXOR Bool=>Bool
@@ -291,7 +291,7 @@ end
291291

292292
@rig (==, first) GxB_EQ_FIRST Bool=>Bool
293293
@rig (==, second) GxB_EQ_SECOND Bool=>Bool
294-
@rig (==, one) GxB_EQ_PAIR Bool=>Bool
294+
@rig (==, pair) GxB_EQ_PAIR Bool=>Bool
295295
@rig (==, ) GxB_EQ_LOR Bool=>Bool
296296
@rig (==, ) GxB_EQ_LAND Bool=>Bool
297297
@rig (==, lxor) GxB_EQ_LXOR Bool=>Bool
@@ -303,7 +303,7 @@ end
303303

304304
@rig (any, first) GxB_ANY_FIRST Bool=>Bool
305305
@rig (any, second) GxB_ANY_SECOND Bool=>Bool
306-
@rig (any, one) GxB_ANY_PAIR Bool=>Bool
306+
@rig (any, pair) GxB_ANY_PAIR Bool=>Bool
307307
@rig (any, ) GxB_ANY_LOR Bool=>Bool
308308
@rig (any, ) GxB_ANY_LAND Bool=>Bool
309309
@rig (any, lxor) GxB_ANY_LXOR Bool=>Bool
@@ -316,7 +316,7 @@ end
316316
# (PLUS, TIMES, ANY) × (FIRST, SECOND, PAIR(ONEB), PLUS, MINUS, RMINUS, TIMES, DIV, RDIV) × Z
317317
@rig (+, first) GxB_PLUS_FIRST Z=>Z
318318
@rig (+, second) GxB_PLUS_SECOND Z=>Z
319-
@rig (+, one) GxB_PLUS_PAIR Z=>Z
319+
@rig (+, pair) GxB_PLUS_PAIR Z=>Z
320320
@rig (+, +) GxB_PLUS_PLUS Z=>Z
321321
@rig (+, -) GxB_PLUS_MINUS Z=>Z
322322
@rig (+, rminus) GxB_PLUS_RMINUS Z=>Z
@@ -326,7 +326,7 @@ end
326326

327327
@rig (*, first) GxB_TIMES_FIRST Z=>Z
328328
@rig (*, second) GxB_TIMES_SECOND Z=>Z
329-
@rig (*, one) GxB_TIMES_PAIR Z=>Z
329+
@rig (*, pair) GxB_TIMES_PAIR Z=>Z
330330
@rig (*, +) GxB_TIMES_PLUS Z=>Z
331331
@rig (*, -) GxB_TIMES_MINUS Z=>Z
332332
@rig (*, rminus) GxB_TIMES_RMINUS Z=>Z
@@ -336,7 +336,7 @@ end
336336

337337
@rig (any, first) GxB_ANY_FIRST Z=>Z
338338
@rig (any, second) GxB_ANY_SECOND Z=>Z
339-
@rig (any, one) GxB_ANY_PAIR Z=>Z
339+
@rig (any, pair) GxB_ANY_PAIR Z=>Z
340340
@rig (any, +) GxB_ANY_PLUS Z=>Z
341341
@rig (any, -) GxB_ANY_MINUS Z=>Z
342342
@rig (any, rminus) GxB_ANY_RMINUS Z=>Z

0 commit comments

Comments
 (0)