From 1cacb7917d86ab70197d523e7dc93283c5b8dad1 Mon Sep 17 00:00:00 2001 From: kirillgarbar Date: Thu, 5 Oct 2023 20:30:12 +0300 Subject: [PATCH 01/23] Set dataset folder to default --- benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs | 2 +- .../GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs index 376d30b2..7a3c1cf6 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs @@ -46,7 +46,7 @@ type Benchmarks<'elem when 'elem : struct>( static member AvailableContexts = Utils.availableContexts static member InputMatrixProviderBuilder pathToConfig = - let datasetFolder = "BFS" + let datasetFolder = "" pathToConfig |> Utils.getMatricesFilenames |> Seq.map diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt b/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt index 6161abd9..d71735c7 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt @@ -1 +1 @@ -BFSBenchmark \ No newline at end of file +BFSWithoutTransferBenchmark From da5cb5e8479f1a266bc266234bbb234fe92a306f Mon Sep 17 00:00:00 2001 From: kirillgarbar Date: Sun, 5 Nov 2023 18:00:33 +0300 Subject: [PATCH 02/23] Matrix loader memory optimization --- src/GraphBLAS-sharp/IO/MtxReader.fs | 72 ++++++++++++++++------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/src/GraphBLAS-sharp/IO/MtxReader.fs b/src/GraphBLAS-sharp/IO/MtxReader.fs index f25ce8c0..fc68be31 100644 --- a/src/GraphBLAS-sharp/IO/MtxReader.fs +++ b/src/GraphBLAS-sharp/IO/MtxReader.fs @@ -68,40 +68,46 @@ type MtxReader(pathToFile: string) = let sortedData = match this.Symmetry with | General -> - [ 0 .. nnz - 1 ] - |> List.map (fun _ -> streamReader.ReadLine().Split(' ')) - |> Array.ofList - |> Array.Parallel.map - (fun line -> - let i = int line.[0] - let j = int line.[1] - - let v = - converter - <| if line.Length > 2 then line.[2] else "" - - struct (pack i j, v)) - |> Array.sortBy (fun struct (packedIndex, _) -> packedIndex) + let result = + [| 0 .. nnz - 1 |] + |> Array.map + (fun _ -> + let line = streamReader.ReadLine().Split(' ') + + let i = int line.[0] + let j = int line.[1] + + let v = + converter + <| if line.Length > 2 then line.[2] else "" + + struct (pack i j, v)) + + Array.sortInPlaceBy (fun struct (packedIndex, _) -> packedIndex) result + result | Symmetric -> - [ 0 .. nnz - 1 ] - |> List.map (fun _ -> streamReader.ReadLine().Split(' ')) - |> Array.ofList - |> Array.Parallel.map - (fun line -> - let i = int line.[0] - let j = int line.[1] - - let v = - converter - <| if line.Length > 2 then line.[2] else "" - - if i = j then - [| struct (pack i j, v) |] - else - [| struct (pack i j, v) - struct (pack j i, v) |]) - |> Array.concat - |> Array.sortBy (fun struct (packedIndex, _) -> packedIndex) + let result = + [| 0 .. nnz - 1 |] + |> Array.map + (fun _ -> + let line = streamReader.ReadLine().Split(' ') + + let i = int line.[0] + let j = int line.[1] + + let v = + converter + <| if line.Length > 2 then line.[2] else "" + + if i = j then + [| struct (pack i j, v) |] + else + [| struct (pack i j, v) + struct (pack j i, v) |]) + |> Array.concat + + Array.sortInPlaceBy (fun struct (packedIndex, _) -> packedIndex) result + result | _ -> failwith <| sprintf "This symmetry processing is not implemented: %A" this.Symmetry From 4875a3cbf3db3e59b46af71a65e1918ab9a965e6 Mon Sep 17 00:00:00 2001 From: kirillgarbar Date: Sun, 5 Nov 2023 18:01:02 +0300 Subject: [PATCH 03/23] Correct context config --- benchmarks/GraphBLAS-sharp.Benchmarks/Configs/Context.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/Context.txt b/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/Context.txt index 04f1c08e..dc8e8842 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/Context.txt +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/Context.txt @@ -1,3 +1,3 @@ -NVIDIA* +AMD* Gpu -32 +64 From e6bae88db215e0afae15b6c464155597b7bb6932 Mon Sep 17 00:00:00 2001 From: kirillgarbar Date: Sun, 5 Nov 2023 18:10:00 +0300 Subject: [PATCH 04/23] Absolute path in bennchmark script --- .../GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt | 2 +- benchmarks/GraphBLAS-sharp.Benchmarks/Scripts/Benchmark.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt b/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt index 6161abd9..708032bc 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt @@ -1 +1 @@ -BFSBenchmark \ No newline at end of file +BFSWithoutTransfer diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Scripts/Benchmark.py b/benchmarks/GraphBLAS-sharp.Benchmarks/Scripts/Benchmark.py index d3bf7559..a67cdbe6 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Scripts/Benchmark.py +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Scripts/Benchmark.py @@ -7,8 +7,8 @@ from dataclasses import dataclass -ROOT = pathlib.Path(__file__).parent.parent.parent.parent -BENCHMARKS = pathlib.Path(__file__).parent.parent +ROOT = pathlib.Path(__file__).resolve().parent.parent.parent.parent +BENCHMARKS = pathlib.Path(__file__).resolve().parent.parent CONFIGS = BENCHMARKS / "Configs" BINARIES = BENCHMARKS / "bin" / "Release" / "net7.0" RESULTS = ROOT / "BenchmarkDotNet.Artifacts" / "results" From 12dd993096665909a79ffb3e1fb9c636c9118349 Mon Sep 17 00:00:00 2001 From: Kirill <71129570+kirillgarbar@users.noreply.github.com> Date: Mon, 6 Nov 2023 16:14:05 +0300 Subject: [PATCH 05/23] New file path for charts --- .github/workflows/build-and-benchmark.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-benchmark.yml b/.github/workflows/build-and-benchmark.yml index 2bde3398..d7225206 100644 --- a/.github/workflows/build-and-benchmark.yml +++ b/.github/workflows/build-and-benchmark.yml @@ -36,7 +36,7 @@ jobs: with: name: BFS tool: 'benchmarkdotnet' - output-file-path: BenchmarkDotNet.Artifacts/results/GraphBLAS.FSharp.Benchmarks.BFSWithoutTransferBenchmarkInt32-report-brief.json + output-file-path: BenchmarkDotNet.Artifacts/results/GraphBLAS.FSharp.Benchmarks.Algorithms.BFS.BFSWithoutTransferBenchmarkInt32-report-brief.json # Access token to deploy GitHub Pages branch github-token: ${{ secrets._GITHUB_TOKEN }} # Push and deploy GitHub pages branch automatically From 21992877295d27c914387146ab635e5da309ae6a Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Fri, 10 Nov 2023 18:15:08 +0300 Subject: [PATCH 06/23] add: matrix intersect --- .../GraphBLAS-sharp.Backend.fsproj | 1 + .../Matrix/COO/Intersect.fs | 64 +++++++++++++++++++ .../Matrix/COO/Matrix.fs | 13 +++- src/GraphBLAS-sharp.Backend/Quotes/Search.fs | 30 +++++++++ 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs diff --git a/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj b/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj index a4268b52..e46ea5d8 100644 --- a/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj +++ b/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj @@ -53,6 +53,7 @@ + diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs new file mode 100644 index 00000000..226384f0 --- /dev/null +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs @@ -0,0 +1,64 @@ +namespace GraphBLAS.FSharp.Backend.Matrix.COO + +open Brahma.FSharp +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Objects +open GraphBLAS.FSharp.Backend.Quotes +open GraphBLAS.FSharp.Objects.ClContextExtensions + +module internal Intersect = + let findIntersectionByKeys (clContext: ClContext) workGroupSize = + + let findIntersection = + <@ fun (ndRange: Range1D) (leftNNZ: int) (rightNNZ: int) (leftRows: ClArray) (leftColumns: ClArray) (rightRows: ClArray) (rightColumns: ClArray) (bitmap: ClArray) -> + + let gid = ndRange.GlobalID0 + let bitmapSize = min leftNNZ rightNNZ + + if gid < bitmapSize then + + let row, column, rows, columns = + if rightNNZ >= leftNNZ then + leftRows.[gid], leftColumns.[gid], leftRows, leftColumns + else + rightRows.[gid], rightColumns.[gid], rightRows, rightColumns + + let index: uint64 = ((uint64 row) <<< 32) ||| (uint64 column) + + let intersect = (%Search.Bin.existsByKey2D) bitmapSize index rows columns + + if intersect then + bitmap.[gid] <- 1 + else + bitmap.[gid] <- 0 @> + + let kernel = + clContext.Compile <| findIntersection + + fun (processor: MailboxProcessor<_>) allocationMode (leftMatrix: ClMatrix.COO<'a>) (rightMatrix: ClMatrix.COO<'b>) -> + + let bitmapSize = min leftMatrix.NNZ rightMatrix.NNZ + + let bitmap = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, bitmapSize) + + let ndRange = Range1D.CreateValid(bitmapSize, workGroupSize) + + let kernel = kernel.GetKernel() + + processor.Post( + Msg.MsgSetArguments + (fun () -> + kernel.KernelFunc + ndRange + leftMatrix.NNZ + rightMatrix.NNZ + leftMatrix.Rows + leftMatrix.Columns + rightMatrix.Rows + rightMatrix.Columns + bitmap) + ) + + processor.Post(Msg.CreateRunMsg<_, _> kernel) + + bitmap diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs index 327a1b45..b4960c1c 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs @@ -197,8 +197,8 @@ module Matrix = /// /// Transposes the given matrix and returns result as a new matrix. /// - ///OpenCL context. - ///Should be a power of 2 and greater than 1. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. let transpose (clContext: ClContext) workGroupSize = let transposeInPlace = transposeInPlace clContext workGroupSize @@ -216,3 +216,12 @@ module Matrix = Columns = copy queue allocationMode matrix.Columns Values = copyData queue allocationMode matrix.Values } |> transposeInPlace queue + + /// + /// Build a bitmap. Maps non-zero elements of the matrix with minimum nnz to 1 + /// if the second matrix has non zero element under the same row and column pair, otherwise 0. + /// + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let findIntersectionByKeys (clContext: ClContext) workGroupSize = + Intersect.findIntersectionByKeys clContext workGroupSize diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Search.fs b/src/GraphBLAS-sharp.Backend/Quotes/Search.fs index 183d3e4c..55600257 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Search.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Search.fs @@ -96,6 +96,36 @@ module Search = result @> + /// + /// Searches value in array by two keys. + /// In case there is a value at the given keys position, it is returned. + /// + let existsByKey2D<'a> = + <@ fun length sourceIndex (rowIndices: ClArray) (columnIndices: ClArray) -> + + let mutable leftEdge = 0 + let mutable rightEdge = length - 1 + + let mutable result = false + + while leftEdge <= rightEdge do + let middleIdx = (leftEdge + rightEdge) / 2 + + let currentIndex: uint64 = + ((uint64 rowIndices.[middleIdx]) <<< 32) + ||| (uint64 columnIndices.[middleIdx]) + + if sourceIndex = currentIndex then + result <- true + + rightEdge <- -1 // TODO() break + elif sourceIndex < currentIndex then + rightEdge <- middleIdx - 1 + else + leftEdge <- middleIdx + 1 + + result @> + /// /// Find lower position of item in array. /// From 00bdd5a7549fddcfa942b01e5dfee4ac48aebb4b Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Tue, 14 Nov 2023 20:22:56 +0300 Subject: [PATCH 07/23] add: msbfs levels --- .../Algorithms/MSBFS.fs | 136 ++++++++++++++++++ src/GraphBLAS-sharp.Backend/Common/ClArray.fs | 111 ++++++++++++++ src/GraphBLAS-sharp.Backend/Common/Map.fs | 30 ++++ .../GraphBLAS-sharp.Backend.fsproj | 1 + .../Matrix/COO/Intersect.fs | 15 +- src/GraphBLAS-sharp.Backend/Matrix/COO/Map.fs | 1 - .../Matrix/COO/Matrix.fs | 32 ++++- .../Matrix/COO/Merge.fs | 53 ++++++- .../Matrix/LIL/Matrix.fs | 7 + src/GraphBLAS-sharp.Backend/Matrix/Matrix.fs | 66 +++++++-- src/GraphBLAS-sharp.Backend/Objects/Matrix.fs | 5 +- .../Quotes/Arithmetic.fs | 3 + .../Vector/Dense/Vector.fs | 31 ++++ .../Vector/Sparse/Vector.fs | 22 +++ src/GraphBLAS-sharp.Backend/Vector/Vector.fs | 43 +----- 15 files changed, 487 insertions(+), 69 deletions(-) create mode 100644 src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs new file mode 100644 index 00000000..4605b3f8 --- /dev/null +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -0,0 +1,136 @@ +namespace GraphBLAS.FSharp.Backend.Algorithms + +open Brahma.FSharp +open FSharp.Quotations +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Objects +open GraphBLAS.FSharp.Objects.ClMatrix +open GraphBLAS.FSharp.Objects.ArraysExtensions +open GraphBLAS.FSharp.Objects.ClContextExtensions +open GraphBLAS.FSharp.Backend.Matrix.LIL +open GraphBLAS.FSharp.Backend.Matrix.COO + +module internal MSBFS = + module Levels = + let private updateFront (clContext: ClContext) workGroupSize = + + let excludeValues = ClArray.excludeElements clContext workGroupSize + + let excludeIndices = ClArray.excludeElements clContext workGroupSize + + fun (queue: MailboxProcessor<_>) allocationMode (front: ClMatrix.COO<_>) (intersection: ClArray) -> + + let newRows = excludeIndices queue allocationMode intersection front.Rows + + let newColumns = excludeIndices queue allocationMode intersection front.Columns + + let newValues = excludeValues queue allocationMode intersection front.Values + + match newRows, newColumns, newValues with + | Some rows, Some columns, Some values -> + { Context = clContext + Rows = rows + Columns = columns + Values = values + RowCount = front.RowCount + ColumnCount = front.ColumnCount } + |> Some + | _ -> None + + let private updateFrontAndLevels (clContext: ClContext) workGroupSize = + + let updateFront = updateFront clContext workGroupSize + + let mergeDisjoint = Matrix.mergeDisjoint clContext workGroupSize + + let findIntersection = Intersect.findKeysIntersection clContext workGroupSize + + fun (queue: MailboxProcessor<_>) allocationMode (levels: ClMatrix.COO<_>) (front: ClMatrix.COO<_>) -> + + // Find intersection of levels and front indices. + let intersection = findIntersection queue DeviceOnly front levels + + // Remove mutual elements + let newFront = updateFront queue allocationMode front intersection + + intersection.Free queue + + match newFront with + | Some f -> + // Update levels + let newLevels = mergeDisjoint queue levels f + newLevels, newFront + | _ -> levels, None + + let run<'a when 'a: struct> + (add: Expr int -> int option>) + (mul: Expr<'a -> int -> int option>) + (clContext: ClContext) + workGroupSize + = + + let spGeMM = + Operations.SpGeMM.expand add mul clContext workGroupSize + + let toCSRInPlace = Matrix.toCSRInPlace clContext workGroupSize + + let updateFrontAndLevels = updateFrontAndLevels clContext workGroupSize + + fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int list) -> + let vertexCount = matrix.RowCount + let sourceVertexCount = source.Length + + let startMatrix = + source + |> List.mapi (fun i vertex -> i, vertex, 1) + + let mutable levels = + startMatrix + |> Matrix.ofList clContext DeviceOnly sourceVertexCount vertexCount + + let mutable front = + startMatrix + |> Matrix.ofList clContext DeviceOnly sourceVertexCount vertexCount + |> toCSRInPlace queue DeviceOnly + + let mutable level = 0 + let mutable stop = false + + while not stop do + level <- level + 1 + + //Getting new frontier + match spGeMM queue DeviceOnly matrix (ClMatrix.CSR front) with + | None -> + front.Dispose queue + stop <- true + | Some newFrontier -> + front.Dispose queue + //Filtering visited vertices + match updateFrontAndLevels queue DeviceOnly levels newFrontier with + | l, Some f -> + front <- toCSRInPlace queue DeviceOnly f + levels.Dispose queue + levels <- l + newFrontier.Dispose queue + | _, None -> + stop <- true + newFrontier.Dispose queue + + levels + + let runSingleSourceMultipleTimes<'a when 'a: struct> + (add: Expr int option -> int option>) + (mul: Expr<'a option -> int option -> int option>) + (clContext: ClContext) + workGroupSize + = + + let SSBFS = BFS.singleSourceSparse add mul clContext workGroupSize + + fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int list) -> + source + |> List.map (SSBFS queue matrix) + + module Parents = + let run = 0 diff --git a/src/GraphBLAS-sharp.Backend/Common/ClArray.fs b/src/GraphBLAS-sharp.Backend/Common/ClArray.fs index dacb249e..168f170a 100644 --- a/src/GraphBLAS-sharp.Backend/Common/ClArray.fs +++ b/src/GraphBLAS-sharp.Backend/Common/ClArray.fs @@ -121,6 +121,37 @@ module ClArray = outputArray + /// + /// Copies all elements from source to destination array. + /// + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let copyTo (clContext: ClContext) workGroupSize = + let copy = + <@ fun (ndRange: Range1D) (source: ClArray<'a>) (destination: ClArray<'a>) inputArrayLength -> + + let i = ndRange.GlobalID0 + + if i < inputArrayLength then + source.[i] <- destination.[i] @> + + let program = clContext.Compile(copy) + + fun (processor: MailboxProcessor<_>) (source: ClArray<'a>) (destination: ClArray<'a>) -> + if source.Length <> destination.Length then + failwith "The source array length differs from the destination array length." + + let ndRange = + Range1D.CreateValid(source.Length, workGroupSize) + + let kernel = program.GetKernel() + + processor.Post( + Msg.MsgSetArguments(fun () -> kernel.KernelFunc ndRange source destination source.Length) + ) + + processor.Post(Msg.CreateRunMsg<_, _> kernel) + /// /// Creates an array of the given size by replicating the values of the given initial array. /// @@ -781,3 +812,83 @@ module ClArray = bitmap.Free processor result + + /// + /// Builds a new array whose elements are the results of applying the given function + /// to each of the elements of the array. + /// + /// The function to transform elements of the array. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let map<'a, 'b> (op: Expr<'a -> 'b>) (clContext: ClContext) workGroupSize = Map.map op clContext workGroupSize + + /// + /// Builds a new array whose elements are the results of applying the given function + /// to each of the elements of the array. + /// + /// The function to transform elements of the array. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let mapInPlace<'a> (op: Expr<'a -> 'a>) (clContext: ClContext) workGroupSize = Map.mapInPlace op clContext workGroupSize + + /// + /// Builds a new array whose elements are the results of applying the given function + /// to the corresponding pairs of values, where the first element of pair is from the given array + /// and the second element is the given value. + /// + /// The function to transform elements of the array. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let mapWithValue<'a, 'b, 'c> (clContext: ClContext) workGroupSize (op: Expr<'a -> 'b -> 'c>) = Map.mapWithValue clContext workGroupSize op + + /// + /// Builds a new array whose elements are the results of applying the given function + /// to the corresponding elements of the two given arrays pairwise. + /// + /// + /// The two input arrays must have the same lengths. + /// + /// The function to transform the pairs of the input elements. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let map2<'a, 'b, 'c> (map: Expr<'a -> 'b -> 'c>) (clContext: ClContext) workGroupSize = Map.map2 map clContext workGroupSize + + /// + /// Fills the third given array with the results of applying the given function + /// to the corresponding elements of the first two given arrays pairwise. + /// + /// + /// The first two input arrays must have the same lengths. + /// + /// The function to transform the pairs of the input elements. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let map2InPlace<'a, 'b, 'c> (map: Expr<'a -> 'b -> 'c>) (clContext: ClContext) workGroupSize = Map.map2InPlace map clContext workGroupSize + + /// + /// Excludes elements, pointed by the bitmap. + /// + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let excludeElements (clContext: ClContext) workGroupSize = + + let invert = mapInPlace ArithmeticOperations.intNotQ clContext workGroupSize + + let prefixSum = PrefixSum.standardExcludeInPlace clContext workGroupSize + + let scatter = Scatter.lastOccurrence clContext workGroupSize + + fun (queue: MailboxProcessor<_>) allocationMode (excludeBitmap: ClArray) (inputArray: ClArray<'a>) -> + + invert queue excludeBitmap + + let length = (prefixSum queue excludeBitmap).ToHostAndFree queue + + if length = 0 then + None + else + let result = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, length) + + scatter queue excludeBitmap inputArray result + + Some result diff --git a/src/GraphBLAS-sharp.Backend/Common/Map.fs b/src/GraphBLAS-sharp.Backend/Common/Map.fs index f22f0f6b..19cda5f4 100644 --- a/src/GraphBLAS-sharp.Backend/Common/Map.fs +++ b/src/GraphBLAS-sharp.Backend/Common/Map.fs @@ -40,6 +40,36 @@ module Map = result + /// + /// Changes elements of the input array, applying the given function + /// to each element of the array. + /// + /// The function to transform elements of the array. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let mapInPlace<'a> (op: Expr<'a -> 'a>) (clContext: ClContext) workGroupSize = + + let map = + <@ fun (ndRange: Range1D) lenght (inputArray: ClArray<'a>) -> + + let gid = ndRange.GlobalID0 + + if gid < lenght then + inputArray.[gid] <- (%op) inputArray.[gid] @> + + let kernel = clContext.Compile map + + fun (processor: MailboxProcessor<_>) (inputArray: ClArray<'a>) -> + + let ndRange = + Range1D.CreateValid(inputArray.Length, workGroupSize) + + let kernel = kernel.GetKernel() + + processor.Post(Msg.MsgSetArguments(fun () -> kernel.KernelFunc ndRange inputArray.Length inputArray)) + + processor.Post(Msg.CreateRunMsg<_, _>(kernel)) + /// /// Builds a new array whose elements are the results of applying the given function /// to the corresponding pairs of values, where the first element of pair is from the given array diff --git a/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj b/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj index e46ea5d8..3921770d 100644 --- a/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj +++ b/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj @@ -69,6 +69,7 @@ + diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs index 226384f0..643fa00c 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs @@ -1,13 +1,12 @@ namespace GraphBLAS.FSharp.Backend.Matrix.COO open Brahma.FSharp -open GraphBLAS.FSharp open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects.ClContextExtensions module internal Intersect = - let findIntersectionByKeys (clContext: ClContext) workGroupSize = + let findKeysIntersection (clContext: ClContext) workGroupSize = let findIntersection = <@ fun (ndRange: Range1D) (leftNNZ: int) (rightNNZ: int) (leftRows: ClArray) (leftColumns: ClArray) (rightRows: ClArray) (rightColumns: ClArray) (bitmap: ClArray) -> @@ -17,15 +16,9 @@ module internal Intersect = if gid < bitmapSize then - let row, column, rows, columns = - if rightNNZ >= leftNNZ then - leftRows.[gid], leftColumns.[gid], leftRows, leftColumns - else - rightRows.[gid], rightColumns.[gid], rightRows, rightColumns + let index: uint64 = ((uint64 leftRows.[gid]) <<< 32) ||| (uint64 leftColumns.[gid]) - let index: uint64 = ((uint64 row) <<< 32) ||| (uint64 column) - - let intersect = (%Search.Bin.existsByKey2D) bitmapSize index rows columns + let intersect = (%Search.Bin.existsByKey2D) bitmapSize index rightRows rightColumns if intersect then bitmap.[gid] <- 1 @@ -37,7 +30,7 @@ module internal Intersect = fun (processor: MailboxProcessor<_>) allocationMode (leftMatrix: ClMatrix.COO<'a>) (rightMatrix: ClMatrix.COO<'b>) -> - let bitmapSize = min leftMatrix.NNZ rightMatrix.NNZ + let bitmapSize = leftMatrix.NNZ let bitmap = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, bitmapSize) diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Map.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Map.fs index 9b9377f0..5d99f062 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Map.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Map.fs @@ -1,6 +1,5 @@ namespace GraphBLAS.FSharp.Backend.Matrix.COO -open System open Brahma.FSharp open GraphBLAS.FSharp.Backend.Matrix open GraphBLAS.FSharp.Backend.Quotes diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs index b4960c1c..13431d19 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs @@ -8,6 +8,7 @@ open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Objects.ClMatrix open GraphBLAS.FSharp.Objects.ClCellExtensions open GraphBLAS.FSharp.Objects.ArraysExtensions +open GraphBLAS.FSharp.Objects.ClContextExtensions module Matrix = /// @@ -218,10 +219,35 @@ module Matrix = |> transposeInPlace queue /// - /// Build a bitmap. Maps non-zero elements of the matrix with minimum nnz to 1 - /// if the second matrix has non zero element under the same row and column pair, otherwise 0. + /// Builds a bitmap. Maps non-zero elements of the left matrix + /// to 1 if the right matrix has non zero element under the same row and column pair, otherwise 0. /// /// OpenCL context. /// Should be a power of 2 and greater than 1. let findIntersectionByKeys (clContext: ClContext) workGroupSize = - Intersect.findIntersectionByKeys clContext workGroupSize + Intersect.findKeysIntersection clContext workGroupSize + + /// + /// Merges two disjoint matrices of the same size. + /// + /// + /// Matrices should have the same number of rows and columns.
+ /// Matrices should not have non zero values with the same index. + ///
+ /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let mergeDisjoint (clContext: ClContext) workGroupSize = Merge.runDisjoint clContext workGroupSize + + let ofList (clContext: ClContext) allocationMode rowCount columnCount (elements: (int * int * 'a) list) = + let rows, columns, values = + elements + |> Array.ofList + |> Array.sortBy (fun (x, _, _) -> x) + |> Array.unzip3 + + { Context = clContext + Rows = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, rows) + Columns = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, columns) + Values = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, values) + RowCount = rowCount + ColumnCount = columnCount } diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Merge.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Merge.fs index 5e847976..cae0817c 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Merge.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Merge.fs @@ -1,8 +1,10 @@ namespace GraphBLAS.FSharp.Backend.Matrix.COO open Brahma.FSharp -open GraphBLAS.FSharp.Objects.ClContextExtensions open GraphBLAS.FSharp.Objects +open GraphBLAS.FSharp.Objects.ClContextExtensions +open GraphBLAS.FSharp.Objects.ClMatrix +open GraphBLAS.FSharp.Objects.ArraysExtensions module Merge = let run<'a, 'b when 'a: struct and 'b: struct> (clContext: ClContext) workGroupSize = @@ -180,3 +182,52 @@ module Merge = processor.Post(Msg.CreateRunMsg<_, _>(kernel)) allRows, allColumns, leftMergedValues, rightMergedValues, isLeft + + let runDisjoint<'a when 'a: struct> (clContext: ClContext) workGroupSize = + + let mergeValues = + <@ fun (ndRange: Range1D) (length: int) (leftValues: ClArray<'a>) (rightValues: ClArray<'a>) (isLeft: ClArray) -> + + let gid = ndRange.GlobalID0 + + if gid < length then + + if isLeft.[gid] = 0 then + leftValues.[gid] <- rightValues.[gid] @> + + let mergeValuesKernel = clContext.Compile(mergeValues) + + let merge = run clContext workGroupSize + + fun (processor: MailboxProcessor<_>) (leftMatrix: ClMatrix.COO<'a>) (rightMatrix: ClMatrix.COO<'a>) -> + + let length = leftMatrix.Columns.Length + rightMatrix.Columns.Length + + let rows, cols, leftValues, rightValues, isLeft = merge processor leftMatrix rightMatrix + + let ndRange = Range1D.CreateValid(length, workGroupSize) + + let mergeValuesKernel = mergeValuesKernel.GetKernel() + + processor.Post( + Msg.MsgSetArguments + (fun () -> + mergeValuesKernel.KernelFunc + ndRange + length + leftValues + rightValues + isLeft) + ) + + processor.Post(Msg.CreateRunMsg<_, _>(mergeValuesKernel)) + + isLeft.Free processor + rightValues.Free processor + + { Context = clContext + Rows = rows + Columns = cols + Values = leftValues + ColumnCount = leftMatrix.ColumnCount + RowCount = leftMatrix.RowCount } diff --git a/src/GraphBLAS-sharp.Backend/Matrix/LIL/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/LIL/Matrix.fs index 838fdead..9b3c2fbd 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/LIL/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/LIL/Matrix.fs @@ -2,6 +2,7 @@ namespace GraphBLAS.FSharp.Backend.Matrix.LIL open Brahma.FSharp open GraphBLAS.FSharp +open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Objects.ClMatrix open GraphBLAS.FSharp.Objects.ClContextExtensions @@ -43,3 +44,9 @@ module Matrix = RowPointers = rowsPointers Columns = columnsIndices Values = values } + + let ofVectors (clContext: ClContext) rowCount columnCount (vectors: ClVector.Sparse<_> option list) = + { Context = clContext + RowCount = rowCount + ColumnCount = columnCount + Rows = vectors } diff --git a/src/GraphBLAS-sharp.Backend/Matrix/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/Matrix.fs index c56ec5ea..789ff43a 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/Matrix.fs @@ -1,7 +1,6 @@ namespace GraphBLAS.FSharp open Brahma.FSharp -open Microsoft.FSharp.Quotations open GraphBLAS.FSharp open GraphBLAS.FSharp.Backend.Matrix open GraphBLAS.FSharp.Backend.Vector @@ -58,10 +57,48 @@ module Matrix = { Context = clContext RowCount = matrix.RowCount ColumnCount = matrix.ColumnCount - Rows = rows - NNZ = matrix.NNZ } + Rows = rows } |> ClMatrix.LIL + /// + /// Creates new matrix with the values from the given one. + /// New matrix represented in the format of the given one. + /// + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let copyTo (clContext: ClContext) workGroupSize = + + let copyTo = ClArray.copyTo clContext workGroupSize + + let copyDataTo = ClArray.copyTo clContext workGroupSize + + let vectorCopyTo = + Sparse.Vector.copyTo clContext workGroupSize + + fun (processor: MailboxProcessor<_>) (source: ClMatrix<'a>) (destination: ClMatrix<'a>) -> + if source.NNZ <> destination.NNZ || source.RowCount <> destination.RowCount || source.ColumnCount <> destination.ColumnCount then + failwith "Two matrices are not of the same size or they have different number of non-zero elements" + + match source, destination with + | ClMatrix.COO s, ClMatrix.COO d -> + copyTo processor s.Rows d.Rows + copyTo processor s.Columns d.Columns + copyDataTo processor s.Values d.Values + | ClMatrix.CSR s, ClMatrix.CSR d -> + copyTo processor s.RowPointers d.RowPointers + copyTo processor s.Columns d.Columns + copyDataTo processor s.Values d.Values + | ClMatrix.CSC s, ClMatrix.CSC d -> + copyTo processor s.Rows d.Rows + copyTo processor s.ColumnPointers d.ColumnPointers + copyDataTo processor s.Values d.Values + | ClMatrix.LIL s, ClMatrix.LIL d -> + List.iter2 (fun sourceVector destinationVector -> + match sourceVector, destinationVector with + | Some sv, Some dv -> vectorCopyTo processor sv dv + | _ -> failwith "Vectors of LIL matrix are not of the same size") s.Rows d.Rows + | _ -> failwith "Matrix formats are not matching" + /// /// Creates a new matrix, represented in CSR format, that is equal to the given one. /// @@ -273,9 +310,9 @@ module Matrix = ///
/// /// The format changes according to the following: - /// * COO -> COO - /// * CSR -> CSC - /// * CSC -> CSR + /// * COO -> COO
+ /// * CSR -> CSC
+ /// * CSC -> CSR
///
///OpenCL context. ///Should be a power of 2 and greater than 1. @@ -296,12 +333,12 @@ module Matrix = ///
/// /// The format changes according to the following: - /// * COO -> COO - /// * CSR -> CSC - /// * CSC -> CSR + /// * COO -> COO
+ /// * CSR -> CSC
+ /// * CSC -> CSR
///
- ///OpenCL context. - ///Should be a power of 2 and greater than 1. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. let transpose (clContext: ClContext) workGroupSize = let COOTranspose = COO.Matrix.transpose clContext workGroupSize @@ -332,3 +369,10 @@ module Matrix = Values = copyData processor allocationMode m.Values } |> ClMatrix.CSR | ClMatrix.LIL _ -> failwith "Not yet implemented" + + let ofList (clContext: ClContext) allocationMode format rowCount columnCount (elements: (int * int * 'a) list) = + match format with + | COO -> + COO.Matrix.ofList clContext allocationMode rowCount columnCount elements + |> ClMatrix.COO + | _ -> failwith "Not implemented" diff --git a/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs b/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs index 81771bd0..b36f1da9 100644 --- a/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs @@ -86,8 +86,7 @@ module ClMatrix = { Context: ClContext RowCount: int ColumnCount: int - Rows: ClVector.Sparse<'elem> option list - NNZ: int } + Rows: ClVector.Sparse<'elem> option list } interface IDeviceMemObject with member this.Dispose q = @@ -95,6 +94,8 @@ module ClMatrix = |> Seq.choose id |> Seq.iter (fun vector -> vector.Dispose q) + member this.NNZ = this.Rows |> List.fold (fun acc row -> match row with | Some r -> acc + r.NNZ | None -> acc) 0 + type Tuple<'elem when 'elem: struct> = { Context: ClContext RowIndices: ClArray diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs index 60654d23..e98e3d76 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs @@ -191,6 +191,9 @@ module ArithmeticOperations = | Some true -> None | _ -> Some true @> + let intNotQ = + <@ fun x -> if x = 0 then 1 else 0 @> + let inline private binOpQ zero op = <@ fun (left: 'a) (right: 'a) -> let result = (%op) left right diff --git a/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs b/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs index 6401a580..6b6a7629 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs @@ -218,3 +218,34 @@ module Vector = result | None -> clContext.CreateClCell Unchecked.defaultof<'a> + + let ofList (clContext: ClContext) workGroupSize = + let scatter = + Common.Scatter.lastOccurrence clContext workGroupSize + + let zeroCreate = + ClArray.zeroCreate clContext workGroupSize + + let map = + Backend.Common.Map.map <@ Some @> clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationMode size (elements: (int * 'a) list) -> + let indices, values = elements |> Array.ofList |> Array.unzip + + let values = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, values) + + let indices = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, indices) + + let mappedValues = map processor DeviceOnly values + + let result = zeroCreate processor allocationMode size + + scatter processor indices mappedValues result + + processor.Post(Msg.CreateFreeMsg(mappedValues)) + processor.Post(Msg.CreateFreeMsg(indices)) + processor.Post(Msg.CreateFreeMsg(values)) + + result diff --git a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs index 6d5bc25d..f8d1a35f 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs @@ -6,6 +6,7 @@ open Microsoft.FSharp.Quotations open GraphBLAS.FSharp open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Objects.ClVector +open GraphBLAS.FSharp.Objects.ClContextExtensions open GraphBLAS.FSharp.Backend.Quotes module Vector = @@ -20,6 +21,15 @@ module Vector = Values = copyData processor allocationMode vector.Values Size = vector.Size } + let copyTo (clContext: ClContext) workGroupSize = + let copyTo = ClArray.copyTo clContext workGroupSize + + let copyDataTo = ClArray.copyTo clContext workGroupSize + + fun (processor: MailboxProcessor<_>) (source: Sparse<'a>) (destination: Sparse<'a>) -> + copyTo processor source.Indices destination.Indices + copyDataTo processor source.Values destination.Values + let map = Map.run let mapWithValue = Map.WithValueOption.run @@ -74,3 +84,15 @@ module Vector = Common.Reduce.reduce opAdd clContext workGroupSize fun (processor: MailboxProcessor<_>) (vector: ClVector.Sparse<'a>) -> reduce processor vector.Values + + let ofList (clContext: ClContext) allocationMode size (elements: (int * 'a) list) = + let indices, values = + elements + |> Array.ofList + |> Array.sortBy fst + |> Array.unzip + + { Context = clContext + Indices = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, indices) + Values = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, values) + Size = size } diff --git a/src/GraphBLAS-sharp.Backend/Vector/Vector.fs b/src/GraphBLAS-sharp.Backend/Vector/Vector.fs index bbba4404..623d59b1 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Vector.fs @@ -46,49 +46,12 @@ module Vector = /// OpenCL context. /// Should be a power of 2 and greater than 1. let ofList (clContext: ClContext) workGroupSize = - let scatter = - Common.Scatter.lastOccurrence clContext workGroupSize - - let zeroCreate = - ClArray.zeroCreate clContext workGroupSize - - let map = - Common.Map.map <@ Some @> clContext workGroupSize + let denseOfList = Dense.Vector.ofList clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode format size (elements: (int * 'a) list) -> match format with - | Sparse -> - let indices, values = - elements - |> Array.ofList - |> Array.sortBy fst - |> Array.unzip - - { Context = clContext - Indices = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, indices) - Values = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, values) - Size = size } - |> ClVector.Sparse - | Dense -> - let indices, values = elements |> Array.ofList |> Array.unzip - - let values = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, values) - - let indices = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, indices) - - let mappedValues = map processor DeviceOnly values - - let result = zeroCreate processor allocationMode size - - scatter processor indices mappedValues result - - processor.Post(Msg.CreateFreeMsg(mappedValues)) - processor.Post(Msg.CreateFreeMsg(indices)) - processor.Post(Msg.CreateFreeMsg(values)) - - ClVector.Dense result + | Sparse -> Sparse.Vector.ofList clContext allocationMode size elements |> ClVector.Sparse + | Dense -> denseOfList processor allocationMode size elements |> ClVector.Dense /// /// Creates new vector with the values from the given one. From 97281a6b3bec535b00af2dd70147c9a3f91bcab5 Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Wed, 15 Nov 2023 17:32:13 +0300 Subject: [PATCH 08/23] add: spgemm coo->csr->coo --- .../Algorithms/MSBFS.fs | 19 +- .../Matrix/COO/Matrix.fs | 80 +++++++- .../Operations/Operations.fs | 122 ++++++++++++ .../Operations/SpGeMM/Expand.fs | 182 +++++++++++++++++- 4 files changed, 390 insertions(+), 13 deletions(-) diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index 4605b3f8..2ab8772e 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -45,7 +45,7 @@ module internal MSBFS = let findIntersection = Intersect.findKeysIntersection clContext workGroupSize - fun (queue: MailboxProcessor<_>) allocationMode (levels: ClMatrix.COO<_>) (front: ClMatrix.COO<_>) -> + fun (queue: MailboxProcessor<_>) allocationMode (front: ClMatrix.COO<_>) (levels: ClMatrix.COO<_>) -> // Find intersection of levels and front indices. let intersection = findIntersection queue DeviceOnly front levels @@ -64,15 +64,15 @@ module internal MSBFS = let run<'a when 'a: struct> (add: Expr int -> int option>) - (mul: Expr<'a -> int -> int option>) + (mul: Expr 'a -> int option>) (clContext: ClContext) workGroupSize = let spGeMM = - Operations.SpGeMM.expand add mul clContext workGroupSize + Operations.SpGeMM.COO.expand add mul clContext workGroupSize - let toCSRInPlace = Matrix.toCSRInPlace clContext workGroupSize + let copy = Matrix.copy clContext workGroupSize let updateFrontAndLevels = updateFrontAndLevels clContext workGroupSize @@ -88,10 +88,7 @@ module internal MSBFS = startMatrix |> Matrix.ofList clContext DeviceOnly sourceVertexCount vertexCount - let mutable front = - startMatrix - |> Matrix.ofList clContext DeviceOnly sourceVertexCount vertexCount - |> toCSRInPlace queue DeviceOnly + let mutable front = copy queue DeviceOnly levels let mutable level = 0 let mutable stop = false @@ -100,16 +97,16 @@ module internal MSBFS = level <- level + 1 //Getting new frontier - match spGeMM queue DeviceOnly matrix (ClMatrix.CSR front) with + match spGeMM queue DeviceOnly (ClMatrix.COO front) matrix with | None -> front.Dispose queue stop <- true | Some newFrontier -> front.Dispose queue //Filtering visited vertices - match updateFrontAndLevels queue DeviceOnly levels newFrontier with + match updateFrontAndLevels queue DeviceOnly newFrontier levels with | l, Some f -> - front <- toCSRInPlace queue DeviceOnly f + front <- f levels.Dispose queue levels <- l newFrontier.Dispose queue diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs index 13431d19..4d7315fa 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs @@ -11,6 +11,25 @@ open GraphBLAS.FSharp.Objects.ArraysExtensions open GraphBLAS.FSharp.Objects.ClContextExtensions module Matrix = + /// + /// Creates new COO matrix with the values from the given one. + /// + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let copy (clContext: ClContext) workGroupSize = + + let copy = ClArray.copy clContext workGroupSize + + let copyData = ClArray.copy clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationMode (matrix: COO<'a>) -> + { Context = clContext + RowCount = matrix.RowCount + ColumnCount = matrix.ColumnCount + Rows = copy processor allocationMode matrix.Rows + Columns = copy processor allocationMode matrix.Columns + Values = copyData processor allocationMode matrix.Values } + /// /// Builds a new COO matrix whose elements are the results of applying the given function /// to each of the elements of the matrix. @@ -85,7 +104,7 @@ module Matrix = /// /// OpenCL context. /// Should be a power of 2 and greater than 1. - let private compressRows (clContext: ClContext) workGroupSize = + let compressRows (clContext: ClContext) workGroupSize = let compressRows = <@ fun (ndRange: Range1D) (rows: ClArray) (nnz: int) (rowPointers: ClArray) -> @@ -251,3 +270,62 @@ module Matrix = Values = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, values) RowCount = rowCount ColumnCount = columnCount } + + /// + /// Returns matrix composed of all elements from the given row range of the input matrix. + /// + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let subRows (clContext: ClContext) workGroupSize = + + let upperBound = ClArray.upperBound clContext workGroupSize + + let blit = ClArray.blit clContext workGroupSize + + let blitData = ClArray.blit clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationMode startRow count (matrix: ClMatrix.COO<'a>) -> + if count <= 0 then + failwith "Count must be greater than zero" + + if startRow < 0 then + failwith "startIndex must be greater then zero" + + if startRow + count > matrix.RowCount then + failwith "startIndex and count sum is larger than the matrix row count" + + let firstRowClCell = clContext.CreateClCell(startRow - 1) + let lastRowClCell = clContext.CreateClCell(startRow + count) + + // extract rows + let firstIndex = (upperBound processor matrix.Rows firstRowClCell).ToHostAndFree processor + let lastIndex = (upperBound processor matrix.Rows lastRowClCell).ToHostAndFree processor - 1 + + firstRowClCell.Free processor + lastRowClCell.Free processor + + let resultLength = lastIndex - firstIndex + 1 + + let rows = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, resultLength) + + blit processor matrix.Columns firstIndex rows 0 resultLength + + // extract values + let values = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, resultLength) + + blitData processor matrix.Values firstIndex values 0 resultLength + + // extract indices + let columns = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, resultLength) + + blit processor matrix.Columns firstIndex columns 0 resultLength + + { Context = clContext + RowCount = matrix.RowCount + ColumnCount = matrix.ColumnCount + Rows = rows + Columns = columns + Values = values } diff --git a/src/GraphBLAS-sharp.Backend/Operations/Operations.fs b/src/GraphBLAS-sharp.Backend/Operations/Operations.fs index 06b2a39a..c6950832 100644 --- a/src/GraphBLAS-sharp.Backend/Operations/Operations.fs +++ b/src/GraphBLAS-sharp.Backend/Operations/Operations.fs @@ -98,6 +98,88 @@ module Operations = |> Some | _ -> failwith "Vector formats are not matching." + /// + /// Applying the given function to the corresponding elements of the two given arrays pairwise. + /// Stores the result in the left vector. + /// + /// + /// The two input arrays must have the same lengths. + /// + /// The function to transform the pairs of the input elements. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let map2InPlace (map: Expr<'a option -> 'b option -> 'a option>) (clContext: ClContext) workGroupSize = + let map2Dense = + Dense.Vector.map2InPlace map clContext workGroupSize + + fun (processor: MailboxProcessor<_>) (leftVector: ClVector<'a>) (rightVector: ClVector<'b>) -> + match leftVector, rightVector with + | ClVector.Dense left, ClVector.Dense right -> map2Dense processor left right left + | _ -> failwith "Unsupported vector format" + + /// + /// Applying the given function to the corresponding elements of the two given arrays pairwise. + /// Stores the result in the given vector. + /// + /// + /// The two input arrays must have the same lengths. + /// + /// The function to transform the pairs of the input elements. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let map2To (map: Expr<'a option -> 'b option -> 'c option>) (clContext: ClContext) workGroupSize = + let map2Dense = + Dense.Vector.map2InPlace map clContext workGroupSize + + fun (processor: MailboxProcessor<_>) (leftVector: ClVector<'a>) (rightVector: ClVector<'b>) (resultVector: ClVector<'c>) -> + match leftVector, rightVector, resultVector with + | ClVector.Dense left, ClVector.Dense right, ClVector.Dense result -> map2Dense processor left right result + | _ -> failwith "Unsupported vector format" + + /// + /// Applying the given function to the corresponding elements of the two given arrays pairwise. + /// Returns new vector. + /// + /// + /// The two input arrays must have the same lengths. + /// + /// The function to transform the pairs of the input elements. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let map2Dense (map: Expr<'a option -> 'b option -> 'a option>) (clContext: ClContext) workGroupSize = + let map2Dense = + Dense.Vector.map2 map clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationFlag (leftVector: ClVector<'a>) (rightVector: ClVector<'b>) -> + match leftVector, rightVector with + | ClVector.Dense left, ClVector.Dense right -> map2Dense processor allocationFlag left right + | _ -> failwith "Unsupported vector format" + + /// + /// Applying the given function to the corresponding elements of the two given arrays pairwise. + /// Returns new vector as option. + /// + /// + /// The two input arrays must have the same lengths. + /// + /// The function to transform the pairs of the input elements. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let map2Sparse (map: Expr<'a option -> 'b option -> 'a option>) (clContext: ClContext) workGroupSize = + let map2Sparse = + Sparse.Map2.run map clContext workGroupSize + + let map2SparseDense = + Sparse.Map2.runSparseDense map clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationFlag (leftVector: ClVector<'a>) (rightVector: ClVector<'b>) -> + match leftVector, rightVector with + | ClVector.Sparse left, ClVector.Sparse right -> + Option.map ClVector.Sparse (map2Sparse processor allocationFlag left right) + | ClVector.Sparse left, ClVector.Dense right -> + Option.map ClVector.Sparse (map2SparseDense processor allocationFlag left right) + | _ -> failwith "Unsupported vector format" + module Matrix = /// /// Builds a new matrix whose elements are the results of applying the given function @@ -374,3 +456,43 @@ module Operations = run processor allocationMode resultCapacity leftMatrix rightMatrix | _ -> failwith "Matrix formats are not matching" + + module COO = + /// + /// Generalized matrix-matrix multiplication. Left matrix should be in COO format. + /// + /// Type of binary function to reduce entries. + /// Type of binary function to combine entries. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let expand + (opAdd: Expr<'c -> 'c -> 'c option>) + (opMul: Expr<'a -> 'b -> 'c option>) + (clContext: ClContext) + workGroupSize + = + + let run = + SpGeMM.Expand.COO.run opAdd opMul clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationMode (leftMatrix: ClMatrix<'a>) (rightMatrix: ClMatrix<'b>) -> + match leftMatrix, rightMatrix with + | ClMatrix.COO leftMatrix, ClMatrix.CSR rightMatrix -> + let allocCapacity = + List.max [ sizeof<'a> + sizeof<'c> + sizeof<'b> ] + |> uint64 + |> (*) 1UL + + let resultCapacity = + (clContext.MaxMemAllocSize / allocCapacity) / 3UL + + let resultCapacity = + (min + <| uint64 System.Int32.MaxValue + <| resultCapacity) + |> int + + run processor allocationMode resultCapacity leftMatrix rightMatrix + | _ -> failwith "Matrix formats are not matching" diff --git a/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs b/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs index e404cf87..407a878c 100644 --- a/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs +++ b/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs @@ -3,7 +3,6 @@ open Brahma.FSharp open FSharp.Quotations open GraphBLAS.FSharp -open GraphBLAS.FSharp open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Objects.ClMatrix open GraphBLAS.FSharp.Objects.ClCellExtensions @@ -499,3 +498,184 @@ module internal Expand = Values = values } |> Some | _ -> None + + module COO = + let runOneStep opAdd opMul (clContext: ClContext) workGroupSize = + + let runCOO = + runCOO opAdd opMul clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationMode (leftMatrix: ClMatrix.COO<'a>) rightMatrixRowsNNZ (rightMatrix: ClMatrix.CSR<'b>) -> + + let _, result = + runCOO processor allocationMode rightMatrixRowsNNZ rightMatrix leftMatrix + + result + |> Option.map + (fun (values, columns, rows) -> + { Context = clContext + RowCount = leftMatrix.RowCount + ColumnCount = rightMatrix.ColumnCount + Rows = rows + Columns = columns + Values = values }) + + let runManySteps opAdd opMul (clContext: ClContext) workGroupSize = + + let compress = COO.Matrix.compressRows clContext workGroupSize + + let gather = + Common.Gather.run clContext workGroupSize + + let upperBound = + ClArray.upperBound clContext workGroupSize + + let set = ClArray.set clContext workGroupSize + + let subMatrix = + COO.Matrix.subRows clContext workGroupSize + + let runCOO = + runCOO opAdd opMul clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationMode maxAllocSize generalLength (leftMatrix: ClMatrix.COO<'a>) segmentLengths rightMatrixRowsNNZ (rightMatrix: ClMatrix.CSR<'b>) -> + + let leftRowPointers = compress processor allocationMode leftMatrix.Rows leftMatrix.RowCount + + // extract segment lengths by left matrix rows pointers + let segmentPointersByLeftMatrixRows = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, leftRowPointers.Length) + + gather processor leftRowPointers segmentLengths segmentPointersByLeftMatrixRows + + // set last element to one step length + set processor segmentPointersByLeftMatrixRows (leftRowPointers.Length - 1) generalLength + + // curring + let upperBound = + upperBound processor segmentPointersByLeftMatrixRows + + let subMatrix = subMatrix processor DeviceOnly + + let runCOO = + runCOO processor allocationMode rightMatrixRowsNNZ rightMatrix + + let rec helper beginRow workOffset previousResult = + if beginRow < leftMatrix.RowCount then + let currentBound = + clContext.CreateClCell(workOffset + maxAllocSize: int) + + // find largest row that fit into maxAllocSize + let upperBound = + (upperBound currentBound).ToHostAndFree processor + + let endRow = upperBound - 2 + + currentBound.Free processor + + // TODO(handle largest rows) + // (we can split row, multiply and merge them but merge path needed) + if endRow = beginRow then + failwith "It is impossible to multiply such a long row" + + // extract matrix TODO(Transfer overhead) + let subMatrix = + subMatrix beginRow (endRow - beginRow) leftMatrix + + // compute sub result + let length, result = runCOO subMatrix + // increase workOffset according to previous expand + let workOffset = workOffset + length + + match result with + | Some result -> + helper endRow workOffset + <| result :: previousResult + | None -> helper endRow workOffset previousResult + else + previousResult + + let result = helper 0 0 [] |> List.rev + + segmentPointersByLeftMatrixRows.Free processor + + result + + let run opAdd opMul (clContext: ClContext) workGroupSize = + + let getNNZInRows = + CSR.Matrix.NNZInRows clContext workGroupSize + + let getSegmentPointers = + getSegmentPointers clContext workGroupSize + + let runOneStep = + runOneStep opAdd opMul clContext workGroupSize + + let concat = ClArray.concat clContext workGroupSize + + let concatData = ClArray.concat clContext workGroupSize + + let runManySteps = + runManySteps opAdd opMul clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationMode maxAllocSize (leftMatrix: ClMatrix.COO<'a>) (rightMatrix: ClMatrix.CSR<'b>) -> + + let rightMatrixRowsNNZ = + getNNZInRows processor DeviceOnly rightMatrix + + let generalLength, segmentLengths = + getSegmentPointers processor leftMatrix.Columns rightMatrixRowsNNZ + + if generalLength = 0 then + None + elif generalLength < maxAllocSize then + segmentLengths.Free processor + + runOneStep processor allocationMode leftMatrix rightMatrixRowsNNZ rightMatrix + else + let result = + runManySteps + processor + allocationMode + maxAllocSize + generalLength + leftMatrix + segmentLengths + rightMatrixRowsNNZ + rightMatrix + + rightMatrixRowsNNZ.Free processor + segmentLengths.Free processor + + match result with + | _ :: _ -> + let valuesList, columnsList, rowsList = result |> List.unzip3 + + let values = + concatData processor allocationMode valuesList + + let columns = + concat processor allocationMode columnsList + + let rows = concat processor allocationMode rowsList + + // TODO(overhead: compute result length 3 time) + // release resources + valuesList + |> List.iter (fun array -> array.Free processor) + + columnsList + |> List.iter (fun array -> array.Free processor) + + rowsList + |> List.iter (fun array -> array.Free processor) + + { Context = clContext + RowCount = leftMatrix.RowCount + ColumnCount = rightMatrix.ColumnCount + Rows = rows + Columns = columns + Values = values } + |> Some + | _ -> None From 1538ad692a25133f97c5c097b15aafe22d7c495f Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Wed, 15 Nov 2023 18:48:59 +0300 Subject: [PATCH 09/23] add: msbfs parents --- .../Algorithms/MSBFS.fs | 115 +++++++++++++++--- .../Algorithms/SSSP.fs | 2 +- .../Quotes/Arithmetic.fs | 11 +- 3 files changed, 106 insertions(+), 22 deletions(-) diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index 2ab8772e..7351e733 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -3,6 +3,7 @@ namespace GraphBLAS.FSharp.Backend.Algorithms open Brahma.FSharp open FSharp.Quotations open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Objects.ClMatrix open GraphBLAS.FSharp.Objects.ArraysExtensions @@ -11,35 +12,35 @@ open GraphBLAS.FSharp.Backend.Matrix.LIL open GraphBLAS.FSharp.Backend.Matrix.COO module internal MSBFS = - module Levels = - let private updateFront (clContext: ClContext) workGroupSize = + let private frontExclude (clContext: ClContext) workGroupSize = - let excludeValues = ClArray.excludeElements clContext workGroupSize + let excludeValues = ClArray.excludeElements clContext workGroupSize - let excludeIndices = ClArray.excludeElements clContext workGroupSize + let excludeIndices = ClArray.excludeElements clContext workGroupSize - fun (queue: MailboxProcessor<_>) allocationMode (front: ClMatrix.COO<_>) (intersection: ClArray) -> + fun (queue: MailboxProcessor<_>) allocationMode (front: ClMatrix.COO<_>) (intersection: ClArray) -> - let newRows = excludeIndices queue allocationMode intersection front.Rows + let newRows = excludeIndices queue allocationMode intersection front.Rows - let newColumns = excludeIndices queue allocationMode intersection front.Columns + let newColumns = excludeIndices queue allocationMode intersection front.Columns - let newValues = excludeValues queue allocationMode intersection front.Values + let newValues = excludeValues queue allocationMode intersection front.Values - match newRows, newColumns, newValues with - | Some rows, Some columns, Some values -> - { Context = clContext - Rows = rows - Columns = columns - Values = values - RowCount = front.RowCount - ColumnCount = front.ColumnCount } - |> Some - | _ -> None + match newRows, newColumns, newValues with + | Some rows, Some columns, Some values -> + { Context = clContext + Rows = rows + Columns = columns + Values = values + RowCount = front.RowCount + ColumnCount = front.ColumnCount } + |> Some + | _ -> None + module Levels = let private updateFrontAndLevels (clContext: ClContext) workGroupSize = - let updateFront = updateFront clContext workGroupSize + let updateFront = frontExclude clContext workGroupSize let mergeDisjoint = Matrix.mergeDisjoint clContext workGroupSize @@ -130,4 +131,78 @@ module internal MSBFS = |> List.map (SSBFS queue matrix) module Parents = - let run = 0 + let updateFrontAndParents (clContext: ClContext) workGroupSize = + // update parents same as levels + // every front value should be equal to its column number + let frontExclude = frontExclude clContext workGroupSize + + let mergeDisjoint = Matrix.mergeDisjoint clContext workGroupSize + + let findIntersection = Intersect.findKeysIntersection clContext workGroupSize + + fun (queue: MailboxProcessor) allocationMode (front: ClMatrix.COO<_>) (parents: ClMatrix.COO<_>) -> + + // Find intersection of levels and front indices. + let intersection = findIntersection queue DeviceOnly front parents + + // Remove mutual elements + let newFront = frontExclude queue allocationMode front intersection + + intersection.Free queue + + match newFront with + | Some f -> + // Update levels + let resultFront = + { f with Values = f.Columns } + let newLevels = mergeDisjoint queue parents f + newLevels, Some resultFront + | _ -> parents, None + + let run<'a when 'a: struct> + (clContext: ClContext) + workGroupSize + = + + let spGeMM = + Operations.SpGeMM.COO.expand (ArithmeticOperations.min 0) (ArithmeticOperations.fst 0) clContext workGroupSize + + let updateFrontAndLevels = updateFrontAndParents clContext workGroupSize + + fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int list) -> + let vertexCount = matrix.RowCount + let sourceVertexCount = source.Length + + let mutable parents = + source + |> List.mapi (fun i vertex -> i, vertex, 0) + |> Matrix.ofList clContext DeviceOnly sourceVertexCount vertexCount + + let mutable front = + source + |> List.mapi (fun i vertex -> i, vertex, vertex) + |> Matrix.ofList clContext DeviceOnly sourceVertexCount vertexCount + + let mutable stop = false + + while not stop do + + //Getting new frontier + match spGeMM queue DeviceOnly (ClMatrix.COO front) matrix with + | None -> + front.Dispose queue + stop <- true + | Some newFrontier -> + front.Dispose queue + //Filtering visited vertices + match updateFrontAndLevels queue DeviceOnly newFrontier parents with + | l, Some f -> + front <- f + parents.Dispose queue + parents <- l + newFrontier.Dispose queue + | _, None -> + stop <- true + newFrontier.Dispose queue + + parents diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/SSSP.fs b/src/GraphBLAS-sharp.Backend/Algorithms/SSSP.fs index 815fde6f..489a796c 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/SSSP.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/SSSP.fs @@ -11,7 +11,7 @@ module internal SSSP = let run (clContext: ClContext) workGroupSize = let less = ArithmeticOperations.less - let min = ArithmeticOperations.min + let min = ArithmeticOperations.minOption let plus = ArithmeticOperations.intSumAsMul let spMVInPlace = diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs index e98e3d76..9db81a58 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs @@ -240,7 +240,7 @@ module ArithmeticOperations = | Some x, None -> Some 1 | _ -> None @> - let min<'a when 'a: comparison> = + let minOption<'a when 'a: comparison> = <@ fun (x: 'a option) (y: 'a option) -> match x, y with | Some x, Some y -> Some(min x y) @@ -248,6 +248,15 @@ module ArithmeticOperations = | None, Some y -> Some y | _ -> None @> + let min zero = + <@ fun x y -> + let result = min x y + if result = zero then None else Some result @> + + let fst zero = + <@ fun x _ -> + if x = zero then None else Some x @> + //PageRank specific let squareOfDifference = <@ fun (x: float32 option) (y: float32 option) -> From cf10d92eb1787c385d7ff1e19e3660d8a7a8365e Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Wed, 15 Nov 2023 21:09:42 +0300 Subject: [PATCH 10/23] fix: msbfs parents --- src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index 7351e733..ee459487 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -169,10 +169,22 @@ module internal MSBFS = let updateFrontAndLevels = updateFrontAndParents clContext workGroupSize - fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int list) -> - let vertexCount = matrix.RowCount + fun (queue: MailboxProcessor) (inputMatrix: ClMatrix<'a>) (source: int list) -> + let vertexCount = inputMatrix.RowCount let sourceVertexCount = source.Length + let matrix = + match inputMatrix with + | ClMatrix.CSR m -> + { Context = clContext + RowPointers = m.RowPointers + Columns = m.Columns + Values = m.Columns + RowCount = m.RowCount + ColumnCount = m.ColumnCount } + |> ClMatrix.CSR + | _ -> failwith "Incorrect format" + let mutable parents = source |> List.mapi (fun i vertex -> i, vertex, 0) @@ -186,7 +198,6 @@ module internal MSBFS = let mutable stop = false while not stop do - //Getting new frontier match spGeMM queue DeviceOnly (ClMatrix.COO front) matrix with | None -> From 1558c6d5aa4dbd5aa9fda6ad9358cd7a37cdc97b Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Fri, 17 Nov 2023 14:09:13 +0300 Subject: [PATCH 11/23] add: tests --- .../Algorithms/Algorithms.fs | 5 + .../Algorithms/MSBFS.fs | 10 +- src/GraphBLAS-sharp/Objects/Matrix.fs | 3 +- .../Backend/Algorithms/MSBFS.fs | 115 ++++++++++++++++++ .../Backend/Matrix/SpGeMM/ExpandCOO.fs | 77 ++++++++++++ .../GraphBLAS-sharp.Tests.fsproj | 2 + tests/GraphBLAS-sharp.Tests/Helpers.fs | 42 +++++++ tests/GraphBLAS-sharp.Tests/Program.fs | 7 +- 8 files changed, 252 insertions(+), 9 deletions(-) create mode 100644 tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs create mode 100644 tests/GraphBLAS-sharp.Tests/Backend/Matrix/SpGeMM/ExpandCOO.fs diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/Algorithms.fs b/src/GraphBLAS-sharp.Backend/Algorithms/Algorithms.fs index 227c443f..180b72b6 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/Algorithms.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/Algorithms.fs @@ -12,6 +12,11 @@ module Algorithms = let singleSourcePushPull = BFS.singleSourcePushPull + module MSBFS = + let runLevels = MSBFS.Levels.run + + let runParents = MSBFS.Parents.run + module SSSP = let run = SSSP.run diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index ee459487..2607df67 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -115,7 +115,7 @@ module internal MSBFS = stop <- true newFrontier.Dispose queue - levels + ClMatrix.COO levels let runSingleSourceMultipleTimes<'a when 'a: struct> (add: Expr int option -> int option>) @@ -131,7 +131,7 @@ module internal MSBFS = |> List.map (SSBFS queue matrix) module Parents = - let updateFrontAndParents (clContext: ClContext) workGroupSize = + let private updateFrontAndParents (clContext: ClContext) workGroupSize = // update parents same as levels // every front value should be equal to its column number let frontExclude = frontExclude clContext workGroupSize @@ -165,7 +165,7 @@ module internal MSBFS = = let spGeMM = - Operations.SpGeMM.COO.expand (ArithmeticOperations.min 0) (ArithmeticOperations.fst 0) clContext workGroupSize + Operations.SpGeMM.COO.expand (ArithmeticOperations.min -1) (ArithmeticOperations.fst -1) clContext workGroupSize let updateFrontAndLevels = updateFrontAndParents clContext workGroupSize @@ -187,7 +187,7 @@ module internal MSBFS = let mutable parents = source - |> List.mapi (fun i vertex -> i, vertex, 0) + |> List.mapi (fun i vertex -> i, vertex, -1) |> Matrix.ofList clContext DeviceOnly sourceVertexCount vertexCount let mutable front = @@ -216,4 +216,4 @@ module internal MSBFS = stop <- true newFrontier.Dispose queue - parents + ClMatrix.COO parents diff --git a/src/GraphBLAS-sharp/Objects/Matrix.fs b/src/GraphBLAS-sharp/Objects/Matrix.fs index e74e9153..84004b1a 100644 --- a/src/GraphBLAS-sharp/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp/Objects/Matrix.fs @@ -187,8 +187,7 @@ module Matrix = { Context = context RowCount = this.RowCount ColumnCount = this.ColumnCount - Rows = rows - NNZ = this.NNZ } + Rows = rows } type Tuples<'a> = { RowIndices: int [] diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs new file mode 100644 index 00000000..8cc65562 --- /dev/null +++ b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs @@ -0,0 +1,115 @@ +module GraphBLAS.FSharp.Tests.Backend.Algorithms.MSBFS + +open Expecto +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend.Quotes +open GraphBLAS.FSharp.Tests +open GraphBLAS.FSharp.Tests.Context +open GraphBLAS.FSharp.Tests.Backend.QuickGraph.Algorithms +open GraphBLAS.FSharp.Tests.Backend.QuickGraph.CreateGraph +open GraphBLAS.FSharp.Objects +open GraphBLAS.FSharp.Objects.MatrixExtensions + +let config = Utils.undirectedAlgoConfig +let workGroupSize = Utils.defaultWorkGroupSize + +let makeLevelsTest context queue bfs (matrix: int [,]) = + let graph = undirectedFromArray2D matrix 0 + + let largestComponent = + ConnectedComponents.largestComponent graph + + if largestComponent.Length > 1 then + let sourceVertexCount = max 2 (largestComponent.Length / 10) + let source = largestComponent.[0 .. sourceVertexCount] |> Array.toList + + let matrixHost = + Utils.createMatrixFromArray2D CSR matrix ((=) 0) + let matrixDevice = matrixHost.ToDevice context + + let expectedArray2D: int [,] = Array2D.zeroCreate sourceVertexCount (Array2D.length2 matrix) + + source + |> Seq.iteri (fun i vertex -> + (snd (BFS.runUndirected graph vertex)) + |> Utils.createArrayFromDictionary (Array2D.length1 matrix) 0 + |> Array.iteri (fun col value -> expectedArray2D.[i, col] <- value)) + + let expected = Utils.createMatrixFromArray2D COO expectedArray2D ((=) 0) + + let actual: ClMatrix = bfs queue matrixDevice source + let actual = actual.ToHostAndFree queue + + matrixDevice.Dispose queue + + match actual, expected with + | Matrix.COO a, Matrix.COO e -> + Utils.compareCOOMatrix (=) a e + | _ -> failwith "Not implemented" + +let createLevelsTest context queue testFun = + testFun + |> makeLevelsTest context queue + |> testPropertyWithConfig config $"test on %A{typeof<'a>}" + +let levelsTestFixtures (testContext: TestContext) = + [ let context = testContext.ClContext + let queue = testContext.Queue + + let bfsLevels = + Algorithms.MSBFS.runLevels + (fst ArithmeticOperations.intAdd) + (fst ArithmeticOperations.intMul) + context + workGroupSize + + createLevelsTest context queue bfsLevels ] + +let levelsTests = + TestCases.gpuTests "MSBFS Levels tests" levelsTestFixtures + +let makeParentsTest context queue bfs (matrix: int [,]) = + let graph = undirectedFromArray2D matrix -1 + + let largestComponent = + ConnectedComponents.largestComponent graph + + if largestComponent.Length > 1 then + let sourceVertexCount = max 2 (largestComponent.Length / 10) + let source = largestComponent.[0 .. sourceVertexCount] |> Array.toList + + let matrixHost = + Utils.createMatrixFromArray2D CSR matrix ((=) -1) + let matrixDevice = matrixHost.ToDevice context + + let expectedArray2D = HostPrimitives.MSBFSParents matrix source + let expected = Utils.createMatrixFromArray2D COO expectedArray2D ((=) -1) + + let actual: ClMatrix = bfs queue matrixDevice source + let actual = actual.ToHostAndFree queue + + matrixDevice.Dispose queue + + match actual, expected with + | Matrix.COO a, Matrix.COO e -> + Utils.compareCOOMatrix (=) a e + | _ -> failwith "Not implemented" + +let createParentsTest context queue testFun = + testFun + |> makeLevelsTest context queue + |> testPropertyWithConfig config $"test on %A{typeof<'a>}" + +let parentsTestFixtures (testContext: TestContext) = + [ let context = testContext.ClContext + let queue = testContext.Queue + + let bfsLevels = + Algorithms.MSBFS.runParents + context + workGroupSize + + createLevelsTest context queue bfsLevels ] + +let parentsTests = + TestCases.gpuTests "MSBFS Levels tests" parentsTestFixtures diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Matrix/SpGeMM/ExpandCOO.fs b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/SpGeMM/ExpandCOO.fs new file mode 100644 index 00000000..43787eac --- /dev/null +++ b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/SpGeMM/ExpandCOO.fs @@ -0,0 +1,77 @@ +module GraphBLAS.FSharp.Tests.Backend.Matrix.SpGeMM.ExpandCOO + +open Expecto +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend.Quotes +open GraphBLAS.FSharp.Objects +open GraphBLAS.FSharp.Objects.ClContextExtensions +open GraphBLAS.FSharp.Objects.MatrixExtensions +open GraphBLAS.FSharp.Test +open GraphBLAS.FSharp.Tests +open GraphBLAS.FSharp.Tests.Backend + +let context = Context.defaultContext.ClContext + +let processor = Context.defaultContext.Queue + +let config = + { Utils.defaultConfig with + arbitrary = [ typeof ] } + +let makeGeneralTest zero isEqual opAdd opMul testFun (leftArray: 'a [,], rightArray: 'a [,]) = + + let leftMatrix = + Utils.createMatrixFromArray2D COO leftArray (isEqual zero) + + let rightMatrix = + Utils.createMatrixFromArray2D CSR rightArray (isEqual zero) + + if leftMatrix.NNZ > 0 && rightMatrix.NNZ > 0 then + let clLeftMatrix = leftMatrix.ToDevice context + let clRightMatrix = rightMatrix.ToDevice context + + let (clMatrixActual: ClMatrix.COO<_> option) = + testFun processor HostInterop clLeftMatrix clRightMatrix + + let expected = + HostPrimitives.array2DMultiplication zero opMul opAdd leftArray rightArray + |> fun array -> Matrix.COO.FromArray2D(array, isEqual zero) + + match clMatrixActual with + | Some clMatrixActual -> + + let matrixActual = clMatrixActual.ToHost processor + clMatrixActual.Dispose processor + + Utils.compareCOOMatrix isEqual matrixActual expected + | None -> + "Expected should be empty" + |> Expect.isTrue (expected.NNZ = 0) + +let createGeneralTest (zero: 'a) isEqual (opAddQ, opAdd) (opMulQ, opMul) testFun = + testFun opAddQ opMulQ context Utils.defaultWorkGroupSize + |> makeGeneralTest zero isEqual opAdd opMul + |> testPropertyWithConfig config $"test on %A{typeof<'a>}" + +let generalTests = + [ createGeneralTest 0 (=) ArithmeticOperations.intAdd ArithmeticOperations.intMul Operations.SpGeMM.COO.expand + + if Utils.isFloat64Available context.ClDevice then + createGeneralTest + 0.0 + Utils.floatIsEqual + ArithmeticOperations.floatAdd + ArithmeticOperations.floatMul + Operations.SpGeMM.COO.expand + + createGeneralTest + 0.0f + Utils.float32IsEqual + ArithmeticOperations.float32Add + ArithmeticOperations.float32Mul + Operations.SpGeMM.COO.expand + createGeneralTest false (=) ArithmeticOperations.boolAdd ArithmeticOperations.boolMul Operations.SpGeMM.COO.expand ] + |> testList "General" + +let tests = + testList "SpGeMM.Expand" [ generalTests ] diff --git a/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj b/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj index 80f70253..8fc687dd 100644 --- a/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj +++ b/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj @@ -20,6 +20,7 @@ + @@ -51,6 +52,7 @@ + diff --git a/tests/GraphBLAS-sharp.Tests/Helpers.fs b/tests/GraphBLAS-sharp.Tests/Helpers.fs index 5f8d043b..0db4a28c 100644 --- a/tests/GraphBLAS-sharp.Tests/Helpers.fs +++ b/tests/GraphBLAS-sharp.Tests/Helpers.fs @@ -337,6 +337,48 @@ module HostPrimitives = op leftElement rightElement + let MSBFSParents matrix source = + let opAdd a b = + let result = min a b + if result = -1 then None else Some result + + let opMul (a: int) _ = if a = -1 then None else Some a + + let array2DMultiplication = array2DMultiplication -1 opMul opAdd + + let front = + Array2D.create + <| Seq.length source + <| Array2D.length1 matrix + <| -1 + + source + |> Seq.iteri (fun row vertex -> + front.[row, vertex] <- vertex) + + let parents = + Array2D.create + <| Seq.length source + <| Array2D.length1 matrix + <| -1 + + let mutable stop = false + + while not stop do + let newFront = array2DMultiplication front matrix + stop <- true + + newFront + |> Array2D.iteri (fun i j value -> + if value <> -1 then + if parents.[i, j] <> -1 then + newFront.[i, j] <- -1 + else + stop <- false + parents.[i, j] <- value) + + front + module Context = type TestContext = { ClContext: ClContext diff --git a/tests/GraphBLAS-sharp.Tests/Program.fs b/tests/GraphBLAS-sharp.Tests/Program.fs index 5b7b7908..47768522 100644 --- a/tests/GraphBLAS-sharp.Tests/Program.fs +++ b/tests/GraphBLAS-sharp.Tests/Program.fs @@ -1,7 +1,6 @@ open Expecto open GraphBLAS.FSharp.Tests open GraphBLAS.FSharp.Tests.Backend -open GraphBLAS.FSharp.Tests.Backend.Matrix let matrixTests = testList @@ -18,6 +17,7 @@ let matrixTests = Matrix.Kronecker.tests Matrix.SpGeMM.Expand.tests + Matrix.SpGeMM.ExpandCOO.tests Matrix.SpGeMM.Masked.tests ] |> testSequenced @@ -92,7 +92,10 @@ let algorithmsTests = testList "Algorithms tests" [ Algorithms.BFS.tests - Algorithms.SSSP.tests ] + Algorithms.SSSP.tests + + Algorithms.MSBFS.levelsTests + Algorithms.MSBFS.parentsTests ] |> testSequenced let deviceTests = From e78e50ea65bcf31191721fb2ff230e5ffeba3b8b Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Fri, 17 Nov 2023 14:10:32 +0300 Subject: [PATCH 12/23] refactor: formatting --- .../Algorithms/MSBFS.fs | 70 +++++++++++-------- src/GraphBLAS-sharp.Backend/Common/ClArray.fs | 32 +++++---- .../Matrix/COO/Intersect.fs | 16 +++-- .../Matrix/COO/Matrix.fs | 16 +++-- .../Matrix/COO/Merge.fs | 16 ++--- src/GraphBLAS-sharp.Backend/Matrix/Matrix.fs | 15 ++-- src/GraphBLAS-sharp.Backend/Objects/Matrix.fs | 9 ++- .../Operations/Operations.fs | 3 +- .../Operations/SpGeMM/Expand.fs | 6 +- .../Quotes/Arithmetic.fs | 12 ++-- .../Vector/Sparse/Vector.fs | 4 +- src/GraphBLAS-sharp.Backend/Vector/Vector.fs | 11 ++- .../Backend/Algorithms/MSBFS.fs | 52 ++++++++------ tests/GraphBLAS-sharp.Tests/Helpers.fs | 24 ++++--- 14 files changed, 176 insertions(+), 110 deletions(-) diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index 2607df67..21eeb023 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -14,17 +14,22 @@ open GraphBLAS.FSharp.Backend.Matrix.COO module internal MSBFS = let private frontExclude (clContext: ClContext) workGroupSize = - let excludeValues = ClArray.excludeElements clContext workGroupSize + let excludeValues = + ClArray.excludeElements clContext workGroupSize - let excludeIndices = ClArray.excludeElements clContext workGroupSize + let excludeIndices = + ClArray.excludeElements clContext workGroupSize fun (queue: MailboxProcessor<_>) allocationMode (front: ClMatrix.COO<_>) (intersection: ClArray) -> - let newRows = excludeIndices queue allocationMode intersection front.Rows + let newRows = + excludeIndices queue allocationMode intersection front.Rows - let newColumns = excludeIndices queue allocationMode intersection front.Columns + let newColumns = + excludeIndices queue allocationMode intersection front.Columns - let newValues = excludeValues queue allocationMode intersection front.Values + let newValues = + excludeValues queue allocationMode intersection front.Values match newRows, newColumns, newValues with | Some rows, Some columns, Some values -> @@ -42,17 +47,21 @@ module internal MSBFS = let updateFront = frontExclude clContext workGroupSize - let mergeDisjoint = Matrix.mergeDisjoint clContext workGroupSize + let mergeDisjoint = + Matrix.mergeDisjoint clContext workGroupSize - let findIntersection = Intersect.findKeysIntersection clContext workGroupSize + let findIntersection = + Intersect.findKeysIntersection clContext workGroupSize fun (queue: MailboxProcessor<_>) allocationMode (front: ClMatrix.COO<_>) (levels: ClMatrix.COO<_>) -> // Find intersection of levels and front indices. - let intersection = findIntersection queue DeviceOnly front levels + let intersection = + findIntersection queue DeviceOnly front levels // Remove mutual elements - let newFront = updateFront queue allocationMode front intersection + let newFront = + updateFront queue allocationMode front intersection intersection.Free queue @@ -75,15 +84,15 @@ module internal MSBFS = let copy = Matrix.copy clContext workGroupSize - let updateFrontAndLevels = updateFrontAndLevels clContext workGroupSize + let updateFrontAndLevels = + updateFrontAndLevels clContext workGroupSize fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int list) -> let vertexCount = matrix.RowCount let sourceVertexCount = source.Length let startMatrix = - source - |> List.mapi (fun i vertex -> i, vertex, 1) + source |> List.mapi (fun i vertex -> i, vertex, 1) let mutable levels = startMatrix @@ -124,11 +133,11 @@ module internal MSBFS = workGroupSize = - let SSBFS = BFS.singleSourceSparse add mul clContext workGroupSize + let SSBFS = + BFS.singleSourceSparse add mul clContext workGroupSize fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int list) -> - source - |> List.map (SSBFS queue matrix) + source |> List.map (SSBFS queue matrix) module Parents = let private updateFrontAndParents (clContext: ClContext) workGroupSize = @@ -136,38 +145,43 @@ module internal MSBFS = // every front value should be equal to its column number let frontExclude = frontExclude clContext workGroupSize - let mergeDisjoint = Matrix.mergeDisjoint clContext workGroupSize + let mergeDisjoint = + Matrix.mergeDisjoint clContext workGroupSize - let findIntersection = Intersect.findKeysIntersection clContext workGroupSize + let findIntersection = + Intersect.findKeysIntersection clContext workGroupSize fun (queue: MailboxProcessor) allocationMode (front: ClMatrix.COO<_>) (parents: ClMatrix.COO<_>) -> // Find intersection of levels and front indices. - let intersection = findIntersection queue DeviceOnly front parents + let intersection = + findIntersection queue DeviceOnly front parents // Remove mutual elements - let newFront = frontExclude queue allocationMode front intersection + let newFront = + frontExclude queue allocationMode front intersection intersection.Free queue match newFront with | Some f -> // Update levels - let resultFront = - { f with Values = f.Columns } + let resultFront = { f with Values = f.Columns } let newLevels = mergeDisjoint queue parents f newLevels, Some resultFront | _ -> parents, None - let run<'a when 'a: struct> - (clContext: ClContext) - workGroupSize - = + let run<'a when 'a: struct> (clContext: ClContext) workGroupSize = let spGeMM = - Operations.SpGeMM.COO.expand (ArithmeticOperations.min -1) (ArithmeticOperations.fst -1) clContext workGroupSize - - let updateFrontAndLevels = updateFrontAndParents clContext workGroupSize + Operations.SpGeMM.COO.expand + (ArithmeticOperations.min -1) + (ArithmeticOperations.fst -1) + clContext + workGroupSize + + let updateFrontAndLevels = + updateFrontAndParents clContext workGroupSize fun (queue: MailboxProcessor) (inputMatrix: ClMatrix<'a>) (source: int list) -> let vertexCount = inputMatrix.RowCount diff --git a/src/GraphBLAS-sharp.Backend/Common/ClArray.fs b/src/GraphBLAS-sharp.Backend/Common/ClArray.fs index 168f170a..8eaa4847 100644 --- a/src/GraphBLAS-sharp.Backend/Common/ClArray.fs +++ b/src/GraphBLAS-sharp.Backend/Common/ClArray.fs @@ -146,9 +146,7 @@ module ClArray = let kernel = program.GetKernel() - processor.Post( - Msg.MsgSetArguments(fun () -> kernel.KernelFunc ndRange source destination source.Length) - ) + processor.Post(Msg.MsgSetArguments(fun () -> kernel.KernelFunc ndRange source destination source.Length)) processor.Post(Msg.CreateRunMsg<_, _> kernel) @@ -829,7 +827,8 @@ module ClArray = /// The function to transform elements of the array. /// OpenCL context. /// Should be a power of 2 and greater than 1. - let mapInPlace<'a> (op: Expr<'a -> 'a>) (clContext: ClContext) workGroupSize = Map.mapInPlace op clContext workGroupSize + let mapInPlace<'a> (op: Expr<'a -> 'a>) (clContext: ClContext) workGroupSize = + Map.mapInPlace op clContext workGroupSize /// /// Builds a new array whose elements are the results of applying the given function @@ -839,7 +838,8 @@ module ClArray = /// The function to transform elements of the array. /// OpenCL context. /// Should be a power of 2 and greater than 1. - let mapWithValue<'a, 'b, 'c> (clContext: ClContext) workGroupSize (op: Expr<'a -> 'b -> 'c>) = Map.mapWithValue clContext workGroupSize op + let mapWithValue<'a, 'b, 'c> (clContext: ClContext) workGroupSize (op: Expr<'a -> 'b -> 'c>) = + Map.mapWithValue clContext workGroupSize op /// /// Builds a new array whose elements are the results of applying the given function @@ -851,7 +851,8 @@ module ClArray = /// The function to transform the pairs of the input elements. /// OpenCL context. /// Should be a power of 2 and greater than 1. - let map2<'a, 'b, 'c> (map: Expr<'a -> 'b -> 'c>) (clContext: ClContext) workGroupSize = Map.map2 map clContext workGroupSize + let map2<'a, 'b, 'c> (map: Expr<'a -> 'b -> 'c>) (clContext: ClContext) workGroupSize = + Map.map2 map clContext workGroupSize /// /// Fills the third given array with the results of applying the given function @@ -863,7 +864,8 @@ module ClArray = /// The function to transform the pairs of the input elements. /// OpenCL context. /// Should be a power of 2 and greater than 1. - let map2InPlace<'a, 'b, 'c> (map: Expr<'a -> 'b -> 'c>) (clContext: ClContext) workGroupSize = Map.map2InPlace map clContext workGroupSize + let map2InPlace<'a, 'b, 'c> (map: Expr<'a -> 'b -> 'c>) (clContext: ClContext) workGroupSize = + Map.map2InPlace map clContext workGroupSize /// /// Excludes elements, pointed by the bitmap. @@ -872,22 +874,28 @@ module ClArray = /// Should be a power of 2 and greater than 1. let excludeElements (clContext: ClContext) workGroupSize = - let invert = mapInPlace ArithmeticOperations.intNotQ clContext workGroupSize + let invert = + mapInPlace ArithmeticOperations.intNotQ clContext workGroupSize - let prefixSum = PrefixSum.standardExcludeInPlace clContext workGroupSize + let prefixSum = + PrefixSum.standardExcludeInPlace clContext workGroupSize - let scatter = Scatter.lastOccurrence clContext workGroupSize + let scatter = + Scatter.lastOccurrence clContext workGroupSize fun (queue: MailboxProcessor<_>) allocationMode (excludeBitmap: ClArray) (inputArray: ClArray<'a>) -> invert queue excludeBitmap - let length = (prefixSum queue excludeBitmap).ToHostAndFree queue + let length = + (prefixSum queue excludeBitmap) + .ToHostAndFree queue if length = 0 then None else - let result = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, length) + let result = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, length) scatter queue excludeBitmap inputArray result diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs index 643fa00c..318ce885 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs @@ -16,25 +16,29 @@ module internal Intersect = if gid < bitmapSize then - let index: uint64 = ((uint64 leftRows.[gid]) <<< 32) ||| (uint64 leftColumns.[gid]) + let index: uint64 = + ((uint64 leftRows.[gid]) <<< 32) + ||| (uint64 leftColumns.[gid]) - let intersect = (%Search.Bin.existsByKey2D) bitmapSize index rightRows rightColumns + let intersect = + (%Search.Bin.existsByKey2D) bitmapSize index rightRows rightColumns if intersect then bitmap.[gid] <- 1 else bitmap.[gid] <- 0 @> - let kernel = - clContext.Compile <| findIntersection + let kernel = clContext.Compile <| findIntersection fun (processor: MailboxProcessor<_>) allocationMode (leftMatrix: ClMatrix.COO<'a>) (rightMatrix: ClMatrix.COO<'b>) -> let bitmapSize = leftMatrix.NNZ - let bitmap = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, bitmapSize) + let bitmap = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, bitmapSize) - let ndRange = Range1D.CreateValid(bitmapSize, workGroupSize) + let ndRange = + Range1D.CreateValid(bitmapSize, workGroupSize) let kernel = kernel.GetKernel() diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs index 4d7315fa..15fb0e24 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs @@ -255,7 +255,8 @@ module Matrix = /// /// OpenCL context. /// Should be a power of 2 and greater than 1. - let mergeDisjoint (clContext: ClContext) workGroupSize = Merge.runDisjoint clContext workGroupSize + let mergeDisjoint (clContext: ClContext) workGroupSize = + Merge.runDisjoint clContext workGroupSize let ofList (clContext: ClContext) allocationMode rowCount columnCount (elements: (int * int * 'a) list) = let rows, columns, values = @@ -278,7 +279,8 @@ module Matrix = /// Should be a power of 2 and greater than 1. let subRows (clContext: ClContext) workGroupSize = - let upperBound = ClArray.upperBound clContext workGroupSize + let upperBound = + ClArray.upperBound clContext workGroupSize let blit = ClArray.blit clContext workGroupSize @@ -298,8 +300,14 @@ module Matrix = let lastRowClCell = clContext.CreateClCell(startRow + count) // extract rows - let firstIndex = (upperBound processor matrix.Rows firstRowClCell).ToHostAndFree processor - let lastIndex = (upperBound processor matrix.Rows lastRowClCell).ToHostAndFree processor - 1 + let firstIndex = + (upperBound processor matrix.Rows firstRowClCell) + .ToHostAndFree processor + + let lastIndex = + (upperBound processor matrix.Rows lastRowClCell) + .ToHostAndFree processor + - 1 firstRowClCell.Free processor lastRowClCell.Free processor diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Merge.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Merge.fs index cae0817c..1401f3cc 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Merge.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Merge.fs @@ -201,23 +201,19 @@ module Merge = fun (processor: MailboxProcessor<_>) (leftMatrix: ClMatrix.COO<'a>) (rightMatrix: ClMatrix.COO<'a>) -> - let length = leftMatrix.Columns.Length + rightMatrix.Columns.Length + let length = + leftMatrix.Columns.Length + + rightMatrix.Columns.Length let rows, cols, leftValues, rightValues, isLeft = merge processor leftMatrix rightMatrix - let ndRange = Range1D.CreateValid(length, workGroupSize) + let ndRange = + Range1D.CreateValid(length, workGroupSize) let mergeValuesKernel = mergeValuesKernel.GetKernel() processor.Post( - Msg.MsgSetArguments - (fun () -> - mergeValuesKernel.KernelFunc - ndRange - length - leftValues - rightValues - isLeft) + Msg.MsgSetArguments(fun () -> mergeValuesKernel.KernelFunc ndRange length leftValues rightValues isLeft) ) processor.Post(Msg.CreateRunMsg<_, _>(mergeValuesKernel)) diff --git a/src/GraphBLAS-sharp.Backend/Matrix/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/Matrix.fs index 789ff43a..b15c85e1 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/Matrix.fs @@ -76,7 +76,9 @@ module Matrix = Sparse.Vector.copyTo clContext workGroupSize fun (processor: MailboxProcessor<_>) (source: ClMatrix<'a>) (destination: ClMatrix<'a>) -> - if source.NNZ <> destination.NNZ || source.RowCount <> destination.RowCount || source.ColumnCount <> destination.ColumnCount then + if source.NNZ <> destination.NNZ + || source.RowCount <> destination.RowCount + || source.ColumnCount <> destination.ColumnCount then failwith "Two matrices are not of the same size or they have different number of non-zero elements" match source, destination with @@ -93,10 +95,13 @@ module Matrix = copyTo processor s.ColumnPointers d.ColumnPointers copyDataTo processor s.Values d.Values | ClMatrix.LIL s, ClMatrix.LIL d -> - List.iter2 (fun sourceVector destinationVector -> - match sourceVector, destinationVector with - | Some sv, Some dv -> vectorCopyTo processor sv dv - | _ -> failwith "Vectors of LIL matrix are not of the same size") s.Rows d.Rows + List.iter2 + (fun sourceVector destinationVector -> + match sourceVector, destinationVector with + | Some sv, Some dv -> vectorCopyTo processor sv dv + | _ -> failwith "Vectors of LIL matrix are not of the same size") + s.Rows + d.Rows | _ -> failwith "Matrix formats are not matching" /// diff --git a/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs b/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs index b36f1da9..766925aa 100644 --- a/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs @@ -94,7 +94,14 @@ module ClMatrix = |> Seq.choose id |> Seq.iter (fun vector -> vector.Dispose q) - member this.NNZ = this.Rows |> List.fold (fun acc row -> match row with | Some r -> acc + r.NNZ | None -> acc) 0 + member this.NNZ = + this.Rows + |> List.fold + (fun acc row -> + match row with + | Some r -> acc + r.NNZ + | None -> acc) + 0 type Tuple<'elem when 'elem: struct> = { Context: ClContext diff --git a/src/GraphBLAS-sharp.Backend/Operations/Operations.fs b/src/GraphBLAS-sharp.Backend/Operations/Operations.fs index c6950832..2e99b7dc 100644 --- a/src/GraphBLAS-sharp.Backend/Operations/Operations.fs +++ b/src/GraphBLAS-sharp.Backend/Operations/Operations.fs @@ -133,7 +133,8 @@ module Operations = fun (processor: MailboxProcessor<_>) (leftVector: ClVector<'a>) (rightVector: ClVector<'b>) (resultVector: ClVector<'c>) -> match leftVector, rightVector, resultVector with - | ClVector.Dense left, ClVector.Dense right, ClVector.Dense result -> map2Dense processor left right result + | ClVector.Dense left, ClVector.Dense right, ClVector.Dense result -> + map2Dense processor left right result | _ -> failwith "Unsupported vector format" /// diff --git a/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs b/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs index 407a878c..45ff0df0 100644 --- a/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs +++ b/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs @@ -522,7 +522,8 @@ module internal Expand = let runManySteps opAdd opMul (clContext: ClContext) workGroupSize = - let compress = COO.Matrix.compressRows clContext workGroupSize + let compress = + COO.Matrix.compressRows clContext workGroupSize let gather = Common.Gather.run clContext workGroupSize @@ -540,7 +541,8 @@ module internal Expand = fun (processor: MailboxProcessor<_>) allocationMode maxAllocSize generalLength (leftMatrix: ClMatrix.COO<'a>) segmentLengths rightMatrixRowsNNZ (rightMatrix: ClMatrix.CSR<'b>) -> - let leftRowPointers = compress processor allocationMode leftMatrix.Rows leftMatrix.RowCount + let leftRowPointers = + compress processor allocationMode leftMatrix.Rows leftMatrix.RowCount // extract segment lengths by left matrix rows pointers let segmentPointersByLeftMatrixRows = diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs index 9db81a58..03107f05 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs @@ -191,8 +191,7 @@ module ArithmeticOperations = | Some true -> None | _ -> Some true @> - let intNotQ = - <@ fun x -> if x = 0 then 1 else 0 @> + let intNotQ = <@ fun x -> if x = 0 then 1 else 0 @> let inline private binOpQ zero op = <@ fun (left: 'a) (right: 'a) -> @@ -251,11 +250,14 @@ module ArithmeticOperations = let min zero = <@ fun x y -> let result = min x y - if result = zero then None else Some result @> + + if result = zero then + None + else + Some result @> let fst zero = - <@ fun x _ -> - if x = zero then None else Some x @> + <@ fun x _ -> if x = zero then None else Some x @> //PageRank specific let squareOfDifference = diff --git a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs index f8d1a35f..1a7fb8f7 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs @@ -27,8 +27,8 @@ module Vector = let copyDataTo = ClArray.copyTo clContext workGroupSize fun (processor: MailboxProcessor<_>) (source: Sparse<'a>) (destination: Sparse<'a>) -> - copyTo processor source.Indices destination.Indices - copyDataTo processor source.Values destination.Values + copyTo processor source.Indices destination.Indices + copyDataTo processor source.Values destination.Values let map = Map.run diff --git a/src/GraphBLAS-sharp.Backend/Vector/Vector.fs b/src/GraphBLAS-sharp.Backend/Vector/Vector.fs index 623d59b1..9494990e 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Vector.fs @@ -46,12 +46,17 @@ module Vector = /// OpenCL context. /// Should be a power of 2 and greater than 1. let ofList (clContext: ClContext) workGroupSize = - let denseOfList = Dense.Vector.ofList clContext workGroupSize + let denseOfList = + Dense.Vector.ofList clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode format size (elements: (int * 'a) list) -> match format with - | Sparse -> Sparse.Vector.ofList clContext allocationMode size elements |> ClVector.Sparse - | Dense -> denseOfList processor allocationMode size elements |> ClVector.Dense + | Sparse -> + Sparse.Vector.ofList clContext allocationMode size elements + |> ClVector.Sparse + | Dense -> + denseOfList processor allocationMode size elements + |> ClVector.Dense /// /// Creates new vector with the values from the given one. diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs index 8cc65562..083ea67f 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs @@ -17,25 +17,32 @@ let makeLevelsTest context queue bfs (matrix: int [,]) = let graph = undirectedFromArray2D matrix 0 let largestComponent = - ConnectedComponents.largestComponent graph + ConnectedComponents.largestComponent graph if largestComponent.Length > 1 then let sourceVertexCount = max 2 (largestComponent.Length / 10) - let source = largestComponent.[0 .. sourceVertexCount] |> Array.toList + + let source = + largestComponent.[0..sourceVertexCount] + |> Array.toList let matrixHost = - Utils.createMatrixFromArray2D CSR matrix ((=) 0) + Utils.createMatrixFromArray2D CSR matrix ((=) 0) + let matrixDevice = matrixHost.ToDevice context - let expectedArray2D: int [,] = Array2D.zeroCreate sourceVertexCount (Array2D.length2 matrix) + let expectedArray2D: int [,] = + Array2D.zeroCreate sourceVertexCount (Array2D.length2 matrix) source - |> Seq.iteri (fun i vertex -> - (snd (BFS.runUndirected graph vertex)) - |> Utils.createArrayFromDictionary (Array2D.length1 matrix) 0 - |> Array.iteri (fun col value -> expectedArray2D.[i, col] <- value)) + |> Seq.iteri + (fun i vertex -> + (snd (BFS.runUndirected graph vertex)) + |> Utils.createArrayFromDictionary (Array2D.length1 matrix) 0 + |> Array.iteri (fun col value -> expectedArray2D.[i, col] <- value)) - let expected = Utils.createMatrixFromArray2D COO expectedArray2D ((=) 0) + let expected = + Utils.createMatrixFromArray2D COO expectedArray2D ((=) 0) let actual: ClMatrix = bfs queue matrixDevice source let actual = actual.ToHostAndFree queue @@ -43,8 +50,7 @@ let makeLevelsTest context queue bfs (matrix: int [,]) = matrixDevice.Dispose queue match actual, expected with - | Matrix.COO a, Matrix.COO e -> - Utils.compareCOOMatrix (=) a e + | Matrix.COO a, Matrix.COO e -> Utils.compareCOOMatrix (=) a e | _ -> failwith "Not implemented" let createLevelsTest context queue testFun = @@ -72,18 +78,25 @@ let makeParentsTest context queue bfs (matrix: int [,]) = let graph = undirectedFromArray2D matrix -1 let largestComponent = - ConnectedComponents.largestComponent graph + ConnectedComponents.largestComponent graph if largestComponent.Length > 1 then let sourceVertexCount = max 2 (largestComponent.Length / 10) - let source = largestComponent.[0 .. sourceVertexCount] |> Array.toList + + let source = + largestComponent.[0..sourceVertexCount] + |> Array.toList let matrixHost = - Utils.createMatrixFromArray2D CSR matrix ((=) -1) + Utils.createMatrixFromArray2D CSR matrix ((=) -1) + let matrixDevice = matrixHost.ToDevice context - let expectedArray2D = HostPrimitives.MSBFSParents matrix source - let expected = Utils.createMatrixFromArray2D COO expectedArray2D ((=) -1) + let expectedArray2D = + HostPrimitives.MSBFSParents matrix source + + let expected = + Utils.createMatrixFromArray2D COO expectedArray2D ((=) -1) let actual: ClMatrix = bfs queue matrixDevice source let actual = actual.ToHostAndFree queue @@ -91,8 +104,7 @@ let makeParentsTest context queue bfs (matrix: int [,]) = matrixDevice.Dispose queue match actual, expected with - | Matrix.COO a, Matrix.COO e -> - Utils.compareCOOMatrix (=) a e + | Matrix.COO a, Matrix.COO e -> Utils.compareCOOMatrix (=) a e | _ -> failwith "Not implemented" let createParentsTest context queue testFun = @@ -105,9 +117,7 @@ let parentsTestFixtures (testContext: TestContext) = let queue = testContext.Queue let bfsLevels = - Algorithms.MSBFS.runParents - context - workGroupSize + Algorithms.MSBFS.runParents context workGroupSize createLevelsTest context queue bfsLevels ] diff --git a/tests/GraphBLAS-sharp.Tests/Helpers.fs b/tests/GraphBLAS-sharp.Tests/Helpers.fs index 0db4a28c..612b7601 100644 --- a/tests/GraphBLAS-sharp.Tests/Helpers.fs +++ b/tests/GraphBLAS-sharp.Tests/Helpers.fs @@ -340,7 +340,11 @@ module HostPrimitives = let MSBFSParents matrix source = let opAdd a b = let result = min a b - if result = -1 then None else Some result + + if result = -1 then + None + else + Some result let opMul (a: int) _ = if a = -1 then None else Some a @@ -353,8 +357,7 @@ module HostPrimitives = <| -1 source - |> Seq.iteri (fun row vertex -> - front.[row, vertex] <- vertex) + |> Seq.iteri (fun row vertex -> front.[row, vertex] <- vertex) let parents = Array2D.create @@ -369,13 +372,14 @@ module HostPrimitives = stop <- true newFront - |> Array2D.iteri (fun i j value -> - if value <> -1 then - if parents.[i, j] <> -1 then - newFront.[i, j] <- -1 - else - stop <- false - parents.[i, j] <- value) + |> Array2D.iteri + (fun i j value -> + if value <> -1 then + if parents.[i, j] <> -1 then + newFront.[i, j] <- -1 + else + stop <- false + parents.[i, j] <- value) front From 95941af50a76531c9b5e2dc08f96212a34d81658 Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Mon, 20 Nov 2023 14:55:12 +0300 Subject: [PATCH 13/23] wip: tests and msbfs bug fix --- .../Algorithms/MSBFS.fs | 14 +- src/GraphBLAS-sharp.Backend/Common/Map.fs | 15 +- .../Matrix/COO/Intersect.fs | 4 +- .../Matrix/COO/Matrix.fs | 2 +- .../Matrix/CSR/Matrix.fs | 3 +- src/GraphBLAS-sharp.Backend/Quotes/Search.fs | 2 +- .../Backend/Algorithms/MSBFS.fs | 8 +- .../Backend/Common/ClArray/ExcludeElements.fs | 61 +++++ .../Backend/Matrix/Intersect.fs | 71 ++++++ .../Backend/Matrix/Merge.fs | 50 +++- tests/GraphBLAS-sharp.Tests/Generators.fs | 226 +++++++++++++++++- .../GraphBLAS-sharp.Tests.fsproj | 2 + tests/GraphBLAS-sharp.Tests/Program.fs | 168 ++++--------- 13 files changed, 491 insertions(+), 135 deletions(-) create mode 100644 tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/ExcludeElements.fs create mode 100644 tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index 21eeb023..8c5ed016 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -8,6 +8,7 @@ open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Objects.ClMatrix open GraphBLAS.FSharp.Objects.ArraysExtensions open GraphBLAS.FSharp.Objects.ClContextExtensions +open GraphBLAS.FSharp.Objects.ClCellExtensions open GraphBLAS.FSharp.Backend.Matrix.LIL open GraphBLAS.FSharp.Backend.Matrix.COO @@ -50,10 +51,12 @@ module internal MSBFS = let mergeDisjoint = Matrix.mergeDisjoint clContext workGroupSize + let setLevel = ClArray.fill clContext workGroupSize + let findIntersection = Intersect.findKeysIntersection clContext workGroupSize - fun (queue: MailboxProcessor<_>) allocationMode (front: ClMatrix.COO<_>) (levels: ClMatrix.COO<_>) -> + fun (queue: MailboxProcessor<_>) allocationMode (level: int) (front: ClMatrix.COO<_>) (levels: ClMatrix.COO<_>) -> // Find intersection of levels and front indices. let intersection = @@ -68,7 +71,14 @@ module internal MSBFS = match newFront with | Some f -> // Update levels + let levelClCell = clContext.CreateClCell level + + setLevel queue levelClCell 0 f.Values.Length f.Values + + levelClCell.Free queue + let newLevels = mergeDisjoint queue levels f + newLevels, newFront | _ -> levels, None @@ -114,7 +124,7 @@ module internal MSBFS = | Some newFrontier -> front.Dispose queue //Filtering visited vertices - match updateFrontAndLevels queue DeviceOnly newFrontier levels with + match updateFrontAndLevels queue DeviceOnly level newFrontier levels with | l, Some f -> front <- f levels.Dispose queue diff --git a/src/GraphBLAS-sharp.Backend/Common/Map.fs b/src/GraphBLAS-sharp.Backend/Common/Map.fs index 19cda5f4..2459e1ef 100644 --- a/src/GraphBLAS-sharp.Backend/Common/Map.fs +++ b/src/GraphBLAS-sharp.Backend/Common/Map.fs @@ -3,6 +3,7 @@ open Brahma.FSharp open Microsoft.FSharp.Quotations open GraphBLAS.FSharp.Objects.ClContextExtensions +open GraphBLAS.FSharp.Objects.ClCellExtensions module Map = /// @@ -15,11 +16,11 @@ module Map = let map<'a, 'b> (op: Expr<'a -> 'b>) (clContext: ClContext) workGroupSize = let map = - <@ fun (ndRange: Range1D) lenght (inputArray: ClArray<'a>) (result: ClArray<'b>) -> + <@ fun (ndRange: Range1D) length (inputArray: ClArray<'a>) (result: ClArray<'b>) -> let gid = ndRange.GlobalID0 - if gid < lenght then + if gid < length then result.[gid] <- (%op) inputArray.[gid] @> let kernel = clContext.Compile map @@ -50,11 +51,11 @@ module Map = let mapInPlace<'a> (op: Expr<'a -> 'a>) (clContext: ClContext) workGroupSize = let map = - <@ fun (ndRange: Range1D) lenght (inputArray: ClArray<'a>) -> + <@ fun (ndRange: Range1D) length (inputArray: ClArray<'a>) -> let gid = ndRange.GlobalID0 - if gid < lenght then + if gid < length then inputArray.[gid] <- (%op) inputArray.[gid] @> let kernel = clContext.Compile map @@ -81,11 +82,11 @@ module Map = let mapWithValue<'a, 'b, 'c> (clContext: ClContext) workGroupSize (op: Expr<'a -> 'b -> 'c>) = let map = - <@ fun (ndRange: Range1D) lenght (value: ClCell<'a>) (inputArray: ClArray<'b>) (result: ClArray<'c>) -> + <@ fun (ndRange: Range1D) length (value: ClCell<'a>) (inputArray: ClArray<'b>) (result: ClArray<'c>) -> let gid = ndRange.GlobalID0 - if gid < lenght then + if gid < length then result.[gid] <- (%op) value.Value inputArray.[gid] @> let kernel = clContext.Compile map @@ -108,6 +109,8 @@ module Map = processor.Post(Msg.CreateRunMsg<_, _>(kernel)) + valueClCell.Free processor + result /// diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs index 318ce885..d5a326a3 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Intersect.fs @@ -12,7 +12,7 @@ module internal Intersect = <@ fun (ndRange: Range1D) (leftNNZ: int) (rightNNZ: int) (leftRows: ClArray) (leftColumns: ClArray) (rightRows: ClArray) (rightColumns: ClArray) (bitmap: ClArray) -> let gid = ndRange.GlobalID0 - let bitmapSize = min leftNNZ rightNNZ + let bitmapSize = leftNNZ if gid < bitmapSize then @@ -21,7 +21,7 @@ module internal Intersect = ||| (uint64 leftColumns.[gid]) let intersect = - (%Search.Bin.existsByKey2D) bitmapSize index rightRows rightColumns + (%Search.Bin.existsByKey2D) rightNNZ index rightRows rightColumns if intersect then bitmap.[gid] <- 1 diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs index 15fb0e24..1dd458aa 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs @@ -243,7 +243,7 @@ module Matrix = /// /// OpenCL context. /// Should be a power of 2 and greater than 1. - let findIntersectionByKeys (clContext: ClContext) workGroupSize = + let findKeysIntersection (clContext: ClContext) workGroupSize = Intersect.findKeysIntersection clContext workGroupSize /// diff --git a/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs index 5cc805f9..0bea32dd 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs @@ -393,8 +393,7 @@ module Matrix = { Context = clContext RowCount = matrix.RowCount ColumnCount = matrix.ColumnCount - Rows = rows - NNZ = matrix.NNZ } + Rows = rows } /// /// Gets the number of non-zero elements in each row. diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Search.fs b/src/GraphBLAS-sharp.Backend/Quotes/Search.fs index 55600257..27687645 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Search.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Search.fs @@ -98,7 +98,7 @@ module Search = /// /// Searches value in array by two keys. - /// In case there is a value at the given keys position, it is returned. + /// In case there is a value at the given keys position, it returns true. /// let existsByKey2D<'a> = <@ fun length sourceIndex (rowIndices: ClArray) (columnIndices: ClArray) -> diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs index 083ea67f..89e6aa74 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs @@ -32,7 +32,7 @@ let makeLevelsTest context queue bfs (matrix: int [,]) = let matrixDevice = matrixHost.ToDevice context let expectedArray2D: int [,] = - Array2D.zeroCreate sourceVertexCount (Array2D.length2 matrix) + Array2D.zeroCreate sourceVertexCount (Array2D.length1 matrix) source |> Seq.iteri @@ -109,7 +109,7 @@ let makeParentsTest context queue bfs (matrix: int [,]) = let createParentsTest context queue testFun = testFun - |> makeLevelsTest context queue + |> makeParentsTest context queue |> testPropertyWithConfig config $"test on %A{typeof<'a>}" let parentsTestFixtures (testContext: TestContext) = @@ -119,7 +119,7 @@ let parentsTestFixtures (testContext: TestContext) = let bfsLevels = Algorithms.MSBFS.runParents context workGroupSize - createLevelsTest context queue bfsLevels ] + createParentsTest context queue bfsLevels ] let parentsTests = - TestCases.gpuTests "MSBFS Levels tests" parentsTestFixtures + TestCases.gpuTests "MSBFS Parents tests" parentsTestFixtures diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/ExcludeElements.fs b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/ExcludeElements.fs new file mode 100644 index 00000000..f938f745 --- /dev/null +++ b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/ExcludeElements.fs @@ -0,0 +1,61 @@ +module GraphBLAS.FSharp.Tests.Backend.Common.ClArray.ExcludeElements + +open Expecto +open Brahma.FSharp +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Test +open GraphBLAS.FSharp.Tests +open GraphBLAS.FSharp.Objects.ArraysExtensions +open GraphBLAS.FSharp.Objects.ClContextExtensions + +let context = Context.defaultContext.ClContext + +let processor = Context.defaultContext.Queue + +let config = + { Utils.defaultConfig with + arbitrary = [ typeof ] } + +let makeTest<'a> isEqual (zero: 'a) testFun ((array, bitmap): 'a array * int array) = + if array.Length > 0 && (Array.exists ((=) 1) bitmap) then + + let arrayCl = context.CreateClArray array + let bitmapCl = context.CreateClArray bitmap + + let actual: ClArray<'a> option = testFun processor HostInterop bitmapCl arrayCl + let actual = + actual + |> Option.map (fun a -> a.ToHostAndFree processor) + + arrayCl.Free processor + bitmapCl.Free processor + + let expected = + (bitmap, array) + ||> Array.zip + |> Array.filter (fun (bit, _) -> bit <> 1) + |> Array.unzip + |> snd + + match actual with + | Some actual -> + "Results must be the same" + |> Utils.compareArrays isEqual actual expected + | None -> + "Expected should be empty" + |> Expect.isEmpty expected + +let createTest<'a> (zero: 'a) isEqual = + ClArray.excludeElements context Utils.defaultWorkGroupSize + |> makeTest<'a> isEqual zero + |> testPropertyWithConfig config $"test on %A{typeof<'a>}" + +let tests = + [ createTest 0 (=) + + if Utils.isFloat64Available context.ClDevice then + createTest 0.0 (=) + + createTest 0.0f (=) + createTest false (=) ] + |> testList "ExcludeElements tests" diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs new file mode 100644 index 00000000..d8a9bf5a --- /dev/null +++ b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs @@ -0,0 +1,71 @@ +module GraphBLAS.FSharp.Tests.Backend.Matrix.Intersect + +open Expecto +open Brahma.FSharp +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend +open GraphBLAS.FSharp.Test +open GraphBLAS.FSharp.Tests +open GraphBLAS.FSharp.Tests.Context +open GraphBLAS.FSharp.Objects +open GraphBLAS.FSharp.Objects.ArraysExtensions + +let config = + { Utils.defaultConfig with + arbitrary = [ typeof ] } + +let workGroupSize = Utils.defaultWorkGroupSize + +let context = Context.defaultContext.ClContext +let processor = Context.defaultContext.Queue + +let makeTest isZero testFun (leftMatrix: 'a [,], rightMatrix: 'a [,]) = + + let m1 = Matrix.COO.FromArray2D(leftMatrix, isZero) + let m2 = Matrix.COO.FromArray2D(rightMatrix, isZero) + + if m1.NNZ > 0 && m2.NNZ > 0 then + let expected = + let leftIndices = + (m1.Rows, m1.Columns) + ||> Array.zip + + let rightIndices = + (m2.Rows, m2.Columns) + ||> Array.zip + + Array.init + <| m1.NNZ + <| fun i -> + let index = leftIndices.[i] + if Array.exists ((=) index) rightIndices then 1 else 0 + + let m1 = m1.ToDevice context + let m2 = m2.ToDevice context + + let actual: ClArray = + testFun processor ClContextExtensions.HostInterop m1 m2 + + let actual = actual.ToHostAndFree processor + + m1.Dispose processor + m2.Dispose processor + + // Check result + "Matrices should be equal" + |> Expect.equal actual expected + +let createTest isZero = + Matrix.COO.Matrix.findKeysIntersection context workGroupSize + |> makeTest isZero + |> testPropertyWithConfig config $"test on %A{typeof<'a>}" + +let tests = + [ createTest ((=) false) + createTest ((=) 0) + createTest ((=) 0uy) + createTest (Utils.float32IsEqual 0.0f) + + if Utils.isFloat64Available context.ClDevice then + createTest (Utils.floatIsEqual 0.0) ] + |> testList "Intersect tests" diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Merge.fs b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Merge.fs index 554fbff2..9d0b80dd 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Merge.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Merge.fs @@ -2,12 +2,14 @@ module GraphBLAS.FSharp.Tests.Backend.Matrix.Merge open Brahma.FSharp open Expecto +open GraphBLAS.FSharp.Test open Microsoft.FSharp.Collections open GraphBLAS.FSharp.Backend open GraphBLAS.FSharp.Tests open GraphBLAS.FSharp.Tests.Backend open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Objects.ArraysExtensions +open GraphBLAS.FSharp.Objects.MatrixExtensions let context = Context.defaultContext.ClContext @@ -108,6 +110,52 @@ let testsCOO = createTestCOO (=) false ] |> testList "COO" +let makeTestCOODisjoint isEqual zero testFun (leftArray: 'a [,], rightArray: 'a [,]) = + + let leftMatrix = + Matrix.COO.FromArray2D(leftArray, isEqual zero) + + let rightMatrix = + Matrix.COO.FromArray2D(rightArray, isEqual zero) + + if leftMatrix.NNZ > 0 && rightMatrix.NNZ > 0 then + + let clLeftMatrix = leftMatrix.ToDevice context + let clRightMatrix = rightMatrix.ToDevice context + + let actual: ClMatrix.COO<'a> = testFun processor clLeftMatrix clRightMatrix + let actual = actual.ToHostAndFree processor + + clLeftMatrix.Dispose processor + clRightMatrix.Dispose processor + + rightArray + |> Array2D.iteri (fun row column value -> leftArray.[row, column] <- value) + + let expected = Matrix.COO.FromArray2D(leftArray, isEqual zero) + + Utils.compareCOOMatrix isEqual actual expected + +let createTestCOODisjoint isEqual (zero: 'a) = + let configDisjoint = + {Utils.defaultConfig with + endSize = 10 + arbitrary = [ typeof ]} + + Matrix.COO.Merge.runDisjoint context Utils.defaultWorkGroupSize + |> makeTestCOODisjoint isEqual zero + |> testPropertyWithConfig configDisjoint $"test on {typeof<'a>}" + +let testsCOODisjoint = + [ createTestCOODisjoint (=) 0 + + if Utils.isFloat64Available context.ClDevice then + createTestCOODisjoint (=) 0.0 + + createTestCOODisjoint (=) 0.0f + createTestCOODisjoint (=) false ] + |> testList "COO Disjoint" + let makeTestCSR isEqual zero testFun (leftArray: 'a [,], rightArray: 'a [,]) = let leftMatrix = Matrix.CSR.FromArray2D(leftArray, isEqual zero) @@ -173,4 +221,4 @@ let testsCSR = |> testList "CSR" let allTests = - [ testsCSR; testsCOO ] |> testList "Merge" + [ testsCSR; testsCOO; testsCOODisjoint ] |> testList "Merge" diff --git a/tests/GraphBLAS-sharp.Tests/Generators.fs b/tests/GraphBLAS-sharp.Tests/Generators.fs index fec8f61e..3cb65f39 100644 --- a/tests/GraphBLAS-sharp.Tests/Generators.fs +++ b/tests/GraphBLAS-sharp.Tests/Generators.fs @@ -167,6 +167,67 @@ module Generators = |> genericSparseGenerator false Arb.generate |> Arb.fromGen + type PairOfSparseMatrices() = + static let pairOfMatricesOfEqualSizeGenerator (valuesGenerator: Gen<'a>) = + gen { + let! nRowsA, nColumnsA = dimension2DGenerator + let! nRowsB, nColumnsB = dimension2DGenerator + + let! matrixA = + valuesGenerator + |> Gen.array2DOfDim (nRowsA, nColumnsA) + + let! matrixB = + valuesGenerator + |> Gen.array2DOfDim (nRowsB, nColumnsB) + + return (matrixA, matrixB) + } + + static member IntType() = + pairOfMatricesOfEqualSizeGenerator + |> genericSparseGenerator 0 Arb.generate + |> Arb.fromGen + + static member FloatType() = + pairOfMatricesOfEqualSizeGenerator + |> genericSparseGenerator + 0. + (Arb.Default.NormalFloat() + |> Arb.toGen + |> Gen.map float) + |> Arb.fromGen + + static member Float32Type() = + pairOfMatricesOfEqualSizeGenerator + |> genericSparseGenerator 0.0f (normalFloat32Generator <| System.Random()) + |> Arb.fromGen + + static member SByteType() = + pairOfMatricesOfEqualSizeGenerator + |> genericSparseGenerator 0y Arb.generate + |> Arb.fromGen + + static member ByteType() = + pairOfMatricesOfEqualSizeGenerator + |> genericSparseGenerator 0uy Arb.generate + |> Arb.fromGen + + static member Int16Type() = + pairOfMatricesOfEqualSizeGenerator + |> genericSparseGenerator 0s Arb.generate + |> Arb.fromGen + + static member UInt16Type() = + pairOfMatricesOfEqualSizeGenerator + |> genericSparseGenerator 0us Arb.generate + |> Arb.fromGen + + static member BoolType() = + pairOfMatricesOfEqualSizeGenerator + |> genericSparseGenerator false Arb.generate + |> Arb.fromGen + type PairOfSparseMatricesOfEqualSize() = static let pairOfMatricesOfEqualSizeGenerator (valuesGenerator: Gen<'a>) = gen { @@ -403,6 +464,95 @@ module Generators = |> genericSparseGenerator false Arb.generate |> Arb.fromGen + type PairOfDisjointMatricesOfTheSameSize() = + static let pairOfDisjointMatricesGenerator zero (valuesGenerator: Gen<'a>) = + gen { + let! rowCount, columnCount = dimension2DGenerator + + let! matrixA = + valuesGenerator + |> Gen.array2DOfDim (rowCount, columnCount) + + let! matrixB = + valuesGenerator + |> Gen.array2DOfDim (rowCount, columnCount) + + for row in 0 .. rowCount - 1 do + for col in 0 .. columnCount - 1 do + + if matrixA.[row, col] <> zero then + matrixB.[row, col] <- matrixA.[row, col] + + return (matrixA, matrixB) + + // let! rowCount, columnCount = dimension2DGenerator + // + // let! arrayA = + // valuesGenerator + // |> Gen.arrayOfLength (rowCount * columnCount) + // + // let! arrayB = + // arrayA + // |> Gen.collectToArr (fun v -> if v = zero then valuesGenerator else Gen.constant zero) + // + // let matrixA = Array2D.zeroCreate rowCount columnCount + // let matrixB = Array2D.zeroCreate rowCount columnCount + // + // (arrayA, arrayB) + // ||> Array.iteri2 (fun i valueA valueB -> + // let row = i / columnCount + // let column = i % columnCount + // + // matrixA.[row, column] <- valueA + // matrixB.[row, column] <- valueB) + // + // return (matrixA, matrixB) + } + + static member IntType() = + (pairOfDisjointMatricesGenerator 0) + |> genericSparseGenerator 0 Arb.generate + |> Arb.fromGen + + static member FloatType() = + (pairOfDisjointMatricesGenerator 0.) + |> genericSparseGenerator + 0. + (Arb.Default.NormalFloat() + |> Arb.toGen + |> Gen.map float) + |> Arb.fromGen + + static member Float32Type() = + (pairOfDisjointMatricesGenerator 0.0f) + |> genericSparseGenerator 0.0f (normalFloat32Generator <| System.Random()) + |> Arb.fromGen + + static member SByteType() = + (pairOfDisjointMatricesGenerator 0y) + |> genericSparseGenerator 0y Arb.generate + |> Arb.fromGen + + static member ByteType() = + (pairOfDisjointMatricesGenerator 0uy) + |> genericSparseGenerator 0uy Arb.generate + |> Arb.fromGen + + static member Int16Type() = + (pairOfDisjointMatricesGenerator 0s) + |> genericSparseGenerator 0s Arb.generate + |> Arb.fromGen + + static member UInt16Type() = + (pairOfDisjointMatricesGenerator 0us) + |> genericSparseGenerator 0us Arb.generate + |> Arb.fromGen + + static member BoolType() = + (pairOfDisjointMatricesGenerator false) + |> genericSparseGenerator false Arb.generate + |> Arb.fromGen + type VectorXMatrix() = static let pairOfVectorAndMatrixOfCompatibleSizeGenerator (valuesGenerator: Gen<'a>) = gen { @@ -1278,6 +1428,79 @@ module Generators = |> Arb.fromGen module ClArray = + type ExcludeElements() = + static let arrayAndBitmap (valuesGenerator: Gen<'a>) zero = + gen { + let! length = Gen.sized <| fun size -> Gen.choose (1, size) + + let! array = Gen.arrayOfLength length valuesGenerator + + let! bitmap = Gen.collectToArr (fun value -> if value = zero then Gen.constant 0 else Gen.choose (0, 1)) array + + return (array, bitmap) + } + + static member IntType() = + arrayAndBitmap + <| Arb.generate + <| 0 + |> Arb.fromGen + + static member FloatType() = + arrayAndBitmap + <| (Arb.Default.NormalFloat() + |> Arb.toGen + |> Gen.map float) + <| 0. + |> Arb.fromGen + + static member Float32Type() = + arrayAndBitmap + <| (normalFloat32Generator <| System.Random()) + <| 0.0f + |> Arb.fromGen + + static member SByteType() = + arrayAndBitmap + <| Arb.generate + <| 0y + |> Arb.fromGen + + static member ByteType() = + arrayAndBitmap + <| Arb.generate + <| 0uy + |> Arb.fromGen + + static member Int16Type() = + arrayAndBitmap + <| Arb.generate + <| 0s + |> Arb.fromGen + + static member UInt16Type() = + arrayAndBitmap + <| Arb.generate + <| 0us + |> Arb.fromGen + + static member Int32Type() = + arrayAndBitmap + <| Arb.generate + <| 0 + |> Arb.fromGen + + static member UInt32Type() = + arrayAndBitmap + <| Arb.generate + <| 0u + |> Arb.fromGen + static member BoolType() = + arrayAndBitmap + <| Arb.generate + <| false + |> Arb.fromGen + type Set() = static let arrayAndChunkPosition (valuesGenerator: Gen<'a>) = gen { @@ -1428,7 +1651,7 @@ module Generators = |> Arb.fromGen static member ByteType() = - arrayAndChunkPosition <| Arb.generate + arrayAndChunkPosition <| Arb.generate |> Arb.fromGen static member Int16Type() = @@ -1450,3 +1673,4 @@ module Generators = static member BoolType() = arrayAndChunkPosition <| Arb.generate |> Arb.fromGen + diff --git a/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj b/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj index 8fc687dd..945ac0a3 100644 --- a/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj +++ b/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj @@ -36,6 +36,7 @@ + @@ -58,6 +59,7 @@ + diff --git a/tests/GraphBLAS-sharp.Tests/Program.fs b/tests/GraphBLAS-sharp.Tests/Program.fs index 47768522..1dfb072b 100644 --- a/tests/GraphBLAS-sharp.Tests/Program.fs +++ b/tests/GraphBLAS-sharp.Tests/Program.fs @@ -2,123 +2,61 @@ open Expecto open GraphBLAS.FSharp.Tests open GraphBLAS.FSharp.Tests.Backend -let matrixTests = - testList - "Matrix" - [ Matrix.Convert.tests - Matrix.Map2.allTests - Matrix.Map.allTests - Matrix.Merge.allTests - Matrix.Transpose.tests - Matrix.RowsLengths.tests - Matrix.ByRows.tests - Matrix.ExpandRows.tests - Matrix.SubRows.tests - Matrix.Kronecker.tests - - Matrix.SpGeMM.Expand.tests - Matrix.SpGeMM.ExpandCOO.tests - Matrix.SpGeMM.Masked.tests ] - |> testSequenced - -let commonTests = - let scanTests = - testList - "Scan" - [ Common.Scan.ByKey.tests - Common.Scan.PrefixSum.tests ] - - let reduceTests = - testList - "Reduce" - [ Common.Reduce.ByKey.allTests - Common.Reduce.Reduce.tests - Common.Reduce.Sum.tests ] - - let clArrayTests = - testList - "ClArray" - [ Common.ClArray.RemoveDuplicates.tests - Common.ClArray.Copy.tests - Common.ClArray.Replicate.tests - Common.ClArray.Exists.tests - Common.ClArray.Map.tests - Common.ClArray.Map2.addTests - Common.ClArray.Map2.mulTests - Common.ClArray.Choose.allTests - Common.ClArray.ChunkBySize.allTests - Common.ClArray.Blit.tests - Common.ClArray.Concat.tests - Common.ClArray.Fill.tests - Common.ClArray.Pairwise.tests - Common.ClArray.UpperBound.tests - Common.ClArray.Set.tests - Common.ClArray.Item.tests ] - - let sortTests = - testList - "Sort" - [ Common.Sort.Bitonic.tests - Common.Sort.Radix.allTests ] - - testList - "Common" - [ Common.Scatter.allTests - Common.Gather.allTests - clArrayTests - sortTests - reduceTests - scanTests ] - |> testSequenced - -let vectorTests = - testList - "Vector" - [ Vector.SpMV.tests - Vector.SpMSpV.tests - Vector.ZeroCreate.tests - Vector.OfList.tests - Vector.Copy.tests - Vector.Convert.tests - Vector.Map.allTests - Vector.Map2.allTests - Vector.AssignByMask.tests - Vector.AssignByMask.complementedTests - Vector.Reduce.tests - Vector.Merge.tests ] - |> testSequenced - -let algorithmsTests = - testList - "Algorithms tests" - [ Algorithms.BFS.tests - Algorithms.SSSP.tests - - Algorithms.MSBFS.levelsTests - Algorithms.MSBFS.parentsTests ] - |> testSequenced - -let deviceTests = - testList - "Device" - [ matrixTests - commonTests - vectorTests - algorithmsTests ] - |> testSequenced - -let hostTests = - testList - "Host" - [ Host.Matrix.FromArray2D.tests - Host.Matrix.Convert.tests - Host.IO.MtxReader.test ] - |> testSequenced +// let matrixTests = +// testList "Matrix" [ Matrix.Intersect.tests ] +// |> testSequenced + +// let commonTests = +// let clArrayTests = +// testList +// "ClArray" +// [ Common.ClArray.ExcludeElements.tests ] + + // testList + // "Common" + // [clArrayTests] + // |> testSequenced +// +// let vectorTests = +// testList +// "Vector" +// [ Vector.SpMV.tests +// Vector.SpMSpV.tests +// Vector.ZeroCreate.tests +// Vector.OfList.tests +// Vector.Copy.tests +// Vector.Convert.tests +// Vector.Map.allTests +// Vector.Map2.allTests +// Vector.AssignByMask.tests +// Vector.AssignByMask.complementedTests +// Vector.Reduce.tests +// Vector.Merge.tests ] +// |> testSequenced + +// let algorithmsTests = +// testList +// "Algorithms tests" +// [ Algorithms.MSBFS.levelsTests +// Algorithms.MSBFS.parentsTests ] +// |> testSequenced + +// let deviceTests = +// testList "Device" [ matrixTests ] +// |> testSequenced + +// let hostTests = +// testList +// "Host" +// [ Host.Matrix.FromArray2D.tests +// Host.Matrix.Convert.tests +// Host.IO.MtxReader.test ] +// |> testSequenced [] let allTests = - testList "All" [ deviceTests; hostTests ] - |> testSequenced + testList "All" [ Algorithms.MSBFS.levelsTests + Algorithms.MSBFS.parentsTests ] |> testSequenced [] -let main argv = allTests |> runTestsWithCLIArgs [] argv +let main argv = allTests |> runTestsWithCLIArgs [ CLIArguments.Allow_Duplicate_Names ] argv From 7b21b4f6113814e7eeb5e9e56261a398c0d848ce Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Tue, 21 Nov 2023 23:13:51 +0300 Subject: [PATCH 14/23] fix: msbfs levels bug --- .../Algorithms/MSBFS.fs | 82 +++++++++++++------ .../Matrix/COO/Matrix.fs | 7 +- .../Quotes/Arithmetic.fs | 8 ++ 3 files changed, 68 insertions(+), 29 deletions(-) diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index 8c5ed016..d263cb4b 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -3,37 +3,55 @@ namespace GraphBLAS.FSharp.Backend.Algorithms open Brahma.FSharp open FSharp.Quotations open GraphBLAS.FSharp -open GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects +open GraphBLAS.FSharp.Common open GraphBLAS.FSharp.Objects.ClMatrix open GraphBLAS.FSharp.Objects.ArraysExtensions open GraphBLAS.FSharp.Objects.ClContextExtensions open GraphBLAS.FSharp.Objects.ClCellExtensions +open GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Backend.Matrix.LIL open GraphBLAS.FSharp.Backend.Matrix.COO module internal MSBFS = let private frontExclude (clContext: ClContext) workGroupSize = - let excludeValues = - ClArray.excludeElements clContext workGroupSize + let invert = + ClArray.mapInPlace ArithmeticOperations.intNotQ clContext workGroupSize + + let prefixSum = + PrefixSum.standardExcludeInPlace clContext workGroupSize + + let scatterIndices = + Scatter.lastOccurrence clContext workGroupSize - let excludeIndices = - ClArray.excludeElements clContext workGroupSize + let scatterValues = + Scatter.lastOccurrence clContext workGroupSize fun (queue: MailboxProcessor<_>) allocationMode (front: ClMatrix.COO<_>) (intersection: ClArray) -> - let newRows = - excludeIndices queue allocationMode intersection front.Rows + invert queue intersection + + let length = + (prefixSum queue intersection) + .ToHostAndFree queue + + if length = 0 then + None + else + let rows = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, length) + + let columns = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, length) - let newColumns = - excludeIndices queue allocationMode intersection front.Columns + let values = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, length) - let newValues = - excludeValues queue allocationMode intersection front.Values + scatterIndices queue intersection front.Rows rows + scatterIndices queue intersection front.Columns columns + scatterValues queue intersection front.Values values - match newRows, newColumns, newValues with - | Some rows, Some columns, Some values -> { Context = clContext Rows = rows Columns = columns @@ -41,7 +59,6 @@ module internal MSBFS = RowCount = front.RowCount ColumnCount = front.ColumnCount } |> Some - | _ -> None module Levels = let private updateFrontAndLevels (clContext: ClContext) workGroupSize = @@ -70,13 +87,14 @@ module internal MSBFS = match newFront with | Some f -> - // Update levels let levelClCell = clContext.CreateClCell level + // Set current level value to all remaining front positions setLevel queue levelClCell 0 f.Values.Length f.Values levelClCell.Free queue + // Update levels let newLevels = mergeDisjoint queue levels f newLevels, newFront @@ -110,7 +128,7 @@ module internal MSBFS = let mutable front = copy queue DeviceOnly levels - let mutable level = 0 + let mutable level = 1 let mutable stop = false while not stop do @@ -121,15 +139,21 @@ module internal MSBFS = | None -> front.Dispose queue stop <- true + | Some newFrontier -> front.Dispose queue + //Filtering visited vertices match updateFrontAndLevels queue DeviceOnly level newFrontier levels with | l, Some f -> front <- f + levels.Dispose queue + levels <- l + newFrontier.Dispose queue + | _, None -> stop <- true newFrontier.Dispose queue @@ -151,8 +175,6 @@ module internal MSBFS = module Parents = let private updateFrontAndParents (clContext: ClContext) workGroupSize = - // update parents same as levels - // every front value should be equal to its column number let frontExclude = frontExclude clContext workGroupSize let mergeDisjoint = @@ -175,10 +197,15 @@ module internal MSBFS = match newFront with | Some f -> - // Update levels let resultFront = { f with Values = f.Columns } - let newLevels = mergeDisjoint queue parents f - newLevels, Some resultFront + + // Update parents + let newParents = mergeDisjoint queue parents f + + f.Values.Free queue + + newParents, Some resultFront + | _ -> parents, None let run<'a when 'a: struct> (clContext: ClContext) workGroupSize = @@ -190,7 +217,7 @@ module internal MSBFS = clContext workGroupSize - let updateFrontAndLevels = + let updateFrontAndParents = updateFrontAndParents clContext workGroupSize fun (queue: MailboxProcessor) (inputMatrix: ClMatrix<'a>) (source: int list) -> @@ -227,15 +254,20 @@ module internal MSBFS = | None -> front.Dispose queue stop <- true + | Some newFrontier -> front.Dispose queue + //Filtering visited vertices - match updateFrontAndLevels queue DeviceOnly newFrontier parents with - | l, Some f -> + match updateFrontAndParents queue DeviceOnly newFrontier parents with + | p, Some f -> front <- f + parents.Dispose queue - parents <- l + parents <- p + newFrontier.Dispose queue + | _, None -> stop <- true newFrontier.Dispose queue diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs index 1dd458aa..c5fa56dd 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs @@ -260,10 +260,9 @@ module Matrix = let ofList (clContext: ClContext) allocationMode rowCount columnCount (elements: (int * int * 'a) list) = let rows, columns, values = - elements - |> Array.ofList - |> Array.sortBy (fun (x, _, _) -> x) - |> Array.unzip3 + let elements = elements |> Array.ofList + elements |> Array.sortInPlaceBy (fun (x, _, _) -> x) + elements |> Array.unzip3 { Context = clContext Rows = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, rows) diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs index 03107f05..3662bd7f 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs @@ -1,6 +1,7 @@ namespace GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects +open Microsoft.FSharp.Quotations module ArithmeticOperations = let inline private mkUnaryOp zero unaryOp = @@ -231,6 +232,13 @@ module ArithmeticOperations = let float32Mul = createPair 0.0f (*) <@ (*) @> + // without zero + let intAddWithoutZero = + <@ fun x y -> Some (x + y) @> + + let intMulWithoutZero = + <@ fun x y -> Some (x * y) @> + // other operations let less<'a when 'a: comparison> = <@ fun (x: 'a option) (y: 'a option) -> From f4016eba3deb2e5baff8104669448e8f33a596b7 Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Tue, 21 Nov 2023 23:14:53 +0300 Subject: [PATCH 15/23] fix: msbfs tests --- .../Backend/Algorithms/MSBFS.fs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs index 89e6aa74..daf3ab23 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs @@ -11,6 +11,7 @@ open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Objects.MatrixExtensions let config = Utils.undirectedAlgoConfig + let workGroupSize = Utils.defaultWorkGroupSize let makeLevelsTest context queue bfs (matrix: int [,]) = @@ -19,11 +20,14 @@ let makeLevelsTest context queue bfs (matrix: int [,]) = let largestComponent = ConnectedComponents.largestComponent graph + Array.sortInPlace largestComponent + if largestComponent.Length > 1 then let sourceVertexCount = max 2 (largestComponent.Length / 10) let source = - largestComponent.[0..sourceVertexCount] + largestComponent.[0..sourceVertexCount - 1] + |> Array.sort |> Array.toList let matrixHost = @@ -35,7 +39,7 @@ let makeLevelsTest context queue bfs (matrix: int [,]) = Array2D.zeroCreate sourceVertexCount (Array2D.length1 matrix) source - |> Seq.iteri + |> List.iteri (fun i vertex -> (snd (BFS.runUndirected graph vertex)) |> Utils.createArrayFromDictionary (Array2D.length1 matrix) 0 @@ -53,7 +57,7 @@ let makeLevelsTest context queue bfs (matrix: int [,]) = | Matrix.COO a, Matrix.COO e -> Utils.compareCOOMatrix (=) a e | _ -> failwith "Not implemented" -let createLevelsTest context queue testFun = +let createLevelsTest<'a> context queue testFun = testFun |> makeLevelsTest context queue |> testPropertyWithConfig config $"test on %A{typeof<'a>}" @@ -64,12 +68,12 @@ let levelsTestFixtures (testContext: TestContext) = let bfsLevels = Algorithms.MSBFS.runLevels - (fst ArithmeticOperations.intAdd) - (fst ArithmeticOperations.intMul) + ArithmeticOperations.intAddWithoutZero + ArithmeticOperations.intMulWithoutZero context workGroupSize - createLevelsTest context queue bfsLevels ] + createLevelsTest context queue bfsLevels ] let levelsTests = TestCases.gpuTests "MSBFS Levels tests" levelsTestFixtures From 94fec78b1a43dbd969a6ac9d7175deedc6c00bd8 Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Wed, 22 Nov 2023 13:28:14 +0300 Subject: [PATCH 16/23] fix: msbfs parents bug --- src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index d263cb4b..a73f9de0 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -183,6 +183,10 @@ module internal MSBFS = let findIntersection = Intersect.findKeysIntersection clContext workGroupSize + let copyIndices = ClArray.copyTo clContext workGroupSize + + // let copyMatrix = Matrix.copy clContext workGroupSize + fun (queue: MailboxProcessor) allocationMode (front: ClMatrix.COO<_>) (parents: ClMatrix.COO<_>) -> // Find intersection of levels and front indices. @@ -197,14 +201,12 @@ module internal MSBFS = match newFront with | Some f -> - let resultFront = { f with Values = f.Columns } - // Update parents let newParents = mergeDisjoint queue parents f - f.Values.Free queue + copyIndices queue f.Columns f.Values - newParents, Some resultFront + newParents, Some f | _ -> parents, None From 3d9654da7e318787e05c8da7864bc98cc2be1e85 Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Thu, 23 Nov 2023 00:00:24 +0300 Subject: [PATCH 17/23] fix: msbfs parents, clarray.copyto bugs --- src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs | 10 ++++++---- src/GraphBLAS-sharp.Backend/Common/ClArray.fs | 2 +- src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs | 12 ++---------- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index a73f9de0..1d6a2512 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -119,6 +119,8 @@ module internal MSBFS = let vertexCount = matrix.RowCount let sourceVertexCount = source.Length + let source = source |> List.sort + let startMatrix = source |> List.mapi (fun i vertex -> i, vertex, 1) @@ -185,8 +187,6 @@ module internal MSBFS = let copyIndices = ClArray.copyTo clContext workGroupSize - // let copyMatrix = Matrix.copy clContext workGroupSize - fun (queue: MailboxProcessor) allocationMode (front: ClMatrix.COO<_>) (parents: ClMatrix.COO<_>) -> // Find intersection of levels and front indices. @@ -214,8 +214,8 @@ module internal MSBFS = let spGeMM = Operations.SpGeMM.COO.expand - (ArithmeticOperations.min -1) - (ArithmeticOperations.fst -1) + (ArithmeticOperations.min) + (ArithmeticOperations.fst) clContext workGroupSize @@ -226,6 +226,8 @@ module internal MSBFS = let vertexCount = inputMatrix.RowCount let sourceVertexCount = source.Length + let source = source |> List.sort + let matrix = match inputMatrix with | ClMatrix.CSR m -> diff --git a/src/GraphBLAS-sharp.Backend/Common/ClArray.fs b/src/GraphBLAS-sharp.Backend/Common/ClArray.fs index 8eaa4847..ad6b3caf 100644 --- a/src/GraphBLAS-sharp.Backend/Common/ClArray.fs +++ b/src/GraphBLAS-sharp.Backend/Common/ClArray.fs @@ -133,7 +133,7 @@ module ClArray = let i = ndRange.GlobalID0 if i < inputArrayLength then - source.[i] <- destination.[i] @> + destination.[i] <- source.[i] @> let program = clContext.Compile(copy) diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs index 3662bd7f..5ed5f6ba 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs @@ -255,17 +255,9 @@ module ArithmeticOperations = | None, Some y -> Some y | _ -> None @> - let min zero = - <@ fun x y -> - let result = min x y + let min<'a when 'a: comparison> = <@ fun (x: 'a) (y: 'a) -> Some (min x y) @> - if result = zero then - None - else - Some result @> - - let fst zero = - <@ fun x _ -> if x = zero then None else Some x @> + let fst<'a> = <@ fun (x: 'a) (_: 'a) -> Some x @> //PageRank specific let squareOfDifference = From e33db1a445be9c438e89bef1803d6c3cc59fd0a6 Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Thu, 23 Nov 2023 00:01:41 +0300 Subject: [PATCH 18/23] fix: mergeDisjoint, msbfs, intersect tests bugs --- .../Backend/Algorithms/MSBFS.fs | 22 ++- .../Backend/Common/ClArray/ExcludeElements.fs | 4 +- .../Backend/Matrix/Intersect.fs | 44 +++-- .../Backend/Matrix/Merge.fs | 25 ++- tests/GraphBLAS-sharp.Tests/Generators.fs | 94 ++++------ tests/GraphBLAS-sharp.Tests/Helpers.fs | 37 ++-- tests/GraphBLAS-sharp.Tests/Program.fs | 169 ++++++++++++------ 7 files changed, 228 insertions(+), 167 deletions(-) diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs index daf3ab23..205e1218 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/MSBFS.fs @@ -79,7 +79,8 @@ let levelsTests = TestCases.gpuTests "MSBFS Levels tests" levelsTestFixtures let makeParentsTest context queue bfs (matrix: int [,]) = - let graph = undirectedFromArray2D matrix -1 + + let graph = undirectedFromArray2D matrix 0 let largestComponent = ConnectedComponents.largestComponent graph @@ -87,20 +88,17 @@ let makeParentsTest context queue bfs (matrix: int [,]) = if largestComponent.Length > 1 then let sourceVertexCount = max 2 (largestComponent.Length / 10) - let source = - largestComponent.[0..sourceVertexCount] - |> Array.toList + let source = largestComponent.[0..sourceVertexCount] + source |> Array.sortInPlace + let source = source |> Array.toList let matrixHost = - Utils.createMatrixFromArray2D CSR matrix ((=) -1) + Utils.createMatrixFromArray2D CSR matrix ((=) 0) let matrixDevice = matrixHost.ToDevice context - let expectedArray2D = - HostPrimitives.MSBFSParents matrix source - let expected = - Utils.createMatrixFromArray2D COO expectedArray2D ((=) -1) + HostPrimitives.MSBFSParents matrix source let actual: ClMatrix = bfs queue matrixDevice source let actual = actual.ToHostAndFree queue @@ -111,7 +109,7 @@ let makeParentsTest context queue bfs (matrix: int [,]) = | Matrix.COO a, Matrix.COO e -> Utils.compareCOOMatrix (=) a e | _ -> failwith "Not implemented" -let createParentsTest context queue testFun = +let createParentsTest<'a> context queue testFun = testFun |> makeParentsTest context queue |> testPropertyWithConfig config $"test on %A{typeof<'a>}" @@ -120,10 +118,10 @@ let parentsTestFixtures (testContext: TestContext) = [ let context = testContext.ClContext let queue = testContext.Queue - let bfsLevels = + let bfsParents = Algorithms.MSBFS.runParents context workGroupSize - createParentsTest context queue bfsLevels ] + createParentsTest context queue bfsParents ] let parentsTests = TestCases.gpuTests "MSBFS Parents tests" parentsTestFixtures diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/ExcludeElements.fs b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/ExcludeElements.fs index f938f745..335cd665 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/ExcludeElements.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/ExcludeElements.fs @@ -22,7 +22,9 @@ let makeTest<'a> isEqual (zero: 'a) testFun ((array, bitmap): 'a array * int arr let arrayCl = context.CreateClArray array let bitmapCl = context.CreateClArray bitmap - let actual: ClArray<'a> option = testFun processor HostInterop bitmapCl arrayCl + let actual: ClArray<'a> option = + testFun processor HostInterop bitmapCl arrayCl + let actual = actual |> Option.map (fun a -> a.ToHostAndFree processor) diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs index d8a9bf5a..bcfe9a77 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs @@ -12,33 +12,39 @@ open GraphBLAS.FSharp.Objects.ArraysExtensions let config = { Utils.defaultConfig with - arbitrary = [ typeof ] } + arbitrary = [ typeof ] } let workGroupSize = Utils.defaultWorkGroupSize -let context = Context.defaultContext.ClContext -let processor = Context.defaultContext.Queue +let context = defaultContext.ClContext +let processor = defaultContext.Queue -let makeTest isZero testFun (leftMatrix: 'a [,], rightMatrix: 'a [,]) = +let makeTest<'a when 'a: struct> isZero testFun (leftMatrix: 'a [,], rightMatrix: 'a [,]) = - let m1 = Matrix.COO.FromArray2D(leftMatrix, isZero) - let m2 = Matrix.COO.FromArray2D(rightMatrix, isZero) + let m1 = + Matrix.COO.FromArray2D(leftMatrix, isZero) + + let m2 = + Matrix.COO.FromArray2D(rightMatrix, isZero) if m1.NNZ > 0 && m2.NNZ > 0 then + let expected = - let leftIndices = - (m1.Rows, m1.Columns) - ||> Array.zip + let mutable index = 0 + let bitmap = Array.zeroCreate m1.NNZ + + leftMatrix + |> Array2D.iteri (fun row col value -> + if row < m2.RowCount + && col < m2.ColumnCount + && not <| isZero rightMatrix.[row, col] + && not <| isZero value then + bitmap.[index] <- 1 - let rightIndices = - (m2.Rows, m2.Columns) - ||> Array.zip + if not <| isZero value then + index <- index + 1) - Array.init - <| m1.NNZ - <| fun i -> - let index = leftIndices.[i] - if Array.exists ((=) index) rightIndices then 1 else 0 + bitmap let m1 = m1.ToDevice context let m2 = m2.ToDevice context @@ -55,9 +61,9 @@ let makeTest isZero testFun (leftMatrix: 'a [,], rightMatrix: 'a [,]) = "Matrices should be equal" |> Expect.equal actual expected -let createTest isZero = +let inline createTest<'a when 'a: struct> (isZero: 'a -> bool) = Matrix.COO.Matrix.findKeysIntersection context workGroupSize - |> makeTest isZero + |> makeTest<'a> isZero |> testPropertyWithConfig config $"test on %A{typeof<'a>}" let tests = diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Merge.fs b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Merge.fs index 9d0b80dd..af7a2700 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Merge.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Merge.fs @@ -110,7 +110,10 @@ let testsCOO = createTestCOO (=) false ] |> testList "COO" -let makeTestCOODisjoint isEqual zero testFun (leftArray: 'a [,], rightArray: 'a [,]) = +let makeTestCOODisjoint isEqual zero testFun (array: ('a * 'a) [,]) = + + let leftArray = Array2D.map fst array + let rightArray = Array2D.map snd array let leftMatrix = Matrix.COO.FromArray2D(leftArray, isEqual zero) @@ -123,24 +126,29 @@ let makeTestCOODisjoint isEqual zero testFun (leftArray: 'a [,], rightArray: 'a let clLeftMatrix = leftMatrix.ToDevice context let clRightMatrix = rightMatrix.ToDevice context - let actual: ClMatrix.COO<'a> = testFun processor clLeftMatrix clRightMatrix + let actual: ClMatrix.COO<'a> = + testFun processor clLeftMatrix clRightMatrix + let actual = actual.ToHostAndFree processor clLeftMatrix.Dispose processor clRightMatrix.Dispose processor rightArray - |> Array2D.iteri (fun row column value -> leftArray.[row, column] <- value) + |> Array2D.iteri + (fun row column value -> + if value <> zero then + leftArray.[row, column] <- value) - let expected = Matrix.COO.FromArray2D(leftArray, isEqual zero) + let expected = + Matrix.COO.FromArray2D(leftArray, isEqual zero) Utils.compareCOOMatrix isEqual actual expected let createTestCOODisjoint isEqual (zero: 'a) = let configDisjoint = - {Utils.defaultConfig with - endSize = 10 - arbitrary = [ typeof ]} + { Utils.defaultConfig with + arbitrary = [ typeof ] } Matrix.COO.Merge.runDisjoint context Utils.defaultWorkGroupSize |> makeTestCOODisjoint isEqual zero @@ -221,4 +229,5 @@ let testsCSR = |> testList "CSR" let allTests = - [ testsCSR; testsCOO; testsCOODisjoint ] |> testList "Merge" + [ testsCSR; testsCOO; testsCOODisjoint ] + |> testList "Merge" diff --git a/tests/GraphBLAS-sharp.Tests/Generators.fs b/tests/GraphBLAS-sharp.Tests/Generators.fs index 3cb65f39..deaab99c 100644 --- a/tests/GraphBLAS-sharp.Tests/Generators.fs +++ b/tests/GraphBLAS-sharp.Tests/Generators.fs @@ -34,9 +34,10 @@ module Generators = } let genericSparseGenerator zero valuesGen handler = - let maxSparsity = 10 + let minSparsity = 10 + let maxSparsity = 50 let upperBound = 100 - let sparsityGen = Gen.choose (1, maxSparsity) + let sparsityGen = Gen.choose (minSparsity, maxSparsity) let genWithSparsity sparseValuesGenProvider = gen { @@ -469,44 +470,22 @@ module Generators = gen { let! rowCount, columnCount = dimension2DGenerator - let! matrixA = - valuesGenerator + let! pairs = + Gen.two valuesGenerator |> Gen.array2DOfDim (rowCount, columnCount) - let! matrixB = - valuesGenerator - |> Gen.array2DOfDim (rowCount, columnCount) + let isZero = (=) zero - for row in 0 .. rowCount - 1 do - for col in 0 .. columnCount - 1 do + let pairs = + pairs + |> Array2D.map + (fun (fst, snd) -> + match () with + | () when isZero fst && not <| isZero snd -> (zero, snd) + | () when not <| isZero fst && isZero snd -> (fst, zero) + | () -> (fst, zero)) - if matrixA.[row, col] <> zero then - matrixB.[row, col] <- matrixA.[row, col] - - return (matrixA, matrixB) - - // let! rowCount, columnCount = dimension2DGenerator - // - // let! arrayA = - // valuesGenerator - // |> Gen.arrayOfLength (rowCount * columnCount) - // - // let! arrayB = - // arrayA - // |> Gen.collectToArr (fun v -> if v = zero then valuesGenerator else Gen.constant zero) - // - // let matrixA = Array2D.zeroCreate rowCount columnCount - // let matrixB = Array2D.zeroCreate rowCount columnCount - // - // (arrayA, arrayB) - // ||> Array.iteri2 (fun i valueA valueB -> - // let row = i / columnCount - // let column = i % columnCount - // - // matrixA.[row, column] <- valueA - // matrixB.[row, column] <- valueB) - // - // return (matrixA, matrixB) + return pairs } static member IntType() = @@ -1435,15 +1414,20 @@ module Generators = let! array = Gen.arrayOfLength length valuesGenerator - let! bitmap = Gen.collectToArr (fun value -> if value = zero then Gen.constant 0 else Gen.choose (0, 1)) array + let! bitmap = + Gen.collectToArr + (fun value -> + if value = zero then + Gen.constant 0 + else + Gen.choose (0, 1)) + array return (array, bitmap) } static member IntType() = - arrayAndBitmap - <| Arb.generate - <| 0 + arrayAndBitmap <| Arb.generate <| 0 |> Arb.fromGen static member FloatType() = @@ -1461,44 +1445,31 @@ module Generators = |> Arb.fromGen static member SByteType() = - arrayAndBitmap - <| Arb.generate - <| 0y + arrayAndBitmap <| Arb.generate <| 0y |> Arb.fromGen static member ByteType() = - arrayAndBitmap - <| Arb.generate - <| 0uy + arrayAndBitmap <| Arb.generate <| 0uy |> Arb.fromGen static member Int16Type() = - arrayAndBitmap - <| Arb.generate - <| 0s + arrayAndBitmap <| Arb.generate <| 0s |> Arb.fromGen static member UInt16Type() = - arrayAndBitmap - <| Arb.generate - <| 0us + arrayAndBitmap <| Arb.generate <| 0us |> Arb.fromGen static member Int32Type() = - arrayAndBitmap - <| Arb.generate - <| 0 + arrayAndBitmap <| Arb.generate <| 0 |> Arb.fromGen static member UInt32Type() = - arrayAndBitmap - <| Arb.generate - <| 0u + arrayAndBitmap <| Arb.generate <| 0u |> Arb.fromGen + static member BoolType() = - arrayAndBitmap - <| Arb.generate - <| false + arrayAndBitmap <| Arb.generate <| false |> Arb.fromGen type Set() = @@ -1673,4 +1644,3 @@ module Generators = static member BoolType() = arrayAndChunkPosition <| Arb.generate |> Arb.fromGen - diff --git a/tests/GraphBLAS-sharp.Tests/Helpers.fs b/tests/GraphBLAS-sharp.Tests/Helpers.fs index 612b7601..e9d2e86a 100644 --- a/tests/GraphBLAS-sharp.Tests/Helpers.fs +++ b/tests/GraphBLAS-sharp.Tests/Helpers.fs @@ -338,23 +338,29 @@ module HostPrimitives = op leftElement rightElement let MSBFSParents matrix source = + let zero = -2 + let opAdd a b = let result = min a b - if result = -1 then + if result = zero then None else Some result - let opMul (a: int) _ = if a = -1 then None else Some a + let opMul (a: int) (b: int) = + if a = zero || b = 0 then + None + else + Some a - let array2DMultiplication = array2DMultiplication -1 opMul opAdd + let array2DMultiplication = array2DMultiplication zero opMul opAdd - let front = + let mutable front = Array2D.create <| Seq.length source <| Array2D.length1 matrix - <| -1 + <| zero source |> Seq.iteri (fun row vertex -> front.[row, vertex] <- vertex) @@ -363,7 +369,10 @@ module HostPrimitives = Array2D.create <| Seq.length source <| Array2D.length1 matrix - <| -1 + <| zero + + source + |> Seq.iteri (fun row vertex -> parents.[row, vertex] <- -1) let mutable stop = false @@ -373,15 +382,19 @@ module HostPrimitives = newFront |> Array2D.iteri - (fun i j value -> - if value <> -1 then - if parents.[i, j] <> -1 then - newFront.[i, j] <- -1 + (fun row col value -> + if value <> zero then + if parents.[row, col] <> zero then + newFront.[row, col] <- zero + else stop <- false - parents.[i, j] <- value) + parents.[row, col] <- value + newFront.[row, col] <- col) + + front <- newFront - front + Utils.createMatrixFromArray2D COO parents ((=) -2) module Context = type TestContext = diff --git a/tests/GraphBLAS-sharp.Tests/Program.fs b/tests/GraphBLAS-sharp.Tests/Program.fs index 1dfb072b..3a59d101 100644 --- a/tests/GraphBLAS-sharp.Tests/Program.fs +++ b/tests/GraphBLAS-sharp.Tests/Program.fs @@ -1,62 +1,125 @@ open Expecto +open GraphBLAS.FSharp.Test.Generators open GraphBLAS.FSharp.Tests open GraphBLAS.FSharp.Tests.Backend -// let matrixTests = -// testList "Matrix" [ Matrix.Intersect.tests ] -// |> testSequenced - -// let commonTests = -// let clArrayTests = -// testList -// "ClArray" -// [ Common.ClArray.ExcludeElements.tests ] - - // testList - // "Common" - // [clArrayTests] - // |> testSequenced -// -// let vectorTests = -// testList -// "Vector" -// [ Vector.SpMV.tests -// Vector.SpMSpV.tests -// Vector.ZeroCreate.tests -// Vector.OfList.tests -// Vector.Copy.tests -// Vector.Convert.tests -// Vector.Map.allTests -// Vector.Map2.allTests -// Vector.AssignByMask.tests -// Vector.AssignByMask.complementedTests -// Vector.Reduce.tests -// Vector.Merge.tests ] -// |> testSequenced - -// let algorithmsTests = -// testList -// "Algorithms tests" -// [ Algorithms.MSBFS.levelsTests -// Algorithms.MSBFS.parentsTests ] -// |> testSequenced - -// let deviceTests = -// testList "Device" [ matrixTests ] -// |> testSequenced - -// let hostTests = -// testList -// "Host" -// [ Host.Matrix.FromArray2D.tests -// Host.Matrix.Convert.tests -// Host.IO.MtxReader.test ] -// |> testSequenced +let matrixTests = + testList + "Matrix" + [ Matrix.Convert.tests + Matrix.Map2.allTests + Matrix.Map.allTests + Matrix.Merge.allTests + Matrix.Transpose.tests + Matrix.RowsLengths.tests + Matrix.ByRows.tests + Matrix.ExpandRows.tests + Matrix.SubRows.tests + Matrix.Intersect.tests + Matrix.Kronecker.tests + + Matrix.SpGeMM.Expand.tests + Matrix.SpGeMM.Masked.tests ] + |> testSequenced + +let commonTests = + let scanTests = + testList + "Scan" + [ Common.Scan.ByKey.tests + Common.Scan.PrefixSum.tests ] + + let reduceTests = + testList + "Reduce" + [ Common.Reduce.ByKey.allTests + Common.Reduce.Reduce.tests + Common.Reduce.Sum.tests ] + + let clArrayTests = + testList + "ClArray" + [ Common.ClArray.RemoveDuplicates.tests + Common.ClArray.Copy.tests + Common.ClArray.Replicate.tests + Common.ClArray.Exists.tests + Common.ClArray.Map.tests + Common.ClArray.Map2.addTests + Common.ClArray.Map2.mulTests + Common.ClArray.Choose.allTests + Common.ClArray.ChunkBySize.allTests + Common.ClArray.Blit.tests + Common.ClArray.Concat.tests + Common.ClArray.Fill.tests + Common.ClArray.Pairwise.tests + Common.ClArray.UpperBound.tests + Common.ClArray.Set.tests + Common.ClArray.Item.tests ] + + let sortTests = + testList + "Sort" + [ Common.Sort.Bitonic.tests + Common.Sort.Radix.allTests ] + + testList + "Common" + [ Common.Scatter.allTests + Common.Gather.allTests + clArrayTests + sortTests + reduceTests + scanTests ] + |> testSequenced + +let vectorTests = + testList + "Vector" + [ Vector.SpMV.tests + Vector.SpMSpV.tests + Vector.ZeroCreate.tests + Vector.OfList.tests + Vector.Copy.tests + Vector.Convert.tests + Vector.Map.allTests + Vector.Map2.allTests + Vector.AssignByMask.tests + Vector.AssignByMask.complementedTests + Vector.Reduce.tests + Vector.Merge.tests ] + |> testSequenced + +let algorithmsTests = + testList + "Algorithms tests" + [ Algorithms.BFS.tests + Algorithms.SSSP.tests + + Algorithms.MSBFS.levelsTests + Algorithms.MSBFS.parentsTests ] + |> testSequenced + +let deviceTests = + testList + "Device" + [ matrixTests + commonTests + vectorTests + algorithmsTests ] + |> testSequenced + +let hostTests = + testList + "Host" + [ Host.Matrix.FromArray2D.tests + Host.Matrix.Convert.tests + Host.IO.MtxReader.test ] + |> testSequenced [] let allTests = - testList "All" [ Algorithms.MSBFS.levelsTests - Algorithms.MSBFS.parentsTests ] |> testSequenced + testList "All" [ deviceTests; hostTests ] + |> testSequenced [] -let main argv = allTests |> runTestsWithCLIArgs [ CLIArguments.Allow_Duplicate_Names ] argv +let main argv = allTests |> runTestsWithCLIArgs [] argv From 63a44e3a88f0225a3c3e3e29b2d2f114f3aa88c7 Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Thu, 23 Nov 2023 00:02:13 +0300 Subject: [PATCH 19/23] refactor: formatting --- .../Algorithms/MSBFS.fs | 3 +-- .../Matrix/COO/Matrix.fs | 5 ++++- .../Quotes/Arithmetic.fs | 9 ++++----- .../Backend/Matrix/Intersect.fs | 19 ++++++++++--------- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index 1d6a2512..30b40b6d 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -33,8 +33,7 @@ module internal MSBFS = invert queue intersection let length = - (prefixSum queue intersection) - .ToHostAndFree queue + (prefixSum queue intersection).ToHostAndFree queue if length = 0 then None diff --git a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs index c5fa56dd..5c7838fc 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/COO/Matrix.fs @@ -261,7 +261,10 @@ module Matrix = let ofList (clContext: ClContext) allocationMode rowCount columnCount (elements: (int * int * 'a) list) = let rows, columns, values = let elements = elements |> Array.ofList - elements |> Array.sortInPlaceBy (fun (x, _, _) -> x) + + elements + |> Array.sortInPlaceBy (fun (x, _, _) -> x) + elements |> Array.unzip3 { Context = clContext diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs index 5ed5f6ba..8dc37dec 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs @@ -233,11 +233,9 @@ module ArithmeticOperations = let float32Mul = createPair 0.0f (*) <@ (*) @> // without zero - let intAddWithoutZero = - <@ fun x y -> Some (x + y) @> + let intAddWithoutZero = <@ fun x y -> Some(x + y) @> - let intMulWithoutZero = - <@ fun x y -> Some (x * y) @> + let intMulWithoutZero = <@ fun x y -> Some(x * y) @> // other operations let less<'a when 'a: comparison> = @@ -255,7 +253,8 @@ module ArithmeticOperations = | None, Some y -> Some y | _ -> None @> - let min<'a when 'a: comparison> = <@ fun (x: 'a) (y: 'a) -> Some (min x y) @> + let min<'a when 'a: comparison> = + <@ fun (x: 'a) (y: 'a) -> Some(min x y) @> let fst<'a> = <@ fun (x: 'a) (_: 'a) -> Some x @> diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs index bcfe9a77..15760ada 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Matrix/Intersect.fs @@ -34,15 +34,16 @@ let makeTest<'a when 'a: struct> isZero testFun (leftMatrix: 'a [,], rightMatrix let bitmap = Array.zeroCreate m1.NNZ leftMatrix - |> Array2D.iteri (fun row col value -> - if row < m2.RowCount - && col < m2.ColumnCount - && not <| isZero rightMatrix.[row, col] - && not <| isZero value then - bitmap.[index] <- 1 - - if not <| isZero value then - index <- index + 1) + |> Array2D.iteri + (fun row col value -> + if row < m2.RowCount + && col < m2.ColumnCount + && not <| isZero rightMatrix.[row, col] + && not <| isZero value then + bitmap.[index] <- 1 + + if not <| isZero value then + index <- index + 1) bitmap From dacc3e14641281b329cd701a123d88e003799b27 Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Sat, 25 Nov 2023 14:36:34 +0300 Subject: [PATCH 20/23] merge dev --- .../Algorithms/BFS.fs | 42 +-- .../Algorithms/PageRank.fs | 132 -------- .../GraphBLAS-sharp.Benchmarks.fsproj | 3 +- .../Matrix/Map2/Map2.fs | 2 +- .../Matrix/SpGeMM/Expand.fs | 21 +- .../Matrix/SpGeMM/Masked.fs | 2 +- .../GraphBLAS-sharp.Benchmarks/Program.fs | 4 +- .../GraphBLAS-sharp.Benchmarks/Vector/Map2.fs | 14 +- paket.lock | 168 +++++----- src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs | 217 ++----------- .../Algorithms/PageRank.fs | 198 ------------ src/GraphBLAS-sharp.Backend/Common/Bitmap.fs | 99 ------ src/GraphBLAS-sharp.Backend/Common/Common.fs | 35 +- .../Common/Sort/Radix.fs | 18 +- src/GraphBLAS-sharp.Backend/Common/Sum.fs | 148 +-------- .../GraphBLAS-sharp.Backend.fsproj | 9 +- .../Matrix/CSR/Matrix.fs | 2 +- src/GraphBLAS-sharp.Backend/Objects/Matrix.fs | 1 + src/GraphBLAS-sharp.Backend/Objects/Vector.fs | 1 + .../Operations/Operations.fs | 83 +---- .../Operations/SpGeMM/Expand.fs | 10 +- .../Operations/SpMSpV.fs | 305 ------------------ .../Quotes/Arithmetic.fs | 56 +--- src/GraphBLAS-sharp.Backend/Quotes/Map.fs | 5 - src/GraphBLAS-sharp.Backend/Quotes/Mask.fs | 6 - src/GraphBLAS-sharp.Backend/Quotes/Search.fs | 26 -- .../Vector/Dense/Vector.fs | 65 +--- .../Vector/Sparse/Common.fs | 3 +- .../Vector/Sparse/Map.fs | 2 +- .../Vector/Sparse/Map2.fs | 138 +------- .../Vector/Sparse/Vector.fs | 2 - .../Backend/Algorithms/BFS.fs | 50 +-- .../Backend/Algorithms/PageRank.fs | 118 ------- .../Backend/Algorithms/SSSP.fs | 63 ---- .../Backend/Common/ClArray/Map.fs | 4 +- .../Backend/Common/ClArray/Map2.fs | 4 +- .../Backend/Common/Reduce/ReduceByKey.fs | 2 +- .../Backend/Common/Sort/Radix.fs | 14 +- .../Backend/QuickGraph/Algorithms/SSSP.fs | 37 --- .../Backend/Vector/AssignByMask.fs | 5 +- .../Backend/Vector/Map2.fs | 19 +- .../Backend/Vector/SpMSpV.fs | 165 ---------- .../Backend/Vector/SpMV.fs | 15 +- .../Vector/{Create.fs => ZeroCreate.fs} | 20 +- .../GraphBLAS-sharp.Tests.fsproj | 6 +- 45 files changed, 250 insertions(+), 2089 deletions(-) delete mode 100644 benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/PageRank.fs delete mode 100644 src/GraphBLAS-sharp.Backend/Algorithms/PageRank.fs delete mode 100644 src/GraphBLAS-sharp.Backend/Common/Bitmap.fs delete mode 100644 src/GraphBLAS-sharp.Backend/Operations/SpMSpV.fs delete mode 100644 tests/GraphBLAS-sharp.Tests/Backend/Algorithms/PageRank.fs delete mode 100644 tests/GraphBLAS-sharp.Tests/Backend/Algorithms/SSSP.fs delete mode 100644 tests/GraphBLAS-sharp.Tests/Backend/QuickGraph/Algorithms/SSSP.fs delete mode 100644 tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMSpV.fs rename tests/GraphBLAS-sharp.Tests/Backend/Vector/{Create.fs => ZeroCreate.fs} (81%) diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs index a0c10cb6..7a3c1cf6 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs @@ -12,8 +12,8 @@ open GraphBLAS.FSharp.Objects.ArraysExtensions open GraphBLAS.FSharp.Backend.Quotes [] -[] -[] +[] +[] [)>] type Benchmarks<'elem when 'elem : struct>( buildFunToBenchmark, @@ -27,7 +27,7 @@ type Benchmarks<'elem when 'elem : struct>( let mutable matrix = Unchecked.defaultof> let mutable matrixHost = Unchecked.defaultof<_> - member val ResultLevels = Unchecked.defaultof> with get,set + member val ResultLevels = Unchecked.defaultof> with get,set [] member val OclContextInfo = Unchecked.defaultof with get, set @@ -71,10 +71,7 @@ type Benchmarks<'elem when 'elem : struct>( member this.ClearInputMatrix() = matrix.Dispose this.Processor - member this.ClearResult() = - match this.ResultLevels with - | ClVector.Dense result -> result.FreeAndWait this.Processor - | _ -> failwith "Impossible" + member this.ClearResult() = this.ResultLevels.FreeAndWait this.Processor member this.ReadMatrix() = let converter = @@ -139,30 +136,6 @@ type BFSWithoutTransferBenchmarkInt32() = static member InputMatrixProvider = Benchmarks<_>.InputMatrixProviderBuilder "BFSBenchmarks.txt" -type BFSPushPullWithoutTransferBenchmarkInt32() = - - inherit WithoutTransferBenchmark( - (Algorithms.BFS.singleSourcePushPull ArithmeticOperations.intSumOption ArithmeticOperations.intMulOption), - int32, - (fun _ -> Utils.nextInt (System.Random())), - 0, - (fun context matrix -> ClMatrix.CSR <| matrix.ToCSR.ToDevice context)) - - static member InputMatrixProvider = - Benchmarks<_>.InputMatrixProviderBuilder "BFSBenchmarks.txt" - -type SSSPWithoutTransferBenchmarkInt32() = - - inherit WithoutTransferBenchmark( - Algorithms.SSSP.run, - int32, - (fun _ -> Utils.nextInt (System.Random())), - 0, - (fun context matrix -> ClMatrix.CSR <| matrix.ToCSR.ToDevice context)) - - static member InputMatrixProvider = - Benchmarks<_>.InputMatrixProviderBuilder "BFSBenchmarks.txt" - type WithTransferBenchmark<'elem when 'elem : struct>( buildFunToBenchmark, converter: string -> 'elem, @@ -194,11 +167,8 @@ type WithTransferBenchmark<'elem when 'elem : struct>( override this.Benchmark() = this.LoadMatrixToGPU() this.BFS() - match this.ResultLevels with - | ClVector.Dense result -> - result.ToHost this.Processor |> ignore - this.Processor.PostAndReply Msg.MsgNotifyMe - | _ -> failwith "Impossible" + this.ResultLevels.ToHost this.Processor |> ignore + this.Processor.PostAndReply Msg.MsgNotifyMe type BFSWithTransferBenchmarkInt32() = diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/PageRank.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/PageRank.fs deleted file mode 100644 index 70273357..00000000 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/PageRank.fs +++ /dev/null @@ -1,132 +0,0 @@ -namespace GraphBLAS.FSharp.Benchmarks.Algorithms.PageRank - -open System.IO -open BenchmarkDotNet.Attributes -open GraphBLAS.FSharp -open GraphBLAS.FSharp.IO -open Brahma.FSharp -open Microsoft.FSharp.Core -open GraphBLAS.FSharp.Objects.ArraysExtensions -open GraphBLAS.FSharp.Benchmarks -open GraphBLAS.FSharp.Objects - -[] -[] -[] -[)>] -type Benchmarks( - buildFunToBenchmark, - converter: string -> float32, - binaryConverter, - buildMatrix) - = - - let mutable funToBenchmark = None - let mutable matrix = Unchecked.defaultof> - let mutable matrixPrepared = Unchecked.defaultof> - let mutable matrixHost = Unchecked.defaultof<_> - - let accuracy = 0.00000001f - - member val Result = Unchecked.defaultof> with get,set - - [] - member val OclContextInfo = Unchecked.defaultof with get, set - - [] - member val InputMatrixReader = Unchecked.defaultof with get, set - - member this.OclContext = (fst this.OclContextInfo).ClContext - member this.WorkGroupSize = snd this.OclContextInfo - - member this.Processor = - let p = (fst this.OclContextInfo).Queue - p.Error.Add(fun e -> failwithf "%A" e) - p - - static member AvailableContexts = Utils.availableContexts - - static member InputMatrixProviderBuilder pathToConfig = - let datasetFolder = "" - pathToConfig - |> Utils.getMatricesFilenames - |> Seq.map - (fun matrixFilename -> - printfn "%A" matrixFilename - - match Path.GetExtension matrixFilename with - | ".mtx" -> MtxReader(Utils.getFullPathToMatrix datasetFolder matrixFilename) - | _ -> failwith "Unsupported matrix format") - - member this.FunToBenchmark = - match funToBenchmark with - | None -> - let x = buildFunToBenchmark this.OclContext this.WorkGroupSize - funToBenchmark <- Some x - x - | Some x -> x - - member this.PageRank() = - this.Result <- this.FunToBenchmark this.Processor matrixPrepared accuracy - - member this.ClearInputMatrix() = - matrix.Dispose this.Processor - - member this.ClearPreparedMatrix() = - matrixPrepared.Dispose this.Processor - - member this.ClearResult() = this.Result.Dispose this.Processor - - member this.ReadMatrix() = - let converter = - match this.InputMatrixReader.Field with - | Pattern -> binaryConverter - | _ -> converter - - matrixHost <- this.InputMatrixReader.ReadMatrix converter - - member this.LoadMatrixToGPU() = - matrix <- buildMatrix this.OclContext matrixHost - - member this.PrepareMatrix() = - matrixPrepared <- Algorithms.PageRank.prepareMatrix this.OclContext this.WorkGroupSize this.Processor matrix - - abstract member GlobalSetup : unit -> unit - - abstract member IterationCleanup : unit -> unit - - abstract member GlobalCleanup : unit -> unit - - abstract member Benchmark : unit -> unit - -type PageRankWithoutTransferBenchmarkFloat32() = - - inherit Benchmarks( - Algorithms.PageRank.run, - float32, - (fun _ -> float32 <| Utils.nextInt (System.Random())), - (fun context matrix -> ClMatrix.CSR <| matrix.ToCSR.ToDevice context)) - - static member InputMatrixProvider = - Benchmarks.InputMatrixProviderBuilder "BFSBenchmarks.txt" - - [] - override this.GlobalSetup() = - this.ReadMatrix() - this.LoadMatrixToGPU() - this.Processor.PostAndReply(Msg.MsgNotifyMe) - this.PrepareMatrix() - this.ClearInputMatrix() - - [] - override this.IterationCleanup() = - this.ClearResult() - - [] - override this.GlobalCleanup() = - this.ClearPreparedMatrix() - - [] - override this.Benchmark() = - this.PageRank() - this.Processor.PostAndReply(Msg.MsgNotifyMe) diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj b/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj index 75ddfc15..6e8486b0 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj @@ -1,4 +1,4 @@ - + Exe @@ -25,7 +25,6 @@ - diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/Map2/Map2.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/Map2/Map2.fs index ab54db75..975e8a72 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/Map2/Map2.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/Map2/Map2.fs @@ -46,7 +46,7 @@ type Benchmarks<'matrixT, 'elem when 'matrixT :> IDeviceMemObject and 'elem : st static member AvailableContexts = Utils.availableContexts static member InputMatricesProviderBuilder pathToConfig = - let datasetFolder = "" + let datasetFolder = "EWiseAdd" pathToConfig |> Utils.getMatricesFilenames |> Seq.map diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Expand.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Expand.fs index e8a75071..0eb398cd 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Expand.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Expand.fs @@ -13,7 +13,7 @@ open GraphBLAS.FSharp.Benchmarks [] [] [] -[)>] +[)>] type Benchmarks<'elem when 'elem : struct>( buildFunToBenchmark, converter: string -> 'elem, @@ -22,9 +22,11 @@ type Benchmarks<'elem when 'elem : struct>( let mutable funToBenchmark = None - let mutable matrix = Unchecked.defaultof> + let mutable firstMatrix = Unchecked.defaultof> + let mutable secondMatrix = Unchecked.defaultof> - let mutable matrixHost = Unchecked.defaultof<_> + let mutable firstMatrixHost = Unchecked.defaultof<_> + let mutable secondMatrixHost = Unchecked.defaultof<_> member val ResultMatrix = Unchecked.defaultof option> with get, set @@ -34,7 +36,7 @@ type Benchmarks<'elem when 'elem : struct>( [] member val InputMatrixReader = Unchecked.defaultof with get, set - member this.OclContext: ClContext = (fst this.OclContextInfo).ClContext + member this.OclContext:ClContext = (fst this.OclContextInfo).ClContext member this.WorkGroupSize = snd this.OclContextInfo member this.Processor = @@ -74,10 +76,11 @@ type Benchmarks<'elem when 'elem : struct>( reader.ReadMatrix converter member this.Mxm() = - this.ResultMatrix <- this.FunToBenchmark this.Processor DeviceOnly matrix matrix + this.ResultMatrix <- this.FunToBenchmark this.Processor DeviceOnly firstMatrix secondMatrix member this.ClearInputMatrices() = - matrix.Dispose this.Processor + firstMatrix.Dispose this.Processor + secondMatrix.Dispose this.Processor member this.ClearResult() = match this.ResultMatrix with @@ -85,10 +88,12 @@ type Benchmarks<'elem when 'elem : struct>( | None -> () member this.ReadMatrices() = - matrixHost <- this.ReadMatrix this.InputMatrixReader + firstMatrixHost <- this.ReadMatrix this.InputMatrixReader + secondMatrixHost <- this.ReadMatrix this.InputMatrixReader member this.LoadMatricesToGPU () = - matrix <- buildMatrix this.OclContext matrixHost + firstMatrix <- buildMatrix this.OclContext firstMatrixHost + secondMatrix <- buildMatrix this.OclContext secondMatrixHost abstract member GlobalSetup : unit -> unit diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Masked.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Masked.fs index ff0495bf..69f0c399 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Masked.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Masked.fs @@ -51,7 +51,7 @@ type Masked<'elem when 'elem : struct>( static member AvaliableContexts = Utils.availableContexts static member InputMatrixProviderBuilder pathToConfig = - let datasetFolder = "" + let datasetFolder = "Mxm" pathToConfig |> Utils.getMatricesFilenames |> Seq.map diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs index 0655cd45..5a3ccf37 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs @@ -4,9 +4,7 @@ open BenchmarkDotNet.Running [] let main argv = let benchmarks = - BenchmarkSwitcher [| typeof - typeof - typeof |] + BenchmarkSwitcher [| typeof |] benchmarks.Run argv |> ignore 0 diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Vector/Map2.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Vector/Map2.fs index 5c4871e2..d4e0078c 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Vector/Map2.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Vector/Map2.fs @@ -27,7 +27,7 @@ type Benchmarks<'elem when 'elem : struct>( member val HostVectorPair = Unchecked.defaultof * Vector<'elem>> with get, set - member val ResultVector = Unchecked.defaultof option> with get,set + member val ResultVector = Unchecked.defaultof> with get,set [] member val OclContextInfo = Unchecked.defaultof with get, set @@ -67,9 +67,7 @@ type Benchmarks<'elem when 'elem : struct>( secondVector.Dispose this.Processor member this.ClearResult() = - match this.ResultVector with - | Some v -> v.Dispose this.Processor - | None -> () + this.ResultVector.Dispose this.Processor member this.CreateVectors() = this.HostVectorPair <- List.last (Gen.sample this.Size 1 generator) @@ -164,12 +162,8 @@ module WithTransfer = override this.Benchmark () = this.LoadVectorsToGPU() this.Map2() - match this.ResultVector with - | Some v -> - v.ToHost this.Processor |> ignore - this.Processor.PostAndReply Msg.MsgNotifyMe - | None -> () - + this.ResultVector.ToHost this.Processor |> ignore + this.Processor.PostAndReply Msg.MsgNotifyMe [] override this.IterationCleanup () = diff --git a/paket.lock b/paket.lock index 7cae92f5..f2bbb161 100644 --- a/paket.lock +++ b/paket.lock @@ -2,8 +2,8 @@ STORAGE: NONE NUGET remote: https://www.nuget.org/api/v2 altcover (7.6.812) - BenchmarkDotNet (0.13.9) - BenchmarkDotNet.Annotations (>= 0.13.9) - restriction: >= netstandard2.0 + BenchmarkDotNet (0.13.6) + BenchmarkDotNet.Annotations (>= 0.13.6) - restriction: >= netstandard2.0 CommandLineParser (>= 2.9.1) - restriction: >= netstandard2.0 Gee.External.Capstone (>= 2.3) - restriction: >= netstandard2.0 Iced (>= 1.17) - restriction: >= netstandard2.0 @@ -18,7 +18,7 @@ NUGET System.Reflection.Emit (>= 4.7) - restriction: && (< net6.0) (>= netstandard2.0) System.Reflection.Emit.Lightweight (>= 4.7) - restriction: && (< net6.0) (>= netstandard2.0) System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: && (< net6.0) (>= netstandard2.0) - BenchmarkDotNet.Annotations (0.13.9) - restriction: >= netstandard2.0 + BenchmarkDotNet.Annotations (0.13.6) - restriction: >= netstandard2.0 Brahma.FSharp (2.0.5) Brahma.FSharp.OpenCL.Printer (>= 2.0.5) - restriction: >= net7.0 Brahma.FSharp.OpenCL.Shared (>= 2.0.5) - restriction: >= net7.0 @@ -83,27 +83,27 @@ NUGET System.Security.Permissions (>= 4.7) - restriction: && (< net472) (>= netstandard2.0) Microsoft.Build.Tasks.Git (1.1.1) - copy_local: true Microsoft.CodeAnalysis.Analyzers (3.3.4) - restriction: >= netstandard2.0 - Microsoft.CodeAnalysis.Common (4.7) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Common (4.6) - restriction: >= netstandard2.0 Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) - restriction: >= netstandard2.0 System.Collections.Immutable (>= 7.0) - restriction: >= netstandard2.0 System.Memory (>= 4.5.5) - restriction: && (< net6.0) (>= netstandard2.0) System.Reflection.Metadata (>= 7.0) - restriction: >= netstandard2.0 System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: >= netstandard2.0 - System.Text.Encoding.CodePages (>= 7.0) - restriction: && (< net6.0) (>= netstandard2.0) + System.Text.Encoding.CodePages (>= 7.0) - restriction: >= netstandard2.0 System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: && (< net6.0) (>= netstandard2.0) - Microsoft.CodeAnalysis.CSharp (4.7) - restriction: >= netstandard2.0 - Microsoft.CodeAnalysis.Common (4.7) - restriction: >= netstandard2.0 - Microsoft.CodeCoverage (17.7.2) - restriction: || (>= net45) (>= netcoreapp2.1) + Microsoft.CodeAnalysis.CSharp (4.6) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Common (4.6) - restriction: >= netstandard2.0 + Microsoft.CodeCoverage (17.6.3) - restriction: || (>= net45) (>= netcoreapp2.1) Microsoft.CSharp (4.7) - restriction: || (&& (< netstandard1.3) (>= uap10.0)) (&& (< netstandard2.0) (>= uap10.0)) - Microsoft.Diagnostics.NETCore.Client (0.2.447801) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.NETCore.Client (0.2.430602) - restriction: >= netstandard2.0 Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: && (< net6.0) (>= netstandard2.0) Microsoft.Extensions.Logging (>= 6.0) - restriction: >= netstandard2.0 System.Buffers (>= 4.5.1) - restriction: && (< net6.0) (>= netstandard2.0) - Microsoft.Diagnostics.Runtime (3.0.442202) - restriction: >= netstandard2.0 - Microsoft.Diagnostics.NETCore.Client (>= 0.2.410101) - restriction: >= netstandard2.0 - System.Collections.Immutable (>= 6.0) - restriction: >= netstandard2.0 - System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: >= netstandard2.0 - Microsoft.Diagnostics.Tracing.TraceEvent (3.1.5) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.Runtime (2.4.416101) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.NETCore.Client (>= 0.2.251802) - restriction: >= netstandard2.0 + System.Collections.Immutable (>= 5.0) - restriction: >= netstandard2.0 + System.Runtime.CompilerServices.Unsafe (>= 5.0) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.Tracing.TraceEvent (3.1.3) - restriction: >= netstandard2.0 System.Runtime.CompilerServices.Unsafe (>= 5.0) - restriction: >= netstandard2.0 Microsoft.DotNet.PlatformAbstractions (3.1.6) - restriction: >= netstandard2.0 System.Runtime.InteropServices.RuntimeInformation (>= 4.0) - restriction: || (>= net45) (&& (>= netstandard1.3) (< netstandard2.0)) @@ -145,11 +145,11 @@ NUGET Microsoft.SourceLink.GitHub (1.0) - copy_local: true Microsoft.Build.Tasks.Git (>= 1.0) Microsoft.SourceLink.Common (>= 1.0) - Microsoft.TestPlatform.ObjectModel (17.7.2) - restriction: >= netcoreapp3.1 + Microsoft.TestPlatform.ObjectModel (17.6.3) - restriction: >= netcoreapp3.1 NuGet.Frameworks (>= 6.5) - restriction: || (>= net462) (>= netstandard2.0) System.Reflection.Metadata (>= 1.6) - restriction: || (>= net462) (>= netstandard2.0) - Microsoft.TestPlatform.TestHost (17.7.2) - restriction: >= netcoreapp2.1 - Microsoft.TestPlatform.ObjectModel (>= 17.7.2) - restriction: >= netcoreapp3.1 + Microsoft.TestPlatform.TestHost (17.6.3) - restriction: >= netcoreapp2.1 + Microsoft.TestPlatform.ObjectModel (>= 17.6.3) - restriction: >= netcoreapp3.1 Newtonsoft.Json (>= 13.0.1) - restriction: >= netcoreapp3.1 Microsoft.Win32.Primitives (4.3) - restriction: || (&& (< net45) (>= net46) (< netstandard1.4) (>= netstandard1.6)) (&& (< net45) (< netstandard1.4) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (< netstandard1.5) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (< netstandard1.5) (>= netstandard1.6) (>= uap10.0)) Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) @@ -214,7 +214,7 @@ NUGET System.Runtime.Serialization.Formatters (>= 4.3) - restriction: && (< net20) (>= netstandard1.3) (< netstandard2.0) System.Runtime.Serialization.Primitives (>= 4.3) - restriction: || (&& (< net20) (>= netstandard1.0) (< netstandard1.3)) (&& (< net20) (>= netstandard1.3) (< netstandard2.0)) System.Xml.XmlDocument (>= 4.3) - restriction: && (< net20) (>= netstandard1.3) (< netstandard2.0) - NuGet.Frameworks (6.7) - restriction: >= netcoreapp3.1 + NuGet.Frameworks (6.6.1) - restriction: >= netcoreapp3.1 Perfolizer (0.2.1) - restriction: >= netstandard2.0 System.Memory (>= 4.5.3) - restriction: >= netstandard2.0 QuikGraph (2.5) @@ -656,7 +656,7 @@ NUGET Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) - System.Text.Encoding.CodePages (7.0) - restriction: && (< net6.0) (>= netstandard2.0) + System.Text.Encoding.CodePages (7.0) - restriction: >= netstandard2.0 System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net462) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netstandard2.0)) System.Text.Encoding.Extensions (4.3) - restriction: || (&& (< net45) (>= net46) (< netstandard1.4) (>= netstandard1.6)) (&& (< net45) (< netstandard1.2) (>= netstandard1.6) (< win8)) (&& (< net45) (< netstandard1.3) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (< netstandard1.4) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (< netstandard1.5) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (< netstandard1.5) (>= netstandard1.6) (>= uap10.0)) (&& (>= netstandard1.6) (< portable-net45+win8+wpa81)) @@ -762,20 +762,20 @@ NUGET BinaryDefense.FSharp.Analyzers.Hashing (0.2.2) FSharp.Analyzers.SDK (>= 0.8) - restriction: >= net5.0 FSharp.Core (>= 5.0.1) - restriction: >= net5.0 - FSharp.Analyzers.SDK (0.14.1) - restriction: >= net5.0 - FSharp.Compiler.Service (>= 43.7.400) - restriction: >= net6.0 - FSharp.Core (>= 7.0.400) - restriction: >= net6.0 + FSharp.Analyzers.SDK (0.12) - restriction: >= net5.0 + FSharp.Compiler.Service (>= 43.7.200) - restriction: >= net6.0 + FSharp.Core (>= 7.0.200) - restriction: >= net6.0 McMaster.NETCore.Plugins (>= 1.4) - restriction: >= net6.0 - FSharp.Compiler.Service (43.7.400) - restriction: >= net6.0 - FSharp.Core (7.0.400) - restriction: >= netstandard2.0 + FSharp.Compiler.Service (43.7.300) - restriction: >= net6.0 + FSharp.Core (7.0.300) - restriction: >= netstandard2.0 System.Buffers (>= 4.5.1) - restriction: >= netstandard2.0 - System.Collections.Immutable (>= 7.0) - restriction: >= netstandard2.0 - System.Diagnostics.DiagnosticSource (>= 7.0.2) - restriction: >= netstandard2.0 + System.Collections.Immutable (>= 6.0) - restriction: >= netstandard2.0 + System.Diagnostics.DiagnosticSource (>= 6.0) - restriction: >= netstandard2.0 System.Memory (>= 4.5.5) - restriction: >= netstandard2.0 System.Reflection.Emit (>= 4.7) - restriction: >= netstandard2.0 - System.Reflection.Metadata (>= 7.0) - restriction: >= netstandard2.0 + System.Reflection.Metadata (>= 6.0.1) - restriction: >= netstandard2.0 System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: >= netstandard2.0 - FSharp.Core (7.0.400) - restriction: >= net5.0 + FSharp.Core (7.0.300) - restriction: >= net5.0 McMaster.NETCore.Plugins (1.4) - restriction: >= net6.0 Microsoft.DotNet.PlatformAbstractions (>= 3.1.6) - restriction: >= netcoreapp2.1 Microsoft.Extensions.DependencyModel (>= 5.0) - restriction: >= netcoreapp2.1 @@ -932,18 +932,17 @@ NUGET FSharp.Control.Reactive (5.0.5) - restriction: >= netstandard2.0 FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 System.Reactive (>= 5.0 < 6.0) - restriction: >= netstandard2.0 - FSharp.Core (7.0.400) - restriction: >= netstandard2.0 - Microsoft.Build.Framework (17.7.2) - restriction: >= netstandard2.0 + FSharp.Core (7.0.300) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (17.6.3) - restriction: >= netstandard2.0 Microsoft.VisualStudio.Setup.Configuration.Interop (>= 3.2.2146) - restriction: >= net472 Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) - System.Memory (>= 4.5.5) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: >= net472 System.Security.Permissions (>= 7.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net7.0) System.Security.Principal.Windows (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) - Microsoft.Build.Utilities.Core (17.7.2) - restriction: >= netstandard2.0 - Microsoft.Build.Framework (>= 17.7.2) - restriction: >= netstandard2.0 + Microsoft.Build.Utilities.Core (17.6.3) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (>= 17.6.3) - restriction: >= netstandard2.0 Microsoft.IO.Redist (>= 6.0) - restriction: >= net472 - Microsoft.NET.StringTools (>= 17.7.2) - restriction: >= netstandard2.0 + Microsoft.NET.StringTools (>= 17.6.3) - restriction: >= netstandard2.0 Microsoft.VisualStudio.Setup.Configuration.Interop (>= 3.2.2146) - restriction: || (>= net472) (>= net7.0) Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) System.Collections.Immutable (>= 7.0) - restriction: >= netstandard2.0 @@ -956,12 +955,12 @@ NUGET Microsoft.IO.Redist (6.0) - restriction: >= net472 System.Buffers (>= 4.5.1) - restriction: >= net472 System.Memory (>= 4.5.4) - restriction: >= net472 - Microsoft.NET.StringTools (17.7.2) - restriction: >= netstandard2.0 + Microsoft.NET.StringTools (17.6.3) - restriction: >= netstandard2.0 System.Memory (>= 4.5.5) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) Microsoft.NETCore.Platforms (7.0.4) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (>= net5.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= netcoreapp2.1) (< netcoreapp3.0)) Microsoft.NETCore.Targets (5.0) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) - Microsoft.VisualStudio.Setup.Configuration.Interop (3.7.2175) - restriction: || (>= net472) (>= net7.0) + Microsoft.VisualStudio.Setup.Configuration.Interop (3.6.2115) - restriction: || (>= net472) (>= net7.0) Microsoft.Win32.Registry (5.0) - restriction: || (&& (< net45) (>= netstandard2.0)) (&& (< net472) (< net7.0) (>= netstandard2.0)) System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= uap10.1) @@ -969,24 +968,25 @@ NUGET System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.1) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) Microsoft.Win32.SystemEvents (7.0) - restriction: >= net6.0 Mono.Posix.NETStandard (1.0) - restriction: >= netstandard2.0 - MSBuild.StructuredLogger (2.1.858) - restriction: >= netstandard2.0 + MSBuild.StructuredLogger (2.1.844) - restriction: >= netstandard2.0 Microsoft.Build.Framework (>= 17.5) - restriction: >= netstandard2.0 Microsoft.Build.Utilities.Core (>= 17.5) - restriction: >= netstandard2.0 Newtonsoft.Json (13.0.3) - restriction: >= netstandard2.0 - NuGet.Common (6.7) - restriction: >= netstandard2.0 - NuGet.Frameworks (>= 6.7) - restriction: >= netstandard2.0 - NuGet.Configuration (6.7) - restriction: >= netstandard2.0 - NuGet.Common (>= 6.7) - restriction: >= netstandard2.0 + NuGet.Common (6.6.1) - restriction: >= netstandard2.0 + NuGet.Frameworks (>= 6.6.1) - restriction: >= netstandard2.0 + NuGet.Configuration (6.6.1) - restriction: >= netstandard2.0 + NuGet.Common (>= 6.6.1) - restriction: >= netstandard2.0 System.Security.Cryptography.ProtectedData (>= 4.4) - restriction: && (< net472) (>= netstandard2.0) - NuGet.Frameworks (6.7) - restriction: >= netstandard2.0 - NuGet.Packaging (6.7) - restriction: >= netstandard2.0 + NuGet.Frameworks (6.6.1) - restriction: >= netstandard2.0 + NuGet.Packaging (6.6.1) - restriction: >= netstandard2.0 Newtonsoft.Json (>= 13.0.1) - restriction: >= netstandard2.0 - NuGet.Configuration (>= 6.7) - restriction: >= netstandard2.0 - NuGet.Versioning (>= 6.7) - restriction: >= netstandard2.0 - System.Security.Cryptography.Pkcs (>= 6.0.4) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) - NuGet.Protocol (6.7) - restriction: >= netstandard2.0 - NuGet.Packaging (>= 6.7) - restriction: >= netstandard2.0 - NuGet.Versioning (6.7) - restriction: >= netstandard2.0 + NuGet.Configuration (>= 6.6.1) - restriction: >= netstandard2.0 + NuGet.Versioning (>= 6.6.1) - restriction: >= netstandard2.0 + System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) + System.Security.Cryptography.Pkcs (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) + NuGet.Protocol (6.6.1) - restriction: >= netstandard2.0 + NuGet.Packaging (>= 6.6.1) - restriction: >= netstandard2.0 + NuGet.Versioning (6.6.1) - restriction: >= netstandard2.0 Octokit (0.48) System.Buffers (4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.1) (>= netstandard2.0)) (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (< netstandard1.1) (>= netstandard2.0) (< win8)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net461) (>= netstandard2.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net462) (>= netstandard2.1)) (&& (< net462) (< net6.0) (>= netstandard2.0)) (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (>= net472) (&& (>= net5.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) (&& (< netstandard1.1) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) System.Collections.Immutable (7.0) - restriction: >= netstandard2.0 @@ -999,9 +999,10 @@ NUGET System.Diagnostics.EventLog (7.0) - restriction: >= net7.0 System.Drawing.Common (7.0) - restriction: >= net6.0 Microsoft.Win32.SystemEvents (>= 7.0) - restriction: >= net6.0 - System.Formats.Asn1 (7.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (>= net5.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarintvos) (< xamarinwatchos)) (>= netstandard2.1) + System.Formats.Asn1 (7.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (>= net5.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= netstandard2.1) System.Buffers (>= 4.5.1) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.IO (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) System.Memory (4.5.5) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net462) (>= netstandard2.0)) (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (>= net472) (&& (>= net5.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.0)) (&& (< net7.0) (>= netstandard2.0)) (&& (>= netstandard2.0) (>= uap10.1)) System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.1)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (>= monotouch) (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (< uap10.1) (>= wpa81)) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) System.Numerics.Vectors (>= 4.4) - restriction: && (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) @@ -1011,7 +1012,7 @@ NUGET System.Reactive (5.0) - restriction: >= netstandard2.0 System.Runtime.InteropServices.WindowsRuntime (>= 4.3) - restriction: && (< net472) (< netcoreapp3.1) (>= netstandard2.0) System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net472) (&& (< netcoreapp3.1) (>= netstandard2.0)) (>= uap10.1) - System.Runtime (4.3.1) - restriction: && (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Runtime (4.3.1) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) Microsoft.NETCore.Platforms (>= 1.1.1) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) Microsoft.NETCore.Targets (>= 1.1.3) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) System.Runtime.CompilerServices.Unsafe (6.0) - restriction: || (&& (>= monoandroid) (< netstandard1.1) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (< monoandroid) (< netstandard1.0) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< netstandard1.1) (>= netstandard2.0) (< win8)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netstandard2.0)) (&& (>= net462) (>= netcoreapp2.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net462) (>= xamarinios)) (&& (>= net462) (>= xamarinmac)) (>= net472) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netstandard2.0)) (&& (< net6.0) (>= xamarinios)) (&& (< net6.0) (>= xamarinmac)) (&& (< netstandard1.0) (>= netstandard2.0) (>= win8)) (&& (< netstandard1.1) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= wp8)) @@ -1019,14 +1020,22 @@ NUGET System.Runtime (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) System.Security.AccessControl (6.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (>= net461) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net462) (>= netstandard2.0)) (&& (< net6.0) (>= netstandard2.0)) (>= netcoreapp2.1) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) System.Security.Principal.Windows (>= 5.0) - restriction: || (>= net461) (&& (< net6.0) (>= netstandard2.0)) - System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (>= net5.0) (< net6.0)) (&& (>= net5.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) + System.Security.Cryptography.Algorithms (4.3.1) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (>= net46) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net461) (< net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) + System.IO (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) + System.Security.Cryptography.Encoding (>= 4.3) - restriction: || (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) + System.Security.Cryptography.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< netstandard1.6)) (>= net463) + System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (< net472) (>= netstandard2.0)) (>= net5.0) (&& (< net6.0) (>= netstandard2.1)) Microsoft.NETCore.Platforms (>= 5.0) - restriction: && (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos) System.Formats.Asn1 (>= 5.0) - restriction: && (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Security.Cryptography.Algorithms (>= 4.3.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net46) (>= netstandard1.6) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6) (< uap10.1)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< net462) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6)) (>= net47) + System.Security.Cryptography.Encoding (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) System.Security.Cryptography.Pkcs (7.0.3) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) System.Buffers (>= 4.5.1) - restriction: && (< net462) (>= netstandard2.0) (< netstandard2.1) System.Formats.Asn1 (>= 7.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (>= netstandard2.1) System.Memory (>= 4.5.5) - restriction: && (< net462) (>= netstandard2.0) (< netstandard2.1) System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) + System.Security.Cryptography.Primitives (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (>= net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (< net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) (&& (>= net47) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net47) (< netstandard1.6) (>= netstandard2.0)) System.Security.Cryptography.ProtectedData (7.0.1) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (< net472) (>= netstandard2.0)) (>= net6.0) System.Memory (>= 4.5.5) - restriction: && (< net462) (< net6.0) (>= netstandard2.0) System.Security.Permissions (7.0) - restriction: >= netstandard2.0 @@ -1074,7 +1083,7 @@ NUGET Fable.Browser.Event (>= 1.5) - restriction: >= netstandard2.0 Fable.Core (>= 3.0) - restriction: >= netstandard2.0 FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 - Fable.Core (4.1) - restriction: >= netstandard2.0 + Fable.Core (4.0) - restriction: >= netstandard2.0 Fable.React (9.3) Fable.React.Types (>= 18.3) - restriction: >= netstandard2.0 Fable.ReactDom.Types (>= 18.2) - restriction: >= netstandard2.0 @@ -1167,23 +1176,22 @@ NUGET System.Runtime.Loader (>= 4.0) - restriction: && (< net461) (>= netstandard2.0) System.Security.Cryptography.Algorithms (>= 4.3) - restriction: && (< net461) (>= netstandard2.0) System.ValueTuple (>= 4.4) - restriction: >= net461 - FSharp.Core (7.0.400) + FSharp.Core (7.0.300) FSharp.Formatting (4.0.0-rc1) FSharp.Compiler.Service (>= 34.1) - restriction: >= netstandard2.0 FSharp.Literate (4.0.0-rc1) FSharp.Compiler.Service (>= 34.1) - restriction: >= netstandard2.0 FSharp.Core (>= 4.7) - restriction: >= netstandard2.0 - Microsoft.Build.Framework (17.7.2) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (17.6.3) - restriction: >= netstandard2.0 Microsoft.VisualStudio.Setup.Configuration.Interop (>= 3.2.2146) - restriction: >= net472 Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) - System.Memory (>= 4.5.5) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: >= net472 System.Security.Permissions (>= 7.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net7.0) System.Security.Principal.Windows (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) - Microsoft.Build.Utilities.Core (17.7.2) - restriction: >= netstandard2.0 - Microsoft.Build.Framework (>= 17.7.2) - restriction: >= netstandard2.0 + Microsoft.Build.Utilities.Core (17.6.3) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (>= 17.6.3) - restriction: >= netstandard2.0 Microsoft.IO.Redist (>= 6.0) - restriction: >= net472 - Microsoft.NET.StringTools (>= 17.7.2) - restriction: >= netstandard2.0 + Microsoft.NET.StringTools (>= 17.6.3) - restriction: >= netstandard2.0 Microsoft.VisualStudio.Setup.Configuration.Interop (>= 3.2.2146) - restriction: || (>= net472) (>= net7.0) Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) System.Collections.Immutable (>= 7.0) - restriction: >= netstandard2.0 @@ -1196,12 +1204,12 @@ NUGET Microsoft.IO.Redist (6.0) - restriction: >= net472 System.Buffers (>= 4.5.1) - restriction: >= net472 System.Memory (>= 4.5.4) - restriction: >= net472 - Microsoft.NET.StringTools (17.7.2) - restriction: >= netstandard2.0 + Microsoft.NET.StringTools (17.6.3) - restriction: >= netstandard2.0 System.Memory (>= 4.5.5) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) Microsoft.NETCore.Platforms (7.0.4) - restriction: || (&& (>= monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (>= monoandroid) (>= netcoreapp2.1) (< netstandard1.3)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (>= net5.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= monotouch) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netcoreapp2.1)) (&& (< net45) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netcoreapp2.0)) (&& (>= net461) (>= netcoreapp2.1)) (&& (>= netcoreapp2.0) (>= uap10.1)) (&& (< netcoreapp2.0) (>= netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp2.1) (< netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp2.1) (>= uap10.1)) Microsoft.NETCore.Targets (5.0) - restriction: || (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< net45) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) - Microsoft.VisualStudio.Setup.Configuration.Interop (3.7.2175) - restriction: || (>= net472) (>= net7.0) + Microsoft.VisualStudio.Setup.Configuration.Interop (3.6.2115) - restriction: || (>= net472) (>= net7.0) Microsoft.Win32.Primitives (4.3) - restriction: && (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) Microsoft.NETCore.Targets (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) @@ -1213,24 +1221,25 @@ NUGET System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.1) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) Microsoft.Win32.SystemEvents (7.0) - restriction: >= net6.0 Mono.Posix.NETStandard (1.0) - restriction: >= netstandard2.0 - MSBuild.StructuredLogger (2.1.858) - restriction: >= netstandard2.0 + MSBuild.StructuredLogger (2.1.844) - restriction: >= netstandard2.0 Microsoft.Build.Framework (>= 17.5) - restriction: >= netstandard2.0 Microsoft.Build.Utilities.Core (>= 17.5) - restriction: >= netstandard2.0 Newtonsoft.Json (13.0.3) - restriction: >= netstandard2.0 - NuGet.Common (6.7) - restriction: >= netstandard2.0 - NuGet.Frameworks (>= 6.7) - restriction: >= netstandard2.0 - NuGet.Configuration (6.7) - restriction: >= netstandard2.0 - NuGet.Common (>= 6.7) - restriction: >= netstandard2.0 + NuGet.Common (6.6.1) - restriction: >= netstandard2.0 + NuGet.Frameworks (>= 6.6.1) - restriction: >= netstandard2.0 + NuGet.Configuration (6.6.1) - restriction: >= netstandard2.0 + NuGet.Common (>= 6.6.1) - restriction: >= netstandard2.0 System.Security.Cryptography.ProtectedData (>= 4.4) - restriction: && (< net472) (>= netstandard2.0) - NuGet.Frameworks (6.7) - restriction: >= netstandard2.0 - NuGet.Packaging (6.7) - restriction: >= netstandard2.0 + NuGet.Frameworks (6.6.1) - restriction: >= netstandard2.0 + NuGet.Packaging (6.6.1) - restriction: >= netstandard2.0 Newtonsoft.Json (>= 13.0.1) - restriction: >= netstandard2.0 - NuGet.Configuration (>= 6.7) - restriction: >= netstandard2.0 - NuGet.Versioning (>= 6.7) - restriction: >= netstandard2.0 - System.Security.Cryptography.Pkcs (>= 6.0.4) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) - NuGet.Protocol (6.7) - restriction: >= netstandard2.0 - NuGet.Packaging (>= 6.7) - restriction: >= netstandard2.0 - NuGet.Versioning (6.7) - restriction: >= netstandard2.0 + NuGet.Configuration (>= 6.6.1) - restriction: >= netstandard2.0 + NuGet.Versioning (>= 6.6.1) - restriction: >= netstandard2.0 + System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) + System.Security.Cryptography.Pkcs (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) + NuGet.Protocol (6.6.1) - restriction: >= netstandard2.0 + NuGet.Packaging (>= 6.6.1) - restriction: >= netstandard2.0 + NuGet.Versioning (6.6.1) - restriction: >= netstandard2.0 runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - restriction: && (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - restriction: && (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - restriction: && (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) @@ -1334,7 +1343,7 @@ NUGET System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) System.Drawing.Common (7.0) - restriction: >= net6.0 Microsoft.Win32.SystemEvents (>= 7.0) - restriction: >= net6.0 - System.Formats.Asn1 (7.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (>= net5.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarintvos) (< xamarinwatchos)) (>= netstandard2.1) + System.Formats.Asn1 (7.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (>= net5.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= netstandard2.1) System.Buffers (>= 4.5.1) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) System.Globalization (4.3) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) @@ -1423,7 +1432,7 @@ NUGET System.Runtime.Extensions (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) System.Security.AccessControl (6.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (>= net461) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net462) (>= netstandard2.0)) (&& (< net6.0) (>= netstandard2.0)) (&& (>= netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netstandard2.0) (>= uap10.1)) System.Security.Principal.Windows (>= 5.0) - restriction: || (>= net461) (&& (< net6.0) (>= netstandard2.0)) - System.Security.Cryptography.Algorithms (4.3.1) - restriction: && (< net461) (>= netstandard2.0) + System.Security.Cryptography.Algorithms (4.3.1) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (>= net46) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net461) (< net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (< net461) (>= netstandard2.0)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - restriction: && (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - restriction: && (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) @@ -1438,9 +1447,10 @@ NUGET System.Security.Cryptography.Encoding (>= 4.3) - restriction: || (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) System.Security.Cryptography.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< netstandard1.6)) (>= net463) System.Text.Encoding (>= 4.3) - restriction: && (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) - System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (>= net5.0) (< net6.0)) (&& (>= net5.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) + System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (< net472) (>= netstandard2.0)) (>= net5.0) (&& (< net6.0) (>= netstandard2.1)) Microsoft.NETCore.Platforms (>= 5.0) - restriction: && (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos) System.Formats.Asn1 (>= 5.0) - restriction: && (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Security.Cryptography.Algorithms (>= 4.3.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net46) (>= netstandard1.6) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6) (< uap10.1)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< net462) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6)) (>= net47) System.Security.Cryptography.Encoding (4.3) - restriction: || (&& (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net461) (>= net463) (>= netstandard2.0)) Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs index 830c0bad..de7f0cc8 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs @@ -5,8 +5,9 @@ open FSharp.Quotations open GraphBLAS.FSharp open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Backend.Quotes -open GraphBLAS.FSharp.Objects.ArraysExtensions +open GraphBLAS.FSharp.Backend.Vector.Dense open GraphBLAS.FSharp.Objects.ClContextExtensions +open GraphBLAS.FSharp.Objects.ArraysExtensions open GraphBLAS.FSharp.Objects.ClCellExtensions module internal BFS = @@ -17,218 +18,54 @@ module internal BFS = workGroupSize = - let spMVInPlace = - Operations.SpMVInPlace add mul clContext workGroupSize + let spMVTo = + Operations.SpMVInplace add mul clContext workGroupSize let zeroCreate = - Vector.zeroCreate clContext workGroupSize + ClArray.zeroCreate clContext workGroupSize let ofList = Vector.ofList clContext workGroupSize - let maskComplementedInPlace = + let maskComplementedTo = Vector.map2InPlace Mask.complementedOp clContext workGroupSize let fillSubVectorTo = - Vector.assignByMaskInPlace Mask.assign clContext workGroupSize + Vector.assignByMaskInPlace (Convert.assignToOption Mask.assign) clContext workGroupSize let containsNonZero = - Vector.exists Predicates.isSome clContext workGroupSize + ClArray.exists Predicates.isSome clContext workGroupSize fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int) -> let vertexCount = matrix.RowCount - let levels = - zeroCreate queue DeviceOnly vertexCount Dense + let levels = zeroCreate queue HostInterop vertexCount - let front = + let frontier = ofList queue DeviceOnly Dense vertexCount [ source, 1 ] - let mutable level = 0 - let mutable stop = false - - while not stop do - level <- level + 1 - - //Assigning new level values - fillSubVectorTo queue levels front level - - //Getting new frontier - spMVInPlace queue matrix front front - - maskComplementedInPlace queue front levels - - //Checking if front is empty - stop <- - not - <| (containsNonZero queue front).ToHostAndFree queue - - front.Dispose queue - - levels - - let singleSourceSparse - (add: Expr int option -> int option>) - (mul: Expr<'a option -> int option -> int option>) - (clContext: ClContext) - workGroupSize - = - - let spMSpV = - Operations.SpMSpV add mul clContext workGroupSize + match frontier with + | ClVector.Dense front -> - let zeroCreate = - Vector.zeroCreate clContext workGroupSize - - let ofList = Vector.ofList clContext workGroupSize - - let maskComplemented = - Vector.map2Sparse Mask.complementedOp clContext workGroupSize - - let fillSubVectorTo = - Vector.assignByMaskInPlace Mask.assign clContext workGroupSize - - fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int) -> - let vertexCount = matrix.RowCount - - let levels = - zeroCreate queue DeviceOnly vertexCount Dense - - let mutable front = - ofList queue DeviceOnly Sparse vertexCount [ source, 1 ] - - let mutable level = 0 - let mutable stop = false + let mutable level = 0 + let mutable stop = false - while not stop do - level <- level + 1 + while not stop do + level <- level + 1 - //Assigning new level values - fillSubVectorTo queue levels front level + //Assigning new level values + fillSubVectorTo queue levels front (clContext.CreateClCell level) levels - //Getting new frontier - match spMSpV queue matrix front with - | None -> - front.Dispose queue - stop <- true - | Some newFrontier -> - front.Dispose queue - //Filtering visited vertices - match maskComplemented queue DeviceOnly newFrontier levels with - | None -> - stop <- true - newFrontier.Dispose queue - | Some f -> - front <- f - newFrontier.Dispose queue - - levels - - - let singleSourcePushPull - (add: Expr int option -> int option>) - (mul: Expr<'a option -> int option -> int option>) - (clContext: ClContext) - workGroupSize - = - - let spMVInPlace = - Operations.SpMVInPlace add mul clContext workGroupSize - - let spMSpV = - Operations.SpMSpV add mul clContext workGroupSize - - let zeroCreate = - Vector.zeroCreate clContext workGroupSize - - let ofList = Vector.ofList clContext workGroupSize - - let maskComplementedInPlace = - Vector.map2InPlace Mask.complementedOp clContext workGroupSize - - let maskComplemented = - Vector.map2Sparse Mask.complementedOp clContext workGroupSize - - let fillSubVectorInPlace = - Vector.assignByMaskInPlace Mask.assign clContext workGroupSize - - let toSparse = Vector.toSparse clContext workGroupSize - - let toDense = Vector.toDense clContext workGroupSize - - let countNNZ = - ClArray.count Predicates.isSome clContext workGroupSize - - //Push or pull functions - let getNNZ (queue: MailboxProcessor) (v: ClVector) = - match v with - | ClVector.Sparse v -> v.NNZ - | ClVector.Dense v -> countNNZ queue v - - let SPARSITY = 0.001f - - let push nnz size = - (float32 nnz) / (float32 size) <= SPARSITY - - fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int) -> - let vertexCount = matrix.RowCount - - let levels = - zeroCreate queue DeviceOnly vertexCount Dense - - let mutable frontier = - ofList queue DeviceOnly Sparse vertexCount [ source, 1 ] - - let mutable level = 0 - let mutable stop = false - - while not stop do - level <- level + 1 - - //Assigning new level values - fillSubVectorInPlace queue levels frontier level - - match frontier with - | ClVector.Sparse _ -> - //Getting new frontier - match spMSpV queue matrix frontier with - | None -> - frontier.Dispose queue - stop <- true - | Some newFrontier -> - frontier.Dispose queue - //Filtering visited vertices - match maskComplemented queue DeviceOnly newFrontier levels with - | None -> - stop <- true - newFrontier.Dispose queue - | Some newMaskedFrontier -> - newFrontier.Dispose queue - - //Push/pull - let NNZ = getNNZ queue newMaskedFrontier - - if (push NNZ newMaskedFrontier.Size) then - frontier <- newMaskedFrontier - else - frontier <- toDense queue DeviceOnly newMaskedFrontier - newMaskedFrontier.Dispose queue - | ClVector.Dense oldFrontier -> //Getting new frontier - spMVInPlace queue matrix frontier frontier - - maskComplementedInPlace queue frontier levels + spMVTo queue matrix frontier frontier - //Emptiness check - let NNZ = getNNZ queue frontier + maskComplementedTo queue front levels front - stop <- NNZ = 0 + //Checking if front is empty + stop <- + not + <| (containsNonZero queue front).ToHostAndFree queue - //Push/pull - if not stop then - if (push NNZ frontier.Size) then - frontier <- toSparse queue DeviceOnly frontier - oldFrontier.Free queue - else - frontier.Dispose queue + front.Free queue - levels + levels + | _ -> failwith "Not implemented" diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/PageRank.fs b/src/GraphBLAS-sharp.Backend/Algorithms/PageRank.fs deleted file mode 100644 index d806b4fe..00000000 --- a/src/GraphBLAS-sharp.Backend/Algorithms/PageRank.fs +++ /dev/null @@ -1,198 +0,0 @@ -namespace GraphBLAS.FSharp.Backend.Algorithms - -open GraphBLAS.FSharp -open GraphBLAS.FSharp.Backend -open Brahma.FSharp -open GraphBLAS.FSharp.Objects -open GraphBLAS.FSharp.Backend.Quotes -open GraphBLAS.FSharp.Backend.Vector.Dense -open GraphBLAS.FSharp.Objects.ClMatrix -open GraphBLAS.FSharp.Objects.ClContextExtensions -open GraphBLAS.FSharp.Objects.ArraysExtensions -open GraphBLAS.FSharp.Objects.ClCellExtensions - -module internal PageRank = - let alpha = 0.85f - - let private countOutDegree (clContext: ClContext) workGroupSize = - - let one = - <@ fun (x: float32 option) (_: int option) -> - let mutable res = 0 - - match x with - | Some _ -> res <- 1 - | None -> () - - if res = 0 then None else Some res @> - - let spMV = - Operations.SpMV.runTo ArithmeticOperations.intSumOption one clContext workGroupSize - - let zeroCreate = - GraphBLAS.FSharp.ClArray.zeroCreate clContext workGroupSize - - fun (queue: MailboxProcessor) (matrix: ClMatrix.CSR) -> - let outDegree: ClArray = - zeroCreate queue DeviceOnly matrix.ColumnCount - - spMV queue matrix outDegree outDegree - - outDegree - - let prepareMatrix (clContext: ClContext) workGroupSize = - - //Passing global variable to kernel in Brahma is not possible - let alpha = alpha - - let op = - <@ fun (x: float32 option) y -> - let mutable res = None - - match x, y with - | Some _, Some y -> res <- Some(alpha / (float32 y)) - | _ -> () - - res @> - - //TODO: generalize to map2 Matrix x Vector - let multiply = - <@ fun (range: Range1D) (numberOfRows: int) (matrixRowPointers: ClArray) (matrixValues: ClArray) (vectorValues: ClArray) (resultMatrixValues: ClArray) -> - - let i = range.GlobalID0 - let li = range.LocalID0 - let group = i / workGroupSize - - if group < numberOfRows then - let rowStart = matrixRowPointers.[group] - let rowEnd = matrixRowPointers.[group + 1] - - let vectorValue = vectorValues.[group] - let mutable index = rowStart + li - - while index < rowEnd do - let matrixValue = matrixValues.[index] - let resultValue = (%op) (Some matrixValue) vectorValue - - match resultValue with - | Some v -> resultMatrixValues.[index] <- v - | None -> () //This should not be reachable - - index <- index + workGroupSize @> - - let countOutDegree = countOutDegree clContext workGroupSize - - let copy = - GraphBLAS.FSharp.ClArray.copy clContext workGroupSize - - let transposeInPlace = - Matrix.CSR.Matrix.transposeInPlace clContext workGroupSize - - let multiply = clContext.Compile multiply - - fun (queue: MailboxProcessor) (matrix: ClMatrix) -> - - match matrix with - | ClMatrix.CSR matrix -> - - let outDegree = countOutDegree queue matrix - - let resultValues = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, matrix.Values.Length) - - let kernel = multiply.GetKernel() - - let ndRange = - Range1D.CreateValid(matrix.RowCount * workGroupSize, workGroupSize) - - queue.Post( - Msg.MsgSetArguments - (fun () -> - kernel.KernelFunc - ndRange - matrix.RowCount - matrix.RowPointers - matrix.Values - outDegree - resultValues) - ) - - queue.Post(Msg.CreateRunMsg<_, _> kernel) - - outDegree.Free queue - - let newMatrix = - { Context = clContext - RowCount = matrix.RowCount - ColumnCount = matrix.ColumnCount - RowPointers = copy queue DeviceOnly matrix.RowPointers - Columns = copy queue DeviceOnly matrix.Columns - Values = resultValues } - - transposeInPlace queue DeviceOnly newMatrix - |> ClMatrix.CSR - | _ -> failwith "Not implemented" - - let run (clContext: ClContext) workGroupSize = - - let squareOfDifference = ArithmeticOperations.squareOfDifference - let plus = ArithmeticOperations.float32SumOption - let mul = ArithmeticOperations.float32MulOption - - let spMVTo = - Operations.SpMVInPlace plus mul clContext workGroupSize - - let addToResult = - GraphBLAS.FSharp.Vector.map2InPlace plus clContext workGroupSize - - let subtractAndSquare = - GraphBLAS.FSharp.Vector.map2To squareOfDifference clContext workGroupSize - - let reduce = - GraphBLAS.FSharp.Vector.reduce <@ (+) @> clContext workGroupSize - - let create = - GraphBLAS.FSharp.Vector.create clContext workGroupSize - - fun (queue: MailboxProcessor) (matrix: ClMatrix) accuracy -> - - let vertexCount = matrix.RowCount - - //None is 0 - let mutable rank = - create queue DeviceOnly vertexCount Dense None - - let mutable prevRank = - create queue DeviceOnly vertexCount Dense (Some(1.0f / (float32 vertexCount))) - - let mutable errors = - create queue DeviceOnly vertexCount Dense None - - let addition = - create queue DeviceOnly vertexCount Dense (Some((1.0f - alpha) / (float32 vertexCount))) - - let mutable error = accuracy + 0.1f - - let mutable i = 0 - - while error > accuracy do - i <- i + 1 - - // rank = matrix*rank + (1 - alpha)/N - spMVTo queue matrix prevRank rank - addToResult queue rank addition - - // error - subtractAndSquare queue rank prevRank errors - error <- sqrt <| (reduce queue errors).ToHostAndFree queue - - //Swap vectors - let temp = rank - rank <- prevRank - prevRank <- temp - - prevRank.Dispose queue - errors.Dispose queue - addition.Dispose queue - - rank diff --git a/src/GraphBLAS-sharp.Backend/Common/Bitmap.fs b/src/GraphBLAS-sharp.Backend/Common/Bitmap.fs deleted file mode 100644 index 889cd43f..00000000 --- a/src/GraphBLAS-sharp.Backend/Common/Bitmap.fs +++ /dev/null @@ -1,99 +0,0 @@ -namespace GraphBLAS.FSharp.Backend.Common - -open Brahma.FSharp -open GraphBLAS.FSharp.Objects.ClContextExtensions -open GraphBLAS.FSharp.Objects.ArraysExtensions -open GraphBLAS.FSharp.Backend.Quotes -open GraphBLAS.FSharp.Backend.Common.Map - -module Bitmap = - let private getUniqueBitmapGeneral predicate (clContext: ClContext) workGroupSize = - - let getUniqueBitmap = - <@ fun (ndRange: Range1D) (inputArray: ClArray<'a>) inputLength (isUniqueBitmap: ClArray) -> - - let gid = ndRange.GlobalID0 - - if gid < inputLength then - let isUnique = (%predicate) gid inputLength inputArray // brahma error - - if isUnique then - isUniqueBitmap.[gid] <- 1 - else - isUniqueBitmap.[gid] <- 0 @> - - let kernel = clContext.Compile(getUniqueBitmap) - - fun (processor: MailboxProcessor<_>) allocationMode (inputArray: ClArray<'a>) -> - - let inputLength = inputArray.Length - - let ndRange = - Range1D.CreateValid(inputLength, workGroupSize) - - let bitmap = - clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, inputLength) - - let kernel = kernel.GetKernel() - - processor.Post(Msg.MsgSetArguments(fun () -> kernel.KernelFunc ndRange inputArray inputLength bitmap)) - - processor.Post(Msg.CreateRunMsg<_, _> kernel) - - bitmap - - /// - /// Gets the bitmap that indicates the first elements of the sequences of consecutive identical elements - /// - /// OpenCL context. - let firstOccurrence clContext = - getUniqueBitmapGeneral - <| Predicates.firstOccurrence () - <| clContext - - /// - /// Gets the bitmap that indicates the last elements of the sequences of consecutive identical elements - /// - /// OpenCL context. - let lastOccurrence clContext = - getUniqueBitmapGeneral - <| Predicates.lastOccurrence () - <| clContext - - let private getUniqueBitmap2General<'a when 'a: equality> getUniqueBitmap (clContext: ClContext) workGroupSize = - - let map = - map2 <@ fun x y -> x ||| y @> clContext workGroupSize - - let firstGetBitmap = getUniqueBitmap clContext workGroupSize - - fun (processor: MailboxProcessor<_>) allocationMode (firstArray: ClArray<'a>) (secondArray: ClArray<'a>) -> - let firstBitmap = - firstGetBitmap processor DeviceOnly firstArray - - let secondBitmap = - firstGetBitmap processor DeviceOnly secondArray - - let result = - map processor allocationMode firstBitmap secondBitmap - - firstBitmap.Free processor - secondBitmap.Free processor - - result - - /// - /// Gets the bitmap that indicates the first elements of the sequences - /// of consecutive identical elements from either first array or second array. - /// - /// OpenCL context. - let firstOccurrence2 clContext = - getUniqueBitmap2General firstOccurrence clContext - - /// - /// Gets the bitmap that indicates the last elements of the sequences - /// of consecutive identical elements from either first array or second array. - /// - /// OpenCL context. - let lastOccurrence2 clContext = - getUniqueBitmap2General lastOccurrence clContext diff --git a/src/GraphBLAS-sharp.Backend/Common/Common.fs b/src/GraphBLAS-sharp.Backend/Common/Common.fs index ae9839f2..53777d33 100644 --- a/src/GraphBLAS-sharp.Backend/Common/Common.fs +++ b/src/GraphBLAS-sharp.Backend/Common/Common.fs @@ -43,20 +43,6 @@ module Common = /// let runByKeysStandard = Sort.Radix.runByKeysStandard - /// - /// Sorts stable input array of values by given integer keys and return only values. - /// - /// - /// - /// let keys = [| 0; 4; 3; 1; 2; 6; 5 |] - /// let values = [| 1.9; 2.8; 3.7; 4.6; 5.5; 6.4; 7.3; |] - /// runByKeysStandard clContext 32 processor keys values - /// ... - /// > val values = [| 1.9; 4.6; 5.5; 3.7; 2.8; 7.3; 6.4 |] - /// - /// - let runByKeysStandardValuesOnly = Sort.Radix.runByKeysStandardValuesOnly - /// /// Sorts stable input array of integer keys. /// @@ -385,27 +371,8 @@ module Common = /// /// The length of the result must be calculated in advance. /// - let segmentSequential<'a> - (reduceOp: Expr<'a option -> 'a option -> 'a option>) - (clContext: ClContext) - workGroupSize - = + let segmentSequential<'a> (reduceOp: Expr<'a -> 'a -> 'a option>) (clContext: ClContext) workGroupSize = Reduce.ByKey.Option.segmentSequential reduceOp clContext workGroupSize - /// - /// Reduces values by key. Each segment is reduced by one work item. - /// - /// ClContext. - /// Work group size. - /// Operation for reducing values. - /// - /// The length of the result and offsets for each segment must be calculated in advance. - /// - let segmentSequentialByOffsets<'a> - (reduceOp: Expr<'a -> 'a -> 'a option>) - (clContext: ClContext) - workGroupSize - = - Reduce.ByKey.Option.segmentSequentialByOffsets reduceOp clContext workGroupSize module ByKey2D = /// diff --git a/src/GraphBLAS-sharp.Backend/Common/Sort/Radix.fs b/src/GraphBLAS-sharp.Backend/Common/Sort/Radix.fs index b7db92d0..03ad4ed0 100644 --- a/src/GraphBLAS-sharp.Backend/Common/Sort/Radix.fs +++ b/src/GraphBLAS-sharp.Backend/Common/Sort/Radix.fs @@ -269,7 +269,7 @@ module internal Radix = failwith "Mismatch of key lengths and value. Lengths must be the same" if values.Length <= 1 then - copy processor DeviceOnly keys, dataCopy processor DeviceOnly values + dataCopy processor allocationMode values else let firstKeys = copy processor DeviceOnly keys @@ -319,26 +319,14 @@ module internal Radix = keysPair <- swap keysPair valuesPair <- swap valuesPair - globalOffset.Free processor localOffset.Free processor shift.Free processor + (fst keysPair).Free processor (snd keysPair).Free processor (snd valuesPair).Free processor - (fst keysPair, fst valuesPair) - - let runByKeysStandardValuesOnly clContext workGroupSize = - let runByKeys = - runByKeys clContext workGroupSize defaultBitCount - - fun (processor: MailboxProcessor<_>) allocationMode (keys: ClArray) (values: ClArray<'a>) -> - let keys, values = - runByKeys processor allocationMode keys values - - keys.Free processor - - values + (fst valuesPair) let runByKeysStandard clContext workGroupSize = runByKeys clContext workGroupSize defaultBitCount diff --git a/src/GraphBLAS-sharp.Backend/Common/Sum.fs b/src/GraphBLAS-sharp.Backend/Common/Sum.fs index 94a745c2..8f3fe936 100644 --- a/src/GraphBLAS-sharp.Backend/Common/Sum.fs +++ b/src/GraphBLAS-sharp.Backend/Common/Sum.fs @@ -428,7 +428,7 @@ module Reduce = let itemKeyId = lid + 1 let startKeyIndex = - (%Search.Bin.lowerPositionLocal) length itemKeyId localBitmap + (%Search.Bin.lowerPosition) length itemKeyId localBitmap match startKeyIndex with | Some startPosition -> @@ -473,135 +473,6 @@ module Reduce = reducedValues, reducedKeys module Option = - /// - /// Reduces values by key. Each segment is reduced by one work item. - /// - /// ClContext. - /// Work group size. - /// Operation for reducing values. - let segmentSequential<'a> - (reduceOp: Expr<'a option -> 'a option -> 'a option>) - (clContext: ClContext) - workGroupSize - = - - let kernel = - <@ fun (ndRange: Range1D) uniqueKeyCount keysLength (offsets: ClArray) (keys: ClArray) (values: ClArray<'a option>) (reducedValues: ClArray<'a>) (firstReducedKeys: ClArray) (resultPositions: ClArray) -> - - let gid = ndRange.GlobalID0 - - if gid < uniqueKeyCount then - let startPosition = - (%Search.Bin.lowerPosition) keysLength gid offsets - - match startPosition with - | Some startPosition -> - let firstSourceKey = keys.[startPosition] - - let mutable sum = None - - let mutable currentPosition = startPosition - - while currentPosition < keysLength - && firstSourceKey = keys.[currentPosition] do - let result = (%reduceOp) sum values.[currentPosition] // brahma error - sum <- result - currentPosition <- currentPosition + 1 - - match sum with - | Some value -> - reducedValues.[gid] <- value - resultPositions.[gid] <- 1 - | None -> resultPositions.[gid] <- 0 - - firstReducedKeys.[gid] <- firstSourceKey - | None -> () @> // not possible if done correctly - - let kernel = clContext.Compile kernel - - let getUniqueBitmap = - Bitmap.lastOccurrence clContext workGroupSize - - let scatterData = - Scatter.lastOccurrence clContext workGroupSize - - let scatterIndices = - Scatter.lastOccurrence clContext workGroupSize - - let prefixSum = - PrefixSum.standardExcludeInPlace clContext workGroupSize - - fun (processor: MailboxProcessor<_>) allocationMode (keys: ClArray) (values: ClArray<'a option>) -> - - let offsets = - getUniqueBitmap processor DeviceOnly keys - - let uniqueKeysCount = - (prefixSum processor offsets) - .ToHostAndFree processor - - let reducedValues = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, uniqueKeysCount) - - let reducedKeys = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, uniqueKeysCount) - - let resultPositions = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, uniqueKeysCount) - - let ndRange = - Range1D.CreateValid(uniqueKeysCount, workGroupSize) - - let kernel = kernel.GetKernel() - - processor.Post( - Msg.MsgSetArguments - (fun () -> - kernel.KernelFunc - ndRange - uniqueKeysCount - keys.Length - offsets - keys - values - reducedValues - reducedKeys - resultPositions) - ) - - processor.Post(Msg.CreateRunMsg<_, _>(kernel)) - - offsets.Free processor - - let resultLength = - (prefixSum processor resultPositions) - .ToHostAndFree processor - - if resultLength = 0 then - reducedValues.Free processor - reducedKeys.Free processor - resultPositions.Free processor - None - else - // write values - let resultValues = - clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, resultLength) - - scatterData processor resultPositions reducedValues resultValues - - reducedValues.Free processor - - // write keys - let resultKeys = - clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, resultLength) - - scatterIndices processor resultPositions reducedKeys resultKeys - - reducedKeys.Free processor - resultPositions.Free processor - - Some(resultValues, resultKeys) - /// /// Reduces values by key. Each segment is reduced by one work item. /// @@ -609,13 +480,9 @@ module Reduce = /// Work group size. /// Operation for reducing values. /// - /// The length of the result and offsets for each segment must be calculated in advance. + /// The length of the result must be calculated in advance. /// - let segmentSequentialByOffsets<'a> - (reduceOp: Expr<'a -> 'a -> 'a option>) - (clContext: ClContext) - workGroupSize - = + let segmentSequential<'a> (reduceOp: Expr<'a -> 'a -> 'a option>) (clContext: ClContext) workGroupSize = let kernel = <@ fun (ndRange: Range1D) uniqueKeyCount keysLength (offsets: ClArray) (keys: ClArray) (values: ClArray<'a>) (reducedValues: ClArray<'a>) (firstReducedKeys: ClArray) (resultPositions: ClArray) -> @@ -701,10 +568,6 @@ module Reduce = .ToHostAndFree processor if resultLength = 0 then - reducedValues.Free processor - reducedKeys.Free processor - resultPositions.Free processor - None else // write values @@ -985,11 +848,6 @@ module Reduce = .ToHostAndFree processor if resultLength = 0 then - reducedValues.Free processor - firstReducedKeys.Free processor - secondReducedKeys.Free processor - resultPositions.Free processor - None else // write value diff --git a/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj b/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj index 3921770d..4198cbe0 100644 --- a/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj +++ b/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj @@ -1,4 +1,4 @@ - + @@ -33,13 +33,10 @@ - - - @@ -61,10 +58,10 @@ - + + - diff --git a/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs index 0bea32dd..8f305001 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs @@ -405,7 +405,7 @@ module Matrix = let pairwise = ClArray.pairwise clContext workGroupSize let subtract = - Backend.Common.Map.map <@ fun (fst, snd) -> snd - fst @> clContext workGroupSize + ClArray.map <@ fun (fst, snd) -> snd - fst @> clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (matrix: ClMatrix.CSR<'b>) -> let pointerPairs = diff --git a/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs b/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs index 766925aa..2ae2678b 100644 --- a/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs @@ -23,6 +23,7 @@ module ClMatrix = q.Post(Msg.CreateFreeMsg<_>(this.Values)) q.Post(Msg.CreateFreeMsg<_>(this.Columns)) q.Post(Msg.CreateFreeMsg<_>(this.RowPointers)) + q.PostAndReply(Msg.MsgNotifyMe) member this.Dispose q = (this :> IDeviceMemObject).Dispose q diff --git a/src/GraphBLAS-sharp.Backend/Objects/Vector.fs b/src/GraphBLAS-sharp.Backend/Objects/Vector.fs index e7a221f1..82e25d8d 100644 --- a/src/GraphBLAS-sharp.Backend/Objects/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Objects/Vector.fs @@ -18,6 +18,7 @@ module ClVector = member this.Dispose(q) = q.Post(Msg.CreateFreeMsg<_>(this.Values)) q.Post(Msg.CreateFreeMsg<_>(this.Indices)) + q.PostAndReply(Msg.MsgNotifyMe) member this.Dispose(q) = (this :> IDeviceMemObject).Dispose(q) diff --git a/src/GraphBLAS-sharp.Backend/Operations/Operations.fs b/src/GraphBLAS-sharp.Backend/Operations/Operations.fs index 2e99b7dc..5f43bc74 100644 --- a/src/GraphBLAS-sharp.Backend/Operations/Operations.fs +++ b/src/GraphBLAS-sharp.Backend/Operations/Operations.fs @@ -1,7 +1,6 @@ namespace GraphBLAS.FSharp open Brahma.FSharp -open Microsoft.FSharp.Core open Microsoft.FSharp.Quotations open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Objects.ClContextExtensions @@ -61,11 +60,11 @@ module Operations = fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector<'a>) (rightVector: ClVector<'b>) -> match leftVector, rightVector with | ClVector.Dense left, ClVector.Dense right -> - map2Dense processor allocationMode left right - |> ClVector.Dense - |> Some + ClVector.Dense + <| map2Dense processor allocationMode left right | ClVector.Sparse left, ClVector.Sparse right -> - Option.map ClVector.Sparse (map2Sparse processor allocationMode left right) + ClVector.Sparse + <| map2Sparse processor allocationMode left right | _ -> failwith "Vector formats are not matching." /// @@ -91,11 +90,11 @@ module Operations = fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector<'a>) (rightVector: ClVector<'b>) -> match leftVector, rightVector with | ClVector.Sparse left, ClVector.Sparse right -> - Option.map ClVector.Sparse (map2Sparse processor allocationMode left right) + ClVector.Sparse + <| map2Sparse processor allocationMode left right | ClVector.Dense left, ClVector.Dense right -> - map2Dense processor allocationMode left right - |> ClVector.Dense - |> Some + ClVector.Dense + <| map2Dense processor allocationMode left right | _ -> failwith "Vector formats are not matching." /// @@ -294,7 +293,7 @@ module Operations = /// Type of binary function to combine entries. /// OpenCL context. /// Should be a power of 2 and greater than 1. - let SpMVInPlace + let SpMVInplace (add: Expr<'c option -> 'c option -> 'c option>) (mul: Expr<'a option -> 'b option -> 'c option>) (clContext: ClContext) @@ -310,69 +309,9 @@ module Operations = | _ -> failwith "Not implemented yet" /// - /// CSR Matrix - dense vector multiplication. - /// - /// Type of binary function to reduce entries. - /// Type of binary function to combine entries. - /// OpenCL context. - /// Should be a power of 2 and greater than 1. - let SpMV - (add: Expr<'c option -> 'c option -> 'c option>) - (mul: Expr<'a option -> 'b option -> 'c option>) - (clContext: ClContext) - workGroupSize - = - - let run = SpMV.run add mul clContext workGroupSize - - fun (queue: MailboxProcessor<_>) allocationFlag (matrix: ClMatrix<'a>) (vector: ClVector<'b>) -> - match matrix, vector with - | ClMatrix.CSR m, ClVector.Dense v -> run queue allocationFlag m v |> ClVector.Dense - | _ -> failwith "Not implemented yet" - - /// - /// CSR Matrix - sparse vector multiplication. Optimized for bool OR and AND operations. - /// - /// Type of binary function to reduce entries. - /// Type of binary function to combine entries. - /// OpenCL context. - /// Should be a power of 2 and greater than 1. - let SpMSpVBool - (add: Expr bool option -> bool option>) - (mul: Expr bool option -> bool option>) - (clContext: ClContext) - workGroupSize - = - - let run = - SpMSpV.runBoolStandard add mul clContext workGroupSize - - fun (queue: MailboxProcessor<_>) (matrix: ClMatrix) (vector: ClVector) -> - match matrix, vector with - | ClMatrix.CSR m, ClVector.Sparse v -> Option.map ClVector.Sparse (run queue m v) - | _ -> failwith "Not implemented yet" - - /// - /// CSR Matrix - sparse vector multiplication. + /// Matrix-vector multiplication. /// - /// Type of binary function to reduce entries. - /// Type of binary function to combine entries. - /// OpenCL context. - /// Should be a power of 2 and greater than 1. - let SpMSpV - (add: Expr<'c option -> 'c option -> 'c option>) - (mul: Expr<'a option -> 'b option -> 'c option>) - (clContext: ClContext) - workGroupSize - = - - let run = - SpMSpV.run add mul clContext workGroupSize - - fun (queue: MailboxProcessor<_>) (matrix: ClMatrix<'a>) (vector: ClVector<'b>) -> - match matrix, vector with - | ClMatrix.CSR m, ClVector.Sparse v -> Option.map ClVector.Sparse (run queue m v) - | _ -> failwith "Not implemented yet" + let SpMV = SpMV.run /// /// Kronecker product for matrices. diff --git a/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs b/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs index 45ff0df0..7c9229a1 100644 --- a/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs +++ b/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs @@ -1,4 +1,4 @@ -namespace GraphBLAS.FSharp.Backend.Operations.SpGeMM +namespace GraphBLAS.FSharp.Backend.Operations.SpGeMM open Brahma.FSharp open FSharp.Quotations @@ -37,7 +37,7 @@ module internal Expand = let multiply (predicate: Expr<'a -> 'b -> 'c option>) (clContext: ClContext) workGroupSize = let getBitmap = - Backend.Common.Map.map2<'a, 'b, int> (Map.choose2Bitmap predicate) clContext workGroupSize + ClArray.map2<'a, 'b, int> (Map.choose2Bitmap predicate) clContext workGroupSize let prefixSum = Common.PrefixSum.standardExcludeInPlace clContext workGroupSize @@ -174,10 +174,10 @@ module internal Expand = let sortByColumnsAndRows (clContext: ClContext) workGroupSize = let sortByKeyIndices = - Common.Sort.Radix.runByKeysStandardValuesOnly clContext workGroupSize + Common.Sort.Radix.runByKeysStandard clContext workGroupSize let sortByKeyValues = - Common.Sort.Radix.runByKeysStandardValuesOnly clContext workGroupSize + Common.Sort.Radix.runByKeysStandard clContext workGroupSize let sortKeys = Common.Sort.Radix.standardRunKeysOnly clContext workGroupSize @@ -213,7 +213,7 @@ module internal Expand = Common.Reduce.ByKey2D.Option.segmentSequential opAdd clContext workGroupSize let getUniqueBitmap = - Backend.Common.Bitmap.lastOccurrence2 clContext workGroupSize + ClArray.Bitmap.lastOccurrence2 clContext workGroupSize let prefixSum = Common.PrefixSum.standardExcludeInPlace clContext workGroupSize diff --git a/src/GraphBLAS-sharp.Backend/Operations/SpMSpV.fs b/src/GraphBLAS-sharp.Backend/Operations/SpMSpV.fs deleted file mode 100644 index bca119a1..00000000 --- a/src/GraphBLAS-sharp.Backend/Operations/SpMSpV.fs +++ /dev/null @@ -1,305 +0,0 @@ -namespace GraphBLAS.FSharp.Backend.Operations - -open Brahma.FSharp -open GraphBLAS.FSharp.Backend.Common -open GraphBLAS.FSharp.Backend.Quotes -open Microsoft.FSharp.Quotations -open GraphBLAS.FSharp.Objects -open GraphBLAS.FSharp.Objects.ClVector -open GraphBLAS.FSharp.Objects.ClContextExtensions -open GraphBLAS.FSharp.Objects.ArraysExtensions -open GraphBLAS.FSharp.Objects.ClCellExtensions - -module SpMSpV = - - //For v in vectorIndices collect R[v] and R[v + 1] - let private collectRows (clContext: ClContext) workGroupSize = - - let collectRows = - <@ fun (ndRange: Range1D) inputSize (vectorIndices: ClArray) (rowOffsets: ClArray) (resultArray: ClArray) -> - - let i = ndRange.GlobalID0 - - //resultArray is twice vector size - if i < (inputSize * 2) then - let columnIndex = vectorIndices.[i / 2] - - if i % 2 = 0 then - resultArray.[i] <- rowOffsets.[columnIndex] - else - resultArray.[i] <- rowOffsets.[columnIndex + 1] - elif i = inputSize * 2 then - resultArray.[i] <- 0 @> - - let collectRows = clContext.Compile collectRows - - fun (queue: MailboxProcessor<_>) size (vectorIndices: ClArray) (rowOffsets: ClArray) -> - - let ndRange = - Range1D.CreateValid(size * 2 + 1, workGroupSize) - - // Last element will contain length of array for gather - let resultRows = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, size * 2 + 1) - - let collectRows = collectRows.GetKernel() - - queue.Post( - Msg.MsgSetArguments(fun () -> collectRows.KernelFunc ndRange size vectorIndices rowOffsets resultRows) - ) - - queue.Post(Msg.CreateRunMsg<_, _>(collectRows)) - - resultRows - - //For above array compute result offsets - let private computeOffsetsInplace (clContext: ClContext) workGroupSize = - - let prepareOffsets = - <@ fun (ndRange: Range1D) inputSize (inputArray: ClArray) -> - - let i = ndRange.GlobalID0 - - if i < inputSize && i % 2 = 0 then - inputArray.[i + 1] <- inputArray.[i + 1] - inputArray.[i] - inputArray.[i] <- 0 @> - - let sum = - PrefixSum.standardExcludeInPlace clContext workGroupSize - - let prepareOffsets = clContext.Compile prepareOffsets - - fun (queue: MailboxProcessor<_>) size (input: ClArray) -> - - let ndRange = Range1D.CreateValid(size, workGroupSize) - - let prepareOffsets = prepareOffsets.GetKernel() - - queue.Post(Msg.MsgSetArguments(fun () -> prepareOffsets.KernelFunc ndRange size input)) - - queue.Post(Msg.CreateRunMsg<_, _>(prepareOffsets)) - - let resSize = (sum queue input).ToHostAndFree queue - - resSize - - //Gather rows from the matrix that will be used in multiplication - let private gather (clContext: ClContext) workGroupSize = - - let gather = - <@ fun (ndRange: Range1D) vectorNNZ (rowOffsets: ClArray) (matrixRowPointers: ClArray) (matrixColumns: ClArray) (matrixValues: ClArray<'a>) (vectorIndices: ClArray) (resultRowsArray: ClArray) (resultIndicesArray: ClArray) (resultValuesArray: ClArray<'a>) -> - - //Serial number of row to gather - let row = ndRange.GlobalID0 - - if row < vectorNNZ then - let offsetIndex = row * 2 + 1 - let rowOffset = rowOffsets.[offsetIndex] - - //vectorIndices.[row] --- actual number of row in matrix - let actualRow = vectorIndices.[row] - let matrixIndexOffset = matrixRowPointers.[actualRow] - - if rowOffset <> rowOffsets.[offsetIndex + 1] then - let rowSize = rowOffsets.[offsetIndex + 1] - rowOffset - - for i in 0 .. rowSize - 1 do - resultRowsArray.[i + rowOffset] <- actualRow - resultIndicesArray.[i + rowOffset] <- matrixColumns.[matrixIndexOffset + i] - resultValuesArray.[i + rowOffset] <- matrixValues.[matrixIndexOffset + i] @> - - let collectRows = collectRows clContext workGroupSize - - let computeOffsetsInplace = - computeOffsetsInplace clContext workGroupSize - - let gather = clContext.Compile gather - - fun (queue: MailboxProcessor<_>) (matrix: ClMatrix.CSR<'a>) (vector: ClVector.Sparse<'b>) -> - - //Collect R[v] and R[v + 1] for each v in vector - let collectedRows = - collectRows queue vector.NNZ vector.Indices matrix.RowPointers - - //Place R[v + 1] - R[v] in previous array and do prefix sum, computing offsets for gather array - let gatherArraySize = - computeOffsetsInplace queue (vector.NNZ * 2 + 1) collectedRows - - if gatherArraySize = 0 then - collectedRows.Free queue - None - else - let ndRange = - Range1D.CreateValid(vector.NNZ, workGroupSize) - - let gather = gather.GetKernel() - - let resultRows = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, gatherArraySize) - - let resultIndices = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, gatherArraySize) - - let resultValues = - clContext.CreateClArrayWithSpecificAllocationMode<'a>(DeviceOnly, gatherArraySize) - - if gatherArraySize > 0 then - queue.Post( - Msg.MsgSetArguments - (fun () -> - gather.KernelFunc - ndRange - vector.NNZ - collectedRows - matrix.RowPointers - matrix.Columns - matrix.Values - vector.Indices - resultRows - resultIndices - resultValues) - ) - - queue.Post(Msg.CreateRunMsg<_, _>(gather)) - - collectedRows.Free queue - - Some(resultRows, resultIndices, resultValues) - - - let private multiplyScalar (clContext: ClContext) (mul: Expr<'a option -> 'b option -> 'c option>) workGroupSize = - - let multiply = - <@ fun (ndRange: Range1D) resultLength vectorLength (rowIndices: ClArray) (matrixValues: ClArray<'a>) (vectorIndices: ClArray) (vectorValues: ClArray<'b>) (resultValues: ClArray<'c option>) -> - let i = ndRange.GlobalID0 - - if i < resultLength then - let index = rowIndices.[i] - let matrixValue = matrixValues.[i] - - let vectorValue = - (%Search.Bin.byKey) vectorLength index vectorIndices vectorValues - - let res = (%mul) (Some matrixValue) vectorValue - resultValues.[i] <- res @> - - let multiply = clContext.Compile multiply - - fun (queue: MailboxProcessor<_>) (columnIndices: ClArray) (matrixValues: ClArray<'a>) (vector: Sparse<'b>) -> - - let resultLength = columnIndices.Length - - let result = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, resultLength) - - let ndRange = - Range1D.CreateValid(resultLength, workGroupSize) - - let multiply = multiply.GetKernel() - - queue.Post( - Msg.MsgSetArguments - (fun () -> - multiply.KernelFunc - ndRange - resultLength - vector.NNZ - columnIndices - matrixValues - vector.Indices - vector.Values - result) - ) - - queue.Post(Msg.CreateRunMsg<_, _>(multiply)) - - result - - let run - (add: Expr<'c option -> 'c option -> 'c option>) - (mul: Expr<'a option -> 'b option -> 'c option>) - (clContext: ClContext) - workGroupSize - = - - //TODO: Common.Gather? - let gather = gather clContext workGroupSize - - //TODO: Radix sort - let sort = - Sort.Bitonic.sortKeyValuesInplace clContext workGroupSize - - let multiplyScalar = - multiplyScalar clContext mul workGroupSize - - let segReduce = - Reduce.ByKey.Option.segmentSequential add clContext workGroupSize - - fun (queue: MailboxProcessor<_>) (matrix: ClMatrix.CSR<'a>) (vector: ClVector.Sparse<'b>) -> - gather queue matrix vector - |> Option.map - (fun (gatherRows, gatherIndices, gatherValues) -> - sort queue gatherIndices gatherRows gatherValues - - let sortedRows, sortedIndices, sortedValues = gatherRows, gatherIndices, gatherValues - - let multipliedValues = - multiplyScalar queue sortedRows sortedValues vector - - sortedValues.Free queue - sortedRows.Free queue - - let result = - segReduce queue DeviceOnly sortedIndices multipliedValues - |> Option.map - (fun (reducedValues, reducedKeys) -> - - { Context = clContext - Indices = reducedKeys - Values = reducedValues - Size = matrix.ColumnCount }) - - multipliedValues.Free queue - sortedIndices.Free queue - - result) - |> Option.bind id - - - let runBoolStandard - (add: Expr<'c option -> 'c option -> 'c option>) - (mul: Expr<'a option -> 'b option -> 'c option>) - (clContext: ClContext) - workGroupSize - = - - let gather = gather clContext workGroupSize - - let sort = - Sort.Radix.standardRunKeysOnly clContext workGroupSize - - let removeDuplicates = - GraphBLAS.FSharp.ClArray.removeDuplications clContext workGroupSize - - let create = - GraphBLAS.FSharp.ClArray.create clContext workGroupSize - - fun (queue: MailboxProcessor<_>) (matrix: ClMatrix.CSR<'a>) (vector: ClVector.Sparse<'b>) -> - - gather queue matrix vector - |> Option.map - (fun (gatherRows, gatherIndices, gatherValues) -> - gatherRows.Free queue - gatherValues.Free queue - - let sortedIndices = sort queue gatherIndices - - let resultIndices = removeDuplicates queue sortedIndices - - gatherIndices.Free queue - sortedIndices.Free queue - - { Context = clContext - Indices = resultIndices - Values = create queue DeviceOnly resultIndices.Length true - Size = matrix.ColumnCount }) diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs index 8dc37dec..f79a2193 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs @@ -1,7 +1,6 @@ -namespace GraphBLAS.FSharp.Backend.Quotes +namespace GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects -open Microsoft.FSharp.Quotations module ArithmeticOperations = let inline private mkUnaryOp zero unaryOp = @@ -37,16 +36,6 @@ module ArithmeticOperations = if res = zero then None else Some res @> - let inline private mkNumericSumAsMul zero = - <@ fun (x: 't option) (y: 't option) -> - let mutable res = None - - match x, y with - | Some f, Some s -> res <- Some(f + s) - | _ -> () - - res @> - let inline private mkNumericMul zero = <@ fun (x: 't option) (y: 't option) -> let mutable res = zero @@ -184,16 +173,12 @@ module ArithmeticOperations = let floatMulAtLeastOne = mkNumericMulAtLeastOne 0.0 let float32MulAtLeastOne = mkNumericMulAtLeastOne 0f - let intSumAsMul = mkNumericSumAsMul System.Int32.MaxValue - let notOption = <@ fun x -> match x with | Some true -> None | _ -> Some true @> - let intNotQ = <@ fun x -> if x = 0 then 1 else 0 @> - let inline private binOpQ zero op = <@ fun (left: 'a) (right: 'a) -> let result = (%op) left right @@ -231,42 +216,3 @@ module ArithmeticOperations = let floatMul = createPair 0.0 (*) <@ (*) @> let float32Mul = createPair 0.0f (*) <@ (*) @> - - // without zero - let intAddWithoutZero = <@ fun x y -> Some(x + y) @> - - let intMulWithoutZero = <@ fun x y -> Some(x * y) @> - - // other operations - let less<'a when 'a: comparison> = - <@ fun (x: 'a option) (y: 'a option) -> - match x, y with - | Some x, Some y -> if (x < y) then Some 1 else None - | Some x, None -> Some 1 - | _ -> None @> - - let minOption<'a when 'a: comparison> = - <@ fun (x: 'a option) (y: 'a option) -> - match x, y with - | Some x, Some y -> Some(min x y) - | Some x, None -> Some x - | None, Some y -> Some y - | _ -> None @> - - let min<'a when 'a: comparison> = - <@ fun (x: 'a) (y: 'a) -> Some(min x y) @> - - let fst<'a> = <@ fun (x: 'a) (_: 'a) -> Some x @> - - //PageRank specific - let squareOfDifference = - <@ fun (x: float32 option) (y: float32 option) -> - let mutable res = 0.0f - - match x, y with - | Some f, Some s -> res <- (f - s) * (f - s) - | Some f, None -> res <- f * f - | None, Some s -> res <- s * s - | None, None -> () - - if res = 0.0f then None else Some res @> diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Map.fs b/src/GraphBLAS-sharp.Backend/Quotes/Map.fs index 9a518e40..2f74a7c5 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Map.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Map.fs @@ -28,11 +28,6 @@ module Map = | Some _ -> 1 | None -> 0 @> - let predicateBitmap<'a> (predicate: Expr<'a -> bool>) = - <@ fun (x: 'a) -> - let res = (%predicate) x - if res then 1 else 0 @> - let inc = <@ fun item -> item + 1 @> let subtraction = <@ fun first second -> first - second @> diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Mask.fs b/src/GraphBLAS-sharp.Backend/Quotes/Mask.fs index 9b19b5b1..3a27b5d6 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Mask.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Mask.fs @@ -7,12 +7,6 @@ module Mask = | _, None -> left | _ -> right @> - let assignComplemented<'a when 'a: struct> = - <@ fun (left: 'a option) (right: 'a option) -> - match left, right with - | _, None -> right - | _ -> left @> - let op<'a, 'b when 'a: struct and 'b: struct> = <@ fun (left: 'a option) (right: 'b option) -> match right with diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Search.fs b/src/GraphBLAS-sharp.Backend/Quotes/Search.fs index 27687645..07660c28 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Search.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Search.fs @@ -130,32 +130,6 @@ module Search = /// Find lower position of item in array. /// let lowerPosition<'a when 'a: equality and 'a: comparison> = - <@ fun length sourceItem (keys: ClArray<'a>) -> - - let mutable leftEdge = 0 - let mutable rightEdge = length - 1 - let mutable resultPosition = None - - while leftEdge <= rightEdge do - let currentPosition = (leftEdge + rightEdge) / 2 - let currentKey = keys.[currentPosition] - - if sourceItem = currentKey then - // remember positions and move left - resultPosition <- Some currentPosition - - rightEdge <- currentPosition - 1 - elif sourceItem < currentKey then - rightEdge <- currentPosition - 1 - else - leftEdge <- currentPosition + 1 - - resultPosition @> - - /// - /// Find lower position of item in array. - /// - let lowerPositionLocal<'a when 'a: equality and 'a: comparison> = <@ fun length sourceItem (keys: 'a []) -> let mutable leftEdge = 0 diff --git a/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs b/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs index 6b6a7629..a99cd8c4 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs @@ -3,7 +3,6 @@ namespace GraphBLAS.FSharp.Backend.Vector.Dense open Brahma.FSharp open Microsoft.FSharp.Quotations open GraphBLAS.FSharp -open GraphBLAS.FSharp.Backend.Common open GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects.ClVector open GraphBLAS.FSharp.Objects.ClContextExtensions @@ -16,7 +15,7 @@ module Vector = workGroupSize = - let map = Map.map op clContext workGroupSize + let map = ClArray.map op clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClArray<'a option>) -> @@ -29,7 +28,7 @@ module Vector = = let map2InPlace = - Map.map2InPlace opAdd clContext workGroupSize + ClArray.map2InPlace opAdd clContext workGroupSize fun (processor: MailboxProcessor<_>) (leftVector: ClArray<'a option>) (rightVector: ClArray<'b option>) (resultVector: ClArray<'c option>) -> @@ -41,7 +40,8 @@ module Vector = workGroupSize = - let map2 = Map.map2 opAdd clContext workGroupSize + let map2 = + ClArray.map2 opAdd clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClArray<'a option>) (rightVector: ClArray<'b option>) -> @@ -66,24 +66,20 @@ module Vector = let kernel = clContext.Compile(fillSubVectorKernel) - fun (processor: MailboxProcessor<_>) (leftVector: ClArray<'a option>) (maskVector: ClArray<'b option>) (value: 'a) (resultVector: ClArray<'a option>) -> + fun (processor: MailboxProcessor<_>) (leftVector: ClArray<'a option>) (maskVector: ClArray<'b option>) (value: ClCell<'a>) (resultVector: ClArray<'a option>) -> let ndRange = Range1D.CreateValid(leftVector.Length, workGroupSize) let kernel = kernel.GetKernel() - let valueCell = clContext.CreateClCell(value) - processor.Post( Msg.MsgSetArguments - (fun () -> kernel.KernelFunc ndRange leftVector.Length leftVector maskVector valueCell resultVector) + (fun () -> kernel.KernelFunc ndRange leftVector.Length leftVector maskVector value resultVector) ) processor.Post(Msg.CreateRunMsg<_, _>(kernel)) - valueCell.Free processor - let assignByMask<'a, 'b when 'a: struct and 'b: struct> (maskOp: Expr<'a option -> 'b option -> 'a -> 'a option>) (clContext: ClContext) @@ -93,7 +89,7 @@ module Vector = let assignByMask = assignByMaskInPlace maskOp clContext workGroupSize - fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClArray<'a option>) (maskVector: ClArray<'b option>) (value: 'a) -> + fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClArray<'a option>) (maskVector: ClArray<'b option>) (value: ClCell<'a>) -> let resultVector = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, leftVector.Length) @@ -101,49 +97,6 @@ module Vector = resultVector - let assignBySparseMaskInPlace<'a, 'b when 'a: struct and 'b: struct> - (maskOp: Expr<'a option -> 'b option -> 'a -> 'a option>) - (clContext: ClContext) - workGroupSize - = - - let fillSubVectorKernel = - <@ fun (ndRange: Range1D) resultLength (leftVector: ClArray<'a option>) (maskVectorIndices: ClArray) (maskVectorValues: ClArray<'b>) (value: ClCell<'a>) (resultVector: ClArray<'a option>) -> - - let gid = ndRange.GlobalID0 - - if gid < resultLength then - let i = maskVectorIndices.[gid] - resultVector.[i] <- (%maskOp) leftVector.[i] (Some maskVectorValues.[gid]) value.Value @> - - let kernel = clContext.Compile(fillSubVectorKernel) - - fun (processor: MailboxProcessor<_>) (leftVector: ClArray<'a option>) (maskVector: Sparse<'b>) (value: 'a) (resultVector: ClArray<'a option>) -> - - let ndRange = - Range1D.CreateValid(maskVector.NNZ, workGroupSize) - - let kernel = kernel.GetKernel() - - let valueCell = clContext.CreateClCell(value) - - processor.Post( - Msg.MsgSetArguments - (fun () -> - kernel.KernelFunc - ndRange - maskVector.NNZ - leftVector - maskVector.Indices - maskVector.Values - valueCell - resultVector) - ) - - processor.Post(Msg.CreateRunMsg<_, _>(kernel)) - - valueCell.Free processor - let toSparse<'a when 'a: struct> (clContext: ClContext) workGroupSize = let scatterValues = @@ -153,7 +106,7 @@ module Vector = Common.Scatter.lastOccurrence clContext workGroupSize let getBitmap = - Map.map (Map.option 1 0) clContext workGroupSize + ClArray.map (Map.option 1 0) clContext workGroupSize let prefixSum = Common.PrefixSum.standardExcludeInPlace clContext workGroupSize @@ -162,7 +115,7 @@ module Vector = ClArray.init Map.id clContext workGroupSize let allValues = - Map.map (Map.optionToValueOrZero Unchecked.defaultof<'a>) clContext workGroupSize + ClArray.map (Map.optionToValueOrZero Unchecked.defaultof<'a>) clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (vector: ClArray<'a option>) -> diff --git a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Common.fs b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Common.fs index 8ad13044..07e6e5e7 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Common.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Common.fs @@ -3,7 +3,6 @@ namespace GraphBLAS.FSharp.Backend.Vector.Sparse open Brahma.FSharp open Microsoft.FSharp.Control open GraphBLAS.FSharp -open GraphBLAS.FSharp.Backend open GraphBLAS.FSharp.Objects.ClVector open GraphBLAS.FSharp.Objects.ClContextExtensions open GraphBLAS.FSharp.Objects.ClCellExtensions @@ -75,7 +74,7 @@ module internal Common = let concatIndices = ClArray.concat clContext workGroupSize let mapIndices = - Common.Map.mapWithValue clContext workGroupSize <@ fun x y -> x + y @> + ClArray.mapWithValue clContext workGroupSize <@ fun x y -> x + y @> fun (processor: MailboxProcessor<_>) allocationMode (vectors: Sparse<'a> seq) -> diff --git a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map.fs b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map.fs index f0a69a41..329e5484 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map.fs @@ -95,7 +95,7 @@ module internal Map = queue.Post(Msg.CreateFreeMsg<_>(indices)) { Context = clContext - Indices = resultIndices + Indices = indices Values = resultValues Size = vector.Size } diff --git a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map2.fs b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map2.fs index fb91840f..feb6e484 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map2.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map2.fs @@ -4,11 +4,9 @@ open Brahma.FSharp open FSharp.Quotations open Microsoft.FSharp.Control open GraphBLAS.FSharp.Objects -open GraphBLAS.FSharp.Objects.ArraysExtensions open GraphBLAS.FSharp.Objects.ClVector open GraphBLAS.FSharp.Objects.ClContextExtensions open GraphBLAS.FSharp.Backend.Quotes -open Microsoft.FSharp.Core module internal Map2 = let private preparePositions<'a, 'b, 'c> opAdd (clContext: ClContext) workGroupSize = @@ -80,7 +78,7 @@ module internal Map2 = preparePositions<'a, 'b, 'c> op clContext workGroupSize let setPositions = - Common.setPositionsOption clContext workGroupSize + Common.setPositions clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector.Sparse<'a>) (rightVector: ClVector.Sparse<'b>) -> @@ -93,113 +91,17 @@ module internal Map2 = rightVector.Values rightVector.Indices - let result = - setPositions processor allocationMode allValues allIndices bitmap - |> Option.map - (fun (resultValues, resultIndices) -> - { Context = clContext - Values = resultValues - Indices = resultIndices - Size = leftVector.Size }) - - allIndices.Free processor - allValues.Free processor - bitmap.Free processor - - result - - let private preparePositionsSparseDense<'a, 'b, 'c> (clContext: ClContext) workGroupSize opAdd = - - let preparePositions (op: Expr<'a option -> 'b option -> 'c option>) = - <@ fun (ndRange: Range1D) length (leftValues: ClArray<'a>) (leftIndices: ClArray) (rightValues: ClArray<'b option>) (resultBitmap: ClArray) (resultValues: ClArray<'c>) (resultIndices: ClArray) -> - - let gid = ndRange.GlobalID0 - - if gid < length then - - let i = leftIndices.[gid] - - let (leftValue: 'a option) = Some leftValues.[gid] - - let (rightValue: 'b option) = rightValues.[i] - - match (%op) leftValue rightValue with - | Some value -> - resultValues.[gid] <- value - resultIndices.[gid] <- i - - resultBitmap.[gid] <- 1 - | None -> resultBitmap.[gid] <- 0 @> - - let kernel = - clContext.Compile <| preparePositions opAdd - - fun (processor: MailboxProcessor<_>) (vectorLenght: int) (leftValues: ClArray<'a>) (leftIndices: ClArray) (rightValues: ClArray<'b option>) -> - - let resultBitmap = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, vectorLenght) - - let resultIndices = - clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, vectorLenght) - - let resultValues = - clContext.CreateClArrayWithSpecificAllocationMode<'c>(DeviceOnly, vectorLenght) - - let ndRange = - Range1D.CreateValid(vectorLenght, workGroupSize) - - let kernel = kernel.GetKernel() - - processor.Post( - Msg.MsgSetArguments - (fun () -> - kernel.KernelFunc - ndRange - vectorLenght - leftValues - leftIndices - rightValues - resultBitmap - resultValues - resultIndices) - ) - - processor.Post(Msg.CreateRunMsg<_, _> kernel) - - resultBitmap, resultValues, resultIndices - - //TODO: unify with sparseXsparse - let runSparseDense<'a, 'b, 'c when 'a: struct and 'b: struct and 'c: struct> - op - (clContext: ClContext) - workGroupSize - = - - let prepare = - preparePositionsSparseDense<'a, 'b, 'c> clContext workGroupSize op - - let setPositions = - Common.setPositionsOption clContext workGroupSize - - fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector.Sparse<'a>) (rightVector: ClArray<'b option>) -> - - let bitmap, allValues, allIndices = - prepare processor leftVector.NNZ leftVector.Values leftVector.Indices rightVector - - let result = + let resultValues, resultIndices = setPositions processor allocationMode allValues allIndices bitmap - |> Option.map - (fun (resultValues, resultIndices) -> - { Context = clContext - Values = resultValues - Indices = resultIndices - Size = leftVector.Size }) - allIndices.Free processor - allValues.Free processor - bitmap.Free processor + processor.Post(Msg.CreateFreeMsg<_>(allIndices)) + processor.Post(Msg.CreateFreeMsg<_>(allValues)) + processor.Post(Msg.CreateFreeMsg<_>(bitmap)) - result + { Context = clContext + Values = resultValues + Indices = resultIndices + Size = max leftVector.Size rightVector.Size } let private preparePositionsAssignByMask<'a, 'b when 'a: struct and 'b: struct> op @@ -281,9 +183,7 @@ module internal Map2 = let setPositions = Common.setPositions clContext workGroupSize - fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector.Sparse<'a>) (rightVector: ClVector.Sparse<'b>) (value: 'a) -> - - let valueCell = clContext.CreateClCell(value) + fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector.Sparse<'a>) (rightVector: ClVector.Sparse<'b>) (value: ClCell<'a>) -> let bitmap, values, indices = prepare @@ -293,12 +193,11 @@ module internal Map2 = leftVector.Indices rightVector.Values rightVector.Indices - valueCell + value let resultValues, resultIndices = setPositions processor allocationMode values indices bitmap - processor.Post(Msg.CreateFreeMsg<_>(valueCell)) processor.Post(Msg.CreateFreeMsg<_>(indices)) processor.Post(Msg.CreateFreeMsg<_>(values)) processor.Post(Msg.CreateFreeMsg<_>(bitmap)) @@ -381,7 +280,7 @@ module internal Map2 = preparePositions<'a, 'b, 'c> op clContext workGroupSize let setPositions = - Common.setPositionsOption clContext workGroupSize + Common.setPositions clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector.Sparse<'a>) (rightVector: ClVector.Sparse<'b>) -> @@ -394,17 +293,14 @@ module internal Map2 = processor.Post(Msg.CreateFreeMsg<_>(rightValues)) processor.Post(Msg.CreateFreeMsg<_>(isLeft)) - let result = + let resultValues, resultIndices = setPositions processor allocationMode allValues allIndices positions - |> Option.map - (fun (resultValues, resultIndices) -> - { Context = clContext - Values = resultValues - Indices = resultIndices - Size = max leftVector.Size rightVector.Size }) processor.Post(Msg.CreateFreeMsg<_>(allIndices)) processor.Post(Msg.CreateFreeMsg<_>(allValues)) processor.Post(Msg.CreateFreeMsg<_>(positions)) - result + { Context = clContext + Values = resultValues + Indices = resultIndices + Size = max leftVector.Size rightVector.Size } diff --git a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs index 1a7fb8f7..98aae51b 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs @@ -36,8 +36,6 @@ module Vector = let map2 = Map2.run - let map2SparseDense = Map2.runSparseDense - let map2AtLeastOne opAdd (clContext: ClContext) workGroupSize allocationMode = Map2.AtLeastOne.run (Convert.atLeastOneToOption opAdd) clContext workGroupSize allocationMode diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/BFS.fs b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/BFS.fs index 92ba3d1b..edf40fea 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/BFS.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/BFS.fs @@ -26,20 +26,6 @@ let testFixtures (testContext: TestContext) = context workGroupSize - let bfsSparse = - Algorithms.BFS.singleSourceSparse - ArithmeticOperations.intSumOption - ArithmeticOperations.intMulOption - context - workGroupSize - - let bfsPushPull = - Algorithms.BFS.singleSourcePushPull - ArithmeticOperations.intSumOption - ArithmeticOperations.intMulOption - context - workGroupSize - testPropertyWithConfig config testName <| fun (matrix: int [,]) -> @@ -60,34 +46,22 @@ let testFixtures (testContext: TestContext) = let matrix = matrixHost.ToDevice context - let res = bfs queue matrix source - - let resSparse = bfsSparse queue matrix source - - let resPushPull = bfsPushPull queue matrix source - - let resHost = res.ToHost queue - let resHostSparse = resSparse.ToHost queue - let resHostPushPull = resPushPull.ToHost queue - - matrix.Dispose queue - res.Dispose queue - resSparse.Dispose queue - resPushPull.Dispose queue + match matrix with + | ClMatrix.CSR mtx -> + let res = + bfs queue matrix source |> ClVector.Dense - match resHost, resHostSparse, resHostPushPull with - | Vector.Dense resHost, Vector.Dense resHostSparse, Vector.Dense resHostPushPull -> - let actual = resHost |> Utils.unwrapOptionArray 0 + let resHost = res.ToHost queue - let actualSparse = - resHostSparse |> Utils.unwrapOptionArray 0 + (mtx :> IDeviceMemObject).Dispose queue + res.Dispose queue - let actualPushPull = - resHostPushPull |> Utils.unwrapOptionArray 0 + match resHost with + | Vector.Dense resHost -> + let actual = resHost |> Utils.unwrapOptionArray 0 - Expect.sequenceEqual actual expected "Dense bfs is not as expected" - Expect.sequenceEqual actualSparse expected "Sparse bfs is not as expected" - Expect.sequenceEqual actualPushPull expected "Push-pull bfs is not as expected" + Expect.sequenceEqual actual expected "Sequences must be equal" + | _ -> failwith "Not implemented" | _ -> failwith "Not implemented" ] let tests = diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/PageRank.fs b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/PageRank.fs deleted file mode 100644 index 72f30025..00000000 --- a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/PageRank.fs +++ /dev/null @@ -1,118 +0,0 @@ -module GraphBLAS.FSharp.Tests.Backend.Algorithms.PageRank - -open Expecto -open GraphBLAS.FSharp -open GraphBLAS.FSharp.Tests -open GraphBLAS.FSharp.Tests.Context -open GraphBLAS.FSharp.Objects.ClVectorExtensions -open GraphBLAS.FSharp.Objects - -let private alpha = 0.85f -let private accuracy = 0.00001f - -let prepareNaive (matrix: float32 [,]) = - let result = Array2D.copy matrix - let rowCount = Array2D.length1 matrix - let outDegrees = Array.zeroCreate rowCount - - //Count degree - Array2D.iteri (fun r c v -> outDegrees.[r] <- outDegrees.[r] + (if v <> 0f then 1f else 0f)) matrix - - //Set value - Array2D.iteri - (fun r c v -> - result.[r, c] <- - if v <> 0f then - alpha / outDegrees.[r] - else - 0f) - matrix - - //Transpose - Array2D.iteri - (fun r c _ -> - if r > c then - let temp = result.[r, c] - result.[r, c] <- result.[c, r] - result.[c, r] <- temp) - matrix - - result - -let pageRankNaive (matrix: float32 [,]) = - let rowCount = Array2D.length1 matrix - let mutable result = Array.zeroCreate rowCount - - let mutable prev = - Array.create rowCount (1f / (float32 rowCount)) - - let mutable error = accuracy + 1f - let addConst = (1f - alpha) / (float32 rowCount) - - while (error > accuracy) do - for r in 0 .. rowCount - 1 do - result.[r] <- 0f - - for c in 0 .. rowCount - 1 do - result.[r] <- result.[r] + matrix.[r, c] * prev.[c] - - result.[r] <- result.[r] + addConst - - error <- - sqrt - <| Array.fold2 (fun e x1 x2 -> e + (x1 - x2) * (x1 - x2)) 0f result prev - - let temp = result - result <- prev - prev <- temp - - prev - -let testFixtures (testContext: TestContext) = - [ let config = Utils.undirectedAlgoConfig - let context = testContext.ClContext - let queue = testContext.Queue - let workGroupSize = Utils.defaultWorkGroupSize - - let testName = - sprintf "Test on %A" testContext.ClContext - - let pageRank = - Algorithms.PageRank.run context workGroupSize - - testPropertyWithConfig config testName - <| fun (matrix: float32 [,]) -> - let matrixHost = - Utils.createMatrixFromArray2D CSR matrix ((=) 0f) - - if matrixHost.NNZ > 0 then - let preparedMatrixExpected = prepareNaive matrix - - let expected = pageRankNaive preparedMatrixExpected - - let matrix = matrixHost.ToDevice context - - let preparedMatrix = - Algorithms.PageRank.prepareMatrix context workGroupSize queue matrix - - let res = pageRank queue preparedMatrix accuracy - - let resHost = res.ToHost queue - - preparedMatrix.Dispose queue - matrix.Dispose queue - res.Dispose queue - - match resHost with - | Vector.Dense resHost -> - let actual = resHost |> Utils.unwrapOptionArray 0f - - for i in 0 .. actual.Length - 1 do - Expect.isTrue - ((abs (actual.[i] - expected.[i])) < accuracy) - (sprintf "Values should be equal. Expected %A, actual %A" expected.[i] actual.[i]) - - | _ -> failwith "Not implemented" ] - -let tests = - TestCases.gpuTests "PageRank tests" testFixtures diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/SSSP.fs b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/SSSP.fs deleted file mode 100644 index 78feff8f..00000000 --- a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/SSSP.fs +++ /dev/null @@ -1,63 +0,0 @@ -module GraphBLAS.FSharp.Tests.Backend.Algorithms.SSSP - -open Expecto -open GraphBLAS.FSharp.Backend -open GraphBLAS.FSharp.Backend.Common -open GraphBLAS.FSharp.Backend.Quotes -open GraphBLAS.FSharp.Tests -open GraphBLAS.FSharp.Tests.Context -open GraphBLAS.FSharp.Tests.Backend.QuickGraph.Algorithms -open GraphBLAS.FSharp.Tests.Backend.QuickGraph.CreateGraph -open GraphBLAS.FSharp.Objects -open GraphBLAS.FSharp.Objects.ClVectorExtensions - -let testFixtures (testContext: TestContext) = - [ let config = Utils.undirectedAlgoConfig - let context = testContext.ClContext - let queue = testContext.Queue - let workGroupSize = Utils.defaultWorkGroupSize - - let testName = - sprintf "Test on %A" testContext.ClContext - - let ssspDense = - Algorithms.SSSP.run context workGroupSize - - testPropertyWithConfig config testName - <| fun (matrix: int [,]) -> - - let matrix = Array2D.map (fun x -> abs x) matrix - - let graph = undirectedFromArray2D matrix 0 - - let largestComponent = - ConnectedComponents.largestComponent graph - - if largestComponent.Length > 0 then - let source = largestComponent.[0] - - let expected = - SSSP.runUndirected matrix (directedFromArray2D matrix 0) source - |> Array.map (Option.map int) - - let matrixHost = - Utils.createMatrixFromArray2D CSR matrix ((=) 0) - - let matrix = matrixHost.ToDevice context - - let resDense = ssspDense queue matrix source - - let resHost = resDense.ToHost queue - - matrix.Dispose queue - resDense.Dispose queue - - match resHost with - | Vector.Dense resHost -> - let actual = resHost - - Expect.sequenceEqual actual expected "Sequences must be equal" - | _ -> failwith "Not implemented" ] - -let tests = - TestCases.gpuTests "SSSP tests" testFixtures diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map.fs b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map.fs index b87816ba..1cb85d29 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map.fs @@ -4,7 +4,7 @@ open Expecto open Brahma.FSharp open GraphBLAS.FSharp.Tests open GraphBLAS.FSharp.Tests.Context -open GraphBLAS.FSharp.Backend.Common +open GraphBLAS.FSharp open GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects.ClContextExtensions @@ -44,7 +44,7 @@ let createTest<'a when 'a: equality> (testContext: TestContext) (zero: 'a) isEqu let context = testContext.ClContext let map = - Map.map (Map.optionToValueOrZero zero) context wgSize + ClArray.map (Map.optionToValueOrZero zero) context wgSize makeTest testContext map zero isEqual |> testPropertyWithConfig config $"Correctness on {typeof<'a>}" diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map2.fs b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map2.fs index 69b28dad..0b5ab49b 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map2.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map2.fs @@ -4,7 +4,7 @@ open Expecto open Brahma.FSharp open GraphBLAS.FSharp.Tests open GraphBLAS.FSharp.Tests.Context -open GraphBLAS.FSharp.Backend.Common +open GraphBLAS.FSharp open GraphBLAS.FSharp.Objects.ClContextExtensions @@ -43,7 +43,7 @@ let createTest<'a when 'a: equality> (testContext: TestContext) isEqual hostMapF let context = testContext.ClContext - let map = Map.map2 mapFunQ context wgSize + let map = ClArray.map2 mapFunQ context wgSize makeTest<'a> testContext map hostMapFun isEqual |> testPropertyWithConfig config $"Correctness on {typeof<'a>}" diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Common/Reduce/ReduceByKey.fs b/tests/GraphBLAS-sharp.Tests/Backend/Common/Reduce/ReduceByKey.fs index 1ff419ef..0e58f323 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Common/Reduce/ReduceByKey.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Common/Reduce/ReduceByKey.fs @@ -430,7 +430,7 @@ let testOption<'a> isEqual reduceOp testFun (array: (int * 'a) []) = |> checkResultOption isEqual keys values reduceOp let createTestOption (isEqual: 'a -> 'a -> bool) (reduceOpQ, reduceOp) = - Common.Reduce.ByKey.Option.segmentSequentialByOffsets reduceOpQ context Utils.defaultWorkGroupSize + Common.Reduce.ByKey.Option.segmentSequential reduceOpQ context Utils.defaultWorkGroupSize |> testOption<'a> isEqual reduceOp |> testPropertyWithConfig { config with diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Common/Sort/Radix.fs b/tests/GraphBLAS-sharp.Tests/Backend/Common/Sort/Radix.fs index 44206379..9de0e054 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Common/Sort/Radix.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Common/Sort/Radix.fs @@ -16,13 +16,8 @@ let processor = Context.defaultContext.Queue let context = Context.defaultContext.ClContext -let checkResultByKeys (inputArray: (int * 'a) []) (actualKeys: int []) (actualValues: 'a []) = - let expected = Seq.sortBy fst inputArray - let expectedKeys = expected |> Seq.map fst - let expectedValues = expected |> Seq.map snd - - "Keys must be the same" - |> Expect.sequenceEqual expectedKeys actualKeys +let checkResultByKeys (inputArray: (int * 'a) []) (actualValues: 'a []) = + let expectedValues = Seq.sortBy fst inputArray |> Seq.map snd "Values must be the same" |> Expect.sequenceEqual expectedValues actualValues @@ -36,13 +31,12 @@ let makeTestByKeys<'a when 'a: equality> sortFun (array: (int * 'a) []) = let clKeys = keys.ToDevice context let clValues = values.ToDevice context - let clActualKeys, clActualValues: ClArray * ClArray<'a> = + let clActualValues: ClArray<'a> = sortFun processor HostInterop clKeys clValues - let actualKeys = clActualKeys.ToHostAndFree processor let actualValues = clActualValues.ToHostAndFree processor - checkResultByKeys array actualKeys actualValues + checkResultByKeys array actualValues let createTestByKeys<'a when 'a: equality and 'a: struct> = let sort = diff --git a/tests/GraphBLAS-sharp.Tests/Backend/QuickGraph/Algorithms/SSSP.fs b/tests/GraphBLAS-sharp.Tests/Backend/QuickGraph/Algorithms/SSSP.fs deleted file mode 100644 index ba4f3328..00000000 --- a/tests/GraphBLAS-sharp.Tests/Backend/QuickGraph/Algorithms/SSSP.fs +++ /dev/null @@ -1,37 +0,0 @@ -namespace GraphBLAS.FSharp.Tests.Backend.QuickGraph.Algorithms - -open QuikGraph -open QuikGraph.Algorithms.ShortestPath -open QuikGraph.Algorithms.Observers - -module SSSP = - let runUndirected (matrix: int [,]) (graph: AdjacencyGraph>) source = - let weight = - fun (e: Edge) -> float matrix.[e.Source, e.Target] - - let dijkstra = - DijkstraShortestPathAlgorithm>(graph, weight) - - // Attach a distance observer to give us the shortest path distances - let distObserver = - VertexDistanceRecorderObserver>(weight) - - distObserver.Attach(dijkstra) |> ignore - - // Attach a Vertex Predecessor Recorder Observer to give us the paths - let predecessorObserver = - VertexPredecessorRecorderObserver>() - - predecessorObserver.Attach(dijkstra) |> ignore - - // Run the algorithm with A set to be the source - dijkstra.Compute(source) - - let res: array = - Array.zeroCreate (Array2D.length1 matrix) - - for kvp in distObserver.Distances do - res.[kvp.Key] <- Some kvp.Value - - res.[source] <- Some 0.0 - res diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Vector/AssignByMask.fs b/tests/GraphBLAS-sharp.Tests/Backend/Vector/AssignByMask.fs index 3c0fb675..737c5831 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Vector/AssignByMask.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Vector/AssignByMask.fs @@ -51,7 +51,7 @@ let checkResult isZero isComplemented (actual: Vector<'a>) (vector: 'a []) (mask let makeTest<'a when 'a: struct and 'a: equality> (isZero: 'a -> bool) (toDense: MailboxProcessor<_> -> AllocationFlag -> ClVector<'a> -> ClVector<'a>) - (fillVector: MailboxProcessor -> AllocationFlag -> ClVector<'a> -> ClVector<'a> -> 'a -> ClVector<'a>) + (fillVector: MailboxProcessor -> AllocationFlag -> ClVector<'a> -> ClVector<'a> -> ClCell<'a> -> ClVector<'a>) isComplemented case (vector: 'a [], mask: 'a [], value: 'a) @@ -72,9 +72,10 @@ let makeTest<'a when 'a: struct and 'a: equality> let clMaskVector = maskVector.ToDevice context try + let clValue = context.CreateClCell<'a> value let clActual = - fillVector q HostInterop clLeftVector clMaskVector value + fillVector q HostInterop clLeftVector clMaskVector clValue let cooClActual = toDense q HostInterop clActual diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Vector/Map2.fs b/tests/GraphBLAS-sharp.Tests/Backend/Vector/Map2.fs index 771798c7..aac15b20 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Vector/Map2.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Vector/Map2.fs @@ -44,7 +44,7 @@ let correctnessGenericTest isEqual zero op - (addFun: MailboxProcessor<_> -> AllocationFlag -> ClVector<'a> -> ClVector<'a> -> ClVector<'a> option) + (addFun: MailboxProcessor<_> -> AllocationFlag -> ClVector<'a> -> ClVector<'a> -> ClVector<'a>) (toDense: MailboxProcessor<_> -> AllocationFlag -> ClVector<'a> -> ClVector<'a>) case (leftArray: 'a [], rightArray: 'a []) @@ -71,20 +71,17 @@ let correctnessGenericTest let res = addFun q HostInterop firstVector secondVector - match res with - | Some res -> - let denseActual = toDense q HostInterop res + firstVector.Dispose q + secondVector.Dispose q - let actual = denseActual.ToHost q + let denseActual = toDense q HostInterop res - res.Dispose q - denseActual.Dispose q + let actual = denseActual.ToHost q - checkResult isEqual zero op actual leftArray rightArray - | _ -> () + res.Dispose q + denseActual.Dispose q - firstVector.Dispose q - secondVector.Dispose q + checkResult isEqual zero op actual leftArray rightArray with | ex when ex.Message = "InvalidBufferSize" -> () | ex -> raise ex diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMSpV.fs b/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMSpV.fs deleted file mode 100644 index c554b25e..00000000 --- a/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMSpV.fs +++ /dev/null @@ -1,165 +0,0 @@ -module GraphBLAS.FSharp.Tests.Backend.Vector.SpMSpV - -open GraphBLAS.FSharp -open GraphBLAS.FSharp.Objects.ArraysExtensions -open Expecto -open GraphBLAS.FSharp.Backend.Quotes -open GraphBLAS.FSharp.Tests -open GraphBLAS.FSharp.Tests.Context -open GraphBLAS.FSharp.Tests.TestCases -open Microsoft.FSharp.Collections -open Microsoft.FSharp.Core -open GraphBLAS.FSharp.Objects - -let config = Utils.defaultConfig - -let wgSize = Utils.defaultWorkGroupSize - -let checkResult - sumOp - mulOp - (zero: 'a) - (baseMtx: 'a [,]) - (baseVtr: 'a []) - (actualIndices: int []) - (actualValues: 'a []) - = - let rows = Array2D.length1 baseMtx - let columns = Array2D.length2 baseMtx - - let expectedV = Array.create columns zero - let mutable expectedIndices = List.Empty - let mutable expectedValues = List.Empty - - for c in 0 .. columns - 1 do - let mutable sum = zero - - for r in 0 .. rows - 1 do - sum <- sumOp sum (mulOp baseMtx.[r, c] baseVtr.[r]) - - expectedV.[c] <- sum - - for i in 0 .. columns - 1 do - if expectedV.[i] <> zero then - expectedIndices <- List.append expectedIndices [ i ] - expectedValues <- List.append expectedValues [ expectedV.[i] ] - - Expect.sequenceEqual - actualIndices - expectedIndices - $"Values should be the same. Actual is {actualIndices}, expected {expectedIndices}." - - Expect.sequenceEqual - actualValues - expectedValues - $"Values should be the same. Actual is {actualValues}, expected {expectedValues}." - -let correctnessGenericTest - (zero: 'a) - some - sumOp - mulOp - (spMV: MailboxProcessor<_> -> ClMatrix<'a> -> ClVector<'a> -> ClVector<'a> option) - (isEqual: 'a -> 'a -> bool) - q - (testContext: TestContext) - (vector: 'a [], matrix: 'a [,], _: bool []) - = - - if (Array2D.length1 matrix > 0 && vector.Length > 0) then - //Ensure that result is not empty - vector.[0] <- some - matrix.[0, 0] <- some - - let mtx = - Utils.createMatrixFromArray2D CSR matrix (isEqual zero) - - let vtr = - Utils.createVectorFromArray Sparse vector (isEqual zero) - - if mtx.NNZ > 0 && vtr.Size > 0 then - try - let m = mtx.ToDevice testContext.ClContext - - let v = vtr.ToDevice testContext.ClContext - - match spMV testContext.Queue m v with - | Some (ClVector.Sparse res) -> - m.Dispose q - v.Dispose q - let hostResIndices = res.Indices.ToHost q - let hostResValues = res.Values.ToHost q - res.Dispose q - - checkResult sumOp mulOp zero matrix vector hostResIndices hostResValues - | _ -> failwith "Result should not be empty while standard operations are tested" - with - | ex when ex.Message = "InvalidBufferSize" -> () - | ex -> raise ex - -let createTest spmspv testContext (zero: 'a) some isEqual add mul addQ mulQ = - let context = testContext.ClContext - let q = testContext.Queue - - let getCorrectnessTestName datatype = - $"Correctness on %s{datatype}, %A{testContext.ClContext}" - - let spMSpV = spmspv addQ mulQ context wgSize - - testContext - |> correctnessGenericTest zero some add mul spMSpV isEqual q - |> testPropertyWithConfig config (getCorrectnessTestName $"{typeof<'a>}") - - -let testFixturesSpMSpV (testContext: TestContext) = - [ let context = testContext.ClContext - let q = testContext.Queue - q.Error.Add(fun e -> failwithf "%A" e) - - createTest - Operations.SpMSpVBool - testContext - false - true - (=) - (||) - (&&) - ArithmeticOperations.boolSumOption - ArithmeticOperations.boolMulOption - - createTest - Operations.SpMSpV - testContext - 0 - 1 - (=) - (+) - (*) - ArithmeticOperations.intSumOption - ArithmeticOperations.intMulOption - - createTest - Operations.SpMSpV - testContext - 0.0f - 1f - (=) - (+) - (*) - ArithmeticOperations.float32SumOption - ArithmeticOperations.float32MulOption - - if Utils.isFloat64Available context.ClDevice then - createTest - Operations.SpMSpV - testContext - 0.0 - 1 - (=) - (+) - (*) - ArithmeticOperations.floatSumOption - ArithmeticOperations.floatMulOption ] - -let tests = - gpuTests "Backend.Vector.SpMSpV tests" testFixturesSpMSpV diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMV.fs b/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMV.fs index 45ab8054..aed7ea50 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMV.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMV.fs @@ -51,7 +51,7 @@ let correctnessGenericTest zero sumOp mulOp - (spMV: MailboxProcessor<_> -> AllocationFlag -> ClMatrix<'a> -> ClVector<'a> -> ClVector<'a>) + (spMV: MailboxProcessor<_> -> AllocationFlag -> ClMatrix.CSR<'a> -> ClArray<'a option> -> ClArray<'a option>) (isEqual: 'a -> 'a -> bool) q (testContext: TestContext) @@ -68,15 +68,14 @@ let correctnessGenericTest try let m = mtx.ToDevice testContext.ClContext - let v = vtr.ToDevice testContext.ClContext + match vtr, m with + | Vector.Dense vtr, ClMatrix.CSR m -> + let v = vtr.ToDevice testContext.ClContext - let res = spMV testContext.Queue HostInterop m v + let res = spMV testContext.Queue HostInterop m v - m.Dispose q - v.Dispose q - - match res with - | ClVector.Dense res -> + (ClMatrix.CSR m).Dispose q + v.Free q let hostRes = res.ToHostAndFree q checkResult isEqual sumOp mulOp zero matrix vector hostRes diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Vector/Create.fs b/tests/GraphBLAS-sharp.Tests/Backend/Vector/ZeroCreate.fs similarity index 81% rename from tests/GraphBLAS-sharp.Tests/Backend/Vector/Create.fs rename to tests/GraphBLAS-sharp.Tests/Backend/Vector/ZeroCreate.fs index 145731d5..79c1e4d9 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Vector/Create.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Vector/ZeroCreate.fs @@ -35,23 +35,19 @@ let correctnessGenericTest<'a when 'a: struct and 'a: equality> (vectorSize: int) = - try - let vectorSize = abs vectorSize + let vectorSize = abs vectorSize - if vectorSize > 0 then - let q = case.TestContext.Queue + if vectorSize > 0 then + let q = case.TestContext.Queue - let clVector = - zeroCreate q HostInterop vectorSize case.Format + let clVector = + zeroCreate q HostInterop vectorSize case.Format - let hostVector = clVector.ToHost q + let hostVector = clVector.ToHost q - clVector.Dispose q + clVector.Dispose q - checkResult vectorSize hostVector - with - | ex when ex.Message = "Attempting to create full sparse vector" -> () - | ex -> raise ex + checkResult vectorSize hostVector let createTest<'a> case = let getCorrectnessTestName dataType = diff --git a/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj b/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj index 945ac0a3..232d332f 100644 --- a/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj +++ b/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj @@ -1,4 +1,4 @@ - + Exe @@ -15,7 +15,6 @@ - @@ -67,9 +66,8 @@ - + - From d6373cc1ec0255ebaf1eb6292f176528840576c5 Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Sat, 25 Nov 2023 15:06:11 +0300 Subject: [PATCH 21/23] revert: kirill's changes comming with pagerank pr --- .../Algorithms/BFS.fs | 42 ++- .../GraphBLAS-sharp.Benchmarks.fsproj | 3 +- .../Matrix/Map2/Map2.fs | 2 +- .../Matrix/SpGeMM/Expand.fs | 21 +- .../Matrix/SpGeMM/Masked.fs | 2 +- .../GraphBLAS-sharp.Benchmarks/Program.fs | 4 +- .../GraphBLAS-sharp.Benchmarks/Vector/Map2.fs | 14 +- paket.lock | 168 +++++----- .../Algorithms/Algorithms.fs | 5 - src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs | 217 +++++++++++-- .../Algorithms/MSBFS.fs | 13 - .../Algorithms/SSSP.fs | 6 +- src/GraphBLAS-sharp.Backend/Common/Bitmap.fs | 99 ++++++ src/GraphBLAS-sharp.Backend/Common/Common.fs | 35 +- .../Common/Sort/Radix.fs | 18 +- src/GraphBLAS-sharp.Backend/Common/Sum.fs | 148 ++++++++- .../GraphBLAS-sharp.Backend.fsproj | 10 +- .../Matrix/CSR/Matrix.fs | 2 +- src/GraphBLAS-sharp.Backend/Objects/Matrix.fs | 1 - src/GraphBLAS-sharp.Backend/Objects/Vector.fs | 1 - .../Operations/Operations.fs | 83 ++++- .../Operations/SpGeMM/Expand.fs | 10 +- .../Operations/SpMSpV.fs | 305 ++++++++++++++++++ .../Quotes/Arithmetic.fs | 43 ++- src/GraphBLAS-sharp.Backend/Quotes/Map.fs | 5 + src/GraphBLAS-sharp.Backend/Quotes/Mask.fs | 6 + src/GraphBLAS-sharp.Backend/Quotes/Search.fs | 26 ++ .../Vector/Dense/Vector.fs | 65 +++- .../Vector/Sparse/Common.fs | 3 +- .../Vector/Sparse/Map.fs | 2 +- .../Vector/Sparse/Map2.fs | 138 +++++++- .../Vector/Sparse/Vector.fs | 2 + src/GraphBLAS-sharp.Backend/Vector/Vector.fs | 75 +++-- .../Backend/Algorithms/BFS.fs | 55 +++- .../Backend/Algorithms/SSSP.fs | 64 ++++ .../Backend/Common/ClArray/Map.fs | 4 +- .../Backend/Common/ClArray/Map2.fs | 4 +- .../Backend/Common/Reduce/ReduceByKey.fs | 2 +- .../Backend/Common/Sort/Radix.fs | 14 +- .../Backend/QuickGraph/Algorithms/SSSP.fs | 37 +++ .../Backend/Vector/AssignByMask.fs | 5 +- .../Backend/Vector/Map2.fs | 19 +- .../Backend/Vector/SpMSpV.fs | 165 ++++++++++ .../Backend/Vector/SpMV.fs | 15 +- .../GraphBLAS-sharp.Tests.fsproj | 5 +- 45 files changed, 1678 insertions(+), 285 deletions(-) create mode 100644 src/GraphBLAS-sharp.Backend/Common/Bitmap.fs create mode 100644 src/GraphBLAS-sharp.Backend/Operations/SpMSpV.fs create mode 100644 tests/GraphBLAS-sharp.Tests/Backend/Algorithms/SSSP.fs create mode 100644 tests/GraphBLAS-sharp.Tests/Backend/QuickGraph/Algorithms/SSSP.fs create mode 100644 tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMSpV.fs diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs index 7a3c1cf6..a0c10cb6 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs @@ -12,8 +12,8 @@ open GraphBLAS.FSharp.Objects.ArraysExtensions open GraphBLAS.FSharp.Backend.Quotes [] -[] -[] +[] +[] [)>] type Benchmarks<'elem when 'elem : struct>( buildFunToBenchmark, @@ -27,7 +27,7 @@ type Benchmarks<'elem when 'elem : struct>( let mutable matrix = Unchecked.defaultof> let mutable matrixHost = Unchecked.defaultof<_> - member val ResultLevels = Unchecked.defaultof> with get,set + member val ResultLevels = Unchecked.defaultof> with get,set [] member val OclContextInfo = Unchecked.defaultof with get, set @@ -71,7 +71,10 @@ type Benchmarks<'elem when 'elem : struct>( member this.ClearInputMatrix() = matrix.Dispose this.Processor - member this.ClearResult() = this.ResultLevels.FreeAndWait this.Processor + member this.ClearResult() = + match this.ResultLevels with + | ClVector.Dense result -> result.FreeAndWait this.Processor + | _ -> failwith "Impossible" member this.ReadMatrix() = let converter = @@ -136,6 +139,30 @@ type BFSWithoutTransferBenchmarkInt32() = static member InputMatrixProvider = Benchmarks<_>.InputMatrixProviderBuilder "BFSBenchmarks.txt" +type BFSPushPullWithoutTransferBenchmarkInt32() = + + inherit WithoutTransferBenchmark( + (Algorithms.BFS.singleSourcePushPull ArithmeticOperations.intSumOption ArithmeticOperations.intMulOption), + int32, + (fun _ -> Utils.nextInt (System.Random())), + 0, + (fun context matrix -> ClMatrix.CSR <| matrix.ToCSR.ToDevice context)) + + static member InputMatrixProvider = + Benchmarks<_>.InputMatrixProviderBuilder "BFSBenchmarks.txt" + +type SSSPWithoutTransferBenchmarkInt32() = + + inherit WithoutTransferBenchmark( + Algorithms.SSSP.run, + int32, + (fun _ -> Utils.nextInt (System.Random())), + 0, + (fun context matrix -> ClMatrix.CSR <| matrix.ToCSR.ToDevice context)) + + static member InputMatrixProvider = + Benchmarks<_>.InputMatrixProviderBuilder "BFSBenchmarks.txt" + type WithTransferBenchmark<'elem when 'elem : struct>( buildFunToBenchmark, converter: string -> 'elem, @@ -167,8 +194,11 @@ type WithTransferBenchmark<'elem when 'elem : struct>( override this.Benchmark() = this.LoadMatrixToGPU() this.BFS() - this.ResultLevels.ToHost this.Processor |> ignore - this.Processor.PostAndReply Msg.MsgNotifyMe + match this.ResultLevels with + | ClVector.Dense result -> + result.ToHost this.Processor |> ignore + this.Processor.PostAndReply Msg.MsgNotifyMe + | _ -> failwith "Impossible" type BFSWithTransferBenchmarkInt32() = diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj b/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj index 6e8486b0..75ddfc15 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj @@ -1,4 +1,4 @@ - + Exe @@ -25,6 +25,7 @@ + diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/Map2/Map2.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/Map2/Map2.fs index 975e8a72..ab54db75 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/Map2/Map2.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/Map2/Map2.fs @@ -46,7 +46,7 @@ type Benchmarks<'matrixT, 'elem when 'matrixT :> IDeviceMemObject and 'elem : st static member AvailableContexts = Utils.availableContexts static member InputMatricesProviderBuilder pathToConfig = - let datasetFolder = "EWiseAdd" + let datasetFolder = "" pathToConfig |> Utils.getMatricesFilenames |> Seq.map diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Expand.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Expand.fs index 0eb398cd..e8a75071 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Expand.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Expand.fs @@ -13,7 +13,7 @@ open GraphBLAS.FSharp.Benchmarks [] [] [] -[)>] +[)>] type Benchmarks<'elem when 'elem : struct>( buildFunToBenchmark, converter: string -> 'elem, @@ -22,11 +22,9 @@ type Benchmarks<'elem when 'elem : struct>( let mutable funToBenchmark = None - let mutable firstMatrix = Unchecked.defaultof> - let mutable secondMatrix = Unchecked.defaultof> + let mutable matrix = Unchecked.defaultof> - let mutable firstMatrixHost = Unchecked.defaultof<_> - let mutable secondMatrixHost = Unchecked.defaultof<_> + let mutable matrixHost = Unchecked.defaultof<_> member val ResultMatrix = Unchecked.defaultof option> with get, set @@ -36,7 +34,7 @@ type Benchmarks<'elem when 'elem : struct>( [] member val InputMatrixReader = Unchecked.defaultof with get, set - member this.OclContext:ClContext = (fst this.OclContextInfo).ClContext + member this.OclContext: ClContext = (fst this.OclContextInfo).ClContext member this.WorkGroupSize = snd this.OclContextInfo member this.Processor = @@ -76,11 +74,10 @@ type Benchmarks<'elem when 'elem : struct>( reader.ReadMatrix converter member this.Mxm() = - this.ResultMatrix <- this.FunToBenchmark this.Processor DeviceOnly firstMatrix secondMatrix + this.ResultMatrix <- this.FunToBenchmark this.Processor DeviceOnly matrix matrix member this.ClearInputMatrices() = - firstMatrix.Dispose this.Processor - secondMatrix.Dispose this.Processor + matrix.Dispose this.Processor member this.ClearResult() = match this.ResultMatrix with @@ -88,12 +85,10 @@ type Benchmarks<'elem when 'elem : struct>( | None -> () member this.ReadMatrices() = - firstMatrixHost <- this.ReadMatrix this.InputMatrixReader - secondMatrixHost <- this.ReadMatrix this.InputMatrixReader + matrixHost <- this.ReadMatrix this.InputMatrixReader member this.LoadMatricesToGPU () = - firstMatrix <- buildMatrix this.OclContext firstMatrixHost - secondMatrix <- buildMatrix this.OclContext secondMatrixHost + matrix <- buildMatrix this.OclContext matrixHost abstract member GlobalSetup : unit -> unit diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Masked.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Masked.fs index 69f0c399..ff0495bf 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Masked.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Matrix/SpGeMM/Masked.fs @@ -51,7 +51,7 @@ type Masked<'elem when 'elem : struct>( static member AvaliableContexts = Utils.availableContexts static member InputMatrixProviderBuilder pathToConfig = - let datasetFolder = "Mxm" + let datasetFolder = "" pathToConfig |> Utils.getMatricesFilenames |> Seq.map diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs index 5a3ccf37..0655cd45 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs @@ -4,7 +4,9 @@ open BenchmarkDotNet.Running [] let main argv = let benchmarks = - BenchmarkSwitcher [| typeof |] + BenchmarkSwitcher [| typeof + typeof + typeof |] benchmarks.Run argv |> ignore 0 diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Vector/Map2.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Vector/Map2.fs index d4e0078c..5c4871e2 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Vector/Map2.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Vector/Map2.fs @@ -27,7 +27,7 @@ type Benchmarks<'elem when 'elem : struct>( member val HostVectorPair = Unchecked.defaultof * Vector<'elem>> with get, set - member val ResultVector = Unchecked.defaultof> with get,set + member val ResultVector = Unchecked.defaultof option> with get,set [] member val OclContextInfo = Unchecked.defaultof with get, set @@ -67,7 +67,9 @@ type Benchmarks<'elem when 'elem : struct>( secondVector.Dispose this.Processor member this.ClearResult() = - this.ResultVector.Dispose this.Processor + match this.ResultVector with + | Some v -> v.Dispose this.Processor + | None -> () member this.CreateVectors() = this.HostVectorPair <- List.last (Gen.sample this.Size 1 generator) @@ -162,8 +164,12 @@ module WithTransfer = override this.Benchmark () = this.LoadVectorsToGPU() this.Map2() - this.ResultVector.ToHost this.Processor |> ignore - this.Processor.PostAndReply Msg.MsgNotifyMe + match this.ResultVector with + | Some v -> + v.ToHost this.Processor |> ignore + this.Processor.PostAndReply Msg.MsgNotifyMe + | None -> () + [] override this.IterationCleanup () = diff --git a/paket.lock b/paket.lock index f2bbb161..7cae92f5 100644 --- a/paket.lock +++ b/paket.lock @@ -2,8 +2,8 @@ STORAGE: NONE NUGET remote: https://www.nuget.org/api/v2 altcover (7.6.812) - BenchmarkDotNet (0.13.6) - BenchmarkDotNet.Annotations (>= 0.13.6) - restriction: >= netstandard2.0 + BenchmarkDotNet (0.13.9) + BenchmarkDotNet.Annotations (>= 0.13.9) - restriction: >= netstandard2.0 CommandLineParser (>= 2.9.1) - restriction: >= netstandard2.0 Gee.External.Capstone (>= 2.3) - restriction: >= netstandard2.0 Iced (>= 1.17) - restriction: >= netstandard2.0 @@ -18,7 +18,7 @@ NUGET System.Reflection.Emit (>= 4.7) - restriction: && (< net6.0) (>= netstandard2.0) System.Reflection.Emit.Lightweight (>= 4.7) - restriction: && (< net6.0) (>= netstandard2.0) System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: && (< net6.0) (>= netstandard2.0) - BenchmarkDotNet.Annotations (0.13.6) - restriction: >= netstandard2.0 + BenchmarkDotNet.Annotations (0.13.9) - restriction: >= netstandard2.0 Brahma.FSharp (2.0.5) Brahma.FSharp.OpenCL.Printer (>= 2.0.5) - restriction: >= net7.0 Brahma.FSharp.OpenCL.Shared (>= 2.0.5) - restriction: >= net7.0 @@ -83,27 +83,27 @@ NUGET System.Security.Permissions (>= 4.7) - restriction: && (< net472) (>= netstandard2.0) Microsoft.Build.Tasks.Git (1.1.1) - copy_local: true Microsoft.CodeAnalysis.Analyzers (3.3.4) - restriction: >= netstandard2.0 - Microsoft.CodeAnalysis.Common (4.6) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Common (4.7) - restriction: >= netstandard2.0 Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) - restriction: >= netstandard2.0 System.Collections.Immutable (>= 7.0) - restriction: >= netstandard2.0 System.Memory (>= 4.5.5) - restriction: && (< net6.0) (>= netstandard2.0) System.Reflection.Metadata (>= 7.0) - restriction: >= netstandard2.0 System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: >= netstandard2.0 - System.Text.Encoding.CodePages (>= 7.0) - restriction: >= netstandard2.0 + System.Text.Encoding.CodePages (>= 7.0) - restriction: && (< net6.0) (>= netstandard2.0) System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: && (< net6.0) (>= netstandard2.0) - Microsoft.CodeAnalysis.CSharp (4.6) - restriction: >= netstandard2.0 - Microsoft.CodeAnalysis.Common (4.6) - restriction: >= netstandard2.0 - Microsoft.CodeCoverage (17.6.3) - restriction: || (>= net45) (>= netcoreapp2.1) + Microsoft.CodeAnalysis.CSharp (4.7) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Common (4.7) - restriction: >= netstandard2.0 + Microsoft.CodeCoverage (17.7.2) - restriction: || (>= net45) (>= netcoreapp2.1) Microsoft.CSharp (4.7) - restriction: || (&& (< netstandard1.3) (>= uap10.0)) (&& (< netstandard2.0) (>= uap10.0)) - Microsoft.Diagnostics.NETCore.Client (0.2.430602) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.NETCore.Client (0.2.447801) - restriction: >= netstandard2.0 Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: && (< net6.0) (>= netstandard2.0) Microsoft.Extensions.Logging (>= 6.0) - restriction: >= netstandard2.0 System.Buffers (>= 4.5.1) - restriction: && (< net6.0) (>= netstandard2.0) - Microsoft.Diagnostics.Runtime (2.4.416101) - restriction: >= netstandard2.0 - Microsoft.Diagnostics.NETCore.Client (>= 0.2.251802) - restriction: >= netstandard2.0 - System.Collections.Immutable (>= 5.0) - restriction: >= netstandard2.0 - System.Runtime.CompilerServices.Unsafe (>= 5.0) - restriction: >= netstandard2.0 - Microsoft.Diagnostics.Tracing.TraceEvent (3.1.3) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.Runtime (3.0.442202) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.NETCore.Client (>= 0.2.410101) - restriction: >= netstandard2.0 + System.Collections.Immutable (>= 6.0) - restriction: >= netstandard2.0 + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.Tracing.TraceEvent (3.1.5) - restriction: >= netstandard2.0 System.Runtime.CompilerServices.Unsafe (>= 5.0) - restriction: >= netstandard2.0 Microsoft.DotNet.PlatformAbstractions (3.1.6) - restriction: >= netstandard2.0 System.Runtime.InteropServices.RuntimeInformation (>= 4.0) - restriction: || (>= net45) (&& (>= netstandard1.3) (< netstandard2.0)) @@ -145,11 +145,11 @@ NUGET Microsoft.SourceLink.GitHub (1.0) - copy_local: true Microsoft.Build.Tasks.Git (>= 1.0) Microsoft.SourceLink.Common (>= 1.0) - Microsoft.TestPlatform.ObjectModel (17.6.3) - restriction: >= netcoreapp3.1 + Microsoft.TestPlatform.ObjectModel (17.7.2) - restriction: >= netcoreapp3.1 NuGet.Frameworks (>= 6.5) - restriction: || (>= net462) (>= netstandard2.0) System.Reflection.Metadata (>= 1.6) - restriction: || (>= net462) (>= netstandard2.0) - Microsoft.TestPlatform.TestHost (17.6.3) - restriction: >= netcoreapp2.1 - Microsoft.TestPlatform.ObjectModel (>= 17.6.3) - restriction: >= netcoreapp3.1 + Microsoft.TestPlatform.TestHost (17.7.2) - restriction: >= netcoreapp2.1 + Microsoft.TestPlatform.ObjectModel (>= 17.7.2) - restriction: >= netcoreapp3.1 Newtonsoft.Json (>= 13.0.1) - restriction: >= netcoreapp3.1 Microsoft.Win32.Primitives (4.3) - restriction: || (&& (< net45) (>= net46) (< netstandard1.4) (>= netstandard1.6)) (&& (< net45) (< netstandard1.4) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (< netstandard1.5) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (< netstandard1.5) (>= netstandard1.6) (>= uap10.0)) Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) @@ -214,7 +214,7 @@ NUGET System.Runtime.Serialization.Formatters (>= 4.3) - restriction: && (< net20) (>= netstandard1.3) (< netstandard2.0) System.Runtime.Serialization.Primitives (>= 4.3) - restriction: || (&& (< net20) (>= netstandard1.0) (< netstandard1.3)) (&& (< net20) (>= netstandard1.3) (< netstandard2.0)) System.Xml.XmlDocument (>= 4.3) - restriction: && (< net20) (>= netstandard1.3) (< netstandard2.0) - NuGet.Frameworks (6.6.1) - restriction: >= netcoreapp3.1 + NuGet.Frameworks (6.7) - restriction: >= netcoreapp3.1 Perfolizer (0.2.1) - restriction: >= netstandard2.0 System.Memory (>= 4.5.3) - restriction: >= netstandard2.0 QuikGraph (2.5) @@ -656,7 +656,7 @@ NUGET Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) - System.Text.Encoding.CodePages (7.0) - restriction: >= netstandard2.0 + System.Text.Encoding.CodePages (7.0) - restriction: && (< net6.0) (>= netstandard2.0) System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net462) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netstandard2.0)) System.Text.Encoding.Extensions (4.3) - restriction: || (&& (< net45) (>= net46) (< netstandard1.4) (>= netstandard1.6)) (&& (< net45) (< netstandard1.2) (>= netstandard1.6) (< win8)) (&& (< net45) (< netstandard1.3) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (< netstandard1.4) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (< netstandard1.5) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (< netstandard1.5) (>= netstandard1.6) (>= uap10.0)) (&& (>= netstandard1.6) (< portable-net45+win8+wpa81)) @@ -762,20 +762,20 @@ NUGET BinaryDefense.FSharp.Analyzers.Hashing (0.2.2) FSharp.Analyzers.SDK (>= 0.8) - restriction: >= net5.0 FSharp.Core (>= 5.0.1) - restriction: >= net5.0 - FSharp.Analyzers.SDK (0.12) - restriction: >= net5.0 - FSharp.Compiler.Service (>= 43.7.200) - restriction: >= net6.0 - FSharp.Core (>= 7.0.200) - restriction: >= net6.0 + FSharp.Analyzers.SDK (0.14.1) - restriction: >= net5.0 + FSharp.Compiler.Service (>= 43.7.400) - restriction: >= net6.0 + FSharp.Core (>= 7.0.400) - restriction: >= net6.0 McMaster.NETCore.Plugins (>= 1.4) - restriction: >= net6.0 - FSharp.Compiler.Service (43.7.300) - restriction: >= net6.0 - FSharp.Core (7.0.300) - restriction: >= netstandard2.0 + FSharp.Compiler.Service (43.7.400) - restriction: >= net6.0 + FSharp.Core (7.0.400) - restriction: >= netstandard2.0 System.Buffers (>= 4.5.1) - restriction: >= netstandard2.0 - System.Collections.Immutable (>= 6.0) - restriction: >= netstandard2.0 - System.Diagnostics.DiagnosticSource (>= 6.0) - restriction: >= netstandard2.0 + System.Collections.Immutable (>= 7.0) - restriction: >= netstandard2.0 + System.Diagnostics.DiagnosticSource (>= 7.0.2) - restriction: >= netstandard2.0 System.Memory (>= 4.5.5) - restriction: >= netstandard2.0 System.Reflection.Emit (>= 4.7) - restriction: >= netstandard2.0 - System.Reflection.Metadata (>= 6.0.1) - restriction: >= netstandard2.0 + System.Reflection.Metadata (>= 7.0) - restriction: >= netstandard2.0 System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: >= netstandard2.0 - FSharp.Core (7.0.300) - restriction: >= net5.0 + FSharp.Core (7.0.400) - restriction: >= net5.0 McMaster.NETCore.Plugins (1.4) - restriction: >= net6.0 Microsoft.DotNet.PlatformAbstractions (>= 3.1.6) - restriction: >= netcoreapp2.1 Microsoft.Extensions.DependencyModel (>= 5.0) - restriction: >= netcoreapp2.1 @@ -932,17 +932,18 @@ NUGET FSharp.Control.Reactive (5.0.5) - restriction: >= netstandard2.0 FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 System.Reactive (>= 5.0 < 6.0) - restriction: >= netstandard2.0 - FSharp.Core (7.0.300) - restriction: >= netstandard2.0 - Microsoft.Build.Framework (17.6.3) - restriction: >= netstandard2.0 + FSharp.Core (7.0.400) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (17.7.2) - restriction: >= netstandard2.0 Microsoft.VisualStudio.Setup.Configuration.Interop (>= 3.2.2146) - restriction: >= net472 Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: >= net472 + System.Memory (>= 4.5.5) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) System.Security.Permissions (>= 7.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net7.0) System.Security.Principal.Windows (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) - Microsoft.Build.Utilities.Core (17.6.3) - restriction: >= netstandard2.0 - Microsoft.Build.Framework (>= 17.6.3) - restriction: >= netstandard2.0 + Microsoft.Build.Utilities.Core (17.7.2) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (>= 17.7.2) - restriction: >= netstandard2.0 Microsoft.IO.Redist (>= 6.0) - restriction: >= net472 - Microsoft.NET.StringTools (>= 17.6.3) - restriction: >= netstandard2.0 + Microsoft.NET.StringTools (>= 17.7.2) - restriction: >= netstandard2.0 Microsoft.VisualStudio.Setup.Configuration.Interop (>= 3.2.2146) - restriction: || (>= net472) (>= net7.0) Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) System.Collections.Immutable (>= 7.0) - restriction: >= netstandard2.0 @@ -955,12 +956,12 @@ NUGET Microsoft.IO.Redist (6.0) - restriction: >= net472 System.Buffers (>= 4.5.1) - restriction: >= net472 System.Memory (>= 4.5.4) - restriction: >= net472 - Microsoft.NET.StringTools (17.6.3) - restriction: >= netstandard2.0 + Microsoft.NET.StringTools (17.7.2) - restriction: >= netstandard2.0 System.Memory (>= 4.5.5) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) Microsoft.NETCore.Platforms (7.0.4) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (>= net5.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= netcoreapp2.1) (< netcoreapp3.0)) Microsoft.NETCore.Targets (5.0) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) - Microsoft.VisualStudio.Setup.Configuration.Interop (3.6.2115) - restriction: || (>= net472) (>= net7.0) + Microsoft.VisualStudio.Setup.Configuration.Interop (3.7.2175) - restriction: || (>= net472) (>= net7.0) Microsoft.Win32.Registry (5.0) - restriction: || (&& (< net45) (>= netstandard2.0)) (&& (< net472) (< net7.0) (>= netstandard2.0)) System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= uap10.1) @@ -968,25 +969,24 @@ NUGET System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.1) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) Microsoft.Win32.SystemEvents (7.0) - restriction: >= net6.0 Mono.Posix.NETStandard (1.0) - restriction: >= netstandard2.0 - MSBuild.StructuredLogger (2.1.844) - restriction: >= netstandard2.0 + MSBuild.StructuredLogger (2.1.858) - restriction: >= netstandard2.0 Microsoft.Build.Framework (>= 17.5) - restriction: >= netstandard2.0 Microsoft.Build.Utilities.Core (>= 17.5) - restriction: >= netstandard2.0 Newtonsoft.Json (13.0.3) - restriction: >= netstandard2.0 - NuGet.Common (6.6.1) - restriction: >= netstandard2.0 - NuGet.Frameworks (>= 6.6.1) - restriction: >= netstandard2.0 - NuGet.Configuration (6.6.1) - restriction: >= netstandard2.0 - NuGet.Common (>= 6.6.1) - restriction: >= netstandard2.0 + NuGet.Common (6.7) - restriction: >= netstandard2.0 + NuGet.Frameworks (>= 6.7) - restriction: >= netstandard2.0 + NuGet.Configuration (6.7) - restriction: >= netstandard2.0 + NuGet.Common (>= 6.7) - restriction: >= netstandard2.0 System.Security.Cryptography.ProtectedData (>= 4.4) - restriction: && (< net472) (>= netstandard2.0) - NuGet.Frameworks (6.6.1) - restriction: >= netstandard2.0 - NuGet.Packaging (6.6.1) - restriction: >= netstandard2.0 + NuGet.Frameworks (6.7) - restriction: >= netstandard2.0 + NuGet.Packaging (6.7) - restriction: >= netstandard2.0 Newtonsoft.Json (>= 13.0.1) - restriction: >= netstandard2.0 - NuGet.Configuration (>= 6.6.1) - restriction: >= netstandard2.0 - NuGet.Versioning (>= 6.6.1) - restriction: >= netstandard2.0 - System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) - System.Security.Cryptography.Pkcs (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) - NuGet.Protocol (6.6.1) - restriction: >= netstandard2.0 - NuGet.Packaging (>= 6.6.1) - restriction: >= netstandard2.0 - NuGet.Versioning (6.6.1) - restriction: >= netstandard2.0 + NuGet.Configuration (>= 6.7) - restriction: >= netstandard2.0 + NuGet.Versioning (>= 6.7) - restriction: >= netstandard2.0 + System.Security.Cryptography.Pkcs (>= 6.0.4) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) + NuGet.Protocol (6.7) - restriction: >= netstandard2.0 + NuGet.Packaging (>= 6.7) - restriction: >= netstandard2.0 + NuGet.Versioning (6.7) - restriction: >= netstandard2.0 Octokit (0.48) System.Buffers (4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.1) (>= netstandard2.0)) (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (< netstandard1.1) (>= netstandard2.0) (< win8)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net461) (>= netstandard2.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net462) (>= netstandard2.1)) (&& (< net462) (< net6.0) (>= netstandard2.0)) (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (>= net472) (&& (>= net5.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) (&& (< netstandard1.1) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) System.Collections.Immutable (7.0) - restriction: >= netstandard2.0 @@ -999,10 +999,9 @@ NUGET System.Diagnostics.EventLog (7.0) - restriction: >= net7.0 System.Drawing.Common (7.0) - restriction: >= net6.0 Microsoft.Win32.SystemEvents (>= 7.0) - restriction: >= net6.0 - System.Formats.Asn1 (7.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (>= net5.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= netstandard2.1) + System.Formats.Asn1 (7.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (>= net5.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarintvos) (< xamarinwatchos)) (>= netstandard2.1) System.Buffers (>= 4.5.1) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) - System.IO (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) System.Memory (4.5.5) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net462) (>= netstandard2.0)) (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (>= net472) (&& (>= net5.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.0)) (&& (< net7.0) (>= netstandard2.0)) (&& (>= netstandard2.0) (>= uap10.1)) System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.1)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (>= monotouch) (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (< uap10.1) (>= wpa81)) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) System.Numerics.Vectors (>= 4.4) - restriction: && (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) @@ -1012,7 +1011,7 @@ NUGET System.Reactive (5.0) - restriction: >= netstandard2.0 System.Runtime.InteropServices.WindowsRuntime (>= 4.3) - restriction: && (< net472) (< netcoreapp3.1) (>= netstandard2.0) System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net472) (&& (< netcoreapp3.1) (>= netstandard2.0)) (>= uap10.1) - System.Runtime (4.3.1) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) + System.Runtime (4.3.1) - restriction: && (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) Microsoft.NETCore.Platforms (>= 1.1.1) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) Microsoft.NETCore.Targets (>= 1.1.3) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) System.Runtime.CompilerServices.Unsafe (6.0) - restriction: || (&& (>= monoandroid) (< netstandard1.1) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (< monoandroid) (< netstandard1.0) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< netstandard1.1) (>= netstandard2.0) (< win8)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netstandard2.0)) (&& (>= net462) (>= netcoreapp2.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net462) (>= xamarinios)) (&& (>= net462) (>= xamarinmac)) (>= net472) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netstandard2.0)) (&& (< net6.0) (>= xamarinios)) (&& (< net6.0) (>= xamarinmac)) (&& (< netstandard1.0) (>= netstandard2.0) (>= win8)) (&& (< netstandard1.1) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= wp8)) @@ -1020,22 +1019,14 @@ NUGET System.Runtime (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) System.Security.AccessControl (6.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (>= net461) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net462) (>= netstandard2.0)) (&& (< net6.0) (>= netstandard2.0)) (>= netcoreapp2.1) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) System.Security.Principal.Windows (>= 5.0) - restriction: || (>= net461) (&& (< net6.0) (>= netstandard2.0)) - System.Security.Cryptography.Algorithms (4.3.1) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (>= net46) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net461) (< net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) - System.IO (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) - System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) - System.Security.Cryptography.Encoding (>= 4.3) - restriction: || (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) - System.Security.Cryptography.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< netstandard1.6)) (>= net463) - System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (< net472) (>= netstandard2.0)) (>= net5.0) (&& (< net6.0) (>= netstandard2.1)) + System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (>= net5.0) (< net6.0)) (&& (>= net5.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) Microsoft.NETCore.Platforms (>= 5.0) - restriction: && (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos) System.Formats.Asn1 (>= 5.0) - restriction: && (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) - System.Security.Cryptography.Algorithms (>= 4.3.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net46) (>= netstandard1.6) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6) (< uap10.1)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< net462) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6)) (>= net47) - System.Security.Cryptography.Encoding (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) System.Security.Cryptography.Pkcs (7.0.3) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) System.Buffers (>= 4.5.1) - restriction: && (< net462) (>= netstandard2.0) (< netstandard2.1) System.Formats.Asn1 (>= 7.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (>= netstandard2.1) System.Memory (>= 4.5.5) - restriction: && (< net462) (>= netstandard2.0) (< netstandard2.1) System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) - System.Security.Cryptography.Primitives (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (>= net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (< net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) (&& (>= net47) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net47) (< netstandard1.6) (>= netstandard2.0)) System.Security.Cryptography.ProtectedData (7.0.1) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (< net472) (>= netstandard2.0)) (>= net6.0) System.Memory (>= 4.5.5) - restriction: && (< net462) (< net6.0) (>= netstandard2.0) System.Security.Permissions (7.0) - restriction: >= netstandard2.0 @@ -1083,7 +1074,7 @@ NUGET Fable.Browser.Event (>= 1.5) - restriction: >= netstandard2.0 Fable.Core (>= 3.0) - restriction: >= netstandard2.0 FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 - Fable.Core (4.0) - restriction: >= netstandard2.0 + Fable.Core (4.1) - restriction: >= netstandard2.0 Fable.React (9.3) Fable.React.Types (>= 18.3) - restriction: >= netstandard2.0 Fable.ReactDom.Types (>= 18.2) - restriction: >= netstandard2.0 @@ -1176,22 +1167,23 @@ NUGET System.Runtime.Loader (>= 4.0) - restriction: && (< net461) (>= netstandard2.0) System.Security.Cryptography.Algorithms (>= 4.3) - restriction: && (< net461) (>= netstandard2.0) System.ValueTuple (>= 4.4) - restriction: >= net461 - FSharp.Core (7.0.300) + FSharp.Core (7.0.400) FSharp.Formatting (4.0.0-rc1) FSharp.Compiler.Service (>= 34.1) - restriction: >= netstandard2.0 FSharp.Literate (4.0.0-rc1) FSharp.Compiler.Service (>= 34.1) - restriction: >= netstandard2.0 FSharp.Core (>= 4.7) - restriction: >= netstandard2.0 - Microsoft.Build.Framework (17.6.3) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (17.7.2) - restriction: >= netstandard2.0 Microsoft.VisualStudio.Setup.Configuration.Interop (>= 3.2.2146) - restriction: >= net472 Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: >= net472 + System.Memory (>= 4.5.5) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) System.Security.Permissions (>= 7.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net7.0) System.Security.Principal.Windows (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) - Microsoft.Build.Utilities.Core (17.6.3) - restriction: >= netstandard2.0 - Microsoft.Build.Framework (>= 17.6.3) - restriction: >= netstandard2.0 + Microsoft.Build.Utilities.Core (17.7.2) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (>= 17.7.2) - restriction: >= netstandard2.0 Microsoft.IO.Redist (>= 6.0) - restriction: >= net472 - Microsoft.NET.StringTools (>= 17.6.3) - restriction: >= netstandard2.0 + Microsoft.NET.StringTools (>= 17.7.2) - restriction: >= netstandard2.0 Microsoft.VisualStudio.Setup.Configuration.Interop (>= 3.2.2146) - restriction: || (>= net472) (>= net7.0) Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net472) (< net7.0) (>= netstandard2.0) System.Collections.Immutable (>= 7.0) - restriction: >= netstandard2.0 @@ -1204,12 +1196,12 @@ NUGET Microsoft.IO.Redist (6.0) - restriction: >= net472 System.Buffers (>= 4.5.1) - restriction: >= net472 System.Memory (>= 4.5.4) - restriction: >= net472 - Microsoft.NET.StringTools (17.6.3) - restriction: >= netstandard2.0 + Microsoft.NET.StringTools (17.7.2) - restriction: >= netstandard2.0 System.Memory (>= 4.5.5) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net7.0) (>= netstandard2.0)) Microsoft.NETCore.Platforms (7.0.4) - restriction: || (&& (>= monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (>= monoandroid) (>= netcoreapp2.1) (< netstandard1.3)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (>= net5.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= monotouch) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netcoreapp2.1)) (&& (< net45) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netcoreapp2.0)) (&& (>= net461) (>= netcoreapp2.1)) (&& (>= netcoreapp2.0) (>= uap10.1)) (&& (< netcoreapp2.0) (>= netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp2.1) (< netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp2.1) (>= uap10.1)) Microsoft.NETCore.Targets (5.0) - restriction: || (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< net45) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) - Microsoft.VisualStudio.Setup.Configuration.Interop (3.6.2115) - restriction: || (>= net472) (>= net7.0) + Microsoft.VisualStudio.Setup.Configuration.Interop (3.7.2175) - restriction: || (>= net472) (>= net7.0) Microsoft.Win32.Primitives (4.3) - restriction: && (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) Microsoft.NETCore.Targets (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) @@ -1221,25 +1213,24 @@ NUGET System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.1) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) Microsoft.Win32.SystemEvents (7.0) - restriction: >= net6.0 Mono.Posix.NETStandard (1.0) - restriction: >= netstandard2.0 - MSBuild.StructuredLogger (2.1.844) - restriction: >= netstandard2.0 + MSBuild.StructuredLogger (2.1.858) - restriction: >= netstandard2.0 Microsoft.Build.Framework (>= 17.5) - restriction: >= netstandard2.0 Microsoft.Build.Utilities.Core (>= 17.5) - restriction: >= netstandard2.0 Newtonsoft.Json (13.0.3) - restriction: >= netstandard2.0 - NuGet.Common (6.6.1) - restriction: >= netstandard2.0 - NuGet.Frameworks (>= 6.6.1) - restriction: >= netstandard2.0 - NuGet.Configuration (6.6.1) - restriction: >= netstandard2.0 - NuGet.Common (>= 6.6.1) - restriction: >= netstandard2.0 + NuGet.Common (6.7) - restriction: >= netstandard2.0 + NuGet.Frameworks (>= 6.7) - restriction: >= netstandard2.0 + NuGet.Configuration (6.7) - restriction: >= netstandard2.0 + NuGet.Common (>= 6.7) - restriction: >= netstandard2.0 System.Security.Cryptography.ProtectedData (>= 4.4) - restriction: && (< net472) (>= netstandard2.0) - NuGet.Frameworks (6.6.1) - restriction: >= netstandard2.0 - NuGet.Packaging (6.6.1) - restriction: >= netstandard2.0 + NuGet.Frameworks (6.7) - restriction: >= netstandard2.0 + NuGet.Packaging (6.7) - restriction: >= netstandard2.0 Newtonsoft.Json (>= 13.0.1) - restriction: >= netstandard2.0 - NuGet.Configuration (>= 6.6.1) - restriction: >= netstandard2.0 - NuGet.Versioning (>= 6.6.1) - restriction: >= netstandard2.0 - System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) - System.Security.Cryptography.Pkcs (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) - NuGet.Protocol (6.6.1) - restriction: >= netstandard2.0 - NuGet.Packaging (>= 6.6.1) - restriction: >= netstandard2.0 - NuGet.Versioning (6.6.1) - restriction: >= netstandard2.0 + NuGet.Configuration (>= 6.7) - restriction: >= netstandard2.0 + NuGet.Versioning (>= 6.7) - restriction: >= netstandard2.0 + System.Security.Cryptography.Pkcs (>= 6.0.4) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) + NuGet.Protocol (6.7) - restriction: >= netstandard2.0 + NuGet.Packaging (>= 6.7) - restriction: >= netstandard2.0 + NuGet.Versioning (6.7) - restriction: >= netstandard2.0 runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - restriction: && (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - restriction: && (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - restriction: && (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) @@ -1343,7 +1334,7 @@ NUGET System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) System.Drawing.Common (7.0) - restriction: >= net6.0 Microsoft.Win32.SystemEvents (>= 7.0) - restriction: >= net6.0 - System.Formats.Asn1 (7.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (>= net5.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= netstandard2.1) + System.Formats.Asn1 (7.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (>= net5.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarintvos) (< xamarinwatchos)) (>= netstandard2.1) System.Buffers (>= 4.5.1) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) System.Globalization (4.3) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) @@ -1432,7 +1423,7 @@ NUGET System.Runtime.Extensions (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) System.Security.AccessControl (6.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (>= net461) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net462) (>= netstandard2.0)) (&& (< net6.0) (>= netstandard2.0)) (&& (>= netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netstandard2.0) (>= uap10.1)) System.Security.Principal.Windows (>= 5.0) - restriction: || (>= net461) (&& (< net6.0) (>= netstandard2.0)) - System.Security.Cryptography.Algorithms (4.3.1) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (>= net46) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net461) (< net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (< net461) (>= netstandard2.0)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) + System.Security.Cryptography.Algorithms (4.3.1) - restriction: && (< net461) (>= netstandard2.0) Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - restriction: && (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - restriction: && (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) @@ -1447,10 +1438,9 @@ NUGET System.Security.Cryptography.Encoding (>= 4.3) - restriction: || (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) System.Security.Cryptography.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< netstandard1.6)) (>= net463) System.Text.Encoding (>= 4.3) - restriction: && (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) - System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (< net472) (>= netstandard2.0)) (>= net5.0) (&& (< net6.0) (>= netstandard2.1)) + System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (>= net5.0) (< net6.0)) (&& (>= net5.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) Microsoft.NETCore.Platforms (>= 5.0) - restriction: && (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos) System.Formats.Asn1 (>= 5.0) - restriction: && (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) - System.Security.Cryptography.Algorithms (>= 4.3.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net46) (>= netstandard1.6) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6) (< uap10.1)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< net462) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6)) (>= net47) System.Security.Cryptography.Encoding (4.3) - restriction: || (&& (< net46) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net461) (>= net463) (>= netstandard2.0)) Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/Algorithms.fs b/src/GraphBLAS-sharp.Backend/Algorithms/Algorithms.fs index 180b72b6..bc7de55d 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/Algorithms.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/Algorithms.fs @@ -19,8 +19,3 @@ module Algorithms = module SSSP = let run = SSSP.run - - module PageRank = - let run = PageRank.run - - let prepareMatrix = PageRank.prepareMatrix diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs index de7f0cc8..29384a87 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/BFS.fs @@ -5,9 +5,8 @@ open FSharp.Quotations open GraphBLAS.FSharp open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Backend.Quotes -open GraphBLAS.FSharp.Backend.Vector.Dense -open GraphBLAS.FSharp.Objects.ClContextExtensions open GraphBLAS.FSharp.Objects.ArraysExtensions +open GraphBLAS.FSharp.Objects.ClContextExtensions open GraphBLAS.FSharp.Objects.ClCellExtensions module internal BFS = @@ -18,54 +17,218 @@ module internal BFS = workGroupSize = - let spMVTo = - Operations.SpMVInplace add mul clContext workGroupSize + let spMVInPlace = + Operations.SpMVInPlace add mul clContext workGroupSize let zeroCreate = - ClArray.zeroCreate clContext workGroupSize + Vector.zeroCreate clContext workGroupSize let ofList = Vector.ofList clContext workGroupSize - let maskComplementedTo = + let maskComplementedInPlace = Vector.map2InPlace Mask.complementedOp clContext workGroupSize let fillSubVectorTo = - Vector.assignByMaskInPlace (Convert.assignToOption Mask.assign) clContext workGroupSize + Vector.assignByMaskInPlace Mask.assign clContext workGroupSize let containsNonZero = - ClArray.exists Predicates.isSome clContext workGroupSize + Vector.exists Predicates.isSome clContext workGroupSize fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int) -> let vertexCount = matrix.RowCount - let levels = zeroCreate queue HostInterop vertexCount + let levels = + zeroCreate queue DeviceOnly vertexCount Dense - let frontier = + let front = ofList queue DeviceOnly Dense vertexCount [ source, 1 ] - match frontier with - | ClVector.Dense front -> + let mutable level = 0 + let mutable stop = false + + while not stop do + level <- level + 1 + + //Assigning new level values + fillSubVectorTo queue levels front level - let mutable level = 0 - let mutable stop = false + //Getting new frontier + spMVInPlace queue matrix front front - while not stop do - level <- level + 1 + maskComplementedInPlace queue front levels - //Assigning new level values - fillSubVectorTo queue levels front (clContext.CreateClCell level) levels + //Checking if front is empty + stop <- + not + <| (containsNonZero queue front).ToHostAndFree queue + + front.Dispose queue + + levels + + let singleSourceSparse + (add: Expr bool option -> bool option>) + (mul: Expr bool option -> bool option>) + (clContext: ClContext) + workGroupSize + = + + let spMSpV = + Operations.SpMSpVBool add mul clContext workGroupSize + + let zeroCreate = + Vector.zeroCreate clContext workGroupSize + + let ofList = Vector.ofList clContext workGroupSize + let maskComplemented = + Vector.map2Sparse Mask.complementedOp clContext workGroupSize + + let fillSubVectorTo = + Vector.assignByMaskInPlace Mask.assign clContext workGroupSize + + fun (queue: MailboxProcessor) (matrix: ClMatrix) (source: int) -> + let vertexCount = matrix.RowCount + + let levels = + zeroCreate queue DeviceOnly vertexCount Dense + + let mutable front = + ofList queue DeviceOnly Sparse vertexCount [ source, true ] + + let mutable level = 0 + let mutable stop = false + + while not stop do + level <- level + 1 + + //Assigning new level values + fillSubVectorTo queue levels front level + + //Getting new frontier + match spMSpV queue matrix front with + | None -> + front.Dispose queue + stop <- true + | Some newFrontier -> + front.Dispose queue + //Filtering visited vertices + match maskComplemented queue DeviceOnly newFrontier levels with + | None -> + stop <- true + newFrontier.Dispose queue + | Some f -> + front <- f + newFrontier.Dispose queue + + levels + + + let singleSourcePushPull + (add: Expr bool option -> bool option>) + (mul: Expr bool option -> bool option>) + (clContext: ClContext) + workGroupSize + = + + let spMVInPlace = + Operations.SpMVInPlace add mul clContext workGroupSize + + let spMSpV = + Operations.SpMSpVBool add mul clContext workGroupSize + + let zeroCreate = + Vector.zeroCreate clContext workGroupSize + + let ofList = Vector.ofList clContext workGroupSize + + let maskComplementedInPlace = + Vector.map2InPlace Mask.complementedOp clContext workGroupSize + + let maskComplemented = + Vector.map2Sparse Mask.complementedOp clContext workGroupSize + + let fillSubVectorInPlace = + Vector.assignByMaskInPlace (Mask.assign) clContext workGroupSize + + let toSparse = Vector.toSparse clContext workGroupSize + + let toDense = Vector.toDense clContext workGroupSize + + let countNNZ = + ClArray.count Predicates.isSome clContext workGroupSize + + //Push or pull functions + let getNNZ (queue: MailboxProcessor) (v: ClVector) = + match v with + | ClVector.Sparse v -> v.NNZ + | ClVector.Dense v -> countNNZ queue v + + let SPARSITY = 0.001f + + let push nnz size = + (float32 nnz) / (float32 size) <= SPARSITY + + fun (queue: MailboxProcessor) (matrix: ClMatrix) (source: int) -> + let vertexCount = matrix.RowCount + + let levels = + zeroCreate queue DeviceOnly vertexCount Dense + + let mutable frontier = + ofList queue DeviceOnly Sparse vertexCount [ source, true ] + + let mutable level = 0 + let mutable stop = false + + while not stop do + level <- level + 1 + + //Assigning new level values + fillSubVectorInPlace queue levels frontier level + + match frontier with + | ClVector.Sparse _ -> + //Getting new frontier + match spMSpV queue matrix frontier with + | None -> + frontier.Dispose queue + stop <- true + | Some newFrontier -> + frontier.Dispose queue + //Filtering visited vertices + match maskComplemented queue DeviceOnly newFrontier levels with + | None -> + stop <- true + newFrontier.Dispose queue + | Some newMaskedFrontier -> + newFrontier.Dispose queue + + //Push/pull + let NNZ = getNNZ queue newMaskedFrontier + + if (push NNZ newMaskedFrontier.Size) then + frontier <- newMaskedFrontier + else + frontier <- toDense queue DeviceOnly newMaskedFrontier + newMaskedFrontier.Dispose queue + | ClVector.Dense oldFrontier -> //Getting new frontier - spMVTo queue matrix frontier frontier + spMVInPlace queue matrix frontier frontier + + maskComplementedInPlace queue frontier levels - maskComplementedTo queue front levels front + //Emptiness check + let NNZ = getNNZ queue frontier - //Checking if front is empty - stop <- - not - <| (containsNonZero queue front).ToHostAndFree queue + stop <- NNZ = 0 - front.Free queue + //Push/pull + if not stop then + if (push NNZ frontier.Size) then + frontier <- toSparse queue DeviceOnly frontier + oldFrontier.Free queue + else + frontier.Dispose queue - levels - | _ -> failwith "Not implemented" + levels diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs index 30b40b6d..b7c82e6a 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/MSBFS.fs @@ -161,19 +161,6 @@ module internal MSBFS = ClMatrix.COO levels - let runSingleSourceMultipleTimes<'a when 'a: struct> - (add: Expr int option -> int option>) - (mul: Expr<'a option -> int option -> int option>) - (clContext: ClContext) - workGroupSize - = - - let SSBFS = - BFS.singleSourceSparse add mul clContext workGroupSize - - fun (queue: MailboxProcessor) (matrix: ClMatrix<'a>) (source: int list) -> - source |> List.map (SSBFS queue matrix) - module Parents = let private updateFrontAndParents (clContext: ClContext) workGroupSize = let frontExclude = frontExclude clContext workGroupSize diff --git a/src/GraphBLAS-sharp.Backend/Algorithms/SSSP.fs b/src/GraphBLAS-sharp.Backend/Algorithms/SSSP.fs index 489a796c..dc4499e9 100644 --- a/src/GraphBLAS-sharp.Backend/Algorithms/SSSP.fs +++ b/src/GraphBLAS-sharp.Backend/Algorithms/SSSP.fs @@ -7,7 +7,7 @@ open GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects.ClContextExtensions open GraphBLAS.FSharp.Objects.ClCellExtensions -module internal SSSP = +module SSSP = let run (clContext: ClContext) workGroupSize = let less = ArithmeticOperations.less @@ -76,4 +76,6 @@ module internal SSSP = front1.Dispose queue front2.Dispose queue - distance + match distance with + | ClVector.Dense dist -> dist + | _ -> failwith "not implemented" diff --git a/src/GraphBLAS-sharp.Backend/Common/Bitmap.fs b/src/GraphBLAS-sharp.Backend/Common/Bitmap.fs new file mode 100644 index 00000000..889cd43f --- /dev/null +++ b/src/GraphBLAS-sharp.Backend/Common/Bitmap.fs @@ -0,0 +1,99 @@ +namespace GraphBLAS.FSharp.Backend.Common + +open Brahma.FSharp +open GraphBLAS.FSharp.Objects.ClContextExtensions +open GraphBLAS.FSharp.Objects.ArraysExtensions +open GraphBLAS.FSharp.Backend.Quotes +open GraphBLAS.FSharp.Backend.Common.Map + +module Bitmap = + let private getUniqueBitmapGeneral predicate (clContext: ClContext) workGroupSize = + + let getUniqueBitmap = + <@ fun (ndRange: Range1D) (inputArray: ClArray<'a>) inputLength (isUniqueBitmap: ClArray) -> + + let gid = ndRange.GlobalID0 + + if gid < inputLength then + let isUnique = (%predicate) gid inputLength inputArray // brahma error + + if isUnique then + isUniqueBitmap.[gid] <- 1 + else + isUniqueBitmap.[gid] <- 0 @> + + let kernel = clContext.Compile(getUniqueBitmap) + + fun (processor: MailboxProcessor<_>) allocationMode (inputArray: ClArray<'a>) -> + + let inputLength = inputArray.Length + + let ndRange = + Range1D.CreateValid(inputLength, workGroupSize) + + let bitmap = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, inputLength) + + let kernel = kernel.GetKernel() + + processor.Post(Msg.MsgSetArguments(fun () -> kernel.KernelFunc ndRange inputArray inputLength bitmap)) + + processor.Post(Msg.CreateRunMsg<_, _> kernel) + + bitmap + + /// + /// Gets the bitmap that indicates the first elements of the sequences of consecutive identical elements + /// + /// OpenCL context. + let firstOccurrence clContext = + getUniqueBitmapGeneral + <| Predicates.firstOccurrence () + <| clContext + + /// + /// Gets the bitmap that indicates the last elements of the sequences of consecutive identical elements + /// + /// OpenCL context. + let lastOccurrence clContext = + getUniqueBitmapGeneral + <| Predicates.lastOccurrence () + <| clContext + + let private getUniqueBitmap2General<'a when 'a: equality> getUniqueBitmap (clContext: ClContext) workGroupSize = + + let map = + map2 <@ fun x y -> x ||| y @> clContext workGroupSize + + let firstGetBitmap = getUniqueBitmap clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationMode (firstArray: ClArray<'a>) (secondArray: ClArray<'a>) -> + let firstBitmap = + firstGetBitmap processor DeviceOnly firstArray + + let secondBitmap = + firstGetBitmap processor DeviceOnly secondArray + + let result = + map processor allocationMode firstBitmap secondBitmap + + firstBitmap.Free processor + secondBitmap.Free processor + + result + + /// + /// Gets the bitmap that indicates the first elements of the sequences + /// of consecutive identical elements from either first array or second array. + /// + /// OpenCL context. + let firstOccurrence2 clContext = + getUniqueBitmap2General firstOccurrence clContext + + /// + /// Gets the bitmap that indicates the last elements of the sequences + /// of consecutive identical elements from either first array or second array. + /// + /// OpenCL context. + let lastOccurrence2 clContext = + getUniqueBitmap2General lastOccurrence clContext diff --git a/src/GraphBLAS-sharp.Backend/Common/Common.fs b/src/GraphBLAS-sharp.Backend/Common/Common.fs index 53777d33..ae9839f2 100644 --- a/src/GraphBLAS-sharp.Backend/Common/Common.fs +++ b/src/GraphBLAS-sharp.Backend/Common/Common.fs @@ -43,6 +43,20 @@ module Common = /// let runByKeysStandard = Sort.Radix.runByKeysStandard + /// + /// Sorts stable input array of values by given integer keys and return only values. + /// + /// + /// + /// let keys = [| 0; 4; 3; 1; 2; 6; 5 |] + /// let values = [| 1.9; 2.8; 3.7; 4.6; 5.5; 6.4; 7.3; |] + /// runByKeysStandard clContext 32 processor keys values + /// ... + /// > val values = [| 1.9; 4.6; 5.5; 3.7; 2.8; 7.3; 6.4 |] + /// + /// + let runByKeysStandardValuesOnly = Sort.Radix.runByKeysStandardValuesOnly + /// /// Sorts stable input array of integer keys. /// @@ -371,8 +385,27 @@ module Common = /// /// The length of the result must be calculated in advance. /// - let segmentSequential<'a> (reduceOp: Expr<'a -> 'a -> 'a option>) (clContext: ClContext) workGroupSize = + let segmentSequential<'a> + (reduceOp: Expr<'a option -> 'a option -> 'a option>) + (clContext: ClContext) + workGroupSize + = Reduce.ByKey.Option.segmentSequential reduceOp clContext workGroupSize + /// + /// Reduces values by key. Each segment is reduced by one work item. + /// + /// ClContext. + /// Work group size. + /// Operation for reducing values. + /// + /// The length of the result and offsets for each segment must be calculated in advance. + /// + let segmentSequentialByOffsets<'a> + (reduceOp: Expr<'a -> 'a -> 'a option>) + (clContext: ClContext) + workGroupSize + = + Reduce.ByKey.Option.segmentSequentialByOffsets reduceOp clContext workGroupSize module ByKey2D = /// diff --git a/src/GraphBLAS-sharp.Backend/Common/Sort/Radix.fs b/src/GraphBLAS-sharp.Backend/Common/Sort/Radix.fs index 03ad4ed0..b7db92d0 100644 --- a/src/GraphBLAS-sharp.Backend/Common/Sort/Radix.fs +++ b/src/GraphBLAS-sharp.Backend/Common/Sort/Radix.fs @@ -269,7 +269,7 @@ module internal Radix = failwith "Mismatch of key lengths and value. Lengths must be the same" if values.Length <= 1 then - dataCopy processor allocationMode values + copy processor DeviceOnly keys, dataCopy processor DeviceOnly values else let firstKeys = copy processor DeviceOnly keys @@ -319,14 +319,26 @@ module internal Radix = keysPair <- swap keysPair valuesPair <- swap valuesPair + globalOffset.Free processor localOffset.Free processor shift.Free processor - (fst keysPair).Free processor (snd keysPair).Free processor (snd valuesPair).Free processor - (fst valuesPair) + (fst keysPair, fst valuesPair) + + let runByKeysStandardValuesOnly clContext workGroupSize = + let runByKeys = + runByKeys clContext workGroupSize defaultBitCount + + fun (processor: MailboxProcessor<_>) allocationMode (keys: ClArray) (values: ClArray<'a>) -> + let keys, values = + runByKeys processor allocationMode keys values + + keys.Free processor + + values let runByKeysStandard clContext workGroupSize = runByKeys clContext workGroupSize defaultBitCount diff --git a/src/GraphBLAS-sharp.Backend/Common/Sum.fs b/src/GraphBLAS-sharp.Backend/Common/Sum.fs index 8f3fe936..94a745c2 100644 --- a/src/GraphBLAS-sharp.Backend/Common/Sum.fs +++ b/src/GraphBLAS-sharp.Backend/Common/Sum.fs @@ -428,7 +428,7 @@ module Reduce = let itemKeyId = lid + 1 let startKeyIndex = - (%Search.Bin.lowerPosition) length itemKeyId localBitmap + (%Search.Bin.lowerPositionLocal) length itemKeyId localBitmap match startKeyIndex with | Some startPosition -> @@ -473,6 +473,135 @@ module Reduce = reducedValues, reducedKeys module Option = + /// + /// Reduces values by key. Each segment is reduced by one work item. + /// + /// ClContext. + /// Work group size. + /// Operation for reducing values. + let segmentSequential<'a> + (reduceOp: Expr<'a option -> 'a option -> 'a option>) + (clContext: ClContext) + workGroupSize + = + + let kernel = + <@ fun (ndRange: Range1D) uniqueKeyCount keysLength (offsets: ClArray) (keys: ClArray) (values: ClArray<'a option>) (reducedValues: ClArray<'a>) (firstReducedKeys: ClArray) (resultPositions: ClArray) -> + + let gid = ndRange.GlobalID0 + + if gid < uniqueKeyCount then + let startPosition = + (%Search.Bin.lowerPosition) keysLength gid offsets + + match startPosition with + | Some startPosition -> + let firstSourceKey = keys.[startPosition] + + let mutable sum = None + + let mutable currentPosition = startPosition + + while currentPosition < keysLength + && firstSourceKey = keys.[currentPosition] do + let result = (%reduceOp) sum values.[currentPosition] // brahma error + sum <- result + currentPosition <- currentPosition + 1 + + match sum with + | Some value -> + reducedValues.[gid] <- value + resultPositions.[gid] <- 1 + | None -> resultPositions.[gid] <- 0 + + firstReducedKeys.[gid] <- firstSourceKey + | None -> () @> // not possible if done correctly + + let kernel = clContext.Compile kernel + + let getUniqueBitmap = + Bitmap.lastOccurrence clContext workGroupSize + + let scatterData = + Scatter.lastOccurrence clContext workGroupSize + + let scatterIndices = + Scatter.lastOccurrence clContext workGroupSize + + let prefixSum = + PrefixSum.standardExcludeInPlace clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationMode (keys: ClArray) (values: ClArray<'a option>) -> + + let offsets = + getUniqueBitmap processor DeviceOnly keys + + let uniqueKeysCount = + (prefixSum processor offsets) + .ToHostAndFree processor + + let reducedValues = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, uniqueKeysCount) + + let reducedKeys = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, uniqueKeysCount) + + let resultPositions = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, uniqueKeysCount) + + let ndRange = + Range1D.CreateValid(uniqueKeysCount, workGroupSize) + + let kernel = kernel.GetKernel() + + processor.Post( + Msg.MsgSetArguments + (fun () -> + kernel.KernelFunc + ndRange + uniqueKeysCount + keys.Length + offsets + keys + values + reducedValues + reducedKeys + resultPositions) + ) + + processor.Post(Msg.CreateRunMsg<_, _>(kernel)) + + offsets.Free processor + + let resultLength = + (prefixSum processor resultPositions) + .ToHostAndFree processor + + if resultLength = 0 then + reducedValues.Free processor + reducedKeys.Free processor + resultPositions.Free processor + None + else + // write values + let resultValues = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, resultLength) + + scatterData processor resultPositions reducedValues resultValues + + reducedValues.Free processor + + // write keys + let resultKeys = + clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, resultLength) + + scatterIndices processor resultPositions reducedKeys resultKeys + + reducedKeys.Free processor + resultPositions.Free processor + + Some(resultValues, resultKeys) + /// /// Reduces values by key. Each segment is reduced by one work item. /// @@ -480,9 +609,13 @@ module Reduce = /// Work group size. /// Operation for reducing values. /// - /// The length of the result must be calculated in advance. + /// The length of the result and offsets for each segment must be calculated in advance. /// - let segmentSequential<'a> (reduceOp: Expr<'a -> 'a -> 'a option>) (clContext: ClContext) workGroupSize = + let segmentSequentialByOffsets<'a> + (reduceOp: Expr<'a -> 'a -> 'a option>) + (clContext: ClContext) + workGroupSize + = let kernel = <@ fun (ndRange: Range1D) uniqueKeyCount keysLength (offsets: ClArray) (keys: ClArray) (values: ClArray<'a>) (reducedValues: ClArray<'a>) (firstReducedKeys: ClArray) (resultPositions: ClArray) -> @@ -568,6 +701,10 @@ module Reduce = .ToHostAndFree processor if resultLength = 0 then + reducedValues.Free processor + reducedKeys.Free processor + resultPositions.Free processor + None else // write values @@ -848,6 +985,11 @@ module Reduce = .ToHostAndFree processor if resultLength = 0 then + reducedValues.Free processor + firstReducedKeys.Free processor + secondReducedKeys.Free processor + resultPositions.Free processor + None else // write value diff --git a/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj b/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj index 4198cbe0..54f8c64d 100644 --- a/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj +++ b/src/GraphBLAS-sharp.Backend/GraphBLAS-sharp.Backend.fsproj @@ -1,4 +1,4 @@ - + @@ -33,10 +33,13 @@ + + + @@ -58,17 +61,16 @@ - - + + - diff --git a/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs b/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs index 8f305001..0bea32dd 100644 --- a/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Matrix/CSR/Matrix.fs @@ -405,7 +405,7 @@ module Matrix = let pairwise = ClArray.pairwise clContext workGroupSize let subtract = - ClArray.map <@ fun (fst, snd) -> snd - fst @> clContext workGroupSize + Backend.Common.Map.map <@ fun (fst, snd) -> snd - fst @> clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (matrix: ClMatrix.CSR<'b>) -> let pointerPairs = diff --git a/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs b/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs index 2ae2678b..766925aa 100644 --- a/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp.Backend/Objects/Matrix.fs @@ -23,7 +23,6 @@ module ClMatrix = q.Post(Msg.CreateFreeMsg<_>(this.Values)) q.Post(Msg.CreateFreeMsg<_>(this.Columns)) q.Post(Msg.CreateFreeMsg<_>(this.RowPointers)) - q.PostAndReply(Msg.MsgNotifyMe) member this.Dispose q = (this :> IDeviceMemObject).Dispose q diff --git a/src/GraphBLAS-sharp.Backend/Objects/Vector.fs b/src/GraphBLAS-sharp.Backend/Objects/Vector.fs index 82e25d8d..e7a221f1 100644 --- a/src/GraphBLAS-sharp.Backend/Objects/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Objects/Vector.fs @@ -18,7 +18,6 @@ module ClVector = member this.Dispose(q) = q.Post(Msg.CreateFreeMsg<_>(this.Values)) q.Post(Msg.CreateFreeMsg<_>(this.Indices)) - q.PostAndReply(Msg.MsgNotifyMe) member this.Dispose(q) = (this :> IDeviceMemObject).Dispose(q) diff --git a/src/GraphBLAS-sharp.Backend/Operations/Operations.fs b/src/GraphBLAS-sharp.Backend/Operations/Operations.fs index 5f43bc74..2e99b7dc 100644 --- a/src/GraphBLAS-sharp.Backend/Operations/Operations.fs +++ b/src/GraphBLAS-sharp.Backend/Operations/Operations.fs @@ -1,6 +1,7 @@ namespace GraphBLAS.FSharp open Brahma.FSharp +open Microsoft.FSharp.Core open Microsoft.FSharp.Quotations open GraphBLAS.FSharp.Objects open GraphBLAS.FSharp.Objects.ClContextExtensions @@ -60,11 +61,11 @@ module Operations = fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector<'a>) (rightVector: ClVector<'b>) -> match leftVector, rightVector with | ClVector.Dense left, ClVector.Dense right -> - ClVector.Dense - <| map2Dense processor allocationMode left right + map2Dense processor allocationMode left right + |> ClVector.Dense + |> Some | ClVector.Sparse left, ClVector.Sparse right -> - ClVector.Sparse - <| map2Sparse processor allocationMode left right + Option.map ClVector.Sparse (map2Sparse processor allocationMode left right) | _ -> failwith "Vector formats are not matching." /// @@ -90,11 +91,11 @@ module Operations = fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector<'a>) (rightVector: ClVector<'b>) -> match leftVector, rightVector with | ClVector.Sparse left, ClVector.Sparse right -> - ClVector.Sparse - <| map2Sparse processor allocationMode left right + Option.map ClVector.Sparse (map2Sparse processor allocationMode left right) | ClVector.Dense left, ClVector.Dense right -> - ClVector.Dense - <| map2Dense processor allocationMode left right + map2Dense processor allocationMode left right + |> ClVector.Dense + |> Some | _ -> failwith "Vector formats are not matching." /// @@ -293,7 +294,7 @@ module Operations = /// Type of binary function to combine entries. /// OpenCL context. /// Should be a power of 2 and greater than 1. - let SpMVInplace + let SpMVInPlace (add: Expr<'c option -> 'c option -> 'c option>) (mul: Expr<'a option -> 'b option -> 'c option>) (clContext: ClContext) @@ -309,9 +310,69 @@ module Operations = | _ -> failwith "Not implemented yet" /// - /// Matrix-vector multiplication. + /// CSR Matrix - dense vector multiplication. + /// + /// Type of binary function to reduce entries. + /// Type of binary function to combine entries. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let SpMV + (add: Expr<'c option -> 'c option -> 'c option>) + (mul: Expr<'a option -> 'b option -> 'c option>) + (clContext: ClContext) + workGroupSize + = + + let run = SpMV.run add mul clContext workGroupSize + + fun (queue: MailboxProcessor<_>) allocationFlag (matrix: ClMatrix<'a>) (vector: ClVector<'b>) -> + match matrix, vector with + | ClMatrix.CSR m, ClVector.Dense v -> run queue allocationFlag m v |> ClVector.Dense + | _ -> failwith "Not implemented yet" + + /// + /// CSR Matrix - sparse vector multiplication. Optimized for bool OR and AND operations. /// - let SpMV = SpMV.run + /// Type of binary function to reduce entries. + /// Type of binary function to combine entries. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let SpMSpVBool + (add: Expr bool option -> bool option>) + (mul: Expr bool option -> bool option>) + (clContext: ClContext) + workGroupSize + = + + let run = + SpMSpV.runBoolStandard add mul clContext workGroupSize + + fun (queue: MailboxProcessor<_>) (matrix: ClMatrix) (vector: ClVector) -> + match matrix, vector with + | ClMatrix.CSR m, ClVector.Sparse v -> Option.map ClVector.Sparse (run queue m v) + | _ -> failwith "Not implemented yet" + + /// + /// CSR Matrix - sparse vector multiplication. + /// + /// Type of binary function to reduce entries. + /// Type of binary function to combine entries. + /// OpenCL context. + /// Should be a power of 2 and greater than 1. + let SpMSpV + (add: Expr<'c option -> 'c option -> 'c option>) + (mul: Expr<'a option -> 'b option -> 'c option>) + (clContext: ClContext) + workGroupSize + = + + let run = + SpMSpV.run add mul clContext workGroupSize + + fun (queue: MailboxProcessor<_>) (matrix: ClMatrix<'a>) (vector: ClVector<'b>) -> + match matrix, vector with + | ClMatrix.CSR m, ClVector.Sparse v -> Option.map ClVector.Sparse (run queue m v) + | _ -> failwith "Not implemented yet" /// /// Kronecker product for matrices. diff --git a/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs b/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs index 7c9229a1..45ff0df0 100644 --- a/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs +++ b/src/GraphBLAS-sharp.Backend/Operations/SpGeMM/Expand.fs @@ -1,4 +1,4 @@ -namespace GraphBLAS.FSharp.Backend.Operations.SpGeMM +namespace GraphBLAS.FSharp.Backend.Operations.SpGeMM open Brahma.FSharp open FSharp.Quotations @@ -37,7 +37,7 @@ module internal Expand = let multiply (predicate: Expr<'a -> 'b -> 'c option>) (clContext: ClContext) workGroupSize = let getBitmap = - ClArray.map2<'a, 'b, int> (Map.choose2Bitmap predicate) clContext workGroupSize + Backend.Common.Map.map2<'a, 'b, int> (Map.choose2Bitmap predicate) clContext workGroupSize let prefixSum = Common.PrefixSum.standardExcludeInPlace clContext workGroupSize @@ -174,10 +174,10 @@ module internal Expand = let sortByColumnsAndRows (clContext: ClContext) workGroupSize = let sortByKeyIndices = - Common.Sort.Radix.runByKeysStandard clContext workGroupSize + Common.Sort.Radix.runByKeysStandardValuesOnly clContext workGroupSize let sortByKeyValues = - Common.Sort.Radix.runByKeysStandard clContext workGroupSize + Common.Sort.Radix.runByKeysStandardValuesOnly clContext workGroupSize let sortKeys = Common.Sort.Radix.standardRunKeysOnly clContext workGroupSize @@ -213,7 +213,7 @@ module internal Expand = Common.Reduce.ByKey2D.Option.segmentSequential opAdd clContext workGroupSize let getUniqueBitmap = - ClArray.Bitmap.lastOccurrence2 clContext workGroupSize + Backend.Common.Bitmap.lastOccurrence2 clContext workGroupSize let prefixSum = Common.PrefixSum.standardExcludeInPlace clContext workGroupSize diff --git a/src/GraphBLAS-sharp.Backend/Operations/SpMSpV.fs b/src/GraphBLAS-sharp.Backend/Operations/SpMSpV.fs new file mode 100644 index 00000000..bca119a1 --- /dev/null +++ b/src/GraphBLAS-sharp.Backend/Operations/SpMSpV.fs @@ -0,0 +1,305 @@ +namespace GraphBLAS.FSharp.Backend.Operations + +open Brahma.FSharp +open GraphBLAS.FSharp.Backend.Common +open GraphBLAS.FSharp.Backend.Quotes +open Microsoft.FSharp.Quotations +open GraphBLAS.FSharp.Objects +open GraphBLAS.FSharp.Objects.ClVector +open GraphBLAS.FSharp.Objects.ClContextExtensions +open GraphBLAS.FSharp.Objects.ArraysExtensions +open GraphBLAS.FSharp.Objects.ClCellExtensions + +module SpMSpV = + + //For v in vectorIndices collect R[v] and R[v + 1] + let private collectRows (clContext: ClContext) workGroupSize = + + let collectRows = + <@ fun (ndRange: Range1D) inputSize (vectorIndices: ClArray) (rowOffsets: ClArray) (resultArray: ClArray) -> + + let i = ndRange.GlobalID0 + + //resultArray is twice vector size + if i < (inputSize * 2) then + let columnIndex = vectorIndices.[i / 2] + + if i % 2 = 0 then + resultArray.[i] <- rowOffsets.[columnIndex] + else + resultArray.[i] <- rowOffsets.[columnIndex + 1] + elif i = inputSize * 2 then + resultArray.[i] <- 0 @> + + let collectRows = clContext.Compile collectRows + + fun (queue: MailboxProcessor<_>) size (vectorIndices: ClArray) (rowOffsets: ClArray) -> + + let ndRange = + Range1D.CreateValid(size * 2 + 1, workGroupSize) + + // Last element will contain length of array for gather + let resultRows = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, size * 2 + 1) + + let collectRows = collectRows.GetKernel() + + queue.Post( + Msg.MsgSetArguments(fun () -> collectRows.KernelFunc ndRange size vectorIndices rowOffsets resultRows) + ) + + queue.Post(Msg.CreateRunMsg<_, _>(collectRows)) + + resultRows + + //For above array compute result offsets + let private computeOffsetsInplace (clContext: ClContext) workGroupSize = + + let prepareOffsets = + <@ fun (ndRange: Range1D) inputSize (inputArray: ClArray) -> + + let i = ndRange.GlobalID0 + + if i < inputSize && i % 2 = 0 then + inputArray.[i + 1] <- inputArray.[i + 1] - inputArray.[i] + inputArray.[i] <- 0 @> + + let sum = + PrefixSum.standardExcludeInPlace clContext workGroupSize + + let prepareOffsets = clContext.Compile prepareOffsets + + fun (queue: MailboxProcessor<_>) size (input: ClArray) -> + + let ndRange = Range1D.CreateValid(size, workGroupSize) + + let prepareOffsets = prepareOffsets.GetKernel() + + queue.Post(Msg.MsgSetArguments(fun () -> prepareOffsets.KernelFunc ndRange size input)) + + queue.Post(Msg.CreateRunMsg<_, _>(prepareOffsets)) + + let resSize = (sum queue input).ToHostAndFree queue + + resSize + + //Gather rows from the matrix that will be used in multiplication + let private gather (clContext: ClContext) workGroupSize = + + let gather = + <@ fun (ndRange: Range1D) vectorNNZ (rowOffsets: ClArray) (matrixRowPointers: ClArray) (matrixColumns: ClArray) (matrixValues: ClArray<'a>) (vectorIndices: ClArray) (resultRowsArray: ClArray) (resultIndicesArray: ClArray) (resultValuesArray: ClArray<'a>) -> + + //Serial number of row to gather + let row = ndRange.GlobalID0 + + if row < vectorNNZ then + let offsetIndex = row * 2 + 1 + let rowOffset = rowOffsets.[offsetIndex] + + //vectorIndices.[row] --- actual number of row in matrix + let actualRow = vectorIndices.[row] + let matrixIndexOffset = matrixRowPointers.[actualRow] + + if rowOffset <> rowOffsets.[offsetIndex + 1] then + let rowSize = rowOffsets.[offsetIndex + 1] - rowOffset + + for i in 0 .. rowSize - 1 do + resultRowsArray.[i + rowOffset] <- actualRow + resultIndicesArray.[i + rowOffset] <- matrixColumns.[matrixIndexOffset + i] + resultValuesArray.[i + rowOffset] <- matrixValues.[matrixIndexOffset + i] @> + + let collectRows = collectRows clContext workGroupSize + + let computeOffsetsInplace = + computeOffsetsInplace clContext workGroupSize + + let gather = clContext.Compile gather + + fun (queue: MailboxProcessor<_>) (matrix: ClMatrix.CSR<'a>) (vector: ClVector.Sparse<'b>) -> + + //Collect R[v] and R[v + 1] for each v in vector + let collectedRows = + collectRows queue vector.NNZ vector.Indices matrix.RowPointers + + //Place R[v + 1] - R[v] in previous array and do prefix sum, computing offsets for gather array + let gatherArraySize = + computeOffsetsInplace queue (vector.NNZ * 2 + 1) collectedRows + + if gatherArraySize = 0 then + collectedRows.Free queue + None + else + let ndRange = + Range1D.CreateValid(vector.NNZ, workGroupSize) + + let gather = gather.GetKernel() + + let resultRows = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, gatherArraySize) + + let resultIndices = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, gatherArraySize) + + let resultValues = + clContext.CreateClArrayWithSpecificAllocationMode<'a>(DeviceOnly, gatherArraySize) + + if gatherArraySize > 0 then + queue.Post( + Msg.MsgSetArguments + (fun () -> + gather.KernelFunc + ndRange + vector.NNZ + collectedRows + matrix.RowPointers + matrix.Columns + matrix.Values + vector.Indices + resultRows + resultIndices + resultValues) + ) + + queue.Post(Msg.CreateRunMsg<_, _>(gather)) + + collectedRows.Free queue + + Some(resultRows, resultIndices, resultValues) + + + let private multiplyScalar (clContext: ClContext) (mul: Expr<'a option -> 'b option -> 'c option>) workGroupSize = + + let multiply = + <@ fun (ndRange: Range1D) resultLength vectorLength (rowIndices: ClArray) (matrixValues: ClArray<'a>) (vectorIndices: ClArray) (vectorValues: ClArray<'b>) (resultValues: ClArray<'c option>) -> + let i = ndRange.GlobalID0 + + if i < resultLength then + let index = rowIndices.[i] + let matrixValue = matrixValues.[i] + + let vectorValue = + (%Search.Bin.byKey) vectorLength index vectorIndices vectorValues + + let res = (%mul) (Some matrixValue) vectorValue + resultValues.[i] <- res @> + + let multiply = clContext.Compile multiply + + fun (queue: MailboxProcessor<_>) (columnIndices: ClArray) (matrixValues: ClArray<'a>) (vector: Sparse<'b>) -> + + let resultLength = columnIndices.Length + + let result = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, resultLength) + + let ndRange = + Range1D.CreateValid(resultLength, workGroupSize) + + let multiply = multiply.GetKernel() + + queue.Post( + Msg.MsgSetArguments + (fun () -> + multiply.KernelFunc + ndRange + resultLength + vector.NNZ + columnIndices + matrixValues + vector.Indices + vector.Values + result) + ) + + queue.Post(Msg.CreateRunMsg<_, _>(multiply)) + + result + + let run + (add: Expr<'c option -> 'c option -> 'c option>) + (mul: Expr<'a option -> 'b option -> 'c option>) + (clContext: ClContext) + workGroupSize + = + + //TODO: Common.Gather? + let gather = gather clContext workGroupSize + + //TODO: Radix sort + let sort = + Sort.Bitonic.sortKeyValuesInplace clContext workGroupSize + + let multiplyScalar = + multiplyScalar clContext mul workGroupSize + + let segReduce = + Reduce.ByKey.Option.segmentSequential add clContext workGroupSize + + fun (queue: MailboxProcessor<_>) (matrix: ClMatrix.CSR<'a>) (vector: ClVector.Sparse<'b>) -> + gather queue matrix vector + |> Option.map + (fun (gatherRows, gatherIndices, gatherValues) -> + sort queue gatherIndices gatherRows gatherValues + + let sortedRows, sortedIndices, sortedValues = gatherRows, gatherIndices, gatherValues + + let multipliedValues = + multiplyScalar queue sortedRows sortedValues vector + + sortedValues.Free queue + sortedRows.Free queue + + let result = + segReduce queue DeviceOnly sortedIndices multipliedValues + |> Option.map + (fun (reducedValues, reducedKeys) -> + + { Context = clContext + Indices = reducedKeys + Values = reducedValues + Size = matrix.ColumnCount }) + + multipliedValues.Free queue + sortedIndices.Free queue + + result) + |> Option.bind id + + + let runBoolStandard + (add: Expr<'c option -> 'c option -> 'c option>) + (mul: Expr<'a option -> 'b option -> 'c option>) + (clContext: ClContext) + workGroupSize + = + + let gather = gather clContext workGroupSize + + let sort = + Sort.Radix.standardRunKeysOnly clContext workGroupSize + + let removeDuplicates = + GraphBLAS.FSharp.ClArray.removeDuplications clContext workGroupSize + + let create = + GraphBLAS.FSharp.ClArray.create clContext workGroupSize + + fun (queue: MailboxProcessor<_>) (matrix: ClMatrix.CSR<'a>) (vector: ClVector.Sparse<'b>) -> + + gather queue matrix vector + |> Option.map + (fun (gatherRows, gatherIndices, gatherValues) -> + gatherRows.Free queue + gatherValues.Free queue + + let sortedIndices = sort queue gatherIndices + + let resultIndices = removeDuplicates queue sortedIndices + + gatherIndices.Free queue + sortedIndices.Free queue + + { Context = clContext + Indices = resultIndices + Values = create queue DeviceOnly resultIndices.Length true + Size = matrix.ColumnCount }) diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs index f79a2193..d66b15e5 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Arithmetic.fs @@ -1,6 +1,7 @@ -namespace GraphBLAS.FSharp.Backend.Quotes +namespace GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects +open Microsoft.FSharp.Quotations module ArithmeticOperations = let inline private mkUnaryOp zero unaryOp = @@ -36,6 +37,16 @@ module ArithmeticOperations = if res = zero then None else Some res @> + let inline private mkNumericSumAsMul zero = + <@ fun (x: 't option) (y: 't option) -> + let mutable res = None + + match x, y with + | Some f, Some s -> res <- Some(f + s) + | _ -> () + + res @> + let inline private mkNumericMul zero = <@ fun (x: 't option) (y: 't option) -> let mutable res = zero @@ -173,12 +184,16 @@ module ArithmeticOperations = let floatMulAtLeastOne = mkNumericMulAtLeastOne 0.0 let float32MulAtLeastOne = mkNumericMulAtLeastOne 0f + let intSumAsMul = mkNumericSumAsMul System.Int32.MaxValue + let notOption = <@ fun x -> match x with | Some true -> None | _ -> Some true @> + let intNotQ = <@ fun x -> if x = 0 then 1 else 0 @> + let inline private binOpQ zero op = <@ fun (left: 'a) (right: 'a) -> let result = (%op) left right @@ -216,3 +231,29 @@ module ArithmeticOperations = let floatMul = createPair 0.0 (*) <@ (*) @> let float32Mul = createPair 0.0f (*) <@ (*) @> + + // without zero + let intAddWithoutZero = <@ fun x y -> Some(x + y) @> + + let intMulWithoutZero = <@ fun x y -> Some(x * y) @> + + // other operations + let less<'a when 'a: comparison> = + <@ fun (x: 'a option) (y: 'a option) -> + match x, y with + | Some x, Some y -> if (x < y) then Some 1 else None + | Some x, None -> Some 1 + | _ -> None @> + + let minOption<'a when 'a: comparison> = + <@ fun (x: 'a option) (y: 'a option) -> + match x, y with + | Some x, Some y -> Some(min x y) + | Some x, None -> Some x + | None, Some y -> Some y + | _ -> None @> + + let min<'a when 'a: comparison> = + <@ fun (x: 'a) (y: 'a) -> Some(min x y) @> + + let fst<'a> = <@ fun (x: 'a) (_: 'a) -> Some x @> diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Map.fs b/src/GraphBLAS-sharp.Backend/Quotes/Map.fs index 2f74a7c5..9a518e40 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Map.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Map.fs @@ -28,6 +28,11 @@ module Map = | Some _ -> 1 | None -> 0 @> + let predicateBitmap<'a> (predicate: Expr<'a -> bool>) = + <@ fun (x: 'a) -> + let res = (%predicate) x + if res then 1 else 0 @> + let inc = <@ fun item -> item + 1 @> let subtraction = <@ fun first second -> first - second @> diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Mask.fs b/src/GraphBLAS-sharp.Backend/Quotes/Mask.fs index 3a27b5d6..9b19b5b1 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Mask.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Mask.fs @@ -7,6 +7,12 @@ module Mask = | _, None -> left | _ -> right @> + let assignComplemented<'a when 'a: struct> = + <@ fun (left: 'a option) (right: 'a option) -> + match left, right with + | _, None -> right + | _ -> left @> + let op<'a, 'b when 'a: struct and 'b: struct> = <@ fun (left: 'a option) (right: 'b option) -> match right with diff --git a/src/GraphBLAS-sharp.Backend/Quotes/Search.fs b/src/GraphBLAS-sharp.Backend/Quotes/Search.fs index 07660c28..27687645 100644 --- a/src/GraphBLAS-sharp.Backend/Quotes/Search.fs +++ b/src/GraphBLAS-sharp.Backend/Quotes/Search.fs @@ -130,6 +130,32 @@ module Search = /// Find lower position of item in array. /// let lowerPosition<'a when 'a: equality and 'a: comparison> = + <@ fun length sourceItem (keys: ClArray<'a>) -> + + let mutable leftEdge = 0 + let mutable rightEdge = length - 1 + let mutable resultPosition = None + + while leftEdge <= rightEdge do + let currentPosition = (leftEdge + rightEdge) / 2 + let currentKey = keys.[currentPosition] + + if sourceItem = currentKey then + // remember positions and move left + resultPosition <- Some currentPosition + + rightEdge <- currentPosition - 1 + elif sourceItem < currentKey then + rightEdge <- currentPosition - 1 + else + leftEdge <- currentPosition + 1 + + resultPosition @> + + /// + /// Find lower position of item in array. + /// + let lowerPositionLocal<'a when 'a: equality and 'a: comparison> = <@ fun length sourceItem (keys: 'a []) -> let mutable leftEdge = 0 diff --git a/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs b/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs index a99cd8c4..6b6a7629 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Dense/Vector.fs @@ -3,6 +3,7 @@ namespace GraphBLAS.FSharp.Backend.Vector.Dense open Brahma.FSharp open Microsoft.FSharp.Quotations open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend.Common open GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects.ClVector open GraphBLAS.FSharp.Objects.ClContextExtensions @@ -15,7 +16,7 @@ module Vector = workGroupSize = - let map = ClArray.map op clContext workGroupSize + let map = Map.map op clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClArray<'a option>) -> @@ -28,7 +29,7 @@ module Vector = = let map2InPlace = - ClArray.map2InPlace opAdd clContext workGroupSize + Map.map2InPlace opAdd clContext workGroupSize fun (processor: MailboxProcessor<_>) (leftVector: ClArray<'a option>) (rightVector: ClArray<'b option>) (resultVector: ClArray<'c option>) -> @@ -40,8 +41,7 @@ module Vector = workGroupSize = - let map2 = - ClArray.map2 opAdd clContext workGroupSize + let map2 = Map.map2 opAdd clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClArray<'a option>) (rightVector: ClArray<'b option>) -> @@ -66,20 +66,24 @@ module Vector = let kernel = clContext.Compile(fillSubVectorKernel) - fun (processor: MailboxProcessor<_>) (leftVector: ClArray<'a option>) (maskVector: ClArray<'b option>) (value: ClCell<'a>) (resultVector: ClArray<'a option>) -> + fun (processor: MailboxProcessor<_>) (leftVector: ClArray<'a option>) (maskVector: ClArray<'b option>) (value: 'a) (resultVector: ClArray<'a option>) -> let ndRange = Range1D.CreateValid(leftVector.Length, workGroupSize) let kernel = kernel.GetKernel() + let valueCell = clContext.CreateClCell(value) + processor.Post( Msg.MsgSetArguments - (fun () -> kernel.KernelFunc ndRange leftVector.Length leftVector maskVector value resultVector) + (fun () -> kernel.KernelFunc ndRange leftVector.Length leftVector maskVector valueCell resultVector) ) processor.Post(Msg.CreateRunMsg<_, _>(kernel)) + valueCell.Free processor + let assignByMask<'a, 'b when 'a: struct and 'b: struct> (maskOp: Expr<'a option -> 'b option -> 'a -> 'a option>) (clContext: ClContext) @@ -89,7 +93,7 @@ module Vector = let assignByMask = assignByMaskInPlace maskOp clContext workGroupSize - fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClArray<'a option>) (maskVector: ClArray<'b option>) (value: ClCell<'a>) -> + fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClArray<'a option>) (maskVector: ClArray<'b option>) (value: 'a) -> let resultVector = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, leftVector.Length) @@ -97,6 +101,49 @@ module Vector = resultVector + let assignBySparseMaskInPlace<'a, 'b when 'a: struct and 'b: struct> + (maskOp: Expr<'a option -> 'b option -> 'a -> 'a option>) + (clContext: ClContext) + workGroupSize + = + + let fillSubVectorKernel = + <@ fun (ndRange: Range1D) resultLength (leftVector: ClArray<'a option>) (maskVectorIndices: ClArray) (maskVectorValues: ClArray<'b>) (value: ClCell<'a>) (resultVector: ClArray<'a option>) -> + + let gid = ndRange.GlobalID0 + + if gid < resultLength then + let i = maskVectorIndices.[gid] + resultVector.[i] <- (%maskOp) leftVector.[i] (Some maskVectorValues.[gid]) value.Value @> + + let kernel = clContext.Compile(fillSubVectorKernel) + + fun (processor: MailboxProcessor<_>) (leftVector: ClArray<'a option>) (maskVector: Sparse<'b>) (value: 'a) (resultVector: ClArray<'a option>) -> + + let ndRange = + Range1D.CreateValid(maskVector.NNZ, workGroupSize) + + let kernel = kernel.GetKernel() + + let valueCell = clContext.CreateClCell(value) + + processor.Post( + Msg.MsgSetArguments + (fun () -> + kernel.KernelFunc + ndRange + maskVector.NNZ + leftVector + maskVector.Indices + maskVector.Values + valueCell + resultVector) + ) + + processor.Post(Msg.CreateRunMsg<_, _>(kernel)) + + valueCell.Free processor + let toSparse<'a when 'a: struct> (clContext: ClContext) workGroupSize = let scatterValues = @@ -106,7 +153,7 @@ module Vector = Common.Scatter.lastOccurrence clContext workGroupSize let getBitmap = - ClArray.map (Map.option 1 0) clContext workGroupSize + Map.map (Map.option 1 0) clContext workGroupSize let prefixSum = Common.PrefixSum.standardExcludeInPlace clContext workGroupSize @@ -115,7 +162,7 @@ module Vector = ClArray.init Map.id clContext workGroupSize let allValues = - ClArray.map (Map.optionToValueOrZero Unchecked.defaultof<'a>) clContext workGroupSize + Map.map (Map.optionToValueOrZero Unchecked.defaultof<'a>) clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (vector: ClArray<'a option>) -> diff --git a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Common.fs b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Common.fs index 07e6e5e7..8ad13044 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Common.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Common.fs @@ -3,6 +3,7 @@ namespace GraphBLAS.FSharp.Backend.Vector.Sparse open Brahma.FSharp open Microsoft.FSharp.Control open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend open GraphBLAS.FSharp.Objects.ClVector open GraphBLAS.FSharp.Objects.ClContextExtensions open GraphBLAS.FSharp.Objects.ClCellExtensions @@ -74,7 +75,7 @@ module internal Common = let concatIndices = ClArray.concat clContext workGroupSize let mapIndices = - ClArray.mapWithValue clContext workGroupSize <@ fun x y -> x + y @> + Common.Map.mapWithValue clContext workGroupSize <@ fun x y -> x + y @> fun (processor: MailboxProcessor<_>) allocationMode (vectors: Sparse<'a> seq) -> diff --git a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map.fs b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map.fs index 329e5484..f0a69a41 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map.fs @@ -95,7 +95,7 @@ module internal Map = queue.Post(Msg.CreateFreeMsg<_>(indices)) { Context = clContext - Indices = indices + Indices = resultIndices Values = resultValues Size = vector.Size } diff --git a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map2.fs b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map2.fs index feb6e484..fb91840f 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map2.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Map2.fs @@ -4,9 +4,11 @@ open Brahma.FSharp open FSharp.Quotations open Microsoft.FSharp.Control open GraphBLAS.FSharp.Objects +open GraphBLAS.FSharp.Objects.ArraysExtensions open GraphBLAS.FSharp.Objects.ClVector open GraphBLAS.FSharp.Objects.ClContextExtensions open GraphBLAS.FSharp.Backend.Quotes +open Microsoft.FSharp.Core module internal Map2 = let private preparePositions<'a, 'b, 'c> opAdd (clContext: ClContext) workGroupSize = @@ -78,7 +80,7 @@ module internal Map2 = preparePositions<'a, 'b, 'c> op clContext workGroupSize let setPositions = - Common.setPositions clContext workGroupSize + Common.setPositionsOption clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector.Sparse<'a>) (rightVector: ClVector.Sparse<'b>) -> @@ -91,17 +93,113 @@ module internal Map2 = rightVector.Values rightVector.Indices - let resultValues, resultIndices = + let result = setPositions processor allocationMode allValues allIndices bitmap + |> Option.map + (fun (resultValues, resultIndices) -> + { Context = clContext + Values = resultValues + Indices = resultIndices + Size = leftVector.Size }) - processor.Post(Msg.CreateFreeMsg<_>(allIndices)) - processor.Post(Msg.CreateFreeMsg<_>(allValues)) - processor.Post(Msg.CreateFreeMsg<_>(bitmap)) + allIndices.Free processor + allValues.Free processor + bitmap.Free processor - { Context = clContext - Values = resultValues - Indices = resultIndices - Size = max leftVector.Size rightVector.Size } + result + + let private preparePositionsSparseDense<'a, 'b, 'c> (clContext: ClContext) workGroupSize opAdd = + + let preparePositions (op: Expr<'a option -> 'b option -> 'c option>) = + <@ fun (ndRange: Range1D) length (leftValues: ClArray<'a>) (leftIndices: ClArray) (rightValues: ClArray<'b option>) (resultBitmap: ClArray) (resultValues: ClArray<'c>) (resultIndices: ClArray) -> + + let gid = ndRange.GlobalID0 + + if gid < length then + + let i = leftIndices.[gid] + + let (leftValue: 'a option) = Some leftValues.[gid] + + let (rightValue: 'b option) = rightValues.[i] + + match (%op) leftValue rightValue with + | Some value -> + resultValues.[gid] <- value + resultIndices.[gid] <- i + + resultBitmap.[gid] <- 1 + | None -> resultBitmap.[gid] <- 0 @> + + let kernel = + clContext.Compile <| preparePositions opAdd + + fun (processor: MailboxProcessor<_>) (vectorLenght: int) (leftValues: ClArray<'a>) (leftIndices: ClArray) (rightValues: ClArray<'b option>) -> + + let resultBitmap = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, vectorLenght) + + let resultIndices = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, vectorLenght) + + let resultValues = + clContext.CreateClArrayWithSpecificAllocationMode<'c>(DeviceOnly, vectorLenght) + + let ndRange = + Range1D.CreateValid(vectorLenght, workGroupSize) + + let kernel = kernel.GetKernel() + + processor.Post( + Msg.MsgSetArguments + (fun () -> + kernel.KernelFunc + ndRange + vectorLenght + leftValues + leftIndices + rightValues + resultBitmap + resultValues + resultIndices) + ) + + processor.Post(Msg.CreateRunMsg<_, _> kernel) + + resultBitmap, resultValues, resultIndices + + //TODO: unify with sparseXsparse + let runSparseDense<'a, 'b, 'c when 'a: struct and 'b: struct and 'c: struct> + op + (clContext: ClContext) + workGroupSize + = + + let prepare = + preparePositionsSparseDense<'a, 'b, 'c> clContext workGroupSize op + + let setPositions = + Common.setPositionsOption clContext workGroupSize + + fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector.Sparse<'a>) (rightVector: ClArray<'b option>) -> + + let bitmap, allValues, allIndices = + prepare processor leftVector.NNZ leftVector.Values leftVector.Indices rightVector + + let result = + setPositions processor allocationMode allValues allIndices bitmap + |> Option.map + (fun (resultValues, resultIndices) -> + { Context = clContext + Values = resultValues + Indices = resultIndices + Size = leftVector.Size }) + + allIndices.Free processor + allValues.Free processor + bitmap.Free processor + + result let private preparePositionsAssignByMask<'a, 'b when 'a: struct and 'b: struct> op @@ -183,7 +281,9 @@ module internal Map2 = let setPositions = Common.setPositions clContext workGroupSize - fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector.Sparse<'a>) (rightVector: ClVector.Sparse<'b>) (value: ClCell<'a>) -> + fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector.Sparse<'a>) (rightVector: ClVector.Sparse<'b>) (value: 'a) -> + + let valueCell = clContext.CreateClCell(value) let bitmap, values, indices = prepare @@ -193,11 +293,12 @@ module internal Map2 = leftVector.Indices rightVector.Values rightVector.Indices - value + valueCell let resultValues, resultIndices = setPositions processor allocationMode values indices bitmap + processor.Post(Msg.CreateFreeMsg<_>(valueCell)) processor.Post(Msg.CreateFreeMsg<_>(indices)) processor.Post(Msg.CreateFreeMsg<_>(values)) processor.Post(Msg.CreateFreeMsg<_>(bitmap)) @@ -280,7 +381,7 @@ module internal Map2 = preparePositions<'a, 'b, 'c> op clContext workGroupSize let setPositions = - Common.setPositions clContext workGroupSize + Common.setPositionsOption clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode (leftVector: ClVector.Sparse<'a>) (rightVector: ClVector.Sparse<'b>) -> @@ -293,14 +394,17 @@ module internal Map2 = processor.Post(Msg.CreateFreeMsg<_>(rightValues)) processor.Post(Msg.CreateFreeMsg<_>(isLeft)) - let resultValues, resultIndices = + let result = setPositions processor allocationMode allValues allIndices positions + |> Option.map + (fun (resultValues, resultIndices) -> + { Context = clContext + Values = resultValues + Indices = resultIndices + Size = max leftVector.Size rightVector.Size }) processor.Post(Msg.CreateFreeMsg<_>(allIndices)) processor.Post(Msg.CreateFreeMsg<_>(allValues)) processor.Post(Msg.CreateFreeMsg<_>(positions)) - { Context = clContext - Values = resultValues - Indices = resultIndices - Size = max leftVector.Size rightVector.Size } + result diff --git a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs index 98aae51b..1a7fb8f7 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Sparse/Vector.fs @@ -36,6 +36,8 @@ module Vector = let map2 = Map2.run + let map2SparseDense = Map2.runSparseDense + let map2AtLeastOne opAdd (clContext: ClContext) workGroupSize allocationMode = Map2.AtLeastOne.run (Convert.atLeastOneToOption opAdd) clContext workGroupSize allocationMode diff --git a/src/GraphBLAS-sharp.Backend/Vector/Vector.fs b/src/GraphBLAS-sharp.Backend/Vector/Vector.fs index 9494990e..f02798d6 100644 --- a/src/GraphBLAS-sharp.Backend/Vector/Vector.fs +++ b/src/GraphBLAS-sharp.Backend/Vector/Vector.fs @@ -14,31 +14,30 @@ open GraphBLAS.FSharp.Backend.Vector [] module Vector = - /// - /// Builds vector of given format with fixed size and fills it with the given value. - /// - /// OpenCL context. - /// Should be a power of 2 and greater than 1. - let create (clContext: ClContext) workGroupSize = - let create = ClArray.create clContext workGroupSize - - fun (processor: MailboxProcessor<_>) allocationMode size format value -> - match format with - | Sparse -> failwith "Attempting to create full sparse vector" - | Dense -> - ClVector.Dense - <| create processor allocationMode size value - /// /// Builds vector of given format with fixed size and fills it with the default values of desired type. /// /// OpenCL context. /// Should be a power of 2 and greater than 1. let zeroCreate (clContext: ClContext) workGroupSize = - let create = create clContext workGroupSize + let zeroCreate = + ClArray.zeroCreate clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode size format -> - create processor allocationMode size format None + match format with + | Sparse -> + ClVector.Sparse + { Context = clContext + Indices = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, [| 0 |]) + Values = + clContext.CreateClArrayWithSpecificAllocationMode( + allocationMode, + [| Unchecked.defaultof<'a> |] + ) // TODO empty vector + Size = size } + | Dense -> + ClVector.Dense + <| zeroCreate processor allocationMode size /// /// Builds vector of given format with fixed size and fills it with the values from the given list. @@ -46,17 +45,49 @@ module Vector = /// OpenCL context. /// Should be a power of 2 and greater than 1. let ofList (clContext: ClContext) workGroupSize = - let denseOfList = - Dense.Vector.ofList clContext workGroupSize + let scatter = + Common.Scatter.lastOccurrence clContext workGroupSize + + let zeroCreate = + ClArray.zeroCreate clContext workGroupSize + + let map = + Common.Map.map <@ Some @> clContext workGroupSize fun (processor: MailboxProcessor<_>) allocationMode format size (elements: (int * 'a) list) -> match format with | Sparse -> - Sparse.Vector.ofList clContext allocationMode size elements + let indices, values = + elements + |> Array.ofList + |> Array.sortBy fst + |> Array.unzip + + { Context = clContext + Indices = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, indices) + Values = clContext.CreateClArrayWithSpecificAllocationMode(allocationMode, values) + Size = size } |> ClVector.Sparse | Dense -> - denseOfList processor allocationMode size elements - |> ClVector.Dense + let indices, values = elements |> Array.ofList |> Array.unzip + + let values = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, values) + + let indices = + clContext.CreateClArrayWithSpecificAllocationMode(DeviceOnly, indices) + + let mappedValues = map processor DeviceOnly values + + let result = zeroCreate processor allocationMode size + + scatter processor indices mappedValues result + + processor.Post(Msg.CreateFreeMsg(mappedValues)) + processor.Post(Msg.CreateFreeMsg(indices)) + processor.Post(Msg.CreateFreeMsg(values)) + + ClVector.Dense result /// /// Creates new vector with the values from the given one. diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/BFS.fs b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/BFS.fs index edf40fea..110dddec 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/BFS.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/BFS.fs @@ -26,6 +26,20 @@ let testFixtures (testContext: TestContext) = context workGroupSize + let bfsSparse = + Algorithms.BFS.singleSourceSparse + ArithmeticOperations.boolSumOption + ArithmeticOperations.boolMulOption + context + workGroupSize + + let bfsPushPull = + Algorithms.BFS.singleSourcePushPull + ArithmeticOperations.boolSumOption + ArithmeticOperations.boolMulOption + context + workGroupSize + testPropertyWithConfig config testName <| fun (matrix: int [,]) -> @@ -44,24 +58,41 @@ let testFixtures (testContext: TestContext) = let matrixHost = Utils.createMatrixFromArray2D CSR matrix ((=) 0) + let matrixHostBool = + Utils.createMatrixFromArray2D CSR (Array2D.map (fun x -> x <> 0) matrix) ((=) false) + let matrix = matrixHost.ToDevice context + let matrixBool = matrixHostBool.ToDevice context + + let res = bfs queue matrix source + + let resSparse = bfsSparse queue matrixBool source + + let resPushPull = bfsPushPull queue matrixBool source + + let resHost = res.ToHost queue + let resHostSparse = resSparse.ToHost queue + let resHostPushPull = resPushPull.ToHost queue - match matrix with - | ClMatrix.CSR mtx -> - let res = - bfs queue matrix source |> ClVector.Dense + matrix.Dispose queue + matrixBool.Dispose queue + res.Dispose queue + resSparse.Dispose queue + resPushPull.Dispose queue - let resHost = res.ToHost queue + match resHost, resHostSparse, resHostPushPull with + | Vector.Dense resHost, Vector.Dense resHostSparse, Vector.Dense resHostPushPull -> + let actual = resHost |> Utils.unwrapOptionArray 0 - (mtx :> IDeviceMemObject).Dispose queue - res.Dispose queue + let actualSparse = + resHostSparse |> Utils.unwrapOptionArray 0 - match resHost with - | Vector.Dense resHost -> - let actual = resHost |> Utils.unwrapOptionArray 0 + let actualPushPull = + resHostPushPull |> Utils.unwrapOptionArray 0 - Expect.sequenceEqual actual expected "Sequences must be equal" - | _ -> failwith "Not implemented" + Expect.sequenceEqual actual expected "Dense bfs is not as expected" + Expect.sequenceEqual actualSparse expected "Sparse bfs is not as expected" + Expect.sequenceEqual actualPushPull expected "Push-pull bfs is not as expected" | _ -> failwith "Not implemented" ] let tests = diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/SSSP.fs b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/SSSP.fs new file mode 100644 index 00000000..fa9cdff7 --- /dev/null +++ b/tests/GraphBLAS-sharp.Tests/Backend/Algorithms/SSSP.fs @@ -0,0 +1,64 @@ +module GraphBLAS.FSharp.Tests.Backend.Algorithms.SSSP + +open Expecto +open GraphBLAS.FSharp.Backend +open GraphBLAS.FSharp.Backend.Common +open GraphBLAS.FSharp.Backend.Quotes +open GraphBLAS.FSharp.Tests +open GraphBLAS.FSharp.Tests.Context +open GraphBLAS.FSharp.Tests.Backend.QuickGraph.Algorithms +open GraphBLAS.FSharp.Tests.Backend.QuickGraph.CreateGraph +open GraphBLAS.FSharp.Objects +open GraphBLAS.FSharp.Objects.ClVectorExtensions + +let testFixtures (testContext: TestContext) = + [ let config = Utils.undirectedAlgoConfig + let context = testContext.ClContext + let queue = testContext.Queue + let workGroupSize = Utils.defaultWorkGroupSize + + let testName = + sprintf "Test on %A" testContext.ClContext + + let ssspDense = + Algorithms.SSSP.run context workGroupSize + + testPropertyWithConfig config testName + <| fun (matrix: int [,]) -> + + let matrix = Array2D.map (fun x -> abs x) matrix + + let graph = undirectedFromArray2D matrix 0 + + let largestComponent = + ConnectedComponents.largestComponent graph + + if largestComponent.Length > 0 then + let source = largestComponent.[0] + + let expected = + SSSP.runUndirected matrix (directedFromArray2D matrix 0) source + |> Array.map (Option.map int) + + let matrixHost = + Utils.createMatrixFromArray2D CSR matrix ((=) 0) + + let matrix = matrixHost.ToDevice context + + let resDense = + ssspDense queue matrix source |> ClVector.Dense + + let resHost = resDense.ToHost queue + + matrix.Dispose queue + resDense.Dispose queue + + match resHost with + | Vector.Dense resHost -> + let actual = resHost + + Expect.sequenceEqual actual expected "Sequences must be equal" + | _ -> failwith "Not implemented" ] + +let tests = + TestCases.gpuTests "SSSP tests" testFixtures diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map.fs b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map.fs index 1cb85d29..b87816ba 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map.fs @@ -4,7 +4,7 @@ open Expecto open Brahma.FSharp open GraphBLAS.FSharp.Tests open GraphBLAS.FSharp.Tests.Context -open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend.Common open GraphBLAS.FSharp.Backend.Quotes open GraphBLAS.FSharp.Objects.ClContextExtensions @@ -44,7 +44,7 @@ let createTest<'a when 'a: equality> (testContext: TestContext) (zero: 'a) isEqu let context = testContext.ClContext let map = - ClArray.map (Map.optionToValueOrZero zero) context wgSize + Map.map (Map.optionToValueOrZero zero) context wgSize makeTest testContext map zero isEqual |> testPropertyWithConfig config $"Correctness on {typeof<'a>}" diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map2.fs b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map2.fs index 0b5ab49b..69b28dad 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map2.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Common/ClArray/Map2.fs @@ -4,7 +4,7 @@ open Expecto open Brahma.FSharp open GraphBLAS.FSharp.Tests open GraphBLAS.FSharp.Tests.Context -open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend.Common open GraphBLAS.FSharp.Objects.ClContextExtensions @@ -43,7 +43,7 @@ let createTest<'a when 'a: equality> (testContext: TestContext) isEqual hostMapF let context = testContext.ClContext - let map = ClArray.map2 mapFunQ context wgSize + let map = Map.map2 mapFunQ context wgSize makeTest<'a> testContext map hostMapFun isEqual |> testPropertyWithConfig config $"Correctness on {typeof<'a>}" diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Common/Reduce/ReduceByKey.fs b/tests/GraphBLAS-sharp.Tests/Backend/Common/Reduce/ReduceByKey.fs index 0e58f323..1ff419ef 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Common/Reduce/ReduceByKey.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Common/Reduce/ReduceByKey.fs @@ -430,7 +430,7 @@ let testOption<'a> isEqual reduceOp testFun (array: (int * 'a) []) = |> checkResultOption isEqual keys values reduceOp let createTestOption (isEqual: 'a -> 'a -> bool) (reduceOpQ, reduceOp) = - Common.Reduce.ByKey.Option.segmentSequential reduceOpQ context Utils.defaultWorkGroupSize + Common.Reduce.ByKey.Option.segmentSequentialByOffsets reduceOpQ context Utils.defaultWorkGroupSize |> testOption<'a> isEqual reduceOp |> testPropertyWithConfig { config with diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Common/Sort/Radix.fs b/tests/GraphBLAS-sharp.Tests/Backend/Common/Sort/Radix.fs index 9de0e054..44206379 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Common/Sort/Radix.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Common/Sort/Radix.fs @@ -16,8 +16,13 @@ let processor = Context.defaultContext.Queue let context = Context.defaultContext.ClContext -let checkResultByKeys (inputArray: (int * 'a) []) (actualValues: 'a []) = - let expectedValues = Seq.sortBy fst inputArray |> Seq.map snd +let checkResultByKeys (inputArray: (int * 'a) []) (actualKeys: int []) (actualValues: 'a []) = + let expected = Seq.sortBy fst inputArray + let expectedKeys = expected |> Seq.map fst + let expectedValues = expected |> Seq.map snd + + "Keys must be the same" + |> Expect.sequenceEqual expectedKeys actualKeys "Values must be the same" |> Expect.sequenceEqual expectedValues actualValues @@ -31,12 +36,13 @@ let makeTestByKeys<'a when 'a: equality> sortFun (array: (int * 'a) []) = let clKeys = keys.ToDevice context let clValues = values.ToDevice context - let clActualValues: ClArray<'a> = + let clActualKeys, clActualValues: ClArray * ClArray<'a> = sortFun processor HostInterop clKeys clValues + let actualKeys = clActualKeys.ToHostAndFree processor let actualValues = clActualValues.ToHostAndFree processor - checkResultByKeys array actualValues + checkResultByKeys array actualKeys actualValues let createTestByKeys<'a when 'a: equality and 'a: struct> = let sort = diff --git a/tests/GraphBLAS-sharp.Tests/Backend/QuickGraph/Algorithms/SSSP.fs b/tests/GraphBLAS-sharp.Tests/Backend/QuickGraph/Algorithms/SSSP.fs new file mode 100644 index 00000000..ba4f3328 --- /dev/null +++ b/tests/GraphBLAS-sharp.Tests/Backend/QuickGraph/Algorithms/SSSP.fs @@ -0,0 +1,37 @@ +namespace GraphBLAS.FSharp.Tests.Backend.QuickGraph.Algorithms + +open QuikGraph +open QuikGraph.Algorithms.ShortestPath +open QuikGraph.Algorithms.Observers + +module SSSP = + let runUndirected (matrix: int [,]) (graph: AdjacencyGraph>) source = + let weight = + fun (e: Edge) -> float matrix.[e.Source, e.Target] + + let dijkstra = + DijkstraShortestPathAlgorithm>(graph, weight) + + // Attach a distance observer to give us the shortest path distances + let distObserver = + VertexDistanceRecorderObserver>(weight) + + distObserver.Attach(dijkstra) |> ignore + + // Attach a Vertex Predecessor Recorder Observer to give us the paths + let predecessorObserver = + VertexPredecessorRecorderObserver>() + + predecessorObserver.Attach(dijkstra) |> ignore + + // Run the algorithm with A set to be the source + dijkstra.Compute(source) + + let res: array = + Array.zeroCreate (Array2D.length1 matrix) + + for kvp in distObserver.Distances do + res.[kvp.Key] <- Some kvp.Value + + res.[source] <- Some 0.0 + res diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Vector/AssignByMask.fs b/tests/GraphBLAS-sharp.Tests/Backend/Vector/AssignByMask.fs index 737c5831..3c0fb675 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Vector/AssignByMask.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Vector/AssignByMask.fs @@ -51,7 +51,7 @@ let checkResult isZero isComplemented (actual: Vector<'a>) (vector: 'a []) (mask let makeTest<'a when 'a: struct and 'a: equality> (isZero: 'a -> bool) (toDense: MailboxProcessor<_> -> AllocationFlag -> ClVector<'a> -> ClVector<'a>) - (fillVector: MailboxProcessor -> AllocationFlag -> ClVector<'a> -> ClVector<'a> -> ClCell<'a> -> ClVector<'a>) + (fillVector: MailboxProcessor -> AllocationFlag -> ClVector<'a> -> ClVector<'a> -> 'a -> ClVector<'a>) isComplemented case (vector: 'a [], mask: 'a [], value: 'a) @@ -72,10 +72,9 @@ let makeTest<'a when 'a: struct and 'a: equality> let clMaskVector = maskVector.ToDevice context try - let clValue = context.CreateClCell<'a> value let clActual = - fillVector q HostInterop clLeftVector clMaskVector clValue + fillVector q HostInterop clLeftVector clMaskVector value let cooClActual = toDense q HostInterop clActual diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Vector/Map2.fs b/tests/GraphBLAS-sharp.Tests/Backend/Vector/Map2.fs index aac15b20..771798c7 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Vector/Map2.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Vector/Map2.fs @@ -44,7 +44,7 @@ let correctnessGenericTest isEqual zero op - (addFun: MailboxProcessor<_> -> AllocationFlag -> ClVector<'a> -> ClVector<'a> -> ClVector<'a>) + (addFun: MailboxProcessor<_> -> AllocationFlag -> ClVector<'a> -> ClVector<'a> -> ClVector<'a> option) (toDense: MailboxProcessor<_> -> AllocationFlag -> ClVector<'a> -> ClVector<'a>) case (leftArray: 'a [], rightArray: 'a []) @@ -71,17 +71,20 @@ let correctnessGenericTest let res = addFun q HostInterop firstVector secondVector - firstVector.Dispose q - secondVector.Dispose q + match res with + | Some res -> + let denseActual = toDense q HostInterop res - let denseActual = toDense q HostInterop res + let actual = denseActual.ToHost q - let actual = denseActual.ToHost q + res.Dispose q + denseActual.Dispose q - res.Dispose q - denseActual.Dispose q + checkResult isEqual zero op actual leftArray rightArray + | _ -> () - checkResult isEqual zero op actual leftArray rightArray + firstVector.Dispose q + secondVector.Dispose q with | ex when ex.Message = "InvalidBufferSize" -> () | ex -> raise ex diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMSpV.fs b/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMSpV.fs new file mode 100644 index 00000000..c554b25e --- /dev/null +++ b/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMSpV.fs @@ -0,0 +1,165 @@ +module GraphBLAS.FSharp.Tests.Backend.Vector.SpMSpV + +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Objects.ArraysExtensions +open Expecto +open GraphBLAS.FSharp.Backend.Quotes +open GraphBLAS.FSharp.Tests +open GraphBLAS.FSharp.Tests.Context +open GraphBLAS.FSharp.Tests.TestCases +open Microsoft.FSharp.Collections +open Microsoft.FSharp.Core +open GraphBLAS.FSharp.Objects + +let config = Utils.defaultConfig + +let wgSize = Utils.defaultWorkGroupSize + +let checkResult + sumOp + mulOp + (zero: 'a) + (baseMtx: 'a [,]) + (baseVtr: 'a []) + (actualIndices: int []) + (actualValues: 'a []) + = + let rows = Array2D.length1 baseMtx + let columns = Array2D.length2 baseMtx + + let expectedV = Array.create columns zero + let mutable expectedIndices = List.Empty + let mutable expectedValues = List.Empty + + for c in 0 .. columns - 1 do + let mutable sum = zero + + for r in 0 .. rows - 1 do + sum <- sumOp sum (mulOp baseMtx.[r, c] baseVtr.[r]) + + expectedV.[c] <- sum + + for i in 0 .. columns - 1 do + if expectedV.[i] <> zero then + expectedIndices <- List.append expectedIndices [ i ] + expectedValues <- List.append expectedValues [ expectedV.[i] ] + + Expect.sequenceEqual + actualIndices + expectedIndices + $"Values should be the same. Actual is {actualIndices}, expected {expectedIndices}." + + Expect.sequenceEqual + actualValues + expectedValues + $"Values should be the same. Actual is {actualValues}, expected {expectedValues}." + +let correctnessGenericTest + (zero: 'a) + some + sumOp + mulOp + (spMV: MailboxProcessor<_> -> ClMatrix<'a> -> ClVector<'a> -> ClVector<'a> option) + (isEqual: 'a -> 'a -> bool) + q + (testContext: TestContext) + (vector: 'a [], matrix: 'a [,], _: bool []) + = + + if (Array2D.length1 matrix > 0 && vector.Length > 0) then + //Ensure that result is not empty + vector.[0] <- some + matrix.[0, 0] <- some + + let mtx = + Utils.createMatrixFromArray2D CSR matrix (isEqual zero) + + let vtr = + Utils.createVectorFromArray Sparse vector (isEqual zero) + + if mtx.NNZ > 0 && vtr.Size > 0 then + try + let m = mtx.ToDevice testContext.ClContext + + let v = vtr.ToDevice testContext.ClContext + + match spMV testContext.Queue m v with + | Some (ClVector.Sparse res) -> + m.Dispose q + v.Dispose q + let hostResIndices = res.Indices.ToHost q + let hostResValues = res.Values.ToHost q + res.Dispose q + + checkResult sumOp mulOp zero matrix vector hostResIndices hostResValues + | _ -> failwith "Result should not be empty while standard operations are tested" + with + | ex when ex.Message = "InvalidBufferSize" -> () + | ex -> raise ex + +let createTest spmspv testContext (zero: 'a) some isEqual add mul addQ mulQ = + let context = testContext.ClContext + let q = testContext.Queue + + let getCorrectnessTestName datatype = + $"Correctness on %s{datatype}, %A{testContext.ClContext}" + + let spMSpV = spmspv addQ mulQ context wgSize + + testContext + |> correctnessGenericTest zero some add mul spMSpV isEqual q + |> testPropertyWithConfig config (getCorrectnessTestName $"{typeof<'a>}") + + +let testFixturesSpMSpV (testContext: TestContext) = + [ let context = testContext.ClContext + let q = testContext.Queue + q.Error.Add(fun e -> failwithf "%A" e) + + createTest + Operations.SpMSpVBool + testContext + false + true + (=) + (||) + (&&) + ArithmeticOperations.boolSumOption + ArithmeticOperations.boolMulOption + + createTest + Operations.SpMSpV + testContext + 0 + 1 + (=) + (+) + (*) + ArithmeticOperations.intSumOption + ArithmeticOperations.intMulOption + + createTest + Operations.SpMSpV + testContext + 0.0f + 1f + (=) + (+) + (*) + ArithmeticOperations.float32SumOption + ArithmeticOperations.float32MulOption + + if Utils.isFloat64Available context.ClDevice then + createTest + Operations.SpMSpV + testContext + 0.0 + 1 + (=) + (+) + (*) + ArithmeticOperations.floatSumOption + ArithmeticOperations.floatMulOption ] + +let tests = + gpuTests "Backend.Vector.SpMSpV tests" testFixturesSpMSpV diff --git a/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMV.fs b/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMV.fs index aed7ea50..45ab8054 100644 --- a/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMV.fs +++ b/tests/GraphBLAS-sharp.Tests/Backend/Vector/SpMV.fs @@ -51,7 +51,7 @@ let correctnessGenericTest zero sumOp mulOp - (spMV: MailboxProcessor<_> -> AllocationFlag -> ClMatrix.CSR<'a> -> ClArray<'a option> -> ClArray<'a option>) + (spMV: MailboxProcessor<_> -> AllocationFlag -> ClMatrix<'a> -> ClVector<'a> -> ClVector<'a>) (isEqual: 'a -> 'a -> bool) q (testContext: TestContext) @@ -68,14 +68,15 @@ let correctnessGenericTest try let m = mtx.ToDevice testContext.ClContext - match vtr, m with - | Vector.Dense vtr, ClMatrix.CSR m -> - let v = vtr.ToDevice testContext.ClContext + let v = vtr.ToDevice testContext.ClContext - let res = spMV testContext.Queue HostInterop m v + let res = spMV testContext.Queue HostInterop m v - (ClMatrix.CSR m).Dispose q - v.Free q + m.Dispose q + v.Dispose q + + match res with + | ClVector.Dense res -> let hostRes = res.ToHostAndFree q checkResult isEqual sumOp mulOp zero matrix vector hostRes diff --git a/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj b/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj index 232d332f..d4913a3d 100644 --- a/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj +++ b/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj @@ -1,4 +1,4 @@ - + Exe @@ -15,10 +15,10 @@ + - @@ -68,6 +68,7 @@ + From 9a9b7f93cb63ac4c64f9365e82604ce7433ad80f Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Sat, 25 Nov 2023 15:14:24 +0300 Subject: [PATCH 22/23] revert: benchmarks changes --- .../Algorithms/BFS.fs | 29 ++----------------- .../GraphBLAS-sharp.Benchmarks.fsproj | 1 - .../GraphBLAS-sharp.Benchmarks/Program.fs | 4 +-- 3 files changed, 3 insertions(+), 31 deletions(-) diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs index a0c10cb6..d8af762f 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Algorithms/BFS.fs @@ -12,8 +12,8 @@ open GraphBLAS.FSharp.Objects.ArraysExtensions open GraphBLAS.FSharp.Backend.Quotes [] -[] -[] +[] +[] [)>] type Benchmarks<'elem when 'elem : struct>( buildFunToBenchmark, @@ -139,30 +139,6 @@ type BFSWithoutTransferBenchmarkInt32() = static member InputMatrixProvider = Benchmarks<_>.InputMatrixProviderBuilder "BFSBenchmarks.txt" -type BFSPushPullWithoutTransferBenchmarkInt32() = - - inherit WithoutTransferBenchmark( - (Algorithms.BFS.singleSourcePushPull ArithmeticOperations.intSumOption ArithmeticOperations.intMulOption), - int32, - (fun _ -> Utils.nextInt (System.Random())), - 0, - (fun context matrix -> ClMatrix.CSR <| matrix.ToCSR.ToDevice context)) - - static member InputMatrixProvider = - Benchmarks<_>.InputMatrixProviderBuilder "BFSBenchmarks.txt" - -type SSSPWithoutTransferBenchmarkInt32() = - - inherit WithoutTransferBenchmark( - Algorithms.SSSP.run, - int32, - (fun _ -> Utils.nextInt (System.Random())), - 0, - (fun context matrix -> ClMatrix.CSR <| matrix.ToCSR.ToDevice context)) - - static member InputMatrixProvider = - Benchmarks<_>.InputMatrixProviderBuilder "BFSBenchmarks.txt" - type WithTransferBenchmark<'elem when 'elem : struct>( buildFunToBenchmark, converter: string -> 'elem, @@ -211,4 +187,3 @@ type BFSWithTransferBenchmarkInt32() = static member InputMatrixProvider = Benchmarks<_>.InputMatrixProviderBuilder "BFSBenchmarks.txt" - diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj b/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj index 75ddfc15..2dd0c406 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/GraphBLAS-sharp.Benchmarks.fsproj @@ -25,7 +25,6 @@ - diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs index 0655cd45..5a3ccf37 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Program.fs @@ -4,9 +4,7 @@ open BenchmarkDotNet.Running [] let main argv = let benchmarks = - BenchmarkSwitcher [| typeof - typeof - typeof |] + BenchmarkSwitcher [| typeof |] benchmarks.Run argv |> ignore 0 From a94fd07e5ec89552061d2da27c7e305a5d12898d Mon Sep 17 00:00:00 2001 From: artemiipatov Date: Sat, 25 Nov 2023 15:38:07 +0300 Subject: [PATCH 23/23] revert: benchmarks configs --- .../GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt b/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt index d71735c7..708032bc 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Configs/WorkflowTargets.txt @@ -1 +1 @@ -BFSWithoutTransferBenchmark +BFSWithoutTransfer