Skip to content

Commit 00bdd5a

Browse files
committed
add: msbfs levels
1 parent 2199287 commit 00bdd5a

15 files changed

Lines changed: 487 additions & 69 deletions

File tree

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
namespace GraphBLAS.FSharp.Backend.Algorithms
2+
3+
open Brahma.FSharp
4+
open FSharp.Quotations
5+
open GraphBLAS.FSharp
6+
open GraphBLAS.FSharp.Objects
7+
open GraphBLAS.FSharp.Objects.ClMatrix
8+
open GraphBLAS.FSharp.Objects.ArraysExtensions
9+
open GraphBLAS.FSharp.Objects.ClContextExtensions
10+
open GraphBLAS.FSharp.Backend.Matrix.LIL
11+
open GraphBLAS.FSharp.Backend.Matrix.COO
12+
13+
module internal MSBFS =
14+
module Levels =
15+
let private updateFront (clContext: ClContext) workGroupSize =
16+
17+
let excludeValues = ClArray.excludeElements clContext workGroupSize
18+
19+
let excludeIndices = ClArray.excludeElements clContext workGroupSize
20+
21+
fun (queue: MailboxProcessor<_>) allocationMode (front: ClMatrix.COO<_>) (intersection: ClArray<int>) ->
22+
23+
let newRows = excludeIndices queue allocationMode intersection front.Rows
24+
25+
let newColumns = excludeIndices queue allocationMode intersection front.Columns
26+
27+
let newValues = excludeValues queue allocationMode intersection front.Values
28+
29+
match newRows, newColumns, newValues with
30+
| Some rows, Some columns, Some values ->
31+
{ Context = clContext
32+
Rows = rows
33+
Columns = columns
34+
Values = values
35+
RowCount = front.RowCount
36+
ColumnCount = front.ColumnCount }
37+
|> Some
38+
| _ -> None
39+
40+
let private updateFrontAndLevels (clContext: ClContext) workGroupSize =
41+
42+
let updateFront = updateFront clContext workGroupSize
43+
44+
let mergeDisjoint = Matrix.mergeDisjoint clContext workGroupSize
45+
46+
let findIntersection = Intersect.findKeysIntersection clContext workGroupSize
47+
48+
fun (queue: MailboxProcessor<_>) allocationMode (levels: ClMatrix.COO<_>) (front: ClMatrix.COO<_>) ->
49+
50+
// Find intersection of levels and front indices.
51+
let intersection = findIntersection queue DeviceOnly front levels
52+
53+
// Remove mutual elements
54+
let newFront = updateFront queue allocationMode front intersection
55+
56+
intersection.Free queue
57+
58+
match newFront with
59+
| Some f ->
60+
// Update levels
61+
let newLevels = mergeDisjoint queue levels f
62+
newLevels, newFront
63+
| _ -> levels, None
64+
65+
let run<'a when 'a: struct>
66+
(add: Expr<int -> int -> int option>)
67+
(mul: Expr<'a -> int -> int option>)
68+
(clContext: ClContext)
69+
workGroupSize
70+
=
71+
72+
let spGeMM =
73+
Operations.SpGeMM.expand add mul clContext workGroupSize
74+
75+
let toCSRInPlace = Matrix.toCSRInPlace clContext workGroupSize
76+
77+
let updateFrontAndLevels = updateFrontAndLevels clContext workGroupSize
78+
79+
fun (queue: MailboxProcessor<Msg>) (matrix: ClMatrix<'a>) (source: int list) ->
80+
let vertexCount = matrix.RowCount
81+
let sourceVertexCount = source.Length
82+
83+
let startMatrix =
84+
source
85+
|> List.mapi (fun i vertex -> i, vertex, 1)
86+
87+
let mutable levels =
88+
startMatrix
89+
|> Matrix.ofList clContext DeviceOnly sourceVertexCount vertexCount
90+
91+
let mutable front =
92+
startMatrix
93+
|> Matrix.ofList clContext DeviceOnly sourceVertexCount vertexCount
94+
|> toCSRInPlace queue DeviceOnly
95+
96+
let mutable level = 0
97+
let mutable stop = false
98+
99+
while not stop do
100+
level <- level + 1
101+
102+
//Getting new frontier
103+
match spGeMM queue DeviceOnly matrix (ClMatrix.CSR front) with
104+
| None ->
105+
front.Dispose queue
106+
stop <- true
107+
| Some newFrontier ->
108+
front.Dispose queue
109+
//Filtering visited vertices
110+
match updateFrontAndLevels queue DeviceOnly levels newFrontier with
111+
| l, Some f ->
112+
front <- toCSRInPlace queue DeviceOnly f
113+
levels.Dispose queue
114+
levels <- l
115+
newFrontier.Dispose queue
116+
| _, None ->
117+
stop <- true
118+
newFrontier.Dispose queue
119+
120+
levels
121+
122+
let runSingleSourceMultipleTimes<'a when 'a: struct>
123+
(add: Expr<int option -> int option -> int option>)
124+
(mul: Expr<'a option -> int option -> int option>)
125+
(clContext: ClContext)
126+
workGroupSize
127+
=
128+
129+
let SSBFS = BFS.singleSourceSparse add mul clContext workGroupSize
130+
131+
fun (queue: MailboxProcessor<Msg>) (matrix: ClMatrix<'a>) (source: int list) ->
132+
source
133+
|> List.map (SSBFS queue matrix)
134+
135+
module Parents =
136+
let run = 0

src/GraphBLAS-sharp.Backend/Common/ClArray.fs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,37 @@ module ClArray =
121121

122122
outputArray
123123

124+
/// <summary>
125+
/// Copies all elements from source to destination array.
126+
/// </summary>
127+
/// <param name="clContext">OpenCL context.</param>
128+
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
129+
let copyTo (clContext: ClContext) workGroupSize =
130+
let copy =
131+
<@ fun (ndRange: Range1D) (source: ClArray<'a>) (destination: ClArray<'a>) inputArrayLength ->
132+
133+
let i = ndRange.GlobalID0
134+
135+
if i < inputArrayLength then
136+
source.[i] <- destination.[i] @>
137+
138+
let program = clContext.Compile(copy)
139+
140+
fun (processor: MailboxProcessor<_>) (source: ClArray<'a>) (destination: ClArray<'a>) ->
141+
if source.Length <> destination.Length then
142+
failwith "The source array length differs from the destination array length."
143+
144+
let ndRange =
145+
Range1D.CreateValid(source.Length, workGroupSize)
146+
147+
let kernel = program.GetKernel()
148+
149+
processor.Post(
150+
Msg.MsgSetArguments(fun () -> kernel.KernelFunc ndRange source destination source.Length)
151+
)
152+
153+
processor.Post(Msg.CreateRunMsg<_, _> kernel)
154+
124155
/// <summary>
125156
/// Creates an array of the given size by replicating the values of the given initial array.
126157
/// </summary>
@@ -781,3 +812,83 @@ module ClArray =
781812
bitmap.Free processor
782813

783814
result
815+
816+
/// <summary>
817+
/// Builds a new array whose elements are the results of applying the given function
818+
/// to each of the elements of the array.
819+
/// </summary>
820+
/// <param name="op">The function to transform elements of the array.</param>
821+
/// <param name="clContext">OpenCL context.</param>
822+
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
823+
let map<'a, 'b> (op: Expr<'a -> 'b>) (clContext: ClContext) workGroupSize = Map.map op clContext workGroupSize
824+
825+
/// <summary>
826+
/// Builds a new array whose elements are the results of applying the given function
827+
/// to each of the elements of the array.
828+
/// </summary>
829+
/// <param name="op">The function to transform elements of the array.</param>
830+
/// <param name="clContext">OpenCL context.</param>
831+
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
832+
let mapInPlace<'a> (op: Expr<'a -> 'a>) (clContext: ClContext) workGroupSize = Map.mapInPlace op clContext workGroupSize
833+
834+
/// <summary>
835+
/// Builds a new array whose elements are the results of applying the given function
836+
/// to the corresponding pairs of values, where the first element of pair is from the given array
837+
/// and the second element is the given value.
838+
/// </summary>
839+
/// <param name="op">The function to transform elements of the array.</param>
840+
/// <param name="clContext">OpenCL context.</param>
841+
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
842+
let mapWithValue<'a, 'b, 'c> (clContext: ClContext) workGroupSize (op: Expr<'a -> 'b -> 'c>) = Map.mapWithValue clContext workGroupSize op
843+
844+
/// <summary>
845+
/// Builds a new array whose elements are the results of applying the given function
846+
/// to the corresponding elements of the two given arrays pairwise.
847+
/// </summary>
848+
/// <remarks>
849+
/// The two input arrays must have the same lengths.
850+
/// </remarks>
851+
/// <param name="map">The function to transform the pairs of the input elements.</param>
852+
/// <param name="clContext">OpenCL context.</param>
853+
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
854+
let map2<'a, 'b, 'c> (map: Expr<'a -> 'b -> 'c>) (clContext: ClContext) workGroupSize = Map.map2 map clContext workGroupSize
855+
856+
/// <summary>
857+
/// Fills the third given array with the results of applying the given function
858+
/// to the corresponding elements of the first two given arrays pairwise.
859+
/// </summary>
860+
/// <remarks>
861+
/// The first two input arrays must have the same lengths.
862+
/// </remarks>
863+
/// <param name="map">The function to transform the pairs of the input elements.</param>
864+
/// <param name="clContext">OpenCL context.</param>
865+
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
866+
let map2InPlace<'a, 'b, 'c> (map: Expr<'a -> 'b -> 'c>) (clContext: ClContext) workGroupSize = Map.map2InPlace map clContext workGroupSize
867+
868+
/// <summary>
869+
/// Excludes elements, pointed by the bitmap.
870+
/// </summary>
871+
/// <param name="clContext">OpenCL context.</param>
872+
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
873+
let excludeElements (clContext: ClContext) workGroupSize =
874+
875+
let invert = mapInPlace ArithmeticOperations.intNotQ clContext workGroupSize
876+
877+
let prefixSum = PrefixSum.standardExcludeInPlace clContext workGroupSize
878+
879+
let scatter = Scatter.lastOccurrence clContext workGroupSize
880+
881+
fun (queue: MailboxProcessor<_>) allocationMode (excludeBitmap: ClArray<int>) (inputArray: ClArray<'a>) ->
882+
883+
invert queue excludeBitmap
884+
885+
let length = (prefixSum queue excludeBitmap).ToHostAndFree queue
886+
887+
if length = 0 then
888+
None
889+
else
890+
let result = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, length)
891+
892+
scatter queue excludeBitmap inputArray result
893+
894+
Some result

src/GraphBLAS-sharp.Backend/Common/Map.fs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,36 @@ module Map =
4040

4141
result
4242

43+
/// <summary>
44+
/// Changes elements of the input array, applying the given function
45+
/// to each element of the array.
46+
/// </summary>
47+
/// <param name="op">The function to transform elements of the array.</param>
48+
/// <param name="clContext">OpenCL context.</param>
49+
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
50+
let mapInPlace<'a> (op: Expr<'a -> 'a>) (clContext: ClContext) workGroupSize =
51+
52+
let map =
53+
<@ fun (ndRange: Range1D) lenght (inputArray: ClArray<'a>) ->
54+
55+
let gid = ndRange.GlobalID0
56+
57+
if gid < lenght then
58+
inputArray.[gid] <- (%op) inputArray.[gid] @>
59+
60+
let kernel = clContext.Compile map
61+
62+
fun (processor: MailboxProcessor<_>) (inputArray: ClArray<'a>) ->
63+
64+
let ndRange =
65+
Range1D.CreateValid(inputArray.Length, workGroupSize)
66+
67+
let kernel = kernel.GetKernel()
68+
69+
processor.Post(Msg.MsgSetArguments(fun () -> kernel.KernelFunc ndRange inputArray.Length inputArray))
70+
71+
processor.Post(Msg.CreateRunMsg<_, _>(kernel))
72+
4373
/// <summary>
4474
/// Builds a new array whose elements are the results of applying the given function
4575
/// to the corresponding pairs of values, where the first element of pair is from the given array

src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
<Compile Include="Operations/Operations.fs" />
7070

7171
<Compile Include="Algorithms/BFS.fs" />
72+
<Compile Include="Algorithms/MSBFS.fs" />
7273
<Compile Include="Algorithms/SSSP.fs" />
7374
<Compile Include="Algorithms/PageRank.fs" />
7475
<Compile Include="Algorithms/Algorithms.fs" />

src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
namespace GraphBLAS.FSharp.Backend.Matrix.COO
22

33
open Brahma.FSharp
4-
open GraphBLAS.FSharp
54
open GraphBLAS.FSharp.Objects
65
open GraphBLAS.FSharp.Backend.Quotes
76
open GraphBLAS.FSharp.Objects.ClContextExtensions
87

98
module internal Intersect =
10-
let findIntersectionByKeys (clContext: ClContext) workGroupSize =
9+
let findKeysIntersection (clContext: ClContext) workGroupSize =
1110

1211
let findIntersection =
1312
<@ fun (ndRange: Range1D) (leftNNZ: int) (rightNNZ: int) (leftRows: ClArray<int>) (leftColumns: ClArray<int>) (rightRows: ClArray<int>) (rightColumns: ClArray<int>) (bitmap: ClArray<int>) ->
@@ -17,15 +16,9 @@ module internal Intersect =
1716

1817
if gid < bitmapSize then
1918

20-
let row, column, rows, columns =
21-
if rightNNZ >= leftNNZ then
22-
leftRows.[gid], leftColumns.[gid], leftRows, leftColumns
23-
else
24-
rightRows.[gid], rightColumns.[gid], rightRows, rightColumns
19+
let index: uint64 = ((uint64 leftRows.[gid]) <<< 32) ||| (uint64 leftColumns.[gid])
2520

26-
let index: uint64 = ((uint64 row) <<< 32) ||| (uint64 column)
27-
28-
let intersect = (%Search.Bin.existsByKey2D) bitmapSize index rows columns
21+
let intersect = (%Search.Bin.existsByKey2D) bitmapSize index rightRows rightColumns
2922

3023
if intersect then
3124
bitmap.[gid] <- 1
@@ -37,7 +30,7 @@ module internal Intersect =
3730

3831
fun (processor: MailboxProcessor<_>) allocationMode (leftMatrix: ClMatrix.COO<'a>) (rightMatrix: ClMatrix.COO<'b>) ->
3932

40-
let bitmapSize = min leftMatrix.NNZ rightMatrix.NNZ
33+
let bitmapSize = leftMatrix.NNZ
4134

4235
let bitmap = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, bitmapSize)
4336

src/GraphBLAS-sharp.Backend/Matrix/COO/Map.fs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
namespace GraphBLAS.FSharp.Backend.Matrix.COO
22

3-
open System
43
open Brahma.FSharp
54
open GraphBLAS.FSharp.Backend.Matrix
65
open GraphBLAS.FSharp.Backend.Quotes

src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ open GraphBLAS.FSharp.Objects
88
open GraphBLAS.FSharp.Objects.ClMatrix
99
open GraphBLAS.FSharp.Objects.ClCellExtensions
1010
open GraphBLAS.FSharp.Objects.ArraysExtensions
11+
open GraphBLAS.FSharp.Objects.ClContextExtensions
1112

1213
module Matrix =
1314
/// <summary>
@@ -218,10 +219,35 @@ module Matrix =
218219
|> transposeInPlace queue
219220

220221
/// <summary>
221-
/// Build a bitmap. Maps non-zero elements of the matrix with minimum nnz to 1
222-
/// if the second matrix has non zero element under the same row and column pair, otherwise 0.
222+
/// Builds a bitmap. Maps non-zero elements of the left matrix
223+
/// to 1 if the right matrix has non zero element under the same row and column pair, otherwise 0.
223224
/// </summary>
224225
/// <param name="clContext">OpenCL context.</param>
225226
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
226227
let findIntersectionByKeys (clContext: ClContext) workGroupSize =
227-
Intersect.findIntersectionByKeys clContext workGroupSize
228+
Intersect.findKeysIntersection clContext workGroupSize
229+
230+
/// <summary>
231+
/// Merges two disjoint matrices of the same size.
232+
/// </summary>
233+
/// <remarks>
234+
/// Matrices should have the same number of rows and columns. <br/>
235+
/// Matrices should not have non zero values with the same index.
236+
/// </remarks>
237+
/// <param name="clContext">OpenCL context.</param>
238+
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
239+
let mergeDisjoint (clContext: ClContext) workGroupSize = Merge.runDisjoint clContext workGroupSize
240+
241+
let ofList (clContext: ClContext) allocationMode rowCount columnCount (elements: (int * int * 'a) list) =
242+
let rows, columns, values =
243+
elements
244+
|> Array.ofList
245+
|> Array.sortBy (fun (x, _, _) -> x)
246+
|> Array.unzip3
247+
248+
{ Context = clContext
249+
Rows = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, rows)
250+
Columns = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, columns)
251+
Values = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, values)
252+
RowCount = rowCount
253+
ColumnCount = columnCount }

0 commit comments

Comments
 (0)