@@ -2,6 +2,7 @@ module GraphBLAS.FSharp.Tests.Backend.Common.Reduce.ByKey
22
33open Expecto
44open GraphBLAS.FSharp .Backend .Common
5+ open GraphBLAS.FSharp .Backend .Quotes
56open GraphBLAS.FSharp .Test
67open GraphBLAS.FSharp .Tests
78open GraphBLAS.FSharp .Backend .Objects .ClContext
@@ -14,6 +15,16 @@ let processor = Context.defaultContext.Queue
1415
1516let config = Utils.defaultConfig
1617
18+ let getOffsets array =
19+ Array.map fst array
20+ |> HostPrimitives.getUniqueBitmapFirstOccurrence
21+ |> HostPrimitives.getBitPositions
22+
23+ let getOffsets2D array =
24+ Array.map ( fun ( fst , snd , _ ) -> fst, snd) array
25+ |> HostPrimitives.getUniqueBitmapFirstOccurrence
26+ |> HostPrimitives.getBitPositions
27+
1728let checkResult isEqual actualKeys actualValues keys values reduceOp =
1829
1930 let expectedKeys , expectedValues =
@@ -336,3 +347,87 @@ let sequentialSegmentTests2D =
336347 createTestSequentialSegments2D< bool> (=) (&&) <@ (&&) @> ]
337348
338349 testList " Sequential segments 2D" [ addTests; mulTests ]
350+
351+ let checkResult2DOption isEqual firstActualKeys secondActualKeys actualValues firstKeys secondKeys values reduceOp =
352+
353+ let reduceOp left right =
354+ match left, right with
355+ | Some left, Some right ->
356+ reduceOp left right
357+ | Some value, None
358+ | None, Some value -> Some value
359+ | _ -> None
360+
361+ let expectedFirstKeys , expectedSecondKeys , expectedValues =
362+ let keys = Array.zip firstKeys secondKeys
363+
364+ Array.zip keys values
365+ |> Array.groupBy fst
366+ |> Array.map ( fun ( key , array ) -> key, Array.map snd array)
367+ |> Array.map ( fun ( key , array ) ->
368+ Array.map Some array
369+ |> Array.reduce reduceOp
370+ |> fun result -> key, result)
371+ |> Array.choose ( fun (( fstKey , sndKey ), value ) ->
372+ match value with
373+ | Some value -> Some ( fstKey, sndKey, value)
374+ | _ -> None )
375+ |> Array.unzip3
376+
377+ " First keys must be the same"
378+ |> Utils.compareArrays (=) firstActualKeys expectedFirstKeys
379+
380+ " Second keys must be the same"
381+ |> Utils.compareArrays (=) secondActualKeys expectedSecondKeys
382+
383+ " Values must the same"
384+ |> Utils.compareArrays isEqual actualValues expectedValues
385+
386+ let test2DOption < 'a > isEqual reduce reduceOp ( array : ( int * int * 'a ) []) =
387+ if array.Length > 0 then
388+ let array = Array.sortBy ( fun ( fst , snd , _ ) -> fst, snd) array
389+
390+ let offsets = getOffsets2D array
391+
392+ let firstKeys , secondKeys , values = Array.unzip3 array
393+
394+ let clOffsets =
395+ context.CreateClArrayWithSpecificAllocationMode( HostInterop, offsets)
396+
397+ let clFirstKeys =
398+ context.CreateClArrayWithSpecificAllocationMode( DeviceOnly, firstKeys)
399+
400+ let clSecondKeys =
401+ context.CreateClArrayWithSpecificAllocationMode( DeviceOnly, secondKeys)
402+
403+ let clValues =
404+ context.CreateClArrayWithSpecificAllocationMode( DeviceOnly, values)
405+
406+ let clFirstActualKeys , clSecondActualKeys , clReducedValues : ClArray < int > * ClArray < int > * ClArray < 'a > =
407+ reduce processor DeviceOnly offsets.Length clOffsets clFirstKeys clSecondKeys clValues
408+
409+ let reducedFirsKeys = clFirstActualKeys.ToHostAndFree processor
410+ let reducesSecondKeys = clSecondActualKeys.ToHostAndFree processor
411+ let reducedValues = clReducedValues.ToHostAndFree processor
412+
413+ checkResult2DOption isEqual reducedFirsKeys reducesSecondKeys reducedValues firstKeys secondKeys values reduceOp
414+
415+ let createTest2DOption ( isEqual : 'a -> 'a -> bool ) ( reduceOpQ , reduceOp ) =
416+ let reduce =
417+ Reduce.ByKey2D.segmentSequentialOption context Utils.defaultWorkGroupSize reduceOpQ
418+
419+ test2DOption< 'a> isEqual reduce reduceOp
420+ |> testPropertyWithConfig { config with arbitrary = [ typeof< Generators.ArrayOfDistinctKeys> ] } $" test on {typeof<'a>}"
421+
422+ let testsByKey2DSegmentsSequential =
423+ [ createTest2DOption (=) ArithmeticOperations.intAdd
424+
425+ if Utils.isFloat64Available context.ClDevice then
426+ createTest2DOption Utils.floatIsEqual ArithmeticOperations.floatAdd
427+
428+ createTest2DOption Utils.float32IsEqual ArithmeticOperations.float32Add
429+ createTest2DOption (=) ArithmeticOperations.boolAdd ]
430+ |> testList " 2D option"
431+
432+
433+
0 commit comments