Skip to content

Commit 050df59

Browse files
committed
toSparse unsorted and tests
1 parent fc0acd1 commit 050df59

File tree

4 files changed

+107
-6
lines changed

4 files changed

+107
-6
lines changed

src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs

+2-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ module internal BFS =
148148
let fillSubVectorInPlace =
149149
Vector.assignByMaskInPlace (Mask.assign) clContext workGroupSize
150150

151-
let toSparse = Vector.toSparse clContext workGroupSize
151+
let toSparse =
152+
Vector.toSparseUnsorted clContext workGroupSize
152153

153154
let toDense = Vector.toDense clContext workGroupSize
154155

src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs

+56
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,63 @@ module Vector =
140140

141141
valueCell.Free()
142142

143+
// TODO: toSparseUnsorted + bitonic probably would work faster
143144
let toSparse<'a when 'a: struct> (clContext: ClContext) workGroupSize =
145+
let scatterValues =
146+
Common.Scatter.lastOccurrence clContext workGroupSize
147+
148+
let scatterIndices =
149+
Common.Scatter.lastOccurrence clContext workGroupSize
150+
151+
let getBitmap =
152+
Map.map (Map.option 1 0) clContext workGroupSize
153+
154+
let prefixSum =
155+
Common.PrefixSum.standardExcludeInPlace clContext workGroupSize
156+
157+
let allIndices =
158+
ClArray.init Map.id clContext workGroupSize
159+
160+
let allValues =
161+
Map.map (Map.optionToValueOrZero Unchecked.defaultof<'a>) clContext workGroupSize
162+
163+
fun (processor: RawCommandQueue) allocationMode (vector: ClArray<'a option>) ->
164+
165+
let positions = getBitmap processor DeviceOnly vector
166+
167+
let resultLength =
168+
(prefixSum processor positions)
169+
.ToHostAndFree(processor)
170+
171+
// compute result indices
172+
let resultIndices =
173+
clContext.CreateClArrayWithSpecificAllocationMode<int>(allocationMode, resultLength)
174+
175+
let allIndices =
176+
allIndices processor DeviceOnly vector.Length
177+
178+
scatterIndices processor positions allIndices resultIndices
179+
180+
allIndices.Free()
181+
182+
// compute result values
183+
let resultValues =
184+
clContext.CreateClArrayWithSpecificAllocationMode<'a>(allocationMode, resultLength)
185+
186+
let allValues = allValues processor DeviceOnly vector
187+
188+
scatterValues processor positions allValues resultValues
189+
190+
allValues.Free()
191+
192+
positions.Free()
193+
194+
{ Context = clContext
195+
Indices = resultIndices
196+
Values = resultValues
197+
Size = vector.Length }
198+
199+
let toSparseUnsorted<'a when 'a: struct> (clContext: ClContext) workGroupSize =
144200

145201
let kernel =
146202
<@ fun (ndRange: Range1D) (inputLength: int) (inputValues: ClArray<'a option>) (resultSize: ClCell<int>) (resultIndices: ClArray<int>) (resultValues: ClArray<'a>) ->

src/GraphBLAS-sharp.Backend/Vector/Vector.fs

+20
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,26 @@ module Vector =
129129
<| toSparse processor allocationMode vector
130130
| ClVector.Sparse _ -> copy processor allocationMode vector
131131

132+
/// <summary>
133+
/// Sparsifies the given vector if it is in a dense format.
134+
/// If the given vector is already sparse, copies it.
135+
/// Works faster than regular version, but indices of the sparse vector are unsorted.
136+
/// </summary>
137+
/// <param name="clContext">OpenCL context.</param>
138+
/// <param name="workGroupSize">Should be a power of 2 and greater than 1.</param>
139+
let toSparseUnsorted (clContext: ClContext) workGroupSize =
140+
let toSparse =
141+
Dense.Vector.toSparseUnsorted clContext workGroupSize
142+
143+
let copy = copy clContext workGroupSize
144+
145+
fun (processor: RawCommandQueue) allocationMode (vector: ClVector<'a>) ->
146+
match vector with
147+
| ClVector.Dense vector ->
148+
ClVector.Sparse
149+
<| toSparse processor allocationMode vector
150+
| ClVector.Sparse _ -> copy processor allocationMode vector
151+
132152
/// <summary>
133153
/// Densifies the given vector if it is in a sparse format.
134154
/// If the given vector is already dense, copies it.

tests/GraphBLAS-sharp.Tests/Backend/Vector/Convert.fs

+29-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ let wgSize = Constants.Common.defaultWorkGroupSize
2222
let makeTest
2323
formatFrom
2424
(convertFun: RawCommandQueue -> AllocationFlag -> ClVector<'a> -> ClVector<'a>)
25+
(convertFunUnsorted: option<RawCommandQueue -> AllocationFlag -> ClVector<'a> -> ClVector<'a>>)
2526
isZero
2627
case
2728
(array: 'a [])
@@ -37,7 +38,7 @@ let makeTest
3738

3839
let actual =
3940
let clVector = vector.ToDevice context
40-
let convertedVector = convertFun q HostInterop clVector
41+
let convertedVector = convertFun q DeviceOnly clVector
4142

4243
let res = convertedVector.ToHost q
4344

@@ -56,6 +57,27 @@ let makeTest
5657

5758
Expect.equal actual expected "Vectors must be the same"
5859

60+
match convertFunUnsorted with
61+
| None -> ()
62+
| Some convertFunUnsorted ->
63+
let clVector = vector.ToDevice context
64+
let convertedVector = convertFunUnsorted q DeviceOnly clVector
65+
66+
let res = convertedVector.ToHost q
67+
68+
match res, expected with
69+
| Vector.Sparse res, Vector.Sparse expected ->
70+
let iv = Array.zip res.Indices res.Values
71+
let resSorted = Array.sortBy (fun (i, v) -> i) iv
72+
let indices, values = Array.unzip resSorted
73+
Expect.equal indices expected.Indices "Indices must be the same"
74+
Expect.equal values expected.Values "Values must be the same"
75+
Expect.equal res.Size expected.Size "Size must be the same"
76+
| _ -> ()
77+
78+
clVector.Dispose()
79+
convertedVector.Dispose()
80+
5981
let testFixtures case =
6082
let getCorrectnessTestName datatype formatFrom =
6183
sprintf $"Correctness on %s{datatype}, %A{formatFrom} -> %A{case.Format}"
@@ -68,19 +90,21 @@ let testFixtures case =
6890
match case.Format with
6991
| Sparse ->
7092
[ let convertFun = Vector.toSparse context wgSize
93+
let convertFunUnsorted = Vector.toSparseUnsorted context wgSize
7194

7295
Utils.listOfUnionCases<VectorFormat>
7396
|> List.map
7497
(fun formatFrom ->
75-
makeTest formatFrom convertFun ((=) 0) case
98+
makeTest formatFrom convertFun (Some convertFunUnsorted) ((=) 0) case
7699
|> testPropertyWithConfig config (getCorrectnessTestName "int" formatFrom))
77100

78101
let convertFun = Vector.toSparse context wgSize
102+
let convertFunUnsorted = Vector.toSparseUnsorted context wgSize
79103

80104
Utils.listOfUnionCases<VectorFormat>
81105
|> List.map
82106
(fun formatFrom ->
83-
makeTest formatFrom convertFun ((=) false) case
107+
makeTest formatFrom convertFun (Some convertFunUnsorted) ((=) false) case
84108
|> testPropertyWithConfig config (getCorrectnessTestName "bool" formatFrom)) ]
85109
|> List.concat
86110
| Dense ->
@@ -89,15 +113,15 @@ let testFixtures case =
89113
Utils.listOfUnionCases<VectorFormat>
90114
|> List.map
91115
(fun formatFrom ->
92-
makeTest formatFrom convertFun ((=) 0) case
116+
makeTest formatFrom convertFun None ((=) 0) case
93117
|> testPropertyWithConfig config (getCorrectnessTestName "int" formatFrom))
94118

95119
let convertFun = Vector.toDense context wgSize
96120

97121
Utils.listOfUnionCases<VectorFormat>
98122
|> List.map
99123
(fun formatFrom ->
100-
makeTest formatFrom convertFun ((=) false) case
124+
makeTest formatFrom convertFun None ((=) false) case
101125
|> testPropertyWithConfig config (getCorrectnessTestName "bool" formatFrom)) ]
102126
|> List.concat
103127

0 commit comments

Comments
 (0)