Skip to content

Commit fd5b518

Browse files
committed
Added the same algorithm for sparse vector
1 parent 951c192 commit fd5b518

6 files changed

Lines changed: 272 additions & 193 deletions

File tree

src/App/Program.fs

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,49 @@ let main argv =
2121
let m = n - 1
2222
m - m % workGroupSize + workGroupSize
2323

24-
let mutable oclContext = OpenCLEvaluationContext("Intel*", DeviceType.Gpu)
25-
// let mutable oclContext = OpenCLEvaluationContext("NVIDIA*")
24+
// let mutable oclContext = OpenCLEvaluationContext("Intel*", DeviceType.Gpu)
25+
let mutable oclContext = OpenCLEvaluationContext("NVIDIA*")
2626

27-
// let leftMatrix = COOMatrix(100, 100, [|0;1;2;3;4;7|], [|1;7;5;6;0;1|], [|1.;2.;-4.;4.;5.;6.|])
28-
// let rightMatrix = COOMatrix(100, 100, [|0;0;1;2;3;4;7|], [|1;5;4;5;7;0;1|], [|1.;2.;-4.;4.;5.;6.;7.|])
29-
// let leftMatrix = COOMatrix(100, 100, [|0;0|], [|0;1|], [|true;true|])
30-
// let rightMatrix = COOMatrix(100, 100, [|0;1|], [|0;0|], [|true;true|])
31-
let leftMatrix = COOMatrix(300, 300, Array.init 500 (fun i -> 10 + i / 300), Array.init 500 (fun i -> i % 300), Array.create 500 true)
32-
let rightMatrix = COOMatrix(300, 300, Array.init 600 (fun i -> i / 300), Array.init 600 (fun i -> i % 300), Array.create 600 true)
27+
28+
let leftVector = SparseVector(100, [|4;10;11|], [|2.;9.;8.|])
29+
let rightVector = SparseVector(100, [|0;1;2;3;4;5|], [|5.;4.;3.;2.;1.;0.|])
3330

3431
let workflow =
3532
opencl {
36-
let! resultMatrix = leftMatrix.EWiseAdd rightMatrix None BooleanSemiring.anyAll//FloatSemiring.addMult
37-
let! tuples = resultMatrix.GetTuples()
38-
return! tuples.ToHost()
39-
//return! resultMatrix.ToHost()
33+
let! resultVector = leftVector.EWiseAdd rightVector None FloatSemiring.addMult
34+
return! resultVector.ToHost()
4035
}
4136

42-
// let resultMatrix : COOMatrix<float> = downcast oclContext.RunSync workflow
43-
// printfn "%O" resultMatrix
4437
let res = oclContext.RunSync workflow
38+
printfn "%A" res
39+
40+
41+
42+
// // let leftMatrix = COOMatrix(100, 100, [|0;1;2;3;4;7|], [|1;7;5;6;0;1|], [|1.;2.;-4.;4.;5.;6.|])
43+
// // let rightMatrix = COOMatrix(100, 100, [|0;0;1;2;3;4;7|], [|1;5;4;5;7;0;1|], [|1.;2.;-4.;4.;5.;6.;7.|])
44+
// // let leftMatrix = COOMatrix(100, 100, [|0;0|], [|0;1|], [|true;true|])
45+
// // let rightMatrix = COOMatrix(100, 100, [|0;1|], [|0;0|], [|true;true|])
46+
// let leftMatrix = COOMatrix(300, 300, Array.init 500 (fun i -> 10 + i / 300), Array.init 500 (fun i -> i % 300), Array.create 500 true)
47+
// let rightMatrix = COOMatrix(300, 300, Array.init 600 (fun i -> i / 300), Array.init 600 (fun i -> i % 300), Array.create 600 true)
48+
49+
// let workflow =
50+
// opencl {
51+
// let! resultMatrix = leftMatrix.EWiseAdd rightMatrix None BooleanSemiring.anyAll//FloatSemiring.addMult
52+
// let! tuples = resultMatrix.GetTuples()
53+
// return! tuples.ToHost()
54+
// //return! resultMatrix.ToHost()
55+
// }
56+
57+
// // let resultMatrix : COOMatrix<float> = downcast oclContext.RunSync workflow
58+
// // printfn "%O" resultMatrix
59+
// let res = oclContext.RunSync workflow
4560

46-
for i in 0 .. res.Values.Length - 1 do
47-
printf "(%A, %A, %A); " res.RowIndices.[i] res.ColumnIndices.[i] res.Values.[i]
61+
// for i in 0 .. res.Values.Length - 1 do
62+
// printf "(%A, %A, %A); " res.RowIndices.[i] res.ColumnIndices.[i] res.Values.[i]
4863

49-
// printfn "%A" res.RowIndices
50-
// printfn "%A" res.ColumnIndices
51-
// printfn "%A" res.Values
64+
// // printfn "%A" res.RowIndices
65+
// // printfn "%A" res.ColumnIndices
66+
// // printfn "%A" res.Values
5267

5368

5469

src/GraphBLAS-sharp/Backend/EWiseAdd.fs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ open GraphBLAS.FSharp.Backend.Common
77

88
module internal EWiseAdd =
99
let cooNotEmpty (matrixLeft: COOFormat<'a>) (matrixRight: COOFormat<'a>) (mask: Mask2D option) (semiring: Semiring<'a>) : OpenCLEvaluation<COOFormat<'a>> = opencl {
10-
let! allRows, allColumns, allValues = Merge.run matrixLeft matrixRight mask
10+
let! allRows, allColumns, allValues = Merge.runM matrixLeft matrixRight mask
1111

1212
let (BinaryOp append) = semiring.PlusMonoid.Append
13-
let! rawPositions = PreparePositions.run allRows allColumns allValues append
13+
let! rawPositions = PreparePositions.runM allRows allColumns allValues append
1414

15-
let! resultRows, resultColumns, resultValues = SetPositions.run allRows allColumns allValues rawPositions
15+
let! resultRows, resultColumns, resultValues = SetPositions.runM allRows allColumns allValues rawPositions
1616

1717
return {
1818
RowCount = matrixLeft.RowCount
@@ -53,3 +53,29 @@ module internal EWiseAdd =
5353
}
5454
}
5555
else cooNotEmpty matrixLeft matrixRight mask semiring
56+
57+
let sparseNotEmpty (leftIndices: int[]) (leftValues: 'a[]) (rightIndices: int[]) (rightValues: 'a[]) (mask: Mask1D option) (semiring: Semiring<'a>) : OpenCLEvaluation<int[] * 'a[]> = opencl {
58+
let! allIndices, allValues = Merge.runV leftIndices leftValues rightIndices rightValues mask
59+
60+
let (BinaryOp append) = semiring.PlusMonoid.Append
61+
let! rawPositions = PreparePositions.runV allIndices allValues append
62+
63+
return! SetPositions.runV allIndices allValues rawPositions
64+
}
65+
66+
let sparse (leftIndices: int[]) (leftValues: 'a[]) (rightIndices: int[]) (rightValues: 'a[]) (mask: Mask1D option) (semiring: Semiring<'a>) : OpenCLEvaluation<int[] * 'a[]> =
67+
if leftValues.Length = 0 then
68+
opencl {
69+
let! resultIndices = Copy.run rightIndices
70+
let! resultValues = Copy.run rightValues
71+
72+
return resultIndices, resultValues
73+
}
74+
elif rightIndices.Length = 0 then
75+
opencl {
76+
let! resultIndices = Copy.run leftIndices
77+
let! resultValues = Copy.run leftValues
78+
79+
return resultIndices, resultValues
80+
}
81+
else sparseNotEmpty leftIndices leftValues rightIndices rightValues mask semiring

src/GraphBLAS-sharp/Backend/Merge.fs

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ open GraphBLAS.FSharp
77
open GraphBLAS.FSharp.Backend.Common
88

99
module internal Merge =
10-
let run (matrixLeft: COOFormat<'a>) (matrixRight: COOFormat<'a>) (mask: Mask2D option) : OpenCLEvaluation<int[] * int[] * 'a[]> = opencl {
10+
let runM (matrixLeft: COOFormat<'a>) (matrixRight: COOFormat<'a>) (mask: Mask2D option) : OpenCLEvaluation<int[] * int[] * 'a[]> = opencl {
1111
let workGroupSize = Utils.workGroupSize
1212
let firstSide = matrixLeft.Values.Length
1313
let secondSide = matrixRight.Values.Length
@@ -125,3 +125,113 @@ module internal Merge =
125125

126126
return allRows, allColumns, allValues
127127
}
128+
129+
let runV (leftIndices: int[]) (leftValues: 'a[]) (rightIndices: int[]) (rightValues: 'a[]) (mask: Mask1D option) : OpenCLEvaluation<int[] * 'a[]> = opencl {
130+
let workGroupSize = Utils.workGroupSize
131+
let firstSide = leftValues.Length
132+
let secondSide = rightValues.Length
133+
let sumOfSides = firstSide + secondSide
134+
135+
let merge =
136+
<@
137+
fun (ndRange: _1D)
138+
(firstIndicesBuffer: int[])
139+
(firstValuesBuffer: 'a[])
140+
(secondIndicesBuffer: int[])
141+
(secondValuesBuffer: 'a[])
142+
(allIndicesBuffer: int[])
143+
(allValuesBuffer: 'a[]) ->
144+
145+
let i = ndRange.GlobalID0
146+
147+
let mutable beginIdxLocal = local ()
148+
let mutable endIdxLocal = local ()
149+
let localID = ndRange.LocalID0
150+
if localID < 2 then
151+
let mutable x = localID * (workGroupSize - 1) + i - 1
152+
if x >= sumOfSides then x <- sumOfSides - 1
153+
let diagonalNumber = x
154+
155+
let mutable leftEdge = diagonalNumber + 1 - secondSide
156+
if leftEdge < 0 then leftEdge <- 0
157+
158+
let mutable rightEdge = firstSide - 1
159+
if rightEdge > diagonalNumber then rightEdge <- diagonalNumber
160+
161+
while leftEdge <= rightEdge do
162+
let middleIdx = (leftEdge + rightEdge) / 2
163+
let firstIndex = firstIndicesBuffer.[middleIdx]
164+
let secondIndex = secondIndicesBuffer.[diagonalNumber - middleIdx]
165+
if firstIndex < secondIndex then leftEdge <- middleIdx + 1 else rightEdge <- middleIdx - 1
166+
167+
// Here localID equals either 0 or 1
168+
if localID = 0 then beginIdxLocal <- leftEdge else endIdxLocal <- leftEdge
169+
barrier ()
170+
171+
let beginIdx = beginIdxLocal
172+
let endIdx = endIdxLocal
173+
let firstLocalLength = endIdx - beginIdx
174+
let mutable x = workGroupSize - firstLocalLength
175+
if endIdx = firstSide then x <- secondSide - i + localID + beginIdx
176+
let secondLocalLength = x
177+
178+
//First indices are from 0 to firstLocalLength - 1 inclusive
179+
//Second indices are from firstLocalLength to firstLocalLength + secondLocalLength - 1 inclusive
180+
let localIndices = localArray<int> workGroupSize
181+
182+
if localID < firstLocalLength then
183+
localIndices.[localID] <- firstIndicesBuffer.[beginIdx + localID]
184+
if localID < secondLocalLength then
185+
localIndices.[firstLocalLength + localID] <- secondIndicesBuffer.[i - beginIdx]
186+
barrier ()
187+
188+
if i < sumOfSides then
189+
let mutable leftEdge = localID + 1 - secondLocalLength
190+
if leftEdge < 0 then leftEdge <- 0
191+
192+
let mutable rightEdge = firstLocalLength - 1
193+
if rightEdge > localID then rightEdge <- localID
194+
195+
while leftEdge <= rightEdge do
196+
let middleIdx = (leftEdge + rightEdge) / 2
197+
let firstIndex = localIndices.[middleIdx]
198+
let secondIndex = localIndices.[firstLocalLength + localID - middleIdx]
199+
if firstIndex < secondIndex then leftEdge <- middleIdx + 1 else rightEdge <- middleIdx - 1
200+
201+
let boundaryX = rightEdge
202+
let boundaryY = localID - leftEdge
203+
204+
// boundaryX and boundaryY can't be off the right edge of array (only off the left edge)
205+
let isValidX = boundaryX >= 0
206+
let isValidY = boundaryY >= 0
207+
208+
let mutable fstIdx = 0
209+
if isValidX then fstIdx <- localIndices.[boundaryX]
210+
211+
let mutable sndIdx = 0
212+
if isValidY then sndIdx <- localIndices.[firstLocalLength + boundaryY]
213+
214+
if not isValidX || isValidY && fstIdx < sndIdx then
215+
allIndicesBuffer.[i] <- sndIdx
216+
allValuesBuffer.[i] <- secondValuesBuffer.[i - localID - beginIdx + boundaryY]
217+
else
218+
allIndicesBuffer.[i] <- fstIdx
219+
allValuesBuffer.[i] <- firstValuesBuffer.[beginIdx + boundaryX]
220+
@>
221+
222+
let allIndices = Array.zeroCreate sumOfSides
223+
let allValues = Array.create sumOfSides Unchecked.defaultof<'a>
224+
225+
do! RunCommand merge <| fun kernelPrepare ->
226+
let ndRange = _1D(Utils.workSize sumOfSides, workGroupSize)
227+
kernelPrepare
228+
ndRange
229+
leftIndices
230+
leftValues
231+
rightIndices
232+
rightValues
233+
allIndices
234+
allValues
235+
236+
return allIndices, allValues
237+
}

src/GraphBLAS-sharp/Backend/PreparePositions.fs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ open GraphBLAS.FSharp.Backend.Common
77
open Microsoft.FSharp.Quotations
88

99
module internal PreparePositions =
10-
let run (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (plus: Expr<'a -> 'a -> 'a>) : OpenCLEvaluation<int[]> = opencl {
10+
let runM (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (plus: Expr<'a -> 'a -> 'a>) : OpenCLEvaluation<int[]> = opencl {
1111
let length = allValues.Length
1212

1313
let preparePositions =
@@ -44,3 +44,39 @@ module internal PreparePositions =
4444

4545
return rawPositions
4646
}
47+
48+
let runV (allIndices: int[]) (allValues: 'a[]) (plus: Expr<'a -> 'a -> 'a>) : OpenCLEvaluation<int[]> = opencl {
49+
let length = allValues.Length
50+
51+
let preparePositions =
52+
<@
53+
fun (ndRange: _1D)
54+
(allIndicesBuffer: int[])
55+
(allValuesBuffer: 'a[])
56+
(rawPositionsBuffer: int[]) ->
57+
58+
let i = ndRange.GlobalID0
59+
60+
if i < length - 1 && allIndicesBuffer.[i] = allIndicesBuffer.[i + 1] then
61+
rawPositionsBuffer.[i] <- 0
62+
63+
//Do not drop explicit zeroes
64+
allValuesBuffer.[i + 1] <- (%plus) allValuesBuffer.[i] allValuesBuffer.[i + 1]
65+
66+
//Drop explicit zeroes
67+
// let localResultBuffer = (%plus) allValuesBuffer.[i] allValuesBuffer.[i + 1]
68+
// if localResultBuffer = zero then rawPositionsBuffer.[i + 1] <- 0 else allValuesBuffer.[i + 1] <- localResultBuffer
69+
@>
70+
71+
let rawPositions = Array.create length 1
72+
73+
do! RunCommand preparePositions <| fun kernelPrepare ->
74+
let ndRange = _1D(Utils.workSize (length - 1), Utils.workGroupSize)
75+
kernelPrepare
76+
ndRange
77+
allIndices
78+
allValues
79+
rawPositions
80+
81+
return rawPositions
82+
}

src/GraphBLAS-sharp/Backend/SetPositions.fs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation
66
open GraphBLAS.FSharp.Backend.Common
77

88
module internal SetPositions =
9-
let run (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (positions: int[]) : OpenCLEvaluation<int[] * int[] * 'a[]> = opencl {
9+
let runM (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (positions: int[]) : OpenCLEvaluation<int[] * int[] * 'a[]> = opencl {
1010
let prefixSumArrayLength = positions.Length
1111

1212
let setPositions =
@@ -54,3 +54,46 @@ module internal SetPositions =
5454

5555
return resultRows, resultColumns, resultValues
5656
}
57+
58+
let runV (allIndices: int[]) (allValues: 'a[]) (positions: int[]) : OpenCLEvaluation<int[] * 'a[]> = opencl {
59+
let prefixSumArrayLength = positions.Length
60+
61+
let setPositions =
62+
<@
63+
fun (ndRange: _1D)
64+
(allIndicesBuffer: int[])
65+
(allValuesBuffer: 'a[])
66+
(prefixSumArrayBuffer: int[])
67+
(resultIndicesBuffer: int[])
68+
(resultValuesBuffer: 'a[]) ->
69+
70+
let i = ndRange.GlobalID0
71+
72+
if i = prefixSumArrayLength - 1 || i < prefixSumArrayLength && prefixSumArrayBuffer.[i] <> prefixSumArrayBuffer.[i + 1] then
73+
let index = prefixSumArrayBuffer.[i]
74+
75+
resultIndicesBuffer.[index] <- allIndicesBuffer.[i]
76+
resultValuesBuffer.[index] <- allValuesBuffer.[i]
77+
@>
78+
79+
let resultLength = Array.zeroCreate 1
80+
81+
do! PrefixSum.run positions resultLength
82+
let! _ = ToHost resultLength
83+
let resultLength = resultLength.[0]
84+
85+
let resultIndices = Array.zeroCreate resultLength
86+
let resultValues = Array.create resultLength Unchecked.defaultof<'a>
87+
88+
do! RunCommand setPositions <| fun kernelPrepare ->
89+
let ndRange = _1D(Utils.workSize positions.Length, Utils.workGroupSize)
90+
kernelPrepare
91+
ndRange
92+
allIndices
93+
allValues
94+
positions
95+
resultIndices
96+
resultValues
97+
98+
return resultIndices, resultValues
99+
}

0 commit comments

Comments
 (0)