From 2f1a18f41ba10ccd804a54f27fe14af95b095a69 Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Tue, 16 Mar 2021 23:45:58 +0300 Subject: [PATCH 01/16] Add graphblas workflow; change def of algebraic structures to interfaces --- .../BenchmarksEWiseAdd.fs | 4 +- .../{Abstracts.fs => Abstract.fs} | 96 ++++++++++--------- src/GraphBLAS-sharp/AlgebraicStructures.fs | 33 +++++++ src/GraphBLAS-sharp/Algorithms/BFS.fs | 2 +- src/GraphBLAS-sharp/Algorithms/SSSP.fs | 2 +- .../Algorithms/TriangleCounting.fs | 4 +- src/GraphBLAS-sharp/Backend/Common/Scan.fs | 45 +++++---- .../Backend/{ => MatrixCOO}/EWiseAdd.fs | 8 +- .../{Implementations.fs => Concrete.fs} | 18 ++-- src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj | 18 ++-- src/GraphBLAS-sharp/GraphblasEvaluation.fs | 40 ++++++++ src/GraphBLAS-sharp/Helpers.fs | 4 +- src/GraphBLAS-sharp/Matrix.fs | 30 ++++++ src/GraphBLAS-sharp/Monoid.fs | 6 -- src/GraphBLAS-sharp/Operators.fs | 12 --- src/GraphBLAS-sharp/Predefined/Boolean.fs | 15 --- src/GraphBLAS-sharp/Predefined/Float.fs | 25 ----- src/GraphBLAS-sharp/Predefined/Float32.fs | 15 --- src/GraphBLAS-sharp/Predefined/Integer.fs | 25 ----- src/GraphBLAS-sharp/Predefined/Monoids/Add.fs | 75 ++++++++------- src/GraphBLAS-sharp/Predefined/Monoids/Any.fs | 9 +- src/GraphBLAS-sharp/Predefined/Monoids/Min.fs | 18 ++-- .../Predefined/Semirings/AddMult.fs | 82 +++++++++------- .../Predefined/Semirings/AnyAll.fs | 10 +- .../Predefined/Semirings/MinAdd.fs | 10 +- src/GraphBLAS-sharp/Scalar.fs | 5 - src/GraphBLAS-sharp/Semiring.fs | 6 -- .../OperationsTests/EWiseAddTests.fs | 34 +++---- 28 files changed, 337 insertions(+), 314 deletions(-) rename src/GraphBLAS-sharp/{Abstracts.fs => Abstract.fs} (67%) create mode 100644 src/GraphBLAS-sharp/AlgebraicStructures.fs rename src/GraphBLAS-sharp/Backend/{ => MatrixCOO}/EWiseAdd.fs (96%) rename src/GraphBLAS-sharp/{Implementations.fs => Concrete.fs} (97%) create mode 100644 src/GraphBLAS-sharp/GraphblasEvaluation.fs delete mode 100644 src/GraphBLAS-sharp/Monoid.fs delete mode 100644 src/GraphBLAS-sharp/Operators.fs delete mode 100644 src/GraphBLAS-sharp/Predefined/Boolean.fs delete mode 100644 src/GraphBLAS-sharp/Predefined/Float.fs delete mode 100644 src/GraphBLAS-sharp/Predefined/Float32.fs delete mode 100644 src/GraphBLAS-sharp/Predefined/Integer.fs delete mode 100644 src/GraphBLAS-sharp/Scalar.fs delete mode 100644 src/GraphBLAS-sharp/Semiring.fs diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs index 9dfb68b0..88617d0c 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs @@ -157,7 +157,7 @@ type EWiseAddBenchmarks4Float32() = [] member this.EWiseAdditionCOOFloat32() = let (ClContext context) = this.OclContext - leftCOO.EWiseAdd rightCOO None Float32Semiring.addMult + leftCOO.EWiseAdd rightCOO None AddMult.float32 |> context.RunSync static member InputMatricesProvider = @@ -227,7 +227,7 @@ type EWiseAddBenchmarks4Bool() = [] member this.EWiseAdditionCOOBool() = let (ClContext context) = this.OclContext - leftCOO.EWiseAdd rightCOO None BooleanSemiring.anyAll + leftCOO.EWiseAdd rightCOO None AnyAll.bool |> context.RunSync static member InputMatricesProvider = diff --git a/src/GraphBLAS-sharp/Abstracts.fs b/src/GraphBLAS-sharp/Abstract.fs similarity index 67% rename from src/GraphBLAS-sharp/Abstracts.fs rename to src/GraphBLAS-sharp/Abstract.fs index 8c0af0f5..e8348814 100644 --- a/src/GraphBLAS-sharp/Abstracts.fs +++ b/src/GraphBLAS-sharp/Abstract.fs @@ -3,24 +3,32 @@ namespace GraphBLAS.FSharp open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -type MatrixTuples<'a when 'a : struct and 'a : equality> = { - RowIndices: int[] - ColumnIndices: int[] - Values: 'a[] -} -with - member this.ToHost() = opencl { - let! rows = ToHost this.RowIndices - let! cols = ToHost this.ColumnIndices - let! vals = ToHost this.Values - - return { - RowIndices = rows - ColumnIndices = cols - Values = vals - } +// algebraic objects + +type MatrixTuples<'a when 'a : struct and 'a : equality> = + { + RowIndices: int[] + ColumnIndices: int[] + Values: 'a[] } + member this.ToHost() = + opencl { + let! rows = ToHost this.RowIndices + let! cols = ToHost this.ColumnIndices + let! vals = ToHost this.Values + + return { + RowIndices = rows + ColumnIndices = cols + Values = vals + } + } + +type Scalar<'a when 'a : struct and 'a : equality> = Scalar of 'a +with + static member op_Implicit (Scalar source) = source + [] type Matrix<'a when 'a : struct and 'a : equality>(nrow: int, ncol: int) = abstract RowCount: int @@ -48,17 +56,17 @@ type Matrix<'a when 'a : struct and 'a : equality>(nrow: int, ncol: int) = abstract Assign: (Mask1D option * int) * Scalar<'a> -> OpenCLEvaluation abstract Assign: (int * Mask1D option) * Scalar<'a> -> OpenCLEvaluation - abstract Mxm: Matrix<'a> -> Mask2D option -> Semiring<'a> -> OpenCLEvaluation> - abstract Mxv: Vector<'a> -> Mask1D option -> Semiring<'a> -> OpenCLEvaluation> - abstract EWiseAdd: Matrix<'a> -> Mask2D option -> Semiring<'a> -> OpenCLEvaluation> - abstract EWiseMult: Matrix<'a> -> Mask2D option -> Semiring<'a> -> OpenCLEvaluation> + abstract Mxm: Matrix<'a> -> Mask2D option -> ISemiring<'a> -> OpenCLEvaluation> + abstract Mxv: Vector<'a> -> Mask1D option -> ISemiring<'a> -> OpenCLEvaluation> + abstract EWiseAdd: Matrix<'a> -> Mask2D option -> ISemiring<'a> -> OpenCLEvaluation> + abstract EWiseMult: Matrix<'a> -> Mask2D option -> ISemiring<'a> -> OpenCLEvaluation> abstract Apply: Mask2D option -> UnaryOp<'a, 'b> -> OpenCLEvaluation> abstract Prune: Mask2D option -> UnaryOp<'a, bool> -> OpenCLEvaluation> - abstract ReduceIn: Mask1D option -> Monoid<'a> -> OpenCLEvaluation> - abstract ReduceOut: Mask1D option -> Monoid<'a> -> OpenCLEvaluation> - abstract Reduce: Monoid<'a> -> OpenCLEvaluation> + abstract ReduceIn: Mask1D option -> IMonoid<'a> -> OpenCLEvaluation> + abstract ReduceOut: Mask1D option -> IMonoid<'a> -> OpenCLEvaluation> + abstract Reduce: IMonoid<'a> -> OpenCLEvaluation> abstract Transpose: unit -> OpenCLEvaluation> - abstract Kronecker: Matrix<'a> -> Mask2D option -> Semiring<'a> -> OpenCLEvaluation> + abstract Kronecker: Matrix<'a> -> Mask2D option -> ISemiring<'a> -> OpenCLEvaluation> and [] Vector<'a when 'a : struct and 'a : equality>(size: int) = abstract Size: int @@ -78,12 +86,12 @@ and [] Vector<'a when 'a : struct and 'a : equality>(size: int) = abstract Assign: int * Scalar<'a> -> OpenCLEvaluation abstract Assign: Mask1D option * Scalar<'a> -> OpenCLEvaluation - abstract Vxm: Matrix<'a> -> Mask1D option -> Semiring<'a> -> OpenCLEvaluation> - abstract EWiseAdd: Vector<'a> -> Mask1D option -> Semiring<'a> -> OpenCLEvaluation> - abstract EWiseMult: Vector<'a> -> Mask1D option -> Semiring<'a> -> OpenCLEvaluation> + abstract Vxm: Matrix<'a> -> Mask1D option -> ISemiring<'a> -> OpenCLEvaluation> + abstract EWiseAdd: Vector<'a> -> Mask1D option -> ISemiring<'a> -> OpenCLEvaluation> + abstract EWiseMult: Vector<'a> -> Mask1D option -> ISemiring<'a> -> OpenCLEvaluation> abstract Apply: Mask1D option -> UnaryOp<'a, 'b> -> OpenCLEvaluation> abstract Prune: Mask1D option -> UnaryOp<'a, bool> -> OpenCLEvaluation> - abstract Reduce: Monoid<'a> -> OpenCLEvaluation> + abstract Reduce: IMonoid<'a> -> OpenCLEvaluation> and Mask1D(indices: int[], size: int, isComplemented: bool) = member this.Indices = indices @@ -97,21 +105,23 @@ and Mask2D(rowIndices: int[], columnIndices: int[], rowCount: int, columnCount: member this.ColumnCount = columnCount member this.IsComplemented = isComplemented -type COOFormat<'a> = { - RowCount: int - ColumnCount: int - Rows: int[] - Columns: int[] - Values: 'a[] -} - -type CSRFormat<'a> = { - ColumnCount: int - RowPointers: int[] - ColumnIndices: int[] - Values: 'a[] -} -with +type COOFormat<'a> = + { + RowCount: int + ColumnCount: int + Rows: int[] + Columns: int[] + Values: 'a[] + } + +type CSRFormat<'a> = + { + ColumnCount: int + RowPointers: int[] + ColumnIndices: int[] + Values: 'a[] + } + static member CreateEmpty<'a>() = { RowPointers = Array.zeroCreate 0 ColumnIndices = Array.zeroCreate 0 diff --git a/src/GraphBLAS-sharp/AlgebraicStructures.fs b/src/GraphBLAS-sharp/AlgebraicStructures.fs new file mode 100644 index 00000000..272e6830 --- /dev/null +++ b/src/GraphBLAS-sharp/AlgebraicStructures.fs @@ -0,0 +1,33 @@ +namespace GraphBLAS.FSharp + +open Microsoft.FSharp.Quotations + +type UnaryOp<'a, 'b> = + | UnaryOp of Expr<'a -> 'b> + static member op_Implicit (UnaryOp source) = source + +type BinaryOp<'a, 'b, 'c> = + | BinaryOp of Expr<'a -> 'b -> 'c> + static member op_Implicit (BinaryOp source) = source + +// делать отдельными классами или оставить аллиасами +type ClosedUnaryOp<'a> = + | ClosedUnaryOp of Expr<'a -> 'a> + static member op_Implicit (UnaryOp source) = source + +type ClosedBinaryOp<'a> = + | ClosedBinaryOp of Expr<'a -> 'a -> 'a> + static member op_Implicit (UnaryOp source) = source + +// associative closed bin op (magma with associative) +type ISemigroup<'a> = + abstract Plus: ClosedBinaryOp<'a> + +// semigroup with id +type IMonoid<'a> = + inherit ISemigroup<'a> + abstract Zero: 'a + +type ISemiring<'a> = + inherit IMonoid<'a> + abstract Times: ClosedBinaryOp<'a> diff --git a/src/GraphBLAS-sharp/Algorithms/BFS.fs b/src/GraphBLAS-sharp/Algorithms/BFS.fs index 278b50c1..d4dbca02 100644 --- a/src/GraphBLAS-sharp/Algorithms/BFS.fs +++ b/src/GraphBLAS-sharp/Algorithms/BFS.fs @@ -19,7 +19,7 @@ module BFS = let! frontierMask = frontier.GetMask() do! levels.Assign(frontierMask, Scalar currentLevel) let! levelsComplemented = levels.GetMask(isComplemented = true) - let! frontier = frontier.Vxm matrix levelsComplemented BooleanSemiring.anyAll + let! frontier = frontier.Vxm matrix levelsComplemented AnyAll.bool currentLevel <- currentLevel + 1 return levels diff --git a/src/GraphBLAS-sharp/Algorithms/SSSP.fs b/src/GraphBLAS-sharp/Algorithms/SSSP.fs index aa3a6263..22a81f12 100644 --- a/src/GraphBLAS-sharp/Algorithms/SSSP.fs +++ b/src/GraphBLAS-sharp/Algorithms/SSSP.fs @@ -13,7 +13,7 @@ module SSSP = opencl { for _ in 1 .. vertexCount - 1 do - let! step = distance.Vxm matrix None FloatSemiring.minAdd + let! step = distance.Vxm matrix None MinAdd.float do! distance.Assign(None, step) return distance diff --git a/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs b/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs index 31f2b802..68a5f6b6 100644 --- a/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs +++ b/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs @@ -17,6 +17,6 @@ module TriangleCounting = let! convertedMatrix = lowerTriangular.Apply None (UnaryOp <@ bool2int @>) let! convertedTransposed = convertedMatrix.Transpose() let! lowerTriangularMask = lowerTriangular.GetMask() - let! result = convertedMatrix.Mxm convertedTransposed lowerTriangularMask IntegerSemiring.addMult - return! result.Reduce IntegerMonoid.add + let! result = convertedMatrix.Mxm convertedTransposed lowerTriangularMask AddMult.int + return! result.Reduce Add.int } diff --git a/src/GraphBLAS-sharp/Backend/Common/Scan.fs b/src/GraphBLAS-sharp/Backend/Common/Scan.fs index a99bf9bb..8ee2213a 100644 --- a/src/GraphBLAS-sharp/Backend/Common/Scan.fs +++ b/src/GraphBLAS-sharp/Backend/Common/Scan.fs @@ -5,7 +5,7 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open Utils -// functions in mudule could be named run\get\if\it\t +// functions in mudule could be named run\get\of\it\t // like mentioned here https://www.reddit.com/r/fsharp/comments/5kvsyk/modules_or_namespaces/dbt0zf7?utm_source=share&utm_medium=web2x&context=3 module internal Scan = let rec v1 (inputArray: int[]) = @@ -93,10 +93,8 @@ module internal Scan = return outputArray } - let v2 (inputArray: int[]) = - let firstIntermediateArray = Array.copy inputArray - let secondIntermediateArray = Array.copy inputArray - let outputArrayLength = firstIntermediateArray.Length + let v2 (inputArray: int[]) = opencl { + let outputArrayLength = inputArray.Length let updateResult = <@ @@ -111,23 +109,24 @@ module internal Scan = else firstIntermediateArrayBuffer.[i] <- secondIntermediateArrayBuffer.[i] + secondIntermediateArrayBuffer.[i - offset] @> - let binder offset firstIntermediateArray secondIntermediateArray kernelP = - let ndRange = _1D(workSize outputArrayLength, workGroupSize) - kernelP - ndRange - offset - firstIntermediateArray - secondIntermediateArray - + let firstIntermediateArray = Array.copy inputArray + let secondIntermediateArray = Array.copy inputArray let swap (a, b) = (b, a) - let mutable arrays = firstIntermediateArray, secondIntermediateArray - opencl { - let mutable offset = 1 - while offset < outputArrayLength do - arrays <- swap arrays - do! RunCommand updateResult <| (binder offset <|| arrays) - offset <- offset * 2 - - return (fst arrays) - } + let mutable arrays = firstIntermediateArray, secondIntermediateArray + let mutable offset = 1 + + while offset < outputArrayLength do + arrays <- swap arrays + do! RunCommand updateResult <| fun kernelPrepare -> + let ndRange = _1D(workSize outputArrayLength, workGroupSize) + kernelPrepare + ndRange + offset + (fst arrays) + (snd arrays) + + offset <- offset * 2 + + return (fst arrays) + } diff --git a/src/GraphBLAS-sharp/Backend/EWiseAdd.fs b/src/GraphBLAS-sharp/Backend/MatrixCOO/EWiseAdd.fs similarity index 96% rename from src/GraphBLAS-sharp/Backend/EWiseAdd.fs rename to src/GraphBLAS-sharp/Backend/MatrixCOO/EWiseAdd.fs index 9af7a196..75b4e785 100644 --- a/src/GraphBLAS-sharp/Backend/EWiseAdd.fs +++ b/src/GraphBLAS-sharp/Backend/MatrixCOO/EWiseAdd.fs @@ -1,4 +1,4 @@ -namespace GraphBLAS.FSharp.Backend +namespace GraphBLAS.FSharp.Backend.MatrixCOO open Brahma.OpenCL open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic @@ -7,10 +7,10 @@ open GraphBLAS.FSharp open GraphBLAS.FSharp.Backend.Common module internal EWiseAdd = - let coo (matrixLeft: COOFormat<'a>) (matrixRight: COOFormat<'a>) (mask: Mask2D option) (semiring: Semiring<'a>) : OpenCLEvaluation> = + let run (matrixLeft: COOFormat<'a>) (matrixRight: COOFormat<'a>) (mask: Mask2D option) (semiring: ISemiring<'a>) : OpenCLEvaluation> = let workGroupSize = Utils.workGroupSize - let (BinaryOp append) = semiring.PlusMonoid.Append - let zero = semiring.PlusMonoid.Zero + let (ClosedBinaryOp append) = semiring.Plus + let zero = semiring.Zero //It is useful to consider that the first array is longer than the second one let firstRows, firstColumns, firstValues, secondRows, secondColumns, secondValues, plus = diff --git a/src/GraphBLAS-sharp/Implementations.fs b/src/GraphBLAS-sharp/Concrete.fs similarity index 97% rename from src/GraphBLAS-sharp/Implementations.fs rename to src/GraphBLAS-sharp/Concrete.fs index d818edbb..19487f94 100644 --- a/src/GraphBLAS-sharp/Implementations.fs +++ b/src/GraphBLAS-sharp/Concrete.fs @@ -6,6 +6,8 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open GraphBLAS.FSharp.Backend.Common open GraphBLAS.FSharp.Backend +// storageFormats (concrete implementation) + type CSRMatrix<'a when 'a : struct and 'a : equality>(csrTuples: CSRFormat<'a>) = inherit Matrix<'a>(csrTuples.RowPointers.Length - 1, csrTuples.ColumnCount) @@ -137,7 +139,7 @@ and COOMatrix<'a when 'a : struct and 'a : equality>(cooFormat: COOFormat<'a>) = override this.EWiseAdd (matrix: Matrix<'a>) (mask: Mask2D option) - (semiring: Semiring<'a>) = + (semiring: ISemiring<'a>) = if (this.RowCount, this.ColumnCount) <> (matrix.RowCount, matrix.ColumnCount) then invalidArg @@ -157,7 +159,7 @@ and COOMatrix<'a when 'a : struct and 'a : equality>(cooFormat: COOFormat<'a>) = match matrix with | :? COOMatrix<'a> as coo -> opencl { - let! cooFormat = EWiseAdd.coo cooFormat coo.Storage mask semiring + let! cooFormat = MatrixCOO.EWiseAdd.run cooFormat coo.Storage mask semiring return upcast COOMatrix(cooFormat) } | _ -> failwith "Not Implemented" @@ -207,15 +209,15 @@ and SparseVector<'a when 'a : struct and 'a : equality>(size: int, indices: int[ override this.Assign (idx: int, Scalar (value: 'a)) : OpenCLEvaluation = failwith "Not Implemented" override this.Assign (mask: Mask1D option, Scalar (value: 'a)) : OpenCLEvaluation = failwith "Not Implemented" - override this.Vxm (matrix: Matrix<'a>) (mask: Mask1D option) (semiring: Semiring<'a>) : OpenCLEvaluation> = failwith "Not Implemented" + override this.Vxm (matrix: Matrix<'a>) (mask: Mask1D option) (semiring: ISemiring<'a>) : OpenCLEvaluation> = failwith "Not Implemented" member internal this.EWiseAddSparse (vector: SparseVector<'a>) (mask: Mask1D option) - (semiring: Semiring<'a>) : OpenCLEvaluation> = + (semiring: ISemiring<'a>) : OpenCLEvaluation> = - let (BinaryOp append) = semiring.PlusMonoid.Append - let zero = semiring.PlusMonoid.Zero + let (ClosedBinaryOp append) = semiring.Plus + let zero = semiring.Zero //It is useful to consider that the first array is longer than the second one let firstIndices, firstValues, secondIndices, secondValues, plus = @@ -375,7 +377,7 @@ and SparseVector<'a when 'a : struct and 'a : equality>(size: int, indices: int[ override this.EWiseAdd (vector: Vector<'a>) (mask: Mask1D option) - (semiring: Semiring<'a>) = + (semiring: ISemiring<'a>) = if vector.Size <> this.Size then invalidArg @@ -399,4 +401,4 @@ and SparseVector<'a when 'a : struct and 'a : equality>(size: int, indices: int[ override this.EWiseMult a b c = failwith "Not Implemented" override this.Apply a b = failwith "Not Implemented" override this.Prune a b = failwith "Not Implemented" - override this.Reduce (monoid: Monoid<'a>) = failwith "Not Implemented" + override this.Reduce (monoid: IMonoid<'a>) = failwith "Not Implemented" diff --git a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj index 6c7dc84b..dec67718 100644 --- a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj +++ b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj @@ -1,4 +1,4 @@ - + netstandard2.1;net461 @@ -11,15 +11,13 @@ - - - - - + + - - + + + @@ -28,10 +26,6 @@ - - - - diff --git a/src/GraphBLAS-sharp/GraphblasEvaluation.fs b/src/GraphBLAS-sharp/GraphblasEvaluation.fs new file mode 100644 index 00000000..1207850e --- /dev/null +++ b/src/GraphBLAS-sharp/GraphblasEvaluation.fs @@ -0,0 +1,40 @@ +namespace GraphBLAS.FSharp + +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic + +type GraphblasContext = + { + ClContext: OpenCLEvaluationContext + } + +type GraphblasEvaluation<'a> = EvalGB of (GraphblasContext -> 'a) + +module EvalGB = + let private runCl env (OpenCLEvaluation f) = f env + + let run env (EvalGB action) = action env + + let ask = EvalGB id + + let asks f = EvalGB f + + let bind f reader = + EvalGB <| fun env -> + let x = run env reader + run env (f x) + + // EvalGB.liftCl x === liftM EvalGB x + let liftCl clEvaluation = + EvalGB <| fun env -> + clEvaluation + |> runCl env.ClContext + +type GraphblasBuilder() = + // monad + member this.Bind(x, f) = EvalGB.bind f x + member this.Return x = EvalGB <| fun _ -> x + +[] +module GraphblasBuilder = + let graphblas = GraphblasBuilder() diff --git a/src/GraphBLAS-sharp/Helpers.fs b/src/GraphBLAS-sharp/Helpers.fs index 546343d2..b403a41a 100644 --- a/src/GraphBLAS-sharp/Helpers.fs +++ b/src/GraphBLAS-sharp/Helpers.fs @@ -1,4 +1,6 @@ namespace GraphBLAS.FSharp module Helpers = - let inline (!>) (x: ^a) : ^b = (^a : (static member op_Implicit : ^a -> ^b) x) + let inline (!>) (x: ^a) : ^b = (^a: (static member op_Implicit : ^a -> ^b) x) + + let inline (^) f x = f x diff --git a/src/GraphBLAS-sharp/Matrix.fs b/src/GraphBLAS-sharp/Matrix.fs index 16437ecb..9bb77ec0 100644 --- a/src/GraphBLAS-sharp/Matrix.fs +++ b/src/GraphBLAS-sharp/Matrix.fs @@ -1,9 +1,16 @@ namespace GraphBLAS.FSharp open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open GraphBLAS.FSharp.Backend [] module Matrix = + + (* + constructors + *) + let build (rowCount: int) (columnCount: int) (rows: int[]) (columns: int[]) (values: 'a[]) : Matrix<'a> = failwith "Not Implemented yet" @@ -18,3 +25,26 @@ module Matrix = let zeroCreate (rowCount: int) (columnCount: int) : Matrix<'a> = failwith "Not Implemented yet" + + (* + methods + *) + + (* + operations + *) + + let eWiseAdd (matrix: Matrix<'a>) (cooFormat: COOFormat<'a>) (mask: Mask2D option) (sr: ISemiring<'a>) = + let s = + match matrix with + | :? COOMatrix<'a> as coo -> + opencl { + let! cooFormat = MatrixCOO.EWiseAdd.run cooFormat coo.Storage mask sr + return COOMatrix(cooFormat) :> Matrix<'a> + } + | _ -> failwith "Not Implemented" + + graphblas { + let! m = EvalGB.liftCl s + return m + } diff --git a/src/GraphBLAS-sharp/Monoid.fs b/src/GraphBLAS-sharp/Monoid.fs deleted file mode 100644 index 5fb09de9..00000000 --- a/src/GraphBLAS-sharp/Monoid.fs +++ /dev/null @@ -1,6 +0,0 @@ -namespace GraphBLAS.FSharp - -type Monoid<'T> = { - Zero: 'T - Append: BinaryOp<'T, 'T, 'T> -} diff --git a/src/GraphBLAS-sharp/Operators.fs b/src/GraphBLAS-sharp/Operators.fs deleted file mode 100644 index 57a0521d..00000000 --- a/src/GraphBLAS-sharp/Operators.fs +++ /dev/null @@ -1,12 +0,0 @@ -namespace GraphBLAS.FSharp - -open Microsoft.FSharp.Quotations - -type UnaryOp<'TIn, 'TOut> = UnaryOp of Expr<'TIn -> 'TOut> -with - static member op_Implicit (UnaryOp source) = source - - -type BinaryOp<'T1, 'T2, 'TOut> = BinaryOp of Expr<'T1 -> 'T2 -> 'TOut> -with - static member op_Implicit (BinaryOp source) = source diff --git a/src/GraphBLAS-sharp/Predefined/Boolean.fs b/src/GraphBLAS-sharp/Predefined/Boolean.fs deleted file mode 100644 index fafbb54a..00000000 --- a/src/GraphBLAS-sharp/Predefined/Boolean.fs +++ /dev/null @@ -1,15 +0,0 @@ -namespace GraphBLAS.FSharp.Predefined - -open GraphBLAS.FSharp - -module BooleanMonoid = - let any: Monoid = { - Zero = false - Append = BinaryOp <@ ( || ) @> - } - -module BooleanSemiring = - let anyAll: Semiring = { - PlusMonoid = BooleanMonoid.any - Times = BinaryOp <@ ( && ) @> - } diff --git a/src/GraphBLAS-sharp/Predefined/Float.fs b/src/GraphBLAS-sharp/Predefined/Float.fs deleted file mode 100644 index e0fb907b..00000000 --- a/src/GraphBLAS-sharp/Predefined/Float.fs +++ /dev/null @@ -1,25 +0,0 @@ -namespace GraphBLAS.FSharp.Predefined - -open GraphBLAS.FSharp - -module FloatMonoid = - let add: Monoid = { - Zero = 0. - Append = BinaryOp <@ ( + ) @> - } - - let min: Monoid = { - Zero = System.Double.PositiveInfinity - Append = BinaryOp <@ fun x y -> System.Math.Min(x, y) @> - } - -module FloatSemiring = - let addMult: Semiring = { - PlusMonoid = FloatMonoid.add - Times = BinaryOp <@ ( * ) @> - } - - let minAdd: Semiring = { - PlusMonoid = FloatMonoid.min - Times = BinaryOp <@ ( + ) @> - } diff --git a/src/GraphBLAS-sharp/Predefined/Float32.fs b/src/GraphBLAS-sharp/Predefined/Float32.fs deleted file mode 100644 index bc2c9e67..00000000 --- a/src/GraphBLAS-sharp/Predefined/Float32.fs +++ /dev/null @@ -1,15 +0,0 @@ -namespace GraphBLAS.FSharp.Predefined - -open GraphBLAS.FSharp - -module Float32Monoid = - let add: Monoid = { - Zero = 0.f - Append = BinaryOp <@ (+) @> - } - -module Float32Semiring = - let addMult: Semiring = { - PlusMonoid = Float32Monoid.add - Times = BinaryOp <@ (*) @> - } diff --git a/src/GraphBLAS-sharp/Predefined/Integer.fs b/src/GraphBLAS-sharp/Predefined/Integer.fs deleted file mode 100644 index 5b166fe7..00000000 --- a/src/GraphBLAS-sharp/Predefined/Integer.fs +++ /dev/null @@ -1,25 +0,0 @@ -namespace GraphBLAS.FSharp.Predefined - -open GraphBLAS.FSharp - -module IntegerMonoid = - let add: Monoid = { - Zero = 0 - Append = BinaryOp <@ ( + ) @> - } - - let min: Monoid = { - Zero = System.Int32.MaxValue - Append = BinaryOp <@ fun x y -> System.Math.Min(x, y) @> - } - -module IntegerSemiring = - let addMult: Semiring = { - PlusMonoid = IntegerMonoid.add - Times = BinaryOp <@ ( * ) @> - } - - // let minFirst<'b> : Semiring = { - // PlusMonoid = IntegerMonoid.min - // Times = BinaryOp <@ fun x y -> x @> - // } diff --git a/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs b/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs index f0925d34..efc71360 100644 --- a/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs +++ b/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs @@ -3,37 +3,44 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module Add = - let int: Monoid = { - Zero = 0 - Append = BinaryOp <@ (+) @> - } - - let float: Monoid = { - Zero = 0. - Append = BinaryOp <@ (+) @> - } - - let float32: Monoid = { - Zero = 0.f - Append = BinaryOp <@ (+) @> - } - - let sbyte: Monoid = { - Zero = 0y - Append = BinaryOp <@ (+) @> - } - - let byte: Monoid = { - Zero = 0uy - Append = BinaryOp <@ (+) @> - } - - let int16: Monoid = { - Zero = 0s - Append = BinaryOp <@ (+) @> - } - - let uint16: Monoid = { - Zero = 0us - Append = BinaryOp <@ (+) @> - } + let int = + { new IMonoid with + member this.Zero = 0 + member this.Plus = ClosedBinaryOp <@ (+) @> + } + + let float = + { new IMonoid with + member this.Zero = 0. + member this.Plus = ClosedBinaryOp <@ (+) @> + } + + let float32 = + { new IMonoid with + member this.Zero = 0f + member this.Plus = ClosedBinaryOp <@ (+) @> + } + + let sbyte = + { new IMonoid with + member this.Zero = 0y + member this.Plus = ClosedBinaryOp <@ (+) @> + } + + let byte = + { new IMonoid with + member this.Zero = 0uy + member this.Plus = ClosedBinaryOp <@ (+) @> + } + + let int16 = + { new IMonoid with + member this.Zero = 0s + member this.Plus = ClosedBinaryOp <@ (+) @> + } + + let uint16 = + { new IMonoid with + member this.Zero = 0us + member this.Plus = ClosedBinaryOp <@ (+) @> + } diff --git a/src/GraphBLAS-sharp/Predefined/Monoids/Any.fs b/src/GraphBLAS-sharp/Predefined/Monoids/Any.fs index 7bd7973c..c17ad46b 100644 --- a/src/GraphBLAS-sharp/Predefined/Monoids/Any.fs +++ b/src/GraphBLAS-sharp/Predefined/Monoids/Any.fs @@ -3,7 +3,8 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module Any = - let bool: Monoid = { - Zero = false - Append = BinaryOp <@ (||) @> - } + let bool = + { new IMonoid with + member this.Zero = false + member this.Plus = ClosedBinaryOp <@ ( || ) @> + } diff --git a/src/GraphBLAS-sharp/Predefined/Monoids/Min.fs b/src/GraphBLAS-sharp/Predefined/Monoids/Min.fs index 2b6791ed..0f73c28e 100644 --- a/src/GraphBLAS-sharp/Predefined/Monoids/Min.fs +++ b/src/GraphBLAS-sharp/Predefined/Monoids/Min.fs @@ -3,12 +3,14 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module Min = - let int: Monoid = { - Zero = System.Int32.MaxValue - Append = BinaryOp <@ fun x y -> System.Math.Min(x, y) @> - } + let int = + { new IMonoid with + member this.Zero = System.Int32.MaxValue + member this.Plus = ClosedBinaryOp <@ fun x y -> System.Math.Min(x, y) @> + } - let float: Monoid = { - Zero = System.Double.PositiveInfinity - Append = BinaryOp <@ fun x y -> System.Math.Min(x, y) @> - } + let float = + { new IMonoid with + member this.Zero = System.Double.PositiveInfinity + member this.Plus = ClosedBinaryOp <@ fun x y -> System.Math.Min(x, y) @> + } diff --git a/src/GraphBLAS-sharp/Predefined/Semirings/AddMult.fs b/src/GraphBLAS-sharp/Predefined/Semirings/AddMult.fs index e0e98dad..c06d0e9f 100644 --- a/src/GraphBLAS-sharp/Predefined/Semirings/AddMult.fs +++ b/src/GraphBLAS-sharp/Predefined/Semirings/AddMult.fs @@ -3,37 +3,51 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module AddMult = - let int: Semiring = { - PlusMonoid = Add.int - Times = BinaryOp <@ (*) @> - } - - let float: Semiring = { - PlusMonoid = Add.float - Times = BinaryOp <@ (*) @> - } - - let float32: Semiring = { - PlusMonoid = Add.float32 - Times = BinaryOp <@ (*) @> - } - - let sbyte: Semiring = { - PlusMonoid = Add.sbyte - Times = BinaryOp <@ (*) @> - } - - let byte: Semiring = { - PlusMonoid = Add.byte - Times = BinaryOp <@ (*) @> - } - - let int16: Semiring = { - PlusMonoid = Add.int16 - Times = BinaryOp <@ (*) @> - } - - let uint16: Semiring = { - PlusMonoid = Add.uint16 - Times = BinaryOp <@ (*) @> - } + let int = + { new ISemiring with + member this.Zero = Add.int.Zero + member this.Plus = Add.int.Plus + member this.Times = ClosedBinaryOp <@ (*) @> + } + + let float = + { new ISemiring with + member this.Zero = Add.float.Zero + member this.Plus = Add.float.Plus + member this.Times = ClosedBinaryOp <@ (*) @> + } + + let float32 = + { new ISemiring with + member this.Zero = Add.float32.Zero + member this.Plus = Add.float32.Plus + member this.Times = ClosedBinaryOp <@ (*) @> + } + + let sbyte = + { new ISemiring with + member this.Zero = Add.sbyte.Zero + member this.Plus = Add.sbyte.Plus + member this.Times = ClosedBinaryOp <@ (*) @> + } + + let byte = + { new ISemiring with + member this.Zero = Add.byte.Zero + member this.Plus = Add.byte.Plus + member this.Times = ClosedBinaryOp <@ (*) @> + } + + let int16 = + { new ISemiring with + member this.Zero = Add.int16.Zero + member this.Plus = Add.int16.Plus + member this.Times = ClosedBinaryOp <@ (*) @> + } + + let uint16 = + { new ISemiring with + member this.Zero = Add.uint16.Zero + member this.Plus = Add.uint16.Plus + member this.Times = ClosedBinaryOp <@ (*) @> + } diff --git a/src/GraphBLAS-sharp/Predefined/Semirings/AnyAll.fs b/src/GraphBLAS-sharp/Predefined/Semirings/AnyAll.fs index 64571c9f..3941acf9 100644 --- a/src/GraphBLAS-sharp/Predefined/Semirings/AnyAll.fs +++ b/src/GraphBLAS-sharp/Predefined/Semirings/AnyAll.fs @@ -3,7 +3,9 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module AnyAll = - let bool: Semiring = { - PlusMonoid = Any.bool - Times = BinaryOp <@ (&&) @> - } + let bool = + { new ISemiring with + member this.Zero = Any.bool.Zero + member this.Plus = Any.bool.Plus + member this.Times = ClosedBinaryOp <@ ( && ) @> + } diff --git a/src/GraphBLAS-sharp/Predefined/Semirings/MinAdd.fs b/src/GraphBLAS-sharp/Predefined/Semirings/MinAdd.fs index 9b382835..2e0d443d 100644 --- a/src/GraphBLAS-sharp/Predefined/Semirings/MinAdd.fs +++ b/src/GraphBLAS-sharp/Predefined/Semirings/MinAdd.fs @@ -3,7 +3,9 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module MinAdd = - let float: Semiring = { - PlusMonoid = Min.float - Times = BinaryOp <@ (+) @> - } + let float = + { new ISemiring with + member this.Zero = Min.float.Zero + member this.Plus = Min.float.Plus + member this.Times = ClosedBinaryOp <@ (+) @> + } diff --git a/src/GraphBLAS-sharp/Scalar.fs b/src/GraphBLAS-sharp/Scalar.fs deleted file mode 100644 index 1f105c7d..00000000 --- a/src/GraphBLAS-sharp/Scalar.fs +++ /dev/null @@ -1,5 +0,0 @@ -namespace GraphBLAS.FSharp - -type Scalar<'a when 'a : struct and 'a : equality> = Scalar of 'a -with - static member op_Implicit (Scalar source) = source diff --git a/src/GraphBLAS-sharp/Semiring.fs b/src/GraphBLAS-sharp/Semiring.fs deleted file mode 100644 index b05c51d4..00000000 --- a/src/GraphBLAS-sharp/Semiring.fs +++ /dev/null @@ -1,6 +0,0 @@ -namespace GraphBLAS.FSharp - -type Semiring<'T> = { - PlusMonoid: Monoid<'T> - Times: BinaryOp<'T, 'T, 'T> -} diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs index 3caad01c..25b059e5 100644 --- a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs @@ -12,31 +12,25 @@ open TypeShape.Core open Expecto.Logging open Expecto.Logging.Message open BackendState +open GraphBLAS.FSharp.Helpers -type OperationParameter = - | MatrixFormatParam of MatrixBackendFormat - | MaskTypeParam of MaskType - -type OperationCase = { - MatrixCase: MatrixBackendFormat - MaskCase: MaskType -} +type OperationCase = + { + MatrixCase: MatrixBackendFormat + MaskCase: MaskType + } let testCases = [ - Utils.listOfUnionCases |> List.map MatrixFormatParam - Utils.listOfUnionCases |> List.map MaskTypeParam + Utils.listOfUnionCases |> List.map box + Utils.listOfUnionCases |> List.map box ] |> Utils.cartesian - |> List.map - (fun list -> - let (MatrixFormatParam marixFormat) = list.[0] - let (MaskTypeParam maskType) = list.[1] - { - MatrixCase = marixFormat - MaskCase = maskType - } - ) + |> List.map ^fun list -> + { + MatrixCase = unbox list.[0] + MaskCase = unbox list.[1] + } type PairOfSparseMatricesOfEqualSize = static member IntType() = @@ -116,7 +110,7 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> (sum: 'a -> 'a -> 'a) (diff: 'a -> 'a -> 'a) (isZero: 'a -> bool) - (semiring: Semiring<'a>) + (semiring: ISemiring<'a>) (case: OperationCase) (matrixA: 'a[,], matrixB: 'a[,]) = From 639f0cb61b4ef4b64ff7a1fe416ada4cf1c53a26 Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Wed, 17 Mar 2021 00:59:19 +0300 Subject: [PATCH 02/16] Change matrix type to union type of concrete formats --- src/GraphBLAS-sharp/Abstract.fs | 130 ------ .../Backend/MatrixCOO/EWiseAdd.fs | 2 +- src/GraphBLAS-sharp/Concrete.fs | 404 ------------------ src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj | 12 +- src/GraphBLAS-sharp/GraphblasEvaluation.fs | 1 + .../{Matrix.fs => Methods/MatrixMethods.fs} | 33 +- .../{Vector.fs => Methods/VectorMethods.fs} | 0 src/GraphBLAS-sharp/Objects/Masks.fs | 13 + src/GraphBLAS-sharp/Objects/Matrix.fs | 22 + src/GraphBLAS-sharp/Objects/Scalar.fs | 5 + src/GraphBLAS-sharp/Objects/Vector.fs | 4 + 11 files changed, 76 insertions(+), 550 deletions(-) delete mode 100644 src/GraphBLAS-sharp/Abstract.fs delete mode 100644 src/GraphBLAS-sharp/Concrete.fs rename src/GraphBLAS-sharp/{Matrix.fs => Methods/MatrixMethods.fs} (57%) rename src/GraphBLAS-sharp/{Vector.fs => Methods/VectorMethods.fs} (100%) create mode 100644 src/GraphBLAS-sharp/Objects/Masks.fs create mode 100644 src/GraphBLAS-sharp/Objects/Matrix.fs create mode 100644 src/GraphBLAS-sharp/Objects/Scalar.fs create mode 100644 src/GraphBLAS-sharp/Objects/Vector.fs diff --git a/src/GraphBLAS-sharp/Abstract.fs b/src/GraphBLAS-sharp/Abstract.fs deleted file mode 100644 index e8348814..00000000 --- a/src/GraphBLAS-sharp/Abstract.fs +++ /dev/null @@ -1,130 +0,0 @@ -namespace GraphBLAS.FSharp - -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation -open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic - -// algebraic objects - -type MatrixTuples<'a when 'a : struct and 'a : equality> = - { - RowIndices: int[] - ColumnIndices: int[] - Values: 'a[] - } - - member this.ToHost() = - opencl { - let! rows = ToHost this.RowIndices - let! cols = ToHost this.ColumnIndices - let! vals = ToHost this.Values - - return { - RowIndices = rows - ColumnIndices = cols - Values = vals - } - } - -type Scalar<'a when 'a : struct and 'a : equality> = Scalar of 'a -with - static member op_Implicit (Scalar source) = source - -[] -type Matrix<'a when 'a : struct and 'a : equality>(nrow: int, ncol: int) = - abstract RowCount: int - abstract ColumnCount: int - default this.RowCount = nrow - default this.ColumnCount = ncol - - abstract Clear: unit -> OpenCLEvaluation - abstract Copy: unit -> OpenCLEvaluation> - abstract Resize: int -> int -> OpenCLEvaluation> - abstract GetNNZ: unit -> OpenCLEvaluation - abstract GetTuples: unit -> OpenCLEvaluation> - abstract GetMask: ?isComplemented: bool -> OpenCLEvaluation - abstract ToHost: unit -> OpenCLEvaluation> - - abstract Extract: Mask2D option -> OpenCLEvaluation> - abstract Extract: (Mask1D option * int) -> OpenCLEvaluation> - abstract Extract: (int * Mask1D option) -> OpenCLEvaluation> - abstract Extract: (int * int) -> OpenCLEvaluation> - abstract Assign: Mask2D option * Matrix<'a> -> OpenCLEvaluation - abstract Assign: (Mask1D option * int) * Vector<'a> -> OpenCLEvaluation - abstract Assign: (int * Mask1D option) * Vector<'a> -> OpenCLEvaluation - abstract Assign: (int * int) * Scalar<'a> -> OpenCLEvaluation - abstract Assign: Mask2D option * Scalar<'a> -> OpenCLEvaluation - abstract Assign: (Mask1D option * int) * Scalar<'a> -> OpenCLEvaluation - abstract Assign: (int * Mask1D option) * Scalar<'a> -> OpenCLEvaluation - - abstract Mxm: Matrix<'a> -> Mask2D option -> ISemiring<'a> -> OpenCLEvaluation> - abstract Mxv: Vector<'a> -> Mask1D option -> ISemiring<'a> -> OpenCLEvaluation> - abstract EWiseAdd: Matrix<'a> -> Mask2D option -> ISemiring<'a> -> OpenCLEvaluation> - abstract EWiseMult: Matrix<'a> -> Mask2D option -> ISemiring<'a> -> OpenCLEvaluation> - abstract Apply: Mask2D option -> UnaryOp<'a, 'b> -> OpenCLEvaluation> - abstract Prune: Mask2D option -> UnaryOp<'a, bool> -> OpenCLEvaluation> - abstract ReduceIn: Mask1D option -> IMonoid<'a> -> OpenCLEvaluation> - abstract ReduceOut: Mask1D option -> IMonoid<'a> -> OpenCLEvaluation> - abstract Reduce: IMonoid<'a> -> OpenCLEvaluation> - abstract Transpose: unit -> OpenCLEvaluation> - abstract Kronecker: Matrix<'a> -> Mask2D option -> ISemiring<'a> -> OpenCLEvaluation> - -and [] Vector<'a when 'a : struct and 'a : equality>(size: int) = - abstract Size: int - default this.Size = size - - abstract Clear: unit -> OpenCLEvaluation - abstract Copy: unit -> OpenCLEvaluation> - abstract Resize: int -> OpenCLEvaluation> - abstract GetNNZ: unit -> OpenCLEvaluation - abstract GetTuples: unit -> OpenCLEvaluation<{| Indices: int[]; Values: 'a[] |}> - abstract GetMask: ?isComplemented: bool -> OpenCLEvaluation - abstract ToHost: unit -> OpenCLEvaluation> - - abstract Extract: Mask1D option -> OpenCLEvaluation> - abstract Extract: int -> OpenCLEvaluation> - abstract Assign: Mask1D option * Vector<'a> -> OpenCLEvaluation - abstract Assign: int * Scalar<'a> -> OpenCLEvaluation - abstract Assign: Mask1D option * Scalar<'a> -> OpenCLEvaluation - - abstract Vxm: Matrix<'a> -> Mask1D option -> ISemiring<'a> -> OpenCLEvaluation> - abstract EWiseAdd: Vector<'a> -> Mask1D option -> ISemiring<'a> -> OpenCLEvaluation> - abstract EWiseMult: Vector<'a> -> Mask1D option -> ISemiring<'a> -> OpenCLEvaluation> - abstract Apply: Mask1D option -> UnaryOp<'a, 'b> -> OpenCLEvaluation> - abstract Prune: Mask1D option -> UnaryOp<'a, bool> -> OpenCLEvaluation> - abstract Reduce: IMonoid<'a> -> OpenCLEvaluation> - -and Mask1D(indices: int[], size: int, isComplemented: bool) = - member this.Indices = indices - member this.Size = size - member this.IsComplemented = isComplemented - -and Mask2D(rowIndices: int[], columnIndices: int[], rowCount: int, columnCount: int, isComplemented: bool) = - member this.RowIndices = rowIndices - member this.ColumnIndices = columnIndices - member this.RowCount = rowCount - member this.ColumnCount = columnCount - member this.IsComplemented = isComplemented - -type COOFormat<'a> = - { - RowCount: int - ColumnCount: int - Rows: int[] - Columns: int[] - Values: 'a[] - } - -type CSRFormat<'a> = - { - ColumnCount: int - RowPointers: int[] - ColumnIndices: int[] - Values: 'a[] - } - - static member CreateEmpty<'a>() = { - RowPointers = Array.zeroCreate 0 - ColumnIndices = Array.zeroCreate 0 - Values = Array.zeroCreate<'a> 0 - ColumnCount = 0 - } diff --git a/src/GraphBLAS-sharp/Backend/MatrixCOO/EWiseAdd.fs b/src/GraphBLAS-sharp/Backend/MatrixCOO/EWiseAdd.fs index 75b4e785..6e84f961 100644 --- a/src/GraphBLAS-sharp/Backend/MatrixCOO/EWiseAdd.fs +++ b/src/GraphBLAS-sharp/Backend/MatrixCOO/EWiseAdd.fs @@ -7,7 +7,7 @@ open GraphBLAS.FSharp open GraphBLAS.FSharp.Backend.Common module internal EWiseAdd = - let run (matrixLeft: COOFormat<'a>) (matrixRight: COOFormat<'a>) (mask: Mask2D option) (semiring: ISemiring<'a>) : OpenCLEvaluation> = + let run (matrixLeft: COOMatrix<'a>) (matrixRight: COOMatrix<'a>) (mask: Mask2D option) (semiring: ISemiring<'a>) : OpenCLEvaluation> = let workGroupSize = Utils.workGroupSize let (ClosedBinaryOp append) = semiring.Plus let zero = semiring.Zero diff --git a/src/GraphBLAS-sharp/Concrete.fs b/src/GraphBLAS-sharp/Concrete.fs deleted file mode 100644 index 19487f94..00000000 --- a/src/GraphBLAS-sharp/Concrete.fs +++ /dev/null @@ -1,404 +0,0 @@ -namespace GraphBLAS.FSharp - -open Brahma.OpenCL -open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation -open GraphBLAS.FSharp.Backend.Common -open GraphBLAS.FSharp.Backend - -// storageFormats (concrete implementation) - -type CSRMatrix<'a when 'a : struct and 'a : equality>(csrTuples: CSRFormat<'a>) = - inherit Matrix<'a>(csrTuples.RowPointers.Length - 1, csrTuples.ColumnCount) - - let rowCount = base.RowCount - let columnCount = base.ColumnCount - - new(rows: int[], columns: int[], values: 'a[]) = CSRMatrix(CSRFormat.CreateEmpty()) - new(pathToMatrix: string) = CSRMatrix(CSRFormat.CreateEmpty()) - - member this.Values = csrTuples.Values - member this.Columns = csrTuples.ColumnIndices - member this.RowPointers = csrTuples.RowPointers - - override this.Clear () = failwith "Not Implemented" - override this.Copy () = failwith "Not Implemented" - override this.Resize a b = failwith "Not Implemented" - override this.GetNNZ () = failwith "Not Implemented" - override this.GetTuples () = failwith "Not Implemented" - override this.GetMask(?isComplemented: bool) = - let isComplemented = defaultArg isComplemented false - failwith "Not Implemented" - override this.ToHost () = failwith "Not implemented" - - override this.Extract (mask: Mask2D option) : OpenCLEvaluation> = failwith "Not Implemented" - override this.Extract (colMask: Mask1D option * int) : OpenCLEvaluation> = failwith "Not Implemented" - override this.Extract (rowMask: int * Mask1D option) : OpenCLEvaluation> = failwith "Not Implemented" - override this.Extract (idx: int * int) : OpenCLEvaluation> = failwith "Not Implemented" - override this.Assign (mask: Mask2D option, value: Matrix<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (colMask: Mask1D option * int, value: Vector<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (rowMask: int * Mask1D option, value: Vector<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (idx: int * int, value: Scalar<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (mask: Mask2D option, value: Scalar<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (colMask: Mask1D option * int, value: Scalar<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (rowMask: int * Mask1D option, value: Scalar<'a>) : OpenCLEvaluation = failwith "Not Implemented" - - override this.Mxm a b c = failwith "Not Implemented" - override this.Mxv a b c = failwith "Not Implemented" - override this.EWiseAdd a b c = failwith "Not Implemented" - override this.EWiseMult a b c = failwith "Not Implemented" - override this.Apply a b = failwith "Not Implemented" - override this.Prune a b = failwith "Not Implemented" - override this.ReduceIn a b = failwith "Not Implemented" - override this.ReduceOut a b = failwith "Not Implemented" - override this.Reduce a = failwith "Not Implemented" - override this.Transpose () = failwith "Not Implemented" - override this.Kronecker a b c = failwith "Not Implemented" - -and COOMatrix<'a when 'a : struct and 'a : equality>(cooFormat: COOFormat<'a>) = - inherit Matrix<'a>(cooFormat.RowCount, cooFormat.ColumnCount) - - new(rowCount: int, columnCount: int, rows: int[], columns: int[], values: 'a[]) = - let cooFormat = { - RowCount = rowCount - ColumnCount = columnCount - Rows = rows - Columns = columns - Values = values - } - - COOMatrix(cooFormat) - - new(array: 'a[,], isZero: 'a -> bool) = - let (rows, cols, vals) = - array - |> Seq.cast<'a> - |> Seq.mapi (fun idx v -> (idx / Array2D.length2 array, idx % Array2D.length2 array, v)) - |> Seq.filter (fun (i, j, v) -> not <| isZero v) - |> Array.ofSeq - |> Array.unzip3 - - COOMatrix(Array2D.length1 array, Array2D.length2 array, rows, cols, vals) - - override this.ToString() = - [ - sprintf "COO Matrix %ix%i \n" cooFormat.RowCount cooFormat.ColumnCount - sprintf "RowIndices: %A \n" cooFormat.Rows - sprintf "ColumnIndices: %A \n" cooFormat.Columns - sprintf "Values: %A \n" cooFormat.Values - ] - |> String.concat "" - - member this.Storage = cooFormat - - member this.Rows with get() = cooFormat.Rows - member this.Columns with get() = cooFormat.Columns - member this.Values with get() = cooFormat.Values - member this.Elements with get() = (cooFormat.Rows, cooFormat.Columns, cooFormat.Values) |||> Array.zip3 - - override this.Clear () = failwith "Not Implemented" - override this.Copy () = failwith "Not Implemented" - override this.Resize a b = failwith "Not Implemented" - override this.GetNNZ () = failwith "Not Implemented" - - override this.GetTuples() = opencl { - return { - RowIndices = this.Rows - ColumnIndices = this.Columns - Values = this.Values - } - } - - override this.GetMask(?isComplemented: bool) = - let isComplemented = defaultArg isComplemented false - failwith "Not Implemented" - - override this.ToHost() = opencl { - let! _ = ToHost this.Rows - let! _ = ToHost this.Columns - let! _ = ToHost this.Values - - return upcast this - } - - override this.Extract (mask: Mask2D option) : OpenCLEvaluation> = failwith "Not Implemented" - override this.Extract (colMask: Mask1D option * int) : OpenCLEvaluation> = failwith "Not Implemented" - override this.Extract (rowMask: int * Mask1D option) : OpenCLEvaluation> = failwith "Not Implemented" - override this.Extract (idx: int * int) : OpenCLEvaluation> = failwith "Not Implemented" - override this.Assign (mask: Mask2D option, value: Matrix<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (colMask: Mask1D option * int, value: Vector<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (rowMask: int * Mask1D option, value: Vector<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (idx: int * int, value: Scalar<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (mask: Mask2D option, value: Scalar<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (colMask: Mask1D option * int, value: Scalar<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (rowMask: int * Mask1D option, value: Scalar<'a>) : OpenCLEvaluation = failwith "Not Implemented" - - override this.Mxm a b c = failwith "Not Implemented" - override this.Mxv a b c = failwith "Not Implemented" - - override this.EWiseAdd - (matrix: Matrix<'a>) - (mask: Mask2D option) - (semiring: ISemiring<'a>) = - - if (this.RowCount, this.ColumnCount) <> (matrix.RowCount, matrix.ColumnCount) then - invalidArg - "matrix" - (sprintf "Argument has invalid dimension. Need %A, but given %A" (this.RowCount, this.ColumnCount) (matrix.RowCount, matrix.ColumnCount)) - - // let mask = - // match matrixMask with - // | Some m -> - // if (m.RowCount, m.ColumnCount) <> (this.RowCount, this.ColumnCount) then - // invalidArg - // "mask" - // (sprintf "Argument has invalid dimension. Need %A, but given %A" (this.RowCount, this.ColumnCount) (m.RowCount, m.ColumnCount)) - // m - // | _ -> Mask2D(Array.empty, this.RowCount, this.ColumnCount, true) // Empty complemented mask is equal to none - - match matrix with - | :? COOMatrix<'a> as coo -> - opencl { - let! cooFormat = MatrixCOO.EWiseAdd.run cooFormat coo.Storage mask semiring - return upcast COOMatrix(cooFormat) - } - | _ -> failwith "Not Implemented" - - override this.EWiseMult a b c = failwith "Not Implemented" - override this.Apply a b = failwith "Not Implemented" - override this.Prune a b = failwith "Not Implemented" - override this.ReduceIn a b = failwith "Not Implemented" - override this.ReduceOut a b = failwith "Not Implemented" - override this.Reduce a = failwith "Not Implemented" - override this.Transpose () = failwith "Not Implemented" - override this.Kronecker a b c = failwith "Not Implemented" - -and SparseVector<'a when 'a : struct and 'a : equality>(size: int, indices: int[], values: 'a[]) = - inherit Vector<'a>(size) - - let mutable indices, values = indices, values - member this.Values with get() = values - member this.Indices with get() = indices - member this.Elements with get() = (indices, values) ||> Array.zip - - override this.Clear () = failwith "Not Implemented" - override this.Copy () = failwith "Not Implemented" - override this.Resize a = failwith "Not Implemented" - override this.GetNNZ () = failwith "Not Implemented" - - override this.GetTuples () = - opencl { - return {| Indices = this.Indices; Values = this.Values |} - } - - override this.GetMask(?isComplemented: bool) = - let isComplemented = defaultArg isComplemented false - failwith "Not Implemented" - - override this.ToHost () = - opencl { - let! _ = ToHost this.Indices - let! _ = ToHost this.Values - - return upcast this - } - - override this.Extract (mask: Mask1D option) : OpenCLEvaluation> = failwith "Not Implemented" - override this.Extract (idx: int) : OpenCLEvaluation> = failwith "Not Implemented" - override this.Assign (mask: Mask1D option, vector: Vector<'a>) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (idx: int, Scalar (value: 'a)) : OpenCLEvaluation = failwith "Not Implemented" - override this.Assign (mask: Mask1D option, Scalar (value: 'a)) : OpenCLEvaluation = failwith "Not Implemented" - - override this.Vxm (matrix: Matrix<'a>) (mask: Mask1D option) (semiring: ISemiring<'a>) : OpenCLEvaluation> = failwith "Not Implemented" - - member internal this.EWiseAddSparse - (vector: SparseVector<'a>) - (mask: Mask1D option) - (semiring: ISemiring<'a>) : OpenCLEvaluation> = - - let (ClosedBinaryOp append) = semiring.Plus - let zero = semiring.Zero - - //It is useful to consider that the first array is longer than the second one - let firstIndices, firstValues, secondIndices, secondValues, plus = - if this.Indices.Length > vector.Indices.Length then - this.Indices, this.Values, vector.Indices, vector.Values, append - else - vector.Indices, vector.Values, this.Indices, this.Values, <@ fun x y -> (%append) y x @> - - let filterThroughMask = - opencl { - //TODO - () - } - - let allIndices = Array.zeroCreate <| firstIndices.Length + secondIndices.Length - let allValues = Array.create (firstValues.Length + secondValues.Length) zero - - let longSide = firstIndices.Length - let shortSide = secondIndices.Length - - let allIndicesLength = allIndices.Length - - let createSortedConcatenation = - <@ - fun (ndRange: _1D) - (firstIndicesBuffer: int[]) - (firstValuesBuffer: 'a[]) - (secondIndicesBuffer: int[]) - (secondValuesBuffer: 'a[]) - (allIndicesBuffer: int[]) - (allValuesBuffer: 'a[]) -> - - let i = ndRange.GlobalID0 - if i < allIndicesLength then - let f n = if 0 > n + 1 - shortSide then 0 else n + 1 - shortSide - let mutable leftEdge = f i - - let g n = if n > longSide - 1 then longSide - 1 else n - let mutable rightEdge = g i - - while leftEdge <= rightEdge do - let middleIdx = (leftEdge + rightEdge) / 2 - if firstIndicesBuffer.[middleIdx] < secondIndicesBuffer.[i - middleIdx] then leftEdge <- middleIdx + 1 else rightEdge <- middleIdx - 1 - - let boundaryX, boundaryY = rightEdge, i - leftEdge - - if boundaryX < 0 then - allIndicesBuffer.[i] <- secondIndicesBuffer.[boundaryY] - allValuesBuffer.[i] <- secondValuesBuffer.[boundaryY] - elif boundaryY < 0 then - allIndicesBuffer.[i] <- firstIndicesBuffer.[boundaryX] - allValuesBuffer.[i] <- firstValuesBuffer.[boundaryX] - else - let firstIndex = firstIndicesBuffer.[boundaryX] - let secondIndex = secondIndicesBuffer.[boundaryY] - if firstIndex < secondIndex then - allIndicesBuffer.[i] <- secondIndex - allValuesBuffer.[i] <- secondValuesBuffer.[boundaryY] - else - allIndicesBuffer.[i] <- firstIndex - allValuesBuffer.[i] <- firstValuesBuffer.[boundaryX] - @> - - let createSortedConcatenation = - opencl { - let binder kernelP = - let ndRange = _1D(Utils.workSize allIndices.Length, Utils.workGroupSize) - kernelP - ndRange - firstIndices - firstValues - secondIndices - secondValues - allIndices - allValues - do! RunCommand createSortedConcatenation binder - } - - let auxiliaryArray = Array.create allIndices.Length 1 - - let fillAuxiliaryArray = - <@ - fun (ndRange: _1D) - (allIndicesBuffer: int[]) - (allValuesBuffer: 'a[]) - (auxiliaryArrayBuffer: int[]) -> - - let i = ndRange.GlobalID0 - - if i + 1 < allIndicesLength && allIndicesBuffer.[i] = allIndicesBuffer.[i + 1] then - auxiliaryArrayBuffer.[i + 1] <- 0 - let localResultBuffer = (%plus) allValuesBuffer.[i] allValuesBuffer.[i + 1] - if localResultBuffer = zero then auxiliaryArrayBuffer.[i] <- 0 else allValuesBuffer.[i] <- localResultBuffer - @> - - let fillAuxiliaryArray = - opencl { - let binder kernelP = - let ndRange = _1D(Utils.workSize (allIndices.Length - 1), Utils.workGroupSize) - kernelP - ndRange - allIndices - allValues - auxiliaryArray - do! RunCommand fillAuxiliaryArray binder - } - - let auxiliaryArrayLength = auxiliaryArray.Length - - let createUnion = - <@ - fun (ndRange: _1D) - (allIndicesBuffer: int[]) - (allValuesBuffer: 'a[]) - (auxiliaryArrayBuffer: int[]) - (prefixSumArrayBuffer: int[]) - (resultIndicesBuffer: int[]) - (resultValuesBuffer: 'a[]) -> - - let i = ndRange.GlobalID0 - - if i < auxiliaryArrayLength && auxiliaryArrayBuffer.[i] = 1 then - let index = prefixSumArrayBuffer.[i] - 1 - - resultIndicesBuffer.[index] <- allIndicesBuffer.[i] - resultValuesBuffer.[index] <- allValuesBuffer.[i] - @> - - let resultIndices = Array.zeroCreate allIndices.Length - let resultValues = Array.create allValues.Length zero - - let createUnion = - opencl { - let! prefixSumArray = Scan.v2 auxiliaryArray - let binder kernelP = - let ndRange = _1D(Utils.workSize auxiliaryArray.Length, Utils.workGroupSize) - kernelP - ndRange - allIndices - allValues - auxiliaryArray - prefixSumArray - resultIndices - resultValues - do! RunCommand createUnion binder - } - - opencl { - do! createSortedConcatenation - do! filterThroughMask - do! fillAuxiliaryArray - do! createUnion - - return upcast SparseVector<'a>(this.Size, resultIndices, resultValues) - } - - override this.EWiseAdd - (vector: Vector<'a>) - (mask: Mask1D option) - (semiring: ISemiring<'a>) = - - if vector.Size <> this.Size then - invalidArg - "vector" - (sprintf "Argument has invalid dimension. Need %i, but given %i" this.Size vector.Size) - - // let mask = - // match mask with - // | Some m -> - // if m.Size <> this.Size then - // invalidArg - // "mask" - // (sprintf "Argument has invalid dimension. Need %i, but given %i" this.Size m.Size) - // m - // | _ -> Mask1D(Array.empty, this.Size, true) // Empty complemented mask is equal to none - - match vector with - | :? SparseVector<'a> -> this.EWiseAddSparse (downcast vector) mask semiring - | _ -> failwith "Not Implemented" - - override this.EWiseMult a b c = failwith "Not Implemented" - override this.Apply a b = failwith "Not Implemented" - override this.Prune a b = failwith "Not Implemented" - override this.Reduce (monoid: IMonoid<'a>) = failwith "Not Implemented" diff --git a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj index dec67718..3e3a7b6c 100644 --- a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj +++ b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj @@ -12,14 +12,16 @@ - + + + + + - - - - + + diff --git a/src/GraphBLAS-sharp/GraphblasEvaluation.fs b/src/GraphBLAS-sharp/GraphblasEvaluation.fs index 1207850e..c3399e3a 100644 --- a/src/GraphBLAS-sharp/GraphblasEvaluation.fs +++ b/src/GraphBLAS-sharp/GraphblasEvaluation.fs @@ -34,6 +34,7 @@ type GraphblasBuilder() = // monad member this.Bind(x, f) = EvalGB.bind f x member this.Return x = EvalGB <| fun _ -> x + member this.ReturnFrom x = x [] module GraphblasBuilder = diff --git a/src/GraphBLAS-sharp/Matrix.fs b/src/GraphBLAS-sharp/Methods/MatrixMethods.fs similarity index 57% rename from src/GraphBLAS-sharp/Matrix.fs rename to src/GraphBLAS-sharp/Methods/MatrixMethods.fs index 9bb77ec0..a7498dd5 100644 --- a/src/GraphBLAS-sharp/Matrix.fs +++ b/src/GraphBLAS-sharp/Methods/MatrixMethods.fs @@ -4,6 +4,22 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open GraphBLAS.FSharp.Backend +type MatrixTuples<'a when 'a : struct and 'a : equality> = + { + RowIndices: int[] + ColumnIndices: int[] + Values: 'a[] + } + + member this.ToHost() = + opencl { + let! _ = ToHost this.RowIndices + let! _ = ToHost this.ColumnIndices + let! _ = ToHost this.Values + + return this + } + [] module Matrix = @@ -34,17 +50,14 @@ module Matrix = operations *) - let eWiseAdd (matrix: Matrix<'a>) (cooFormat: COOFormat<'a>) (mask: Mask2D option) (sr: ISemiring<'a>) = - let s = - match matrix with - | :? COOMatrix<'a> as coo -> + let eWiseAdd (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) (mask: Mask2D option) (semiring: ISemiring<'a>) = + let operationResult = + match leftMatrix, rightMatrix with + | COOMatrix left, COOMatrix right -> opencl { - let! cooFormat = MatrixCOO.EWiseAdd.run cooFormat coo.Storage mask sr - return COOMatrix(cooFormat) :> Matrix<'a> + let! result = MatrixCOO.EWiseAdd.run left right mask semiring + return COOMatrix(result) } | _ -> failwith "Not Implemented" - graphblas { - let! m = EvalGB.liftCl s - return m - } + graphblas { return! EvalGB.liftCl operationResult } diff --git a/src/GraphBLAS-sharp/Vector.fs b/src/GraphBLAS-sharp/Methods/VectorMethods.fs similarity index 100% rename from src/GraphBLAS-sharp/Vector.fs rename to src/GraphBLAS-sharp/Methods/VectorMethods.fs diff --git a/src/GraphBLAS-sharp/Objects/Masks.fs b/src/GraphBLAS-sharp/Objects/Masks.fs new file mode 100644 index 00000000..6dbdadd0 --- /dev/null +++ b/src/GraphBLAS-sharp/Objects/Masks.fs @@ -0,0 +1,13 @@ +namespace GraphBLAS.FSharp + +type Mask1D(indices: int[], size: int, isComplemented: bool) = + member this.Indices = indices + member this.Size = size + member this.IsComplemented = isComplemented + +type Mask2D(rowIndices: int[], columnIndices: int[], rowCount: int, columnCount: int, isComplemented: bool) = + member this.RowIndices = rowIndices + member this.ColumnIndices = columnIndices + member this.RowCount = rowCount + member this.ColumnCount = columnCount + member this.IsComplemented = isComplemented diff --git a/src/GraphBLAS-sharp/Objects/Matrix.fs b/src/GraphBLAS-sharp/Objects/Matrix.fs new file mode 100644 index 00000000..445c9de8 --- /dev/null +++ b/src/GraphBLAS-sharp/Objects/Matrix.fs @@ -0,0 +1,22 @@ +namespace GraphBLAS.FSharp + +type Matrix<'a> = + | CSRMatrix of CSRMatrix<'a> + | COOMatrix of COOMatrix<'a> + +and CSRMatrix<'a> = + { + ColumnCount: int + RowPointers: int[] + ColumnIndices: int[] + Values: 'a[] + } + +and COOMatrix<'a> = + { + RowCount: int + ColumnCount: int + Rows: int[] + Columns: int[] + Values: 'a[] + } diff --git a/src/GraphBLAS-sharp/Objects/Scalar.fs b/src/GraphBLAS-sharp/Objects/Scalar.fs new file mode 100644 index 00000000..df9dabc9 --- /dev/null +++ b/src/GraphBLAS-sharp/Objects/Scalar.fs @@ -0,0 +1,5 @@ +namespace GraphBLAS.FSharp + +type Scalar<'a when 'a : struct and 'a : equality> = + | Scalar of 'a + static member op_Implicit (Scalar source) = source diff --git a/src/GraphBLAS-sharp/Objects/Vector.fs b/src/GraphBLAS-sharp/Objects/Vector.fs new file mode 100644 index 00000000..a7f9b587 --- /dev/null +++ b/src/GraphBLAS-sharp/Objects/Vector.fs @@ -0,0 +1,4 @@ +namespace GraphBLAS.FSharp + +type Vector<'a> = + | COOVector From 6418bfd7589548f7ce43f3f0459b8363bbdfe7eb Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Wed, 17 Mar 2021 01:22:48 +0300 Subject: [PATCH 03/16] Rename matrices types --- .../Backend/{MatrixCOO => COOMatrix}/EWiseAdd.fs | 2 +- src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj | 6 +++--- src/GraphBLAS-sharp/Methods/{MatrixMethods.fs => Matrix.fs} | 6 +++--- src/GraphBLAS-sharp/Methods/{VectorMethods.fs => Vector.fs} | 0 src/GraphBLAS-sharp/Objects/Matrix.fs | 4 ++-- src/GraphBLAS-sharp/Objects/Vector.fs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) rename src/GraphBLAS-sharp/Backend/{MatrixCOO => COOMatrix}/EWiseAdd.fs (99%) rename src/GraphBLAS-sharp/Methods/{MatrixMethods.fs => Matrix.fs} (91%) rename src/GraphBLAS-sharp/Methods/{VectorMethods.fs => Vector.fs} (100%) diff --git a/src/GraphBLAS-sharp/Backend/MatrixCOO/EWiseAdd.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs similarity index 99% rename from src/GraphBLAS-sharp/Backend/MatrixCOO/EWiseAdd.fs rename to src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs index 6e84f961..90aa7286 100644 --- a/src/GraphBLAS-sharp/Backend/MatrixCOO/EWiseAdd.fs +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs @@ -1,4 +1,4 @@ -namespace GraphBLAS.FSharp.Backend.MatrixCOO +namespace GraphBLAS.FSharp.Backend.COOMatrix open Brahma.OpenCL open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic diff --git a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj index 3e3a7b6c..ca974b30 100644 --- a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj +++ b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj @@ -19,9 +19,9 @@ - - - + + + diff --git a/src/GraphBLAS-sharp/Methods/MatrixMethods.fs b/src/GraphBLAS-sharp/Methods/Matrix.fs similarity index 91% rename from src/GraphBLAS-sharp/Methods/MatrixMethods.fs rename to src/GraphBLAS-sharp/Methods/Matrix.fs index a7498dd5..61385221 100644 --- a/src/GraphBLAS-sharp/Methods/MatrixMethods.fs +++ b/src/GraphBLAS-sharp/Methods/Matrix.fs @@ -53,10 +53,10 @@ module Matrix = let eWiseAdd (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) (mask: Mask2D option) (semiring: ISemiring<'a>) = let operationResult = match leftMatrix, rightMatrix with - | COOMatrix left, COOMatrix right -> + | MatrixCOO left, MatrixCOO right -> opencl { - let! result = MatrixCOO.EWiseAdd.run left right mask semiring - return COOMatrix(result) + let! result = COOMatrix.EWiseAdd.run left right mask semiring + return MatrixCOO result } | _ -> failwith "Not Implemented" diff --git a/src/GraphBLAS-sharp/Methods/VectorMethods.fs b/src/GraphBLAS-sharp/Methods/Vector.fs similarity index 100% rename from src/GraphBLAS-sharp/Methods/VectorMethods.fs rename to src/GraphBLAS-sharp/Methods/Vector.fs diff --git a/src/GraphBLAS-sharp/Objects/Matrix.fs b/src/GraphBLAS-sharp/Objects/Matrix.fs index 445c9de8..3e6035b3 100644 --- a/src/GraphBLAS-sharp/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp/Objects/Matrix.fs @@ -1,8 +1,8 @@ namespace GraphBLAS.FSharp type Matrix<'a> = - | CSRMatrix of CSRMatrix<'a> - | COOMatrix of COOMatrix<'a> + | MatrixCSR of CSRMatrix<'a> + | MatrixCOO of COOMatrix<'a> and CSRMatrix<'a> = { diff --git a/src/GraphBLAS-sharp/Objects/Vector.fs b/src/GraphBLAS-sharp/Objects/Vector.fs index a7f9b587..6e424da3 100644 --- a/src/GraphBLAS-sharp/Objects/Vector.fs +++ b/src/GraphBLAS-sharp/Objects/Vector.fs @@ -1,4 +1,4 @@ namespace GraphBLAS.FSharp type Vector<'a> = - | COOVector + | VectorCOO From a1d3e19d008b82d6c3a4d48771f5b31e82348b1f Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Wed, 17 Mar 2021 14:17:35 +0300 Subject: [PATCH 04/16] Move matrix and vector operations --- src/GraphBLAS-sharp/Algorithms/BFS.fs | 14 ++--- src/GraphBLAS-sharp/Algorithms/SSSP.fs | 10 ++-- .../Algorithms/TriangleCounting.fs | 16 ++--- src/GraphBLAS-sharp/GraphblasEvaluation.fs | 34 +++++++++-- src/GraphBLAS-sharp/Methods/Matrix.fs | 43 ++++++++++++- src/GraphBLAS-sharp/Methods/Vector.fs | 60 +++++++++++++++++++ src/GraphBLAS-sharp/Objects/Matrix.fs | 20 +++++++ .../OperationsTests/EWiseAddTests.fs | 39 +++++------- 8 files changed, 186 insertions(+), 50 deletions(-) diff --git a/src/GraphBLAS-sharp/Algorithms/BFS.fs b/src/GraphBLAS-sharp/Algorithms/BFS.fs index d4dbca02..7cdd7fc6 100644 --- a/src/GraphBLAS-sharp/Algorithms/BFS.fs +++ b/src/GraphBLAS-sharp/Algorithms/BFS.fs @@ -8,18 +8,18 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation [] module BFS = - let levelBFS (matrix: Matrix) (source: int) : OpenCLEvaluation> = - let vertexCount = matrix.RowCount + let levelBFS (matrix: Matrix) (source: int) : GraphblasEvaluation> = + let vertexCount = Matrix.rowCount matrix let levels = Vector.ofArray <| Array.zeroCreate vertexCount <| (=) 0 let frontier = Vector.ofTuples vertexCount [source, true] - opencl { + graphblas { let mutable currentLevel = 1 while currentLevel < vertexCount do - let! frontierMask = frontier.GetMask() - do! levels.Assign(frontierMask, Scalar currentLevel) - let! levelsComplemented = levels.GetMask(isComplemented = true) - let! frontier = frontier.Vxm matrix levelsComplemented AnyAll.bool + let! frontierMask = Vector.mask frontier + do! Vector.fillSubVector frontierMask (Scalar currentLevel) levels + let! levelsComplemented = Vector.complemented levels + let! frontier = Vector.vxm AnyAll.bool levelsComplemented frontier matrix currentLevel <- currentLevel + 1 return levels diff --git a/src/GraphBLAS-sharp/Algorithms/SSSP.fs b/src/GraphBLAS-sharp/Algorithms/SSSP.fs index 22a81f12..9990ef8b 100644 --- a/src/GraphBLAS-sharp/Algorithms/SSSP.fs +++ b/src/GraphBLAS-sharp/Algorithms/SSSP.fs @@ -7,14 +7,14 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation [] module SSSP = - let SSSP (matrix: Matrix) (source: int) : OpenCLEvaluation> = - let vertexCount = matrix.RowCount + let SSSP (matrix: Matrix) (source: int) : GraphblasEvaluation> = + let vertexCount = Matrix.rowCount matrix let distance = Vector.ofTuples vertexCount [source, 0.] - opencl { + graphblas { for _ in 1 .. vertexCount - 1 do - let! step = distance.Vxm matrix None MinAdd.float - do! distance.Assign(None, step) + let! step = Vector.vxm MinAdd.float None distance matrix + do! distance |> Vector.assignSubVector None step return distance } diff --git a/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs b/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs index 68a5f6b6..f6f53ce0 100644 --- a/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs +++ b/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs @@ -7,16 +7,16 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation [] module TriangleCounting = - // скорее всего, тут не скаляр возвращать нужно, а инт - let sandiaTriangleCount (lowerTriangular: Matrix) : OpenCLEvaluation> = + let sandiaTriangleCount (lowerTriangular: Matrix) : GraphblasEvaluation = let bool2int = function | true -> 1 | false -> 0 - opencl { - let! convertedMatrix = lowerTriangular.Apply None (UnaryOp <@ bool2int @>) - let! convertedTransposed = convertedMatrix.Transpose() - let! lowerTriangularMask = lowerTriangular.GetMask() - let! result = convertedMatrix.Mxm convertedTransposed lowerTriangularMask AddMult.int - return! result.Reduce Add.int + graphblas { + let! convertedMatrix = lowerTriangular |> Matrix.apply (UnaryOp <@ bool2int @>) None + let! convertedTransposed = convertedMatrix |> Matrix.transpose + let! lowerTriangularMask = lowerTriangular |> Matrix.mask + let! result = Matrix.mxm AddMult.int lowerTriangularMask convertedMatrix convertedTransposed + let! (Scalar count) = result |> Matrix.reduce Add.int + return count } diff --git a/src/GraphBLAS-sharp/GraphblasEvaluation.fs b/src/GraphBLAS-sharp/GraphblasEvaluation.fs index c3399e3a..16df9215 100644 --- a/src/GraphBLAS-sharp/GraphblasEvaluation.fs +++ b/src/GraphBLAS-sharp/GraphblasEvaluation.fs @@ -24,18 +24,44 @@ module EvalGB = let x = run env reader run env (f x) + let ret x = + EvalGB <| fun _ -> x + // EvalGB.liftCl x === liftM EvalGB x let liftCl clEvaluation = EvalGB <| fun env -> - clEvaluation - |> runCl env.ClContext + runCl env.ClContext clEvaluation + + let runWithClContext clContext (EvalGB action) = + action { ClContext = clContext } type GraphblasBuilder() = - // monad member this.Bind(x, f) = EvalGB.bind f x - member this.Return x = EvalGB <| fun _ -> x + member this.Return x = EvalGB.ret x member this.ReturnFrom x = x + member this.Zero() = + EvalGB.ret () + + member this.Combine(m1, m2) = + EvalGB <| fun env -> + EvalGB.run env m1 + EvalGB.run env m2 + + member this.Delay rest = + EvalGB <| fun env -> + EvalGB.run env <| rest () + + member this.While(predicate, body) = + EvalGB <| fun env -> + while predicate () do + EvalGB.run env body + + member this.For(sequence, f) = + EvalGB <| fun env -> + for elem in sequence do + EvalGB.run env (f elem) + [] module GraphblasBuilder = let graphblas = GraphblasBuilder() diff --git a/src/GraphBLAS-sharp/Methods/Matrix.fs b/src/GraphBLAS-sharp/Methods/Matrix.fs index 61385221..d4488751 100644 --- a/src/GraphBLAS-sharp/Methods/Matrix.fs +++ b/src/GraphBLAS-sharp/Methods/Matrix.fs @@ -4,7 +4,7 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open GraphBLAS.FSharp.Backend -type MatrixTuples<'a when 'a : struct and 'a : equality> = +type MatrixTuples<'a> = { RowIndices: int[] ColumnIndices: int[] @@ -46,11 +46,41 @@ module Matrix = methods *) + let rowCount (matrix: Matrix<'a>) : int = failwith "Not Implemented yet" + let columnCount (matrix: Matrix<'a>) : int = failwith "Not Implemented yet" + let clear (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let copy (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let resize (rowCount: int) (columnCount: int) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let nnz (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let tuples (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let mask (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let complemented (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + // let finish \ eval \ toHost + + (* + assignment, extraction and filling + *) + + let extractSubMatrix (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let extractSubRow (rowIdx: int) (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let extractSubCol (colIdx: int) (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let extractElement (rowIdx: int) (colIdx: int) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let assignSubMatrix (mask: Mask2D option) (source: Matrix<'a>) (target: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let assignSubRow (rowIdx: int) (mask: Mask2D option) (source: Vector<'a>) (target: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let assignSubCol (colIdx: int) (mask: Mask2D option) (source: Vector<'a>) (target: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let assignElement (rowIdx: int) (colIdx: int) (source: Scalar<'a>) (target: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let fillSubMatrix (mask: Mask2D option) (filler: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let fillSubRow (rowIdx: int) (mask: Mask2D option) (filler: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let fillSubCol (colIdx: int) (mask: Mask2D option) (filler: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + (* operations *) - let eWiseAdd (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) (mask: Mask2D option) (semiring: ISemiring<'a>) = + let mxm (semiring: ISemiring<'a>) (mask: Mask2D option) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let mxv (semiring: ISemiring<'a>) (mask: Mask1D option) (matrix: Matrix<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + + let eWiseAdd (semiring: ISemiring<'a>) (mask: Mask2D option) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = let operationResult = match leftMatrix, rightMatrix with | MatrixCOO left, MatrixCOO right -> @@ -61,3 +91,12 @@ module Matrix = | _ -> failwith "Not Implemented" graphblas { return! EvalGB.liftCl operationResult } + + let eWiseMult (semiring: ISemiring<'a>) (mask: Mask2D option) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let apply (mapper: UnaryOp<'a, 'b>) (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let prune (predicate: UnaryOp<'a, bool>) (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let reduceRows (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let reduceCols (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let reduce (monoid: IMonoid<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let transpose (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let kronecker (semiring: ISemiring<'a>) (mask: Mask2D option) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" diff --git a/src/GraphBLAS-sharp/Methods/Vector.fs b/src/GraphBLAS-sharp/Methods/Vector.fs index 09699d0b..6fee386e 100644 --- a/src/GraphBLAS-sharp/Methods/Vector.fs +++ b/src/GraphBLAS-sharp/Methods/Vector.fs @@ -1,7 +1,30 @@ namespace GraphBLAS.FSharp +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open GraphBLAS.FSharp.Backend + +type VectorTuples<'a> = + { + Indices: int[] + Values: 'a[] + } + + member this.ToHost() = + opencl { + let! _ = ToHost this.Indices + let! _ = ToHost this.Values + + return this + } + [] module Vector = + + (* + constructors + *) + let build (size: int) (indices: int[]) (values: int[]) : Vector<'a> = failwith "Not Implemented yet" @@ -17,3 +40,40 @@ module Vector = let zeroCreate (size: int) : Vector<'a> = failwith "Not Implemented yet" + + + (* + methods + *) + + let size (vector: Vector<'a>) : int = failwith "Not Implemented yet" + let clear (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let copy (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let resize (size: int) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let nnz (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let tuples (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let mask (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let complemented (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + // let finish \ eval \ toHost + + (* + assignment, extraction and filling + *) + + // добавить функции, чтобы разделить поведение при наличии и отсутствии маски (assignSubVector и assignVector) + let extractSubVector (mask: Mask1D option) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let extractElement (idx: int) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let assignSubVector (mask: Mask1D option) (source: Vector<'a>) (target: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let assignElement (idx: int) (source: Scalar<'a>) (target: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let fillSubVector (mask: Mask1D option) (filler: Scalar<'a>) (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + + (* + operations + *) + + let vxm (semiring: ISemiring<'a>) (mask: Mask1D option) (vector: Vector<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseAdd (semiring: ISemiring<'a>) (mask: Mask1D option) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseMult (semiring: ISemiring<'a>) (mask: Mask2D option) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let apply (mapper: UnaryOp<'a, 'b>) (mask: Mask1D option) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let prune (predicate: UnaryOp<'a, bool>) (mask: Mask1D option) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let reduce (monoid: IMonoid<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" diff --git a/src/GraphBLAS-sharp/Objects/Matrix.fs b/src/GraphBLAS-sharp/Objects/Matrix.fs index 3e6035b3..719e7049 100644 --- a/src/GraphBLAS-sharp/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp/Objects/Matrix.fs @@ -20,3 +20,23 @@ and COOMatrix<'a> = Columns: int[] Values: 'a[] } + + static member FromTuples(rowCount: int, columnCount: int, rows: int[], columns: int[], values: 'a[]) = + { + RowCount = rowCount + ColumnCount = columnCount + Rows = rows + Columns = columns + Values = values + } + + static member FromArray2D(array: 'a[,], isZero: 'a -> bool) = + let (rows, cols, vals) = + array + |> Seq.cast<'a> + |> Seq.mapi (fun idx v -> (idx / Array2D.length2 array, idx % Array2D.length2 array, v)) + |> Seq.filter (fun (i, j, v) -> not <| isZero v) + |> Array.ofSeq + |> Array.unzip3 + + COOMatrix.FromTuples(Array2D.length1 array, Array2D.length2 array, rows, cols, vals) diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs index 25b059e5..7f8af013 100644 --- a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs @@ -89,22 +89,7 @@ type PairOfSparseMatricesOfEqualSize = ] ) |> Arb.fromGen -let createMatrix<'a when 'a : struct and 'a : equality> matrixFormat args = - match matrixFormat with - | CSR -> - Activator.CreateInstanceGeneric>( - Array.singleton typeof<'a>, args - ) - |> unbox> - :> Matrix<'a> - | COO -> - Activator.CreateInstanceGeneric>( - Array.singleton typeof<'a>, args - ) - |> unbox> - :> Matrix<'a> - -let logger = Log.create "Sample" +let logger = Log.create "eWiseAddTests" let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> (sum: 'a -> 'a -> 'a) @@ -114,6 +99,11 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> (case: OperationCase) (matrixA: 'a[,], matrixB: 'a[,]) = + let createMatrixFromArray2D matrixFormat array isZero = + match matrixFormat with + | CSR -> failwith "Not implemented" + | COO -> MatrixCOO <| COOMatrix.FromArray2D(array, isZero) + let eWiseAddNaive (matrixA: 'a[,]) (matrixB: 'a[,]) = let left = matrixA |> Seq.cast<'a> let right = matrixB |> Seq.cast<'a> @@ -141,8 +131,8 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> let eWiseAddGB (matrixA: 'a[,]) (matrixB: 'a[,]) = try - let left = createMatrix<'a> case.MatrixCase [|matrixA; isZero|] - let right = createMatrix<'a> case.MatrixCase [|matrixB; isZero|] + let left = createMatrixFromArray2D case.MatrixCase matrixA isZero + let right = createMatrixFromArray2D case.MatrixCase matrixB isZero logger.debug ( eventX "Left matrix is \n{matrix}" @@ -154,12 +144,12 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> >> setField "matrix" right ) - opencl { - let! result = left.EWiseAdd right None semiring - let! tuples = result.GetTuples() - return! tuples.ToHost() + graphblas { + let! result = Matrix.eWiseAdd semiring None left right + let! tuples = Matrix.tuples result + return! EvalGB.liftCl <| tuples.ToHost() } - |> oclContext.RunSync + |> EvalGB.runWithClContext oclContext finally oclContext.Provider.CloseAllBuffers() @@ -196,8 +186,9 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> let config = { FsCheckConfig.defaultConfig with arbitrary = [typeof] + maxTest = 50 startSize = 0 - maxTest = 10 + endSize = 1_000_000 } // https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/language-specification/types#value-types From 113ffcc532f68640645a093b12e294995bf4679e Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Wed, 17 Mar 2021 16:16:01 +0300 Subject: [PATCH 05/16] Add monoidic type --- src/GraphBLAS-sharp/AlgebraicStructures.fs | 18 ++++++++++++++++++ src/GraphBLAS-sharp/Predefined/Monoids/Add.fs | 16 ++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/GraphBLAS-sharp/AlgebraicStructures.fs b/src/GraphBLAS-sharp/AlgebraicStructures.fs index 272e6830..00fd64d9 100644 --- a/src/GraphBLAS-sharp/AlgebraicStructures.fs +++ b/src/GraphBLAS-sharp/AlgebraicStructures.fs @@ -31,3 +31,21 @@ type IMonoid<'a> = type ISemiring<'a> = inherit IMonoid<'a> abstract Times: ClosedBinaryOp<'a> + +// на самом деле должен быть "зависымым типом" +// (если получает ноль, то Zero, иначе Just x) +// но он будет оборачивать 'a только на стороне F# +// => можно сделать специальный статик коснтруктор для инстансов +// (если так делать, то уже не получится оставить его генерик типом) +// (можно в конструктор передавать проверку на ноль первым параметром, тогда норм) +type MonoidicType<'a> = + | Just of 'a + | Zero + +(* + мотивация + хотим, чтобы ноль был нулем (даже если он в матрице будет хранится) + и все моноиды, определенные над MonoidicType 'a имели корректную семантику + (если получился 0 и мы сменили моноид, то этот элемент все еще будет нудем в другом моноиде) + то избавимся от кастов +*) diff --git a/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs b/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs index efc71360..1de777fb 100644 --- a/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs +++ b/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs @@ -44,3 +44,19 @@ module Add = member this.Zero = 0us member this.Plus = ClosedBinaryOp <@ (+) @> } + + let monoidicFloat = + { new IMonoid> with + member this.Zero = Just 0. + member this.Plus = + <@ + fun x y -> + match x, y with + | Just x, Just y -> + let result = x + y + if abs result < 1e-16 then Zero else Just result + | Just x, Zero -> Just x + | Zero, Just y -> Just y + | Zero, Zero -> Zero + @> |> ClosedBinaryOp + } From f5e8e28073ddaf3a324a6e25ee9b36734a92bbbf Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Wed, 17 Mar 2021 16:25:27 +0300 Subject: [PATCH 06/16] Chnage value of zero in monoidic float; make monoidicType struct --- src/GraphBLAS-sharp/AlgebraicStructures.fs | 1 + src/GraphBLAS-sharp/Predefined/Monoids/Add.fs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/GraphBLAS-sharp/AlgebraicStructures.fs b/src/GraphBLAS-sharp/AlgebraicStructures.fs index 00fd64d9..f87ec57b 100644 --- a/src/GraphBLAS-sharp/AlgebraicStructures.fs +++ b/src/GraphBLAS-sharp/AlgebraicStructures.fs @@ -38,6 +38,7 @@ type ISemiring<'a> = // => можно сделать специальный статик коснтруктор для инстансов // (если так делать, то уже не получится оставить его генерик типом) // (можно в конструктор передавать проверку на ноль первым параметром, тогда норм) +[] type MonoidicType<'a> = | Just of 'a | Zero diff --git a/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs b/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs index 1de777fb..b3ff3939 100644 --- a/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs +++ b/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs @@ -47,7 +47,7 @@ module Add = let monoidicFloat = { new IMonoid> with - member this.Zero = Just 0. + member this.Zero = Zero member this.Plus = <@ fun x y -> From b29f5b2a583fcf70ded3b8f834919cf597063027 Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Fri, 19 Mar 2021 20:54:23 +0300 Subject: [PATCH 07/16] Add sync functions for tuples --- src/GraphBLAS-sharp/Algorithms/BFS.fs | 4 ++-- src/GraphBLAS-sharp/Algorithms/SSSP.fs | 2 +- src/GraphBLAS-sharp/GraphblasEvaluation.fs | 9 ++++---- src/GraphBLAS-sharp/Methods/Matrix.fs | 21 +++++++++++-------- src/GraphBLAS-sharp/Methods/Vector.fs | 21 ++++++++++--------- src/GraphBLAS-sharp/Predefined/Monoids/Add.fs | 2 +- .../OperationsTests/EWiseAddTests.fs | 3 ++- tests/GraphBLAS-sharp.Tests/Program.fs | 3 +-- 8 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/GraphBLAS-sharp/Algorithms/BFS.fs b/src/GraphBLAS-sharp/Algorithms/BFS.fs index 7cdd7fc6..ebc50df5 100644 --- a/src/GraphBLAS-sharp/Algorithms/BFS.fs +++ b/src/GraphBLAS-sharp/Algorithms/BFS.fs @@ -10,8 +10,8 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation module BFS = let levelBFS (matrix: Matrix) (source: int) : GraphblasEvaluation> = let vertexCount = Matrix.rowCount matrix - let levels = Vector.ofArray <| Array.zeroCreate vertexCount <| (=) 0 - let frontier = Vector.ofTuples vertexCount [source, true] + let levels = Vector.ofArray <| (=) 0 <| Array.zeroCreate vertexCount + let frontier = Vector.ofList vertexCount [source, true] graphblas { let mutable currentLevel = 1 diff --git a/src/GraphBLAS-sharp/Algorithms/SSSP.fs b/src/GraphBLAS-sharp/Algorithms/SSSP.fs index 9990ef8b..86c0da27 100644 --- a/src/GraphBLAS-sharp/Algorithms/SSSP.fs +++ b/src/GraphBLAS-sharp/Algorithms/SSSP.fs @@ -9,7 +9,7 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation module SSSP = let SSSP (matrix: Matrix) (source: int) : GraphblasEvaluation> = let vertexCount = Matrix.rowCount matrix - let distance = Vector.ofTuples vertexCount [source, 0.] + let distance = Vector.ofList vertexCount [source, 0.] graphblas { for _ in 1 .. vertexCount - 1 do diff --git a/src/GraphBLAS-sharp/GraphblasEvaluation.fs b/src/GraphBLAS-sharp/GraphblasEvaluation.fs index 16df9215..9f4a5f5a 100644 --- a/src/GraphBLAS-sharp/GraphblasEvaluation.fs +++ b/src/GraphBLAS-sharp/GraphblasEvaluation.fs @@ -24,11 +24,10 @@ module EvalGB = let x = run env reader run env (f x) - let ret x = + let return' x = EvalGB <| fun _ -> x - // EvalGB.liftCl x === liftM EvalGB x - let liftCl clEvaluation = + let fromCl clEvaluation = EvalGB <| fun env -> runCl env.ClContext clEvaluation @@ -37,11 +36,11 @@ module EvalGB = type GraphblasBuilder() = member this.Bind(x, f) = EvalGB.bind f x - member this.Return x = EvalGB.ret x + member this.Return x = EvalGB.return' x member this.ReturnFrom x = x member this.Zero() = - EvalGB.ret () + EvalGB.return' () member this.Combine(m1, m2) = EvalGB <| fun env -> diff --git a/src/GraphBLAS-sharp/Methods/Matrix.fs b/src/GraphBLAS-sharp/Methods/Matrix.fs index d4488751..41fead96 100644 --- a/src/GraphBLAS-sharp/Methods/Matrix.fs +++ b/src/GraphBLAS-sharp/Methods/Matrix.fs @@ -11,14 +11,17 @@ type MatrixTuples<'a> = Values: 'a[] } - member this.ToHost() = +// ждём тайпклассов чтобы можно было вызывать synchronize для всех объектов, +// для которых он реализован, не привязывая реализацию к классу (как стратегия) +module MatrixTuples = + let synchronize (matrixTuples: MatrixTuples<'a>) = opencl { - let! _ = ToHost this.RowIndices - let! _ = ToHost this.ColumnIndices - let! _ = ToHost this.Values - - return this + let! _ = ToHost matrixTuples.RowIndices + let! _ = ToHost matrixTuples.ColumnIndices + let! _ = ToHost matrixTuples.Values + return () } + |> EvalGB.fromCl [] module Matrix = @@ -30,7 +33,7 @@ module Matrix = let build (rowCount: int) (columnCount: int) (rows: int[]) (columns: int[]) (values: 'a[]) : Matrix<'a> = failwith "Not Implemented yet" - let ofArray2D (array: 'a[,]) (isZero: 'a -> bool) : Matrix<'a> = + let ofArray2D (isZero: 'a -> bool) (array: 'a[,]) : Matrix<'a> = failwith "Not Implemented yet" let fromFile (pathToMatrix: string) : Matrix<'a> = @@ -55,7 +58,7 @@ module Matrix = let tuples (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let mask (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let complemented (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - // let finish \ eval \ toHost + let synchronize (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" (* assignment, extraction and filling @@ -90,7 +93,7 @@ module Matrix = } | _ -> failwith "Not Implemented" - graphblas { return! EvalGB.liftCl operationResult } + graphblas { return! EvalGB.fromCl operationResult } let eWiseMult (semiring: ISemiring<'a>) (mask: Mask2D option) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let apply (mapper: UnaryOp<'a, 'b>) (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" diff --git a/src/GraphBLAS-sharp/Methods/Vector.fs b/src/GraphBLAS-sharp/Methods/Vector.fs index 6fee386e..2550b924 100644 --- a/src/GraphBLAS-sharp/Methods/Vector.fs +++ b/src/GraphBLAS-sharp/Methods/Vector.fs @@ -10,13 +10,14 @@ type VectorTuples<'a> = Values: 'a[] } - member this.ToHost() = +module VectorTuples = + let synchronize (vectorTuples: VectorTuples<'a>) = opencl { - let! _ = ToHost this.Indices - let! _ = ToHost this.Values - - return this + let! _ = ToHost vectorTuples.Indices + let! _ = ToHost vectorTuples.Values + return () } + |> EvalGB.fromCl [] module Vector = @@ -28,20 +29,19 @@ module Vector = let build (size: int) (indices: int[]) (values: int[]) : Vector<'a> = failwith "Not Implemented yet" - // ambiguous name (tuples = коллекция троек или 3 коллекции) - let ofTuples (size: int) (elements: (int * 'a) list) : Vector<'a> = + let ofList (size: int) (elements: (int * 'a) list) : Vector<'a> = failwith "Not Implemented yet" - let ofArray (array: 'a[]) (isZero: 'a -> bool) : Vector<'a> = + let ofArray (isZero: 'a -> bool) (array: 'a[]) : Vector<'a> = failwith "Not Implemented yet" let init (size: int) (initializer: int -> 'a) : Vector<'a> = failwith "Not Implemented yet" + // обоснован ли этот метод или можно просто create x использовать let zeroCreate (size: int) : Vector<'a> = failwith "Not Implemented yet" - (* methods *) @@ -52,9 +52,10 @@ module Vector = let resize (size: int) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let nnz (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let tuples (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + // возвращается option, чтобы потом можно было бы сразу передавать её в методы (тк они option принимают) let mask (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let complemented (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - // let finish \ eval \ toHost + let synchronize (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" (* assignment, extraction and filling diff --git a/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs b/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs index b3ff3939..8a2e2a9f 100644 --- a/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs +++ b/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs @@ -17,7 +17,7 @@ module Add = let float32 = { new IMonoid with - member this.Zero = 0f + member this.Zero = 0.f member this.Plus = ClosedBinaryOp <@ (+) @> } diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs index 7f8af013..612bd130 100644 --- a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs @@ -147,7 +147,8 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> graphblas { let! result = Matrix.eWiseAdd semiring None left right let! tuples = Matrix.tuples result - return! EvalGB.liftCl <| tuples.ToHost() + do! MatrixTuples.synchronize tuples + return tuples } |> EvalGB.runWithClContext oclContext diff --git a/tests/GraphBLAS-sharp.Tests/Program.fs b/tests/GraphBLAS-sharp.Tests/Program.fs index 15c0e502..e59a05ac 100644 --- a/tests/GraphBLAS-sharp.Tests/Program.fs +++ b/tests/GraphBLAS-sharp.Tests/Program.fs @@ -6,10 +6,9 @@ let allTests = testList "All tests" [ EWiseAdd.tests ] + |> testSequenced -// sequenced test? [] let main argv = allTests - |> testSequenced |> runTestsWithCLIArgs [] argv From d28348d9e1e683d7acd4b3ddaea6a49b429575ce Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Tue, 23 Mar 2021 20:46:27 +0300 Subject: [PATCH 08/16] Add storage for dense vector; extended api with unmasked methods --- src/GraphBLAS-sharp/AlgebraicStructures.fs | 7 +- src/GraphBLAS-sharp/Algorithms/BFS.fs | 28 ++-- src/GraphBLAS-sharp/Algorithms/SSSP.fs | 20 --- .../Algorithms/ShortestPath.fs | 18 +++ .../Algorithms/TriangleCounting.fs | 18 ++- src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj | 2 +- src/GraphBLAS-sharp/Methods/Matrix.fs | 121 ++++++++++++++---- src/GraphBLAS-sharp/Methods/Vector.fs | 56 +++++--- src/GraphBLAS-sharp/Objects/Scalar.fs | 3 +- src/GraphBLAS-sharp/Objects/Vector.fs | 15 ++- .../OperationsTests/EWiseAddTests.fs | 2 +- 11 files changed, 196 insertions(+), 94 deletions(-) delete mode 100644 src/GraphBLAS-sharp/Algorithms/SSSP.fs create mode 100644 src/GraphBLAS-sharp/Algorithms/ShortestPath.fs diff --git a/src/GraphBLAS-sharp/AlgebraicStructures.fs b/src/GraphBLAS-sharp/AlgebraicStructures.fs index f87ec57b..98911220 100644 --- a/src/GraphBLAS-sharp/AlgebraicStructures.fs +++ b/src/GraphBLAS-sharp/AlgebraicStructures.fs @@ -4,26 +4,21 @@ open Microsoft.FSharp.Quotations type UnaryOp<'a, 'b> = | UnaryOp of Expr<'a -> 'b> - static member op_Implicit (UnaryOp source) = source type BinaryOp<'a, 'b, 'c> = | BinaryOp of Expr<'a -> 'b -> 'c> - static member op_Implicit (BinaryOp source) = source -// делать отдельными классами или оставить аллиасами type ClosedUnaryOp<'a> = | ClosedUnaryOp of Expr<'a -> 'a> - static member op_Implicit (UnaryOp source) = source type ClosedBinaryOp<'a> = | ClosedBinaryOp of Expr<'a -> 'a -> 'a> - static member op_Implicit (UnaryOp source) = source // associative closed bin op (magma with associative) type ISemigroup<'a> = abstract Plus: ClosedBinaryOp<'a> -// semigroup with id +/// Semigroup with identity type IMonoid<'a> = inherit ISemigroup<'a> abstract Zero: 'a diff --git a/src/GraphBLAS-sharp/Algorithms/BFS.fs b/src/GraphBLAS-sharp/Algorithms/BFS.fs index ebc50df5..a29a9755 100644 --- a/src/GraphBLAS-sharp/Algorithms/BFS.fs +++ b/src/GraphBLAS-sharp/Algorithms/BFS.fs @@ -6,24 +6,24 @@ open GraphBLAS.FSharp open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation -[] module BFS = - let levelBFS (matrix: Matrix) (source: int) : GraphblasEvaluation> = + let level (matrix: Matrix) (source: int) = graphblas { let vertexCount = Matrix.rowCount matrix - let levels = Vector.ofArray <| (=) 0 <| Array.zeroCreate vertexCount + let levels = Vector.zeroCreate vertexCount 0 let frontier = Vector.ofList vertexCount [source, true] - graphblas { - let mutable currentLevel = 1 - while currentLevel < vertexCount do - let! frontierMask = Vector.mask frontier - do! Vector.fillSubVector frontierMask (Scalar currentLevel) levels - let! levelsComplemented = Vector.complemented levels - let! frontier = Vector.vxm AnyAll.bool levelsComplemented frontier matrix - currentLevel <- currentLevel + 1 - - return levels - } + let mutable currentLevel = 1 + while currentLevel < vertexCount do + let! frontierMask = Vector.mask frontier + do! levels |> Vector.fillSubVector frontierMask (Scalar currentLevel) + + let! levelsComplemented = Vector.complemented levels + let! frontier = (frontier, matrix) ||> Vector.vxmWithMask AnyAll.bool levelsComplemented + + currentLevel <- currentLevel + 1 + + return levels + } // let parentBFS (matrix: Matrix) (source: int) : Vector = // let vertexCount = matrix.RowCount diff --git a/src/GraphBLAS-sharp/Algorithms/SSSP.fs b/src/GraphBLAS-sharp/Algorithms/SSSP.fs deleted file mode 100644 index 86c0da27..00000000 --- a/src/GraphBLAS-sharp/Algorithms/SSSP.fs +++ /dev/null @@ -1,20 +0,0 @@ -namespace GraphBLAS.FSharp.Algorithms - -open GraphBLAS.FSharp.Predefined -open GraphBLAS.FSharp -open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation - -[] -module SSSP = - let SSSP (matrix: Matrix) (source: int) : GraphblasEvaluation> = - let vertexCount = Matrix.rowCount matrix - let distance = Vector.ofList vertexCount [source, 0.] - - graphblas { - for _ in 1 .. vertexCount - 1 do - let! step = Vector.vxm MinAdd.float None distance matrix - do! distance |> Vector.assignSubVector None step - - return distance - } diff --git a/src/GraphBLAS-sharp/Algorithms/ShortestPath.fs b/src/GraphBLAS-sharp/Algorithms/ShortestPath.fs new file mode 100644 index 00000000..86be3288 --- /dev/null +++ b/src/GraphBLAS-sharp/Algorithms/ShortestPath.fs @@ -0,0 +1,18 @@ +namespace GraphBLAS.FSharp.Algorithms + +open GraphBLAS.FSharp.Predefined +open GraphBLAS.FSharp +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation + +module ShortestPath = + let singleSource (matrix: Matrix) (source: int) = graphblas { + let vertexCount = Matrix.rowCount matrix + let distance = Vector.ofList vertexCount [source, 0.] + + for _ = 1 to vertexCount - 1 do + let! step = (distance, matrix) ||> Vector.vxm MinAdd.float + do! distance |> Vector.assignVector step + + return distance + } diff --git a/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs b/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs index f6f53ce0..3d196c44 100644 --- a/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs +++ b/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs @@ -5,18 +5,16 @@ open GraphBLAS.FSharp open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation -[] module TriangleCounting = - let sandiaTriangleCount (lowerTriangular: Matrix) : GraphblasEvaluation = + let sandia (lowerTriangular: Matrix) = graphblas { let bool2int = function | true -> 1 | false -> 0 - graphblas { - let! convertedMatrix = lowerTriangular |> Matrix.apply (UnaryOp <@ bool2int @>) None - let! convertedTransposed = convertedMatrix |> Matrix.transpose - let! lowerTriangularMask = lowerTriangular |> Matrix.mask - let! result = Matrix.mxm AddMult.int lowerTriangularMask convertedMatrix convertedTransposed - let! (Scalar count) = result |> Matrix.reduce Add.int - return count - } + let! convertedMatrix = lowerTriangular |> Matrix.apply (UnaryOp <@ bool2int @>) + let! convertedTransposed = convertedMatrix |> Matrix.transpose + let! lowerTriangularMask = lowerTriangular |> Matrix.mask + let! result = Matrix.mxmWithMask AddMult.int lowerTriangularMask convertedMatrix convertedTransposed + let! (Scalar count) = result |> Matrix.reduce Add.int + return count + } diff --git a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj index ca974b30..08939e33 100644 --- a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj +++ b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj @@ -29,7 +29,7 @@ - + Always diff --git a/src/GraphBLAS-sharp/Methods/Matrix.fs b/src/GraphBLAS-sharp/Methods/Matrix.fs index 41fead96..f4ad3d11 100644 --- a/src/GraphBLAS-sharp/Methods/Matrix.fs +++ b/src/GraphBLAS-sharp/Methods/Matrix.fs @@ -1,7 +1,6 @@ namespace GraphBLAS.FSharp open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open GraphBLAS.FSharp.Backend type MatrixTuples<'a> = @@ -56,50 +55,124 @@ module Matrix = let resize (rowCount: int) (columnCount: int) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let nnz (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let tuples (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let mask (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let complemented (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let mask (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let complemented (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let synchronize (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" (* assignment, extraction and filling *) - let extractSubMatrix (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let extractSubRow (rowIdx: int) (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let extractSubCol (colIdx: int) (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let extractElement (rowIdx: int) (colIdx: int) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let assignSubMatrix (mask: Mask2D option) (source: Matrix<'a>) (target: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let assignSubRow (rowIdx: int) (mask: Mask2D option) (source: Vector<'a>) (target: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let assignSubCol (colIdx: int) (mask: Mask2D option) (source: Vector<'a>) (target: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let assignElement (rowIdx: int) (colIdx: int) (source: Scalar<'a>) (target: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let fillSubMatrix (mask: Mask2D option) (filler: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let fillSubRow (rowIdx: int) (mask: Mask2D option) (filler: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let fillSubCol (colIdx: int) (mask: Mask2D option) (filler: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + /// mat.[mask] + let extractSubMatrix (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = + failwith "Not Implemented yet" + + /// mat.[rowIdx. *] + let extractRow (rowIdx: int) (matrix: Matrix<'a>) : GraphblasEvaluation> = + failwith "Not Implemented yet" + + /// mat.[rowIdx, mask] + let extractSubRow (rowIdx: int) (mask: Mask2D) (matrix: Matrix<'a>) : GraphblasEvaluation> = + failwith "Not Implemented yet" + + /// mat.[*, colIdx] + let extractCol (colIdx: int) (matrix: Matrix<'a>) : GraphblasEvaluation> = + failwith "Not Implemented yet" + + /// mat.[mask. colIdx] + let extractSubCol (colIdx: int) (mask: Mask2D) (matrix: Matrix<'a>) : GraphblasEvaluation> = + failwith "Not Implemented yet" + + /// mat.[rowIdx, colIdx] + let extractValue (rowIdx: int) (colIdx: int) (matrix: Matrix<'a>) : GraphblasEvaluation> = + failwith "Not Implemented yet" + + /// t <- s + let assignMatrix (source: Matrix<'a>) (target: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// t.[mask] <- s + let assignSubMatrix (mask: Mask2D) (source: Matrix<'a>) (target: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// t.[rowIdx, *] <- s + let assignRow (rowIdx: int) (source: Vector<'a>) (target: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// t.[rowIdx, mask] <- s + let assignSubRow (rowIdx: int) (mask: Mask1D) (source: Vector<'a>) (target: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// t.[*, colIdx] <- s + let assignCol (colIdx: int) (source: Vector<'a>) (target: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// t.[mask, colIdx] <- s + let assignSubCol (colIdx: int) (mask: Mask1D) (source: Vector<'a>) (target: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// mat.[i, j] <- value + let assignValue (rowIdx: int) (colIdx: int) (value: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// mat.[*, *] <- value + let fillMatrix (value: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// mat.[mask] <- value + let fillSubMatrix (mask: Mask2D) (value: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// mat.[rowIdx, *] <- value + let fillRow (rowIdx: int) (value: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// mat.[rowIdx, mask] <- value + let fillSubRow (rowIdx: int) (mask: Mask1D) (value: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// mat.[*, colIdx] <- value + let fillCol (colIdx: int) (value: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" + + /// mat.[mask, colIdx] <- value + let fillSubCol (colIdx: int) (mask: Mask1D) (value: Scalar<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" (* operations *) - let mxm (semiring: ISemiring<'a>) (mask: Mask2D option) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let mxv (semiring: ISemiring<'a>) (mask: Mask1D option) (matrix: Matrix<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let mxm (semiring: ISemiring<'a>) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let mxv (semiring: ISemiring<'a>) (matrix: Matrix<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let eWiseAdd (semiring: ISemiring<'a>) (mask: Mask2D option) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = + let eWiseAdd (semiring: ISemiring<'a>) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = let operationResult = match leftMatrix, rightMatrix with | MatrixCOO left, MatrixCOO right -> opencl { - let! result = COOMatrix.EWiseAdd.run left right mask semiring + let! result = COOMatrix.EWiseAdd.run left right None semiring return MatrixCOO result } | _ -> failwith "Not Implemented" graphblas { return! EvalGB.fromCl operationResult } - let eWiseMult (semiring: ISemiring<'a>) (mask: Mask2D option) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let apply (mapper: UnaryOp<'a, 'b>) (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let prune (predicate: UnaryOp<'a, bool>) (mask: Mask2D option) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let reduceRows (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let reduceCols (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseMult (semiring: ISemiring<'a>) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let apply (mapper: UnaryOp<'a, 'b>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let prune (predicate: UnaryOp<'a, bool>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let reduceRows (monoid: IMonoid<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let reduceCols (monoid: IMonoid<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let reduce (monoid: IMonoid<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let transpose (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let kronecker (semiring: ISemiring<'a>) (mask: Mask2D option) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let kronecker (semiring: ISemiring<'a>) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + + let mxmWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let mxvWithMask (semiring: ISemiring<'a>) (mask: Mask1D) (matrix: Matrix<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseAddWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseMultWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let applyWithMask (mapper: UnaryOp<'a, 'b>) (mask: Mask2D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let pruneWithMask (predicate: UnaryOp<'a, bool>) (mask: Mask2D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let reduceRowsWithMask (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let reduceColsWithMask (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let kroneckerWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" diff --git a/src/GraphBLAS-sharp/Methods/Vector.fs b/src/GraphBLAS-sharp/Methods/Vector.fs index 2550b924..71235174 100644 --- a/src/GraphBLAS-sharp/Methods/Vector.fs +++ b/src/GraphBLAS-sharp/Methods/Vector.fs @@ -38,10 +38,18 @@ module Vector = let init (size: int) (initializer: int -> 'a) : Vector<'a> = failwith "Not Implemented yet" - // обоснован ли этот метод или можно просто create x использовать - let zeroCreate (size: int) : Vector<'a> = + // Можно сделать явный метод makeSparse isZero, который бы делал плотные векторы разреженными + let create (size: int) (value: 'a) : Vector<'a> = failwith "Not Implemented yet" + // можно не указывать явный ноль, тк 'a -- структура, для которого есть unchecked.defaultof, + // а массивы с с помощью zeroCreate создать + let zeroCreate (size: int) (zero: 'a) : Vector<'a> = + failwith "Not Implemented yet" + + // let makeSparse (isZero: 'a -> bool) (vector: Vector<'a>) : Vector<'a> = + // failwith "Not Implemented yet" + (* methods *) @@ -52,29 +60,47 @@ module Vector = let resize (size: int) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let nnz (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let tuples (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - // возвращается option, чтобы потом можно было бы сразу передавать её в методы (тк они option принимают) - let mask (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let complemented (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let mask (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let complemented (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let synchronize (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" (* assignment, extraction and filling *) - // добавить функции, чтобы разделить поведение при наличии и отсутствии маски (assignSubVector и assignVector) - let extractSubVector (mask: Mask1D option) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let extractElement (idx: int) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let assignSubVector (mask: Mask1D option) (source: Vector<'a>) (target: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let assignElement (idx: int) (source: Scalar<'a>) (target: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let fillSubVector (mask: Mask1D option) (filler: Scalar<'a>) (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + /// vec.[mask] + let extractSubVector (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + + /// vec.[idx] + let extractValue (idx: int) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + + /// t <- vec + let assignVector (source: Vector<'a>) (target: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + + /// t.[mask] <- vec + let assignSubVector (mask: Mask1D) (source: Vector<'a>) (target: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + + /// t.[idx] <- value + let assignValue (idx: int) (value: Scalar<'a>) (target: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + + /// vec.[*] <- value + let fillVector (value: Scalar<'a>) (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + + /// vec.[mask] <- value + let fillSubVector (mask: Mask1D) (value: Scalar<'a>) (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" (* operations *) - let vxm (semiring: ISemiring<'a>) (mask: Mask1D option) (vector: Vector<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let vxm (semiring: ISemiring<'a>) (vector: Vector<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let eWiseAdd (semiring: ISemiring<'a>) (mask: Mask1D option) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let eWiseMult (semiring: ISemiring<'a>) (mask: Mask2D option) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let apply (mapper: UnaryOp<'a, 'b>) (mask: Mask1D option) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let prune (predicate: UnaryOp<'a, bool>) (mask: Mask1D option) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseMult (semiring: ISemiring<'a>) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let apply (mapper: UnaryOp<'a, 'b>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let prune (predicate: UnaryOp<'a, bool>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let reduce (monoid: IMonoid<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + + let vxmWithMask (semiring: ISemiring<'a>) (mask: Mask1D) (vector: Vector<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseAddWithMask (semiring: ISemiring<'a>) (mask: Mask1D) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let applyWithMask (mapper: UnaryOp<'a, 'b>) (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let pruneWithMask (predicate: UnaryOp<'a, bool>) (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" diff --git a/src/GraphBLAS-sharp/Objects/Scalar.fs b/src/GraphBLAS-sharp/Objects/Scalar.fs index df9dabc9..fb4e2f9a 100644 --- a/src/GraphBLAS-sharp/Objects/Scalar.fs +++ b/src/GraphBLAS-sharp/Objects/Scalar.fs @@ -1,5 +1,4 @@ namespace GraphBLAS.FSharp -type Scalar<'a when 'a : struct and 'a : equality> = +type Scalar<'a> = | Scalar of 'a - static member op_Implicit (Scalar source) = source diff --git a/src/GraphBLAS-sharp/Objects/Vector.fs b/src/GraphBLAS-sharp/Objects/Vector.fs index 6e424da3..578d6a1e 100644 --- a/src/GraphBLAS-sharp/Objects/Vector.fs +++ b/src/GraphBLAS-sharp/Objects/Vector.fs @@ -1,4 +1,17 @@ namespace GraphBLAS.FSharp type Vector<'a> = - | VectorCOO + | VectorCOO of COOVector<'a> + | VectorDense of ArrayVector<'a> + +and COOVector<'a> = + { + Size: int + Indices: int[] + Values: 'a[] + } + +and ArrayVector<'a> = + { + Values: 'a[] + } diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs index 612bd130..0b86dea9 100644 --- a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs @@ -145,7 +145,7 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> ) graphblas { - let! result = Matrix.eWiseAdd semiring None left right + let! result = Matrix.eWiseAdd semiring left right let! tuples = Matrix.tuples result do! MatrixTuples.synchronize tuples return tuples From 048949c38b7cd0d7439173353ba86cbe0ffdeb05 Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Tue, 23 Mar 2021 21:38:35 +0300 Subject: [PATCH 09/16] Now matrices are generated with arbitrary sparsity --- src/GraphBLAS-sharp/AlgebraicStructures.fs | 14 +- src/GraphBLAS-sharp/Algorithms/BFS.fs | 17 --- .../Algorithms/TriangleCounting.fs | 2 +- src/GraphBLAS-sharp/Objects/Scalar.fs | 3 +- .../OperationsTests/EWiseAddTests.fs | 128 +++++++++++------- 5 files changed, 86 insertions(+), 78 deletions(-) diff --git a/src/GraphBLAS-sharp/AlgebraicStructures.fs b/src/GraphBLAS-sharp/AlgebraicStructures.fs index 98911220..981a52bf 100644 --- a/src/GraphBLAS-sharp/AlgebraicStructures.fs +++ b/src/GraphBLAS-sharp/AlgebraicStructures.fs @@ -2,17 +2,11 @@ namespace GraphBLAS.FSharp open Microsoft.FSharp.Quotations -type UnaryOp<'a, 'b> = - | UnaryOp of Expr<'a -> 'b> +type UnaryOp<'a, 'b> = UnaryOp of Expr<'a -> 'b> +type BinaryOp<'a, 'b, 'c> = BinaryOp of Expr<'a -> 'b -> 'c> -type BinaryOp<'a, 'b, 'c> = - | BinaryOp of Expr<'a -> 'b -> 'c> - -type ClosedUnaryOp<'a> = - | ClosedUnaryOp of Expr<'a -> 'a> - -type ClosedBinaryOp<'a> = - | ClosedBinaryOp of Expr<'a -> 'a -> 'a> +type ClosedUnaryOp<'a> = ClosedUnaryOp of Expr<'a -> 'a> +type ClosedBinaryOp<'a> = ClosedBinaryOp of Expr<'a -> 'a -> 'a> // associative closed bin op (magma with associative) type ISemigroup<'a> = diff --git a/src/GraphBLAS-sharp/Algorithms/BFS.fs b/src/GraphBLAS-sharp/Algorithms/BFS.fs index a29a9755..98640a5b 100644 --- a/src/GraphBLAS-sharp/Algorithms/BFS.fs +++ b/src/GraphBLAS-sharp/Algorithms/BFS.fs @@ -1,10 +1,7 @@ namespace GraphBLAS.FSharp.Algorithms open GraphBLAS.FSharp.Predefined -open GraphBLAS.FSharp.Helpers open GraphBLAS.FSharp -open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation module BFS = let level (matrix: Matrix) (source: int) = graphblas { @@ -24,17 +21,3 @@ module BFS = return levels } - - // let parentBFS (matrix: Matrix) (source: int) : Vector = - // let vertexCount = matrix.RowCount - // let parents = SparseVector(vertexCount, [source, -1]) - - // let id = DenseVector(Array.init vertexCount id, IntegerMonoid.add) - // let frontier = SparseVector(vertexCount, [source, source]) - - // for _ in 1 .. vertexCount - 1 do - // frontier.[parents.Complemented] <- (frontier @. matrix) parents.Complemented IntegerSemiring.minFirst - // parents.[frontier.Mask] <- frontier - // frontier.[frontier.Mask] <- id - - // upcast parents diff --git a/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs b/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs index 3d196c44..8678039f 100644 --- a/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs +++ b/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs @@ -14,7 +14,7 @@ module TriangleCounting = let! convertedMatrix = lowerTriangular |> Matrix.apply (UnaryOp <@ bool2int @>) let! convertedTransposed = convertedMatrix |> Matrix.transpose let! lowerTriangularMask = lowerTriangular |> Matrix.mask - let! result = Matrix.mxmWithMask AddMult.int lowerTriangularMask convertedMatrix convertedTransposed + let! result = (convertedMatrix, convertedTransposed) ||> Matrix.mxmWithMask AddMult.int lowerTriangularMask let! (Scalar count) = result |> Matrix.reduce Add.int return count } diff --git a/src/GraphBLAS-sharp/Objects/Scalar.fs b/src/GraphBLAS-sharp/Objects/Scalar.fs index fb4e2f9a..80bec2cc 100644 --- a/src/GraphBLAS-sharp/Objects/Scalar.fs +++ b/src/GraphBLAS-sharp/Objects/Scalar.fs @@ -1,4 +1,3 @@ namespace GraphBLAS.FSharp -type Scalar<'a> = - | Scalar of 'a +type Scalar<'a> = Scalar of 'a diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs index 0b86dea9..29acc0cd 100644 --- a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs @@ -3,10 +3,7 @@ module EWiseAdd open Expecto open FsCheck open GraphBLAS.FSharp -open MathNet.Numerics -open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic open GraphBLAS.FSharp.Tests -open System open GraphBLAS.FSharp.Predefined open TypeShape.Core open Expecto.Logging @@ -14,6 +11,8 @@ open Expecto.Logging.Message open BackendState open GraphBLAS.FSharp.Helpers +let logger = Log.create "EWiseAddTests" + type OperationCase = { MatrixCase: MatrixBackendFormat @@ -32,64 +31,97 @@ let testCases = MaskCase = unbox list.[1] } -type PairOfSparseMatricesOfEqualSize = +type PairOfSparseMatricesOfEqualSize() = + static let MaxSparcity = 100 + static let SparsityGen = Gen.choose (0, MaxSparcity) + static let GenericSparseGen valueGenProvider = + gen { + let! sparsity = SparsityGen + logger.debug ( + eventX "Sparcity is {sp} of {ms}" + >> setField "sp" sparsity + >> setField "ms" MaxSparcity + ) + + return! valueGenProvider sparsity + } + static member IntType() = - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.oneof [ - Arb.generate - Gen.constant 0 - ] - ) |> Arb.fromGen + fun sparsity -> + Generators.pairOfMatricesOfEqualSizeGenerator ( + Gen.frequency [ + (MaxSparcity - sparsity, Arb.generate) + (sparsity, Gen.constant 0) + ] + ) + |> GenericSparseGen + |> Arb.fromGen static member FloatType() = - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.oneof [ - (Arb.Default.NormalFloat() |> Arb.toGen |> Gen.map float) - Gen.constant 0. - ] - ) |> Arb.fromGen + fun sparsity -> + Generators.pairOfMatricesOfEqualSizeGenerator ( + Gen.frequency [ + (MaxSparcity - sparsity, Arb.Default.NormalFloat() |> Arb.toGen |> Gen.map float) + (sparsity, Gen.constant 0.) + ] + ) + |> GenericSparseGen + |> Arb.fromGen static member SByteType() = - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.oneof [ - Arb.generate - Gen.constant 0y - ] - ) |> Arb.fromGen + fun sparsity -> + Generators.pairOfMatricesOfEqualSizeGenerator ( + Gen.frequency [ + (MaxSparcity - sparsity, Arb.generate) + (sparsity, Gen.constant 0y) + ] + ) + |> GenericSparseGen + |> Arb.fromGen static member ByteType() = - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.oneof [ - Arb.generate - Gen.constant 0uy - ] - ) |> Arb.fromGen + fun sparsity -> + Generators.pairOfMatricesOfEqualSizeGenerator ( + Gen.frequency [ + (MaxSparcity - sparsity, Arb.generate) + (sparsity, Gen.constant 0uy) + ] + ) + |> GenericSparseGen + |> Arb.fromGen static member Int16Type() = - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.oneof [ - Arb.generate - Gen.constant 0s - ] - ) |> Arb.fromGen + fun sparsity -> + Generators.pairOfMatricesOfEqualSizeGenerator ( + Gen.frequency [ + (MaxSparcity - sparsity, Arb.generate) + (sparsity, Gen.constant 0s) + ] + ) + |> GenericSparseGen + |> Arb.fromGen static member UInt16Type() = - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.oneof [ - Arb.generate - Gen.constant 0us - ] - ) |> Arb.fromGen + fun sparsity -> + Generators.pairOfMatricesOfEqualSizeGenerator ( + Gen.frequency [ + (MaxSparcity - sparsity, Arb.generate) + (sparsity, Gen.constant 0us) + ] + ) + |> GenericSparseGen + |> Arb.fromGen static member BoolType() = - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.oneof [ - Arb.generate - Gen.constant false - ] - ) |> Arb.fromGen - -let logger = Log.create "eWiseAddTests" + fun sparsity -> + Generators.pairOfMatricesOfEqualSizeGenerator ( + Gen.frequency [ + (MaxSparcity - sparsity, Arb.generate) + (sparsity, Gen.constant false) + ] + ) + |> GenericSparseGen + |> Arb.fromGen let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> (sum: 'a -> 'a -> 'a) From 2e0dfe84013f7beea1c070e08ab2d448d3965973 Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Tue, 23 Mar 2021 23:00:29 +0300 Subject: [PATCH 10/16] Add impl of Matrix.tuples for COOMatrix --- .../Backend/COOMatrix/GetTuples.fs | 14 +++++++++ src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj | 5 +++- src/GraphBLAS-sharp/Methods/Matrix.fs | 29 ++++++------------- src/GraphBLAS-sharp/Methods/Vector.fs | 19 ------------ src/GraphBLAS-sharp/Objects/MatrixTuples.fs | 23 +++++++++++++++ src/GraphBLAS-sharp/Objects/VectorTuples.fs | 19 ++++++++++++ 6 files changed, 69 insertions(+), 40 deletions(-) create mode 100644 src/GraphBLAS-sharp/Backend/COOMatrix/GetTuples.fs create mode 100644 src/GraphBLAS-sharp/Objects/MatrixTuples.fs create mode 100644 src/GraphBLAS-sharp/Objects/VectorTuples.fs diff --git a/src/GraphBLAS-sharp/Backend/COOMatrix/GetTuples.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/GetTuples.fs new file mode 100644 index 00000000..1d0a766e --- /dev/null +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/GetTuples.fs @@ -0,0 +1,14 @@ +namespace GraphBLAS.FSharp.Backend.COOMatrix + +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open GraphBLAS.FSharp + +module internal GetTuples = + let from (matrix: COOMatrix<'a>) = opencl { + return { + RowIndices = matrix.Rows + ColumnIndices = matrix.Columns + Values = matrix.Values + } + } diff --git a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj index 08939e33..b400c04d 100644 --- a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj +++ b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj @@ -14,11 +14,14 @@ + + + @@ -36,4 +39,4 @@ - + \ No newline at end of file diff --git a/src/GraphBLAS-sharp/Methods/Matrix.fs b/src/GraphBLAS-sharp/Methods/Matrix.fs index f4ad3d11..37d34127 100644 --- a/src/GraphBLAS-sharp/Methods/Matrix.fs +++ b/src/GraphBLAS-sharp/Methods/Matrix.fs @@ -3,25 +3,6 @@ namespace GraphBLAS.FSharp open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic open GraphBLAS.FSharp.Backend -type MatrixTuples<'a> = - { - RowIndices: int[] - ColumnIndices: int[] - Values: 'a[] - } - -// ждём тайпклассов чтобы можно было вызывать synchronize для всех объектов, -// для которых он реализован, не привязывая реализацию к классу (как стратегия) -module MatrixTuples = - let synchronize (matrixTuples: MatrixTuples<'a>) = - opencl { - let! _ = ToHost matrixTuples.RowIndices - let! _ = ToHost matrixTuples.ColumnIndices - let! _ = ToHost matrixTuples.Values - return () - } - |> EvalGB.fromCl - [] module Matrix = @@ -54,7 +35,15 @@ module Matrix = let copy (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let resize (rowCount: int) (columnCount: int) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let nnz (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let tuples (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + + let tuples (matrix: Matrix<'a>) : GraphblasEvaluation> = + let matrixTuples = + match matrix with + | MatrixCOO coo -> COOMatrix.GetTuples.from coo + | _ -> failwith "Not Implemented" + + graphblas { return! EvalGB.fromCl matrixTuples } + let mask (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let complemented (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let synchronize (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" diff --git a/src/GraphBLAS-sharp/Methods/Vector.fs b/src/GraphBLAS-sharp/Methods/Vector.fs index 71235174..3989346a 100644 --- a/src/GraphBLAS-sharp/Methods/Vector.fs +++ b/src/GraphBLAS-sharp/Methods/Vector.fs @@ -1,24 +1,5 @@ namespace GraphBLAS.FSharp -open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation -open GraphBLAS.FSharp.Backend - -type VectorTuples<'a> = - { - Indices: int[] - Values: 'a[] - } - -module VectorTuples = - let synchronize (vectorTuples: VectorTuples<'a>) = - opencl { - let! _ = ToHost vectorTuples.Indices - let! _ = ToHost vectorTuples.Values - return () - } - |> EvalGB.fromCl - [] module Vector = diff --git a/src/GraphBLAS-sharp/Objects/MatrixTuples.fs b/src/GraphBLAS-sharp/Objects/MatrixTuples.fs new file mode 100644 index 00000000..6fac85c0 --- /dev/null +++ b/src/GraphBLAS-sharp/Objects/MatrixTuples.fs @@ -0,0 +1,23 @@ +namespace GraphBLAS.FSharp + +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation + +type MatrixTuples<'a> = + { + RowIndices: int[] + ColumnIndices: int[] + Values: 'a[] + } + +// ждём тайпклассов чтобы можно было вызывать synchronize для всех объектов, +// для которых он реализован, не привязывая реализацию к классу (как стратегия) +module MatrixTuples = + let synchronize (matrixTuples: MatrixTuples<'a>) = + opencl { + let! _ = ToHost matrixTuples.RowIndices + let! _ = ToHost matrixTuples.ColumnIndices + let! _ = ToHost matrixTuples.Values + return () + } + |> EvalGB.fromCl diff --git a/src/GraphBLAS-sharp/Objects/VectorTuples.fs b/src/GraphBLAS-sharp/Objects/VectorTuples.fs new file mode 100644 index 00000000..1a3df254 --- /dev/null +++ b/src/GraphBLAS-sharp/Objects/VectorTuples.fs @@ -0,0 +1,19 @@ +namespace GraphBLAS.FSharp + +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation + +type VectorTuples<'a> = + { + Indices: int[] + Values: 'a[] + } + +module VectorTuples = + let synchronize (vectorTuples: VectorTuples<'a>) = + opencl { + let! _ = ToHost vectorTuples.Indices + let! _ = ToHost vectorTuples.Values + return () + } + |> EvalGB.fromCl From ada8e4397900fa93784ddeb673b243159ea8f81a Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Wed, 24 Mar 2021 16:47:04 +0300 Subject: [PATCH 11/16] Refactor --- .../BenchmarksBFS.fs | 6 +- .../BenchmarksEWiseAdd.fs | 32 +++--- .../GraphBLAS-sharp.Benchmarks/Utils.fs | 2 +- src/GraphBLAS-sharp/Algorithms/BFS.fs | 2 +- src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj | 5 +- src/GraphBLAS-sharp/GraphblasEvaluation.fs | 19 +++- src/GraphBLAS-sharp/Helpers.fs | 26 +++++ src/GraphBLAS-sharp/IO/MtxReader.fs | 105 ++++++++++++++++++ src/GraphBLAS-sharp/Methods/Matrix.fs | 14 +++ src/GraphBLAS-sharp/Methods/Vector.fs | 12 ++ src/GraphBLAS-sharp/Objects/Matrix.fs | 10 ++ src/GraphBLAS-sharp/Objects/MatrixTuples.fs | 23 ---- src/GraphBLAS-sharp/Objects/Vector.fs | 6 + src/GraphBLAS-sharp/Objects/VectorTuples.fs | 19 ---- tests/GraphBLAS-sharp.Tests/Common.fs | 4 - .../OperationsTests/EWiseAddTests.fs | 49 ++++---- 16 files changed, 241 insertions(+), 93 deletions(-) create mode 100644 src/GraphBLAS-sharp/IO/MtxReader.fs delete mode 100644 src/GraphBLAS-sharp/Objects/MatrixTuples.fs delete mode 100644 src/GraphBLAS-sharp/Objects/VectorTuples.fs diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksBFS.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksBFS.fs index b168ddcd..613f9d4e 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksBFS.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksBFS.fs @@ -20,12 +20,12 @@ type BFSBenchmark4CSRMatrix() = [] member this.BuildMatrix() = - matrix <- CSRMatrix(this.PathToGraph) - source <- random.Next matrix.RowCount + matrix <- MatrixCSR <| CSRMatrix.FromFile this.PathToGraph + source <- random.Next <| Matrix.rowCount matrix [] member this.LevelBFS() = - levelBFS matrix source + BFS.levelSingleSource matrix source /// Sequence of paths to files where data for benchmarking will be taken from static member GraphPaths = seq { diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs index 88617d0c..952b5073 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs @@ -97,8 +97,8 @@ type EWiseAddBenchmarks4Float32() = let mutable leftCOO = Unchecked.defaultof> let mutable rightCOO = Unchecked.defaultof> - member val FirstMatrix = Unchecked.defaultof> with get, set - member val SecondMatrix = Unchecked.defaultof> with get, set + member val FirstMatrix = Unchecked.defaultof> with get, set + member val SecondMatrix = Unchecked.defaultof> with get, set [] member this.FormInputData() = @@ -130,13 +130,13 @@ type EWiseAddBenchmarks4Float32() = Array.blit this.FirstMatrix.Values 0 leftVals 0 this.FirstMatrix.Values.Length leftCOO <- - COOMatrix( + COOMatrix.FromTuples( this.FirstMatrix.RowCount, this.FirstMatrix.ColumnCount, leftRows, leftCols, leftVals - ) :> Matrix + ) |> MatrixCOO let rightRows = Array.zeroCreate this.SecondMatrix.Rows.Length let rightCols = Array.zeroCreate this.SecondMatrix.Columns.Length @@ -146,19 +146,19 @@ type EWiseAddBenchmarks4Float32() = Array.blit this.SecondMatrix.Values 0 rightVals 0 this.SecondMatrix.Values.Length rightCOO <- - COOMatrix( + COOMatrix.FromTuples( this.SecondMatrix.RowCount, this.SecondMatrix.ColumnCount, rightRows, rightCols, rightVals - ) :> Matrix + ) |> MatrixCOO [] member this.EWiseAdditionCOOFloat32() = let (ClContext context) = this.OclContext - leftCOO.EWiseAdd rightCOO None AddMult.float32 - |> context.RunSync + (leftCOO, rightCOO) ||> Matrix.eWiseAdd AddMult.float32 + |> EvalGB.runWithClContext context static member InputMatricesProvider = "EWiseAddBenchmarks4Float32.txt" @@ -176,8 +176,8 @@ type EWiseAddBenchmarks4Bool() = let mutable leftCOO = Unchecked.defaultof> let mutable rightCOO = Unchecked.defaultof> - member val FirstMatrix = Unchecked.defaultof> with get, set - member val SecondMatrix = Unchecked.defaultof> with get, set + member val FirstMatrix = Unchecked.defaultof> with get, set + member val SecondMatrix = Unchecked.defaultof> with get, set [] member this.FormInputData() = @@ -201,13 +201,13 @@ type EWiseAddBenchmarks4Bool() = Array.blit this.FirstMatrix.Columns 0 leftCols 0 this.FirstMatrix.Columns.Length leftCOO <- - COOMatrix( + COOMatrix.FromTuples( this.FirstMatrix.RowCount, this.FirstMatrix.ColumnCount, leftRows, leftCols, leftVals - ) :> Matrix + ) |> MatrixCOO let rightRows = Array.zeroCreate this.SecondMatrix.Rows.Length let rightCols = Array.zeroCreate this.SecondMatrix.Columns.Length @@ -216,19 +216,19 @@ type EWiseAddBenchmarks4Bool() = Array.blit this.SecondMatrix.Columns 0 rightCols 0 this.SecondMatrix.Columns.Length rightCOO <- - COOMatrix( + COOMatrix.FromTuples( this.SecondMatrix.RowCount, this.SecondMatrix.ColumnCount, rightRows, rightCols, rightVals - ) :> Matrix + ) |> MatrixCOO [] member this.EWiseAdditionCOOBool() = let (ClContext context) = this.OclContext - leftCOO.EWiseAdd rightCOO None AnyAll.bool - |> context.RunSync + (leftCOO, rightCOO) ||> Matrix.eWiseAdd AnyAll.bool + |> EvalGB.runWithClContext context static member InputMatricesProvider = "EWiseAddBenchmarks4Bool.txt" diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/Utils.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/Utils.fs index cc534598..171278df 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/Utils.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/Utils.fs @@ -122,7 +122,7 @@ module Utils = ColumnCount = mtx.Shape.ColumnCount } - let transposeCOO (matrix: COOFormat<'a>) = + let transposeCOO (matrix: COOMatrix<'a>) = printfn "Start transpose COO" (matrix.Columns, matrix.Rows, matrix.Values) diff --git a/src/GraphBLAS-sharp/Algorithms/BFS.fs b/src/GraphBLAS-sharp/Algorithms/BFS.fs index 98640a5b..0c2cd34a 100644 --- a/src/GraphBLAS-sharp/Algorithms/BFS.fs +++ b/src/GraphBLAS-sharp/Algorithms/BFS.fs @@ -4,7 +4,7 @@ open GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module BFS = - let level (matrix: Matrix) (source: int) = graphblas { + let levelSingleSource (matrix: Matrix) (source: int) = graphblas { let vertexCount = Matrix.rowCount matrix let levels = Vector.zeroCreate vertexCount 0 let frontier = Vector.ofList vertexCount [source, true] diff --git a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj index b400c04d..dd1167a0 100644 --- a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj +++ b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj @@ -14,15 +14,14 @@ - - + @@ -39,4 +38,4 @@ - \ No newline at end of file + diff --git a/src/GraphBLAS-sharp/GraphblasEvaluation.fs b/src/GraphBLAS-sharp/GraphblasEvaluation.fs index 9f4a5f5a..2758966d 100644 --- a/src/GraphBLAS-sharp/GraphblasEvaluation.fs +++ b/src/GraphBLAS-sharp/GraphblasEvaluation.fs @@ -2,6 +2,7 @@ namespace GraphBLAS.FSharp open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open GraphBLAS.FSharp.Helpers type GraphblasContext = { @@ -11,6 +12,10 @@ type GraphblasContext = type GraphblasEvaluation<'a> = EvalGB of (GraphblasContext -> 'a) module EvalGB = + let defaultEnv = { + ClContext = OpenCLEvaluationContext() + } + let private runCl env (OpenCLEvaluation f) = f env let run env (EvalGB action) = action env @@ -24,15 +29,25 @@ module EvalGB = let x = run env reader run env (f x) + let (>>=) x f = bind f x + let return' x = EvalGB <| fun _ -> x + let returnFrom x = x + let fromCl clEvaluation = EvalGB <| fun env -> runCl env.ClContext clEvaluation - let runWithClContext clContext (EvalGB action) = - action { ClContext = clContext } + let withClContext clContext (EvalGB action) = + ask >>= fun env -> + return' ^ action { env with ClContext = clContext } + + let runSync (EvalGB action) = + let result = action defaultEnv + defaultEnv.ClContext.CommandQueue.Finish() |> ignore + result type GraphblasBuilder() = member this.Bind(x, f) = EvalGB.bind f x diff --git a/src/GraphBLAS-sharp/Helpers.fs b/src/GraphBLAS-sharp/Helpers.fs index b403a41a..a1377113 100644 --- a/src/GraphBLAS-sharp/Helpers.fs +++ b/src/GraphBLAS-sharp/Helpers.fs @@ -1,6 +1,32 @@ namespace GraphBLAS.FSharp +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open OpenCL.Net +open System.Text.RegularExpressions + +[] module Helpers = let inline (!>) (x: ^a) : ^b = (^a: (static member op_Implicit : ^a -> ^b) x) let inline (^) f x = f x + +module Utils = + let avaliableContexts (platformRegex: string) = + let mutable e = ErrorCode.Unknown + Cl.GetPlatformIDs &e + |> Array.collect (fun platform -> Cl.GetDeviceIDs(platform, DeviceType.All, &e)) + |> Seq.ofArray + |> Seq.distinctBy (fun device -> Cl.GetDeviceInfo(device, DeviceInfo.Name, &e).ToString()) + |> Seq.filter + (fun device -> + let platform = Cl.GetDeviceInfo(device, DeviceInfo.Platform, &e).CastTo() + let platformName = Cl.GetPlatformInfo(platform, PlatformInfo.Name, &e).ToString() + (Regex platformRegex).IsMatch platformName + ) + |> Seq.map + (fun device -> + let platform = Cl.GetDeviceInfo(device, DeviceInfo.Platform, &e).CastTo() + let platformName = Cl.GetPlatformInfo(platform, PlatformInfo.Name, &e).ToString() + let deviceType = Cl.GetDeviceInfo(device, DeviceInfo.Type, &e).CastTo() + OpenCLEvaluationContext(platformName, deviceType) + ) diff --git a/src/GraphBLAS-sharp/IO/MtxReader.fs b/src/GraphBLAS-sharp/IO/MtxReader.fs new file mode 100644 index 00000000..44eda56e --- /dev/null +++ b/src/GraphBLAS-sharp/IO/MtxReader.fs @@ -0,0 +1,105 @@ +namespace GraphBLAS.FSharp.IO + +open System.IO +open GraphBLAS.FSharp +open System + +type MtxShape = + { + Filename: string + Object: string + Format: string + Field: string + Symmetry: string + Size: int[] + } + + member this.RowCount = this.Size.[0] + member this.ColumnCount = this.Size.[1] + + override this.ToString() = + sprintf "%s" <| Path.GetFileNameWithoutExtension this.Filename + +module MtxReader = + let private readShapeWithReader (streamReader: StreamReader) (pathToFile: string) = + let shape = streamReader.ReadLine().Split(' ') + let object = shape.[1] + let format = shape.[2] + let field = shape.[3] + let symmetry = shape.[4] + + while streamReader.Peek() = int '%' do + streamReader.ReadLine() |> ignore + + let size = + streamReader.ReadLine().Split(' ') + |> Array.map int + + { + Filename = pathToFile |> Path.GetFileName + Object = object + Format = format + Field = field + Symmetry = symmetry + Size = size + } + + let readShapeFromFile (pathToFile: string) = + use streamReader = new StreamReader(pathToFile) + readShapeWithReader streamReader pathToFile + + let private readGenericMatrixFromFile (pathToFile: string) : Matrix<'a> = + use streamReader = new StreamReader(pathToFile) + let shape = readShapeWithReader streamReader pathToFile + + let len = + match shape.Format with + | "array" -> shape.Size.[0] * shape.Size.[1] + | "coordinate" -> shape.Size.[2] + | _ -> failwith "Unsupported matrix format" + + let data = + [0 .. len - 1] + |> List.map (fun _ -> streamReader.ReadLine().Split(' ')) + + let makeCOO () = + let pack x y = (uint64 x <<< 32) ||| (uint64 y) + let unpack x = (int ((x &&& 0xFFFFFFFF0000000UL) >>> 32)), (int (x &&& 0xFFFFFFFUL)) + + data + |> Array.ofList + |> Array.Parallel.map + (fun line -> + let value = Convert.ChangeType(line.[2], typeof<'a>) |> unbox<'a> + struct(pack <| int line.[0] <| int line.[1], value) + ) + |> Array.sortBy (fun struct(packedIndex, _) -> packedIndex) + |> + fun data -> + let rows = Array.zeroCreate data.Length + let cols = Array.zeroCreate data.Length + let values = Array.zeroCreate data.Length + + Array.Parallel.iteri (fun i struct(packedIndex, value) -> + let (rowIdx, columnIdx) = unpack packedIndex + // in mtx indecies start at 1 + rows.[i] <- rowIdx - 1 + cols.[i] <- columnIdx - 1 + values.[i] <- value + ) data + + { + Rows = rows + Columns = cols + Values = values + RowCount = shape.RowCount + ColumnCount = shape.ColumnCount + } + + + match shape.Format with + | "array" -> failwith "Unsupported matrix format" + | "coordinate" -> MatrixCOO <| makeCOO () + + let readRealMatrix (pathToFile: string) : Matrix = + readGenericMatrixFromFile pathToFile diff --git a/src/GraphBLAS-sharp/Methods/Matrix.fs b/src/GraphBLAS-sharp/Methods/Matrix.fs index 37d34127..4faff2ea 100644 --- a/src/GraphBLAS-sharp/Methods/Matrix.fs +++ b/src/GraphBLAS-sharp/Methods/Matrix.fs @@ -47,6 +47,7 @@ module Matrix = let mask (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let complemented (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let synchronize (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + // let convert<'a when 'a :> Matrix<'a>>() = () (* assignment, extraction and filling @@ -165,3 +166,16 @@ module Matrix = let reduceRowsWithMask (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let reduceColsWithMask (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let kroneckerWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + +// ждём тайпклассов чтобы можно было вызывать synchronize для всех объектов, +// для которых он реализован, не привязывая реализацию к классу (как стратегия) +[] +module MatrixTuples = + let synchronize (matrixTuples: MatrixTuples<'a>) = + opencl { + let! _ = ToHost matrixTuples.RowIndices + let! _ = ToHost matrixTuples.ColumnIndices + let! _ = ToHost matrixTuples.Values + return () + } + |> EvalGB.fromCl diff --git a/src/GraphBLAS-sharp/Methods/Vector.fs b/src/GraphBLAS-sharp/Methods/Vector.fs index 3989346a..839a2a4f 100644 --- a/src/GraphBLAS-sharp/Methods/Vector.fs +++ b/src/GraphBLAS-sharp/Methods/Vector.fs @@ -1,5 +1,7 @@ namespace GraphBLAS.FSharp +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic + [] module Vector = @@ -85,3 +87,13 @@ module Vector = let eWiseAddWithMask (semiring: ISemiring<'a>) (mask: Mask1D) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let applyWithMask (mapper: UnaryOp<'a, 'b>) (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let pruneWithMask (predicate: UnaryOp<'a, bool>) (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + +[] +module VectorTuples = + let synchronize (vectorTuples: VectorTuples<'a>) = + opencl { + let! _ = ToHost vectorTuples.Indices + let! _ = ToHost vectorTuples.Values + return () + } + |> EvalGB.fromCl diff --git a/src/GraphBLAS-sharp/Objects/Matrix.fs b/src/GraphBLAS-sharp/Objects/Matrix.fs index 719e7049..a865fd3f 100644 --- a/src/GraphBLAS-sharp/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp/Objects/Matrix.fs @@ -12,6 +12,9 @@ and CSRMatrix<'a> = Values: 'a[] } + static member FromFile(pathToMatrix: string) : CSRMatrix<'a> = + failwith "Not Implemented yet" + and COOMatrix<'a> = { RowCount: int @@ -40,3 +43,10 @@ and COOMatrix<'a> = |> Array.unzip3 COOMatrix.FromTuples(Array2D.length1 array, Array2D.length2 array, rows, cols, vals) + +type MatrixTuples<'a> = + { + RowIndices: int[] + ColumnIndices: int[] + Values: 'a[] + } diff --git a/src/GraphBLAS-sharp/Objects/MatrixTuples.fs b/src/GraphBLAS-sharp/Objects/MatrixTuples.fs deleted file mode 100644 index 6fac85c0..00000000 --- a/src/GraphBLAS-sharp/Objects/MatrixTuples.fs +++ /dev/null @@ -1,23 +0,0 @@ -namespace GraphBLAS.FSharp - -open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation - -type MatrixTuples<'a> = - { - RowIndices: int[] - ColumnIndices: int[] - Values: 'a[] - } - -// ждём тайпклассов чтобы можно было вызывать synchronize для всех объектов, -// для которых он реализован, не привязывая реализацию к классу (как стратегия) -module MatrixTuples = - let synchronize (matrixTuples: MatrixTuples<'a>) = - opencl { - let! _ = ToHost matrixTuples.RowIndices - let! _ = ToHost matrixTuples.ColumnIndices - let! _ = ToHost matrixTuples.Values - return () - } - |> EvalGB.fromCl diff --git a/src/GraphBLAS-sharp/Objects/Vector.fs b/src/GraphBLAS-sharp/Objects/Vector.fs index 578d6a1e..d3154ac6 100644 --- a/src/GraphBLAS-sharp/Objects/Vector.fs +++ b/src/GraphBLAS-sharp/Objects/Vector.fs @@ -15,3 +15,9 @@ and ArrayVector<'a> = { Values: 'a[] } + +type VectorTuples<'a> = + { + Indices: int[] + Values: 'a[] + } diff --git a/src/GraphBLAS-sharp/Objects/VectorTuples.fs b/src/GraphBLAS-sharp/Objects/VectorTuples.fs deleted file mode 100644 index 1a3df254..00000000 --- a/src/GraphBLAS-sharp/Objects/VectorTuples.fs +++ /dev/null @@ -1,19 +0,0 @@ -namespace GraphBLAS.FSharp - -open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation - -type VectorTuples<'a> = - { - Indices: int[] - Values: 'a[] - } - -module VectorTuples = - let synchronize (vectorTuples: VectorTuples<'a>) = - opencl { - let! _ = ToHost vectorTuples.Indices - let! _ = ToHost vectorTuples.Values - return () - } - |> EvalGB.fromCl diff --git a/tests/GraphBLAS-sharp.Tests/Common.fs b/tests/GraphBLAS-sharp.Tests/Common.fs index d08884fd..4d50b7ed 100644 --- a/tests/GraphBLAS-sharp.Tests/Common.fs +++ b/tests/GraphBLAS-sharp.Tests/Common.fs @@ -18,10 +18,6 @@ type MaskType = | Complemented | NoMask -module BackendState = - let mutable oclContext = OpenCLEvaluationContext() - let mutable matrixBackendFormat = CSR - module Generators = let dimension2DGenerator = Gen.sized <| fun size -> diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs index 29acc0cd..2d2cdebc 100644 --- a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs @@ -8,27 +8,30 @@ open GraphBLAS.FSharp.Predefined open TypeShape.Core open Expecto.Logging open Expecto.Logging.Message -open BackendState -open GraphBLAS.FSharp.Helpers +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation let logger = Log.create "EWiseAddTests" type OperationCase = { + ClContext: OpenCLEvaluationContext MatrixCase: MatrixBackendFormat MaskCase: MaskType } let testCases = [ - Utils.listOfUnionCases |> List.map box - Utils.listOfUnionCases |> List.map box + Utils.avaliableContexts "*" |> Seq.map box + Utils.listOfUnionCases |> Seq.map box + Utils.listOfUnionCases |> Seq.map box ] + |> List.map List.ofSeq |> Utils.cartesian |> List.map ^fun list -> { - MatrixCase = unbox list.[0] - MaskCase = unbox list.[1] + ClContext = unbox list.[0] + MatrixCase = unbox list.[1] + MaskCase = unbox list.[2] } type PairOfSparseMatricesOfEqualSize() = @@ -124,6 +127,7 @@ type PairOfSparseMatricesOfEqualSize() = |> Arb.fromGen let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> + (oclContext: OpenCLEvaluationContext) (sum: 'a -> 'a -> 'a) (diff: 'a -> 'a -> 'a) (isZero: 'a -> bool) @@ -182,7 +186,8 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> do! MatrixTuples.synchronize tuples return tuples } - |> EvalGB.runWithClContext oclContext + |> EvalGB.withClContext oclContext + |> EvalGB.runSync finally oclContext.Provider.CloseAllBuffers() @@ -226,33 +231,35 @@ let config = { // https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/language-specification/types#value-types let testFixtures case = [ + let getTestName datatype = sprintf "Correctness on %s, %A, %A" datatype case.MatrixCase case.MaskCase + case - |> checkCorrectnessGeneric (+) (-) ((=) 0) AddMult.int - |> testPropertyWithConfig config (sprintf "Correctness on int, %A, %A" case.MatrixCase case.MaskCase) + |> checkCorrectnessGeneric case.ClContext (+) (-) ((=) 0) AddMult.int + |> testPropertyWithConfig config (getTestName "int") case - |> checkCorrectnessGeneric (+) (-) (fun x -> abs x < Accuracy.medium.absolute) AddMult.float - |> testPropertyWithConfig config (sprintf "Correctness on float, %A, %A" case.MatrixCase case.MaskCase) + |> checkCorrectnessGeneric case.ClContext (+) (-) (fun x -> abs x < Accuracy.medium.absolute) AddMult.float + |> testPropertyWithConfig config (getTestName "float") case - |> checkCorrectnessGeneric (+) (-) ((=) 0y) AddMult.sbyte - |> testPropertyWithConfig config (sprintf "Correctness on sbyte, %A, %A" case.MatrixCase case.MaskCase) + |> checkCorrectnessGeneric case.ClContext (+) (-) ((=) 0y) AddMult.sbyte + |> testPropertyWithConfig config (getTestName "sbyte") case - |> checkCorrectnessGeneric (+) (-) ((=) 0uy) AddMult.byte - |> testPropertyWithConfig config (sprintf "Correctness on byte, %A, %A" case.MatrixCase case.MaskCase) + |> checkCorrectnessGeneric case.ClContext (+) (-) ((=) 0uy) AddMult.byte + |> testPropertyWithConfig config (getTestName "byte") case - |> checkCorrectnessGeneric (+) (-) ((=) 0s) AddMult.int16 - |> testPropertyWithConfig config (sprintf "Correctness on int16, %A, %A" case.MatrixCase case.MaskCase) + |> checkCorrectnessGeneric case.ClContext (+) (-) ((=) 0s) AddMult.int16 + |> testPropertyWithConfig config (getTestName "int16") case - |> checkCorrectnessGeneric (+) (-) ((=) 0us) AddMult.uint16 - |> testPropertyWithConfig config (sprintf "Correctness on uint16, %A, %A" case.MatrixCase case.MaskCase) + |> checkCorrectnessGeneric case.ClContext (+) (-) ((=) 0us) AddMult.uint16 + |> testPropertyWithConfig config (getTestName "uint16") case - |> checkCorrectnessGeneric (||) (<>) not AnyAll.bool - |> testPropertyWithConfig config (sprintf "Correctness on bool, %A, %A" case.MatrixCase case.MaskCase) + |> checkCorrectnessGeneric case.ClContext (||) (<>) not AnyAll.bool + |> testPropertyWithConfig config (getTestName "bool") ] let tests = From 9645c63ddbdca5d8b06c52a356cbc193f345038d Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Sat, 27 Mar 2021 12:27:43 +0300 Subject: [PATCH 12/16] Change prune to select --- .../Algorithms/TriangleCounting.fs | 15 +++++------ src/GraphBLAS-sharp/Methods/Matrix.fs | 6 ++--- src/GraphBLAS-sharp/Methods/Vector.fs | 26 ++++++++++++------- src/GraphBLAS-sharp/Objects/Masks.fs | 5 ++++ src/GraphBLAS-sharp/Objects/Matrix.fs | 5 ++++ src/GraphBLAS-sharp/Objects/Vector.fs | 4 +++ tests/GraphBLAS-sharp.Tests/Common.fs | 12 --------- .../OperationsTests/EWiseAddTests.fs | 4 +-- 8 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs b/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs index 8678039f..f115cbb1 100644 --- a/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs +++ b/src/GraphBLAS-sharp/Algorithms/TriangleCounting.fs @@ -2,19 +2,16 @@ namespace GraphBLAS.FSharp.Algorithms open GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp -open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation module TriangleCounting = - let sandia (lowerTriangular: Matrix) = graphblas { - let bool2int = function - | true -> 1 - | false -> 0 + let sandia (matrix: Matrix) = graphblas { + let! lowerTriangular = matrix |> Matrix.select (UnaryOp <@ fun (i, j, _) -> i <= j @>) + let! matrix' = lowerTriangular |> Matrix.apply (UnaryOp <@ function | true -> 1 | false -> 0 @>) + let! transposed = matrix' |> Matrix.transpose - let! convertedMatrix = lowerTriangular |> Matrix.apply (UnaryOp <@ bool2int @>) - let! convertedTransposed = convertedMatrix |> Matrix.transpose let! lowerTriangularMask = lowerTriangular |> Matrix.mask - let! result = (convertedMatrix, convertedTransposed) ||> Matrix.mxmWithMask AddMult.int lowerTriangularMask + let! result = (matrix', transposed) ||> Matrix.mxmWithMask AddMult.int lowerTriangularMask let! (Scalar count) = result |> Matrix.reduce Add.int + return count } diff --git a/src/GraphBLAS-sharp/Methods/Matrix.fs b/src/GraphBLAS-sharp/Methods/Matrix.fs index 4faff2ea..067018e1 100644 --- a/src/GraphBLAS-sharp/Methods/Matrix.fs +++ b/src/GraphBLAS-sharp/Methods/Matrix.fs @@ -46,8 +46,8 @@ module Matrix = let mask (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let complemented (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let switchTo (matrixType: MatrixType) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let synchronize (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - // let convert<'a when 'a :> Matrix<'a>>() = () (* assignment, extraction and filling @@ -150,7 +150,7 @@ module Matrix = let eWiseMult (semiring: ISemiring<'a>) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let apply (mapper: UnaryOp<'a, 'b>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let prune (predicate: UnaryOp<'a, bool>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let select (predicate: UnaryOp) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let reduceRows (monoid: IMonoid<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let reduceCols (monoid: IMonoid<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let reduce (monoid: IMonoid<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" @@ -162,7 +162,7 @@ module Matrix = let eWiseAddWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let eWiseMultWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let applyWithMask (mapper: UnaryOp<'a, 'b>) (mask: Mask2D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let pruneWithMask (predicate: UnaryOp<'a, bool>) (mask: Mask2D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let selectWithMask (predicate: UnaryOp) (mask: Mask2D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let reduceRowsWithMask (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let reduceColsWithMask (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let kroneckerWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" diff --git a/src/GraphBLAS-sharp/Methods/Vector.fs b/src/GraphBLAS-sharp/Methods/Vector.fs index 839a2a4f..2c2d24ef 100644 --- a/src/GraphBLAS-sharp/Methods/Vector.fs +++ b/src/GraphBLAS-sharp/Methods/Vector.fs @@ -45,6 +45,7 @@ module Vector = let tuples (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let mask (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let complemented (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let switchTo (vectorType: VectorType) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let synchronize (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" (* @@ -52,25 +53,32 @@ module Vector = *) /// vec.[mask] - let extractSubVector (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let extractSubVector (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = + failwith "Not Implemented yet" /// vec.[idx] - let extractValue (idx: int) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let extractValue (idx: int) (vector: Vector<'a>) : GraphblasEvaluation> = + failwith "Not Implemented yet" /// t <- vec - let assignVector (source: Vector<'a>) (target: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let assignVector (source: Vector<'a>) (target: Vector<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" /// t.[mask] <- vec - let assignSubVector (mask: Mask1D) (source: Vector<'a>) (target: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let assignSubVector (mask: Mask1D) (source: Vector<'a>) (target: Vector<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" /// t.[idx] <- value - let assignValue (idx: int) (value: Scalar<'a>) (target: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let assignValue (idx: int) (value: Scalar<'a>) (target: Vector<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" /// vec.[*] <- value - let fillVector (value: Scalar<'a>) (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let fillVector (value: Scalar<'a>) (vector: Vector<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" /// vec.[mask] <- value - let fillSubVector (mask: Mask1D) (value: Scalar<'a>) (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" + let fillSubVector (mask: Mask1D) (value: Scalar<'a>) (vector: Vector<'a>) : GraphblasEvaluation = + failwith "Not Implemented yet" (* operations @@ -80,13 +88,13 @@ module Vector = let eWiseAdd (semiring: ISemiring<'a>) (mask: Mask1D option) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let eWiseMult (semiring: ISemiring<'a>) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let apply (mapper: UnaryOp<'a, 'b>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let prune (predicate: UnaryOp<'a, bool>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let select (predicate: UnaryOp<'a, bool>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let reduce (monoid: IMonoid<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let vxmWithMask (semiring: ISemiring<'a>) (mask: Mask1D) (vector: Vector<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let eWiseAddWithMask (semiring: ISemiring<'a>) (mask: Mask1D) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let applyWithMask (mapper: UnaryOp<'a, 'b>) (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let pruneWithMask (predicate: UnaryOp<'a, bool>) (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let selectWithMask (predicate: UnaryOp<'a, bool>) (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" [] module VectorTuples = diff --git a/src/GraphBLAS-sharp/Objects/Masks.fs b/src/GraphBLAS-sharp/Objects/Masks.fs index 6dbdadd0..57c528f2 100644 --- a/src/GraphBLAS-sharp/Objects/Masks.fs +++ b/src/GraphBLAS-sharp/Objects/Masks.fs @@ -1,5 +1,10 @@ namespace GraphBLAS.FSharp +type MaskType = + | Regular + | Complemented + | NoMask + type Mask1D(indices: int[], size: int, isComplemented: bool) = member this.Indices = indices member this.Size = size diff --git a/src/GraphBLAS-sharp/Objects/Matrix.fs b/src/GraphBLAS-sharp/Objects/Matrix.fs index a865fd3f..14d4bd89 100644 --- a/src/GraphBLAS-sharp/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp/Objects/Matrix.fs @@ -1,5 +1,10 @@ namespace GraphBLAS.FSharp +// matrixFormat +type MatrixType = + | CSR + | COO + type Matrix<'a> = | MatrixCSR of CSRMatrix<'a> | MatrixCOO of COOMatrix<'a> diff --git a/src/GraphBLAS-sharp/Objects/Vector.fs b/src/GraphBLAS-sharp/Objects/Vector.fs index d3154ac6..69094fbb 100644 --- a/src/GraphBLAS-sharp/Objects/Vector.fs +++ b/src/GraphBLAS-sharp/Objects/Vector.fs @@ -1,5 +1,9 @@ namespace GraphBLAS.FSharp +type VectorType = + | COO + | Dense + type Vector<'a> = | VectorCOO of COOVector<'a> | VectorDense of ArrayVector<'a> diff --git a/tests/GraphBLAS-sharp.Tests/Common.fs b/tests/GraphBLAS-sharp.Tests/Common.fs index 4d50b7ed..0aefd725 100644 --- a/tests/GraphBLAS-sharp.Tests/Common.fs +++ b/tests/GraphBLAS-sharp.Tests/Common.fs @@ -6,18 +6,6 @@ open GraphBLAS.FSharp open Microsoft.FSharp.Reflection open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation -type MatrixBackendFormat = - | CSR - | COO - -type VectorBackendFormat = - | Sparse - -type MaskType = - | Regular - | Complemented - | NoMask - module Generators = let dimension2DGenerator = Gen.sized <| fun size -> diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs index 2d2cdebc..0a8d9fcc 100644 --- a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs @@ -15,14 +15,14 @@ let logger = Log.create "EWiseAddTests" type OperationCase = { ClContext: OpenCLEvaluationContext - MatrixCase: MatrixBackendFormat + MatrixCase: MatrixType MaskCase: MaskType } let testCases = [ Utils.avaliableContexts "*" |> Seq.map box - Utils.listOfUnionCases |> Seq.map box + Utils.listOfUnionCases |> Seq.map box Utils.listOfUnionCases |> Seq.map box ] |> List.map List.ofSeq From 5fe00e78a48c519228f17a7b99f7b79ba5e0e3cc Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Sat, 27 Mar 2021 14:12:06 +0300 Subject: [PATCH 13/16] Refactor after merge --- .../Backend/COOMatrix/EWiseAdd.fs | 43 ++----- .../{ => COOMatrix/Utilities}/Merge.fs | 115 +---------------- .../Utilities}/PreparePositions.fs | 41 +----- .../{ => COOMatrix/Utilities}/SetPositions.fs | 48 +------ .../Backend/COOVector/EWiseAdd.fs | 37 ++++++ .../Backend/COOVector/Utilities/Merge.fs | 119 ++++++++++++++++++ .../COOVector/Utilities/PreparePositions.fs | 45 +++++++ .../COOVector/Utilities/SetPositions.fs | 51 ++++++++ src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj | 21 ++-- src/GraphBLAS-sharp/GraphblasEvaluation.fs | 8 ++ .../OperationsTests/EWiseAddTests.fs | 19 ++- 11 files changed, 305 insertions(+), 242 deletions(-) rename src/GraphBLAS-sharp/Backend/{ => COOMatrix/Utilities}/Merge.fs (52%) rename src/GraphBLAS-sharp/Backend/{ => COOMatrix/Utilities}/PreparePositions.fs (50%) rename src/GraphBLAS-sharp/Backend/{ => COOMatrix/Utilities}/SetPositions.fs (54%) create mode 100644 src/GraphBLAS-sharp/Backend/COOVector/EWiseAdd.fs create mode 100644 src/GraphBLAS-sharp/Backend/COOVector/Utilities/Merge.fs create mode 100644 src/GraphBLAS-sharp/Backend/COOVector/Utilities/PreparePositions.fs create mode 100644 src/GraphBLAS-sharp/Backend/COOVector/Utilities/SetPositions.fs diff --git a/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs index ad4d524d..3d3140b5 100644 --- a/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs @@ -1,18 +1,18 @@ namespace GraphBLAS.FSharp.Backend.COOMatrix open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open GraphBLAS.FSharp open GraphBLAS.FSharp.Backend.Common +open GraphBLAS.FSharp.Backend.COOMatrix.Utilities module internal EWiseAdd = - let cooNotEmpty (matrixLeft: COOFormat<'a>) (matrixRight: COOFormat<'a>) (mask: Mask2D option) (semiring: Semiring<'a>) : OpenCLEvaluation> = opencl { - let! allRows, allColumns, allValues = Merge.runForMatrix matrixLeft matrixRight mask + let private runNonEmpty (matrixLeft: COOMatrix<'a>) (matrixRight: COOMatrix<'a>) (mask: Mask2D option) (semiring: ISemiring<'a>) = opencl { + let! allRows, allColumns, allValues = merge matrixLeft matrixRight mask - let (BinaryOp append) = semiring.PlusMonoid.Append - let! rawPositions = PreparePositions.runForMatrix allRows allColumns allValues append + let (ClosedBinaryOp plus) = semiring.Plus + let! rawPositions = preparePositions allRows allColumns allValues plus - let! resultRows, resultColumns, resultValues = SetPositions.runForMatrix allRows allColumns allValues rawPositions + let! resultRows, resultColumns, resultValues = setPositions allRows allColumns allValues rawPositions return { RowCount = matrixLeft.RowCount @@ -23,7 +23,7 @@ module internal EWiseAdd = } } - let coo (matrixLeft: COOFormat<'a>) (matrixRight: COOFormat<'a>) (mask: Mask2D option) (semiring: Semiring<'a>) : OpenCLEvaluation> = + let run (matrixLeft: COOMatrix<'a>) (matrixRight: COOMatrix<'a>) (mask: Mask2D option) (semiring: ISemiring<'a>) = if matrixLeft.Values.Length = 0 then opencl { let! resultRows = Copy.run matrixRight.Rows @@ -38,6 +38,7 @@ module internal EWiseAdd = Values = resultValues } } + elif matrixRight.Values.Length = 0 then opencl { let! resultRows = Copy.run matrixLeft.Rows @@ -52,30 +53,6 @@ module internal EWiseAdd = Values = resultValues } } - else cooNotEmpty matrixLeft matrixRight mask semiring - - let sparseNotEmpty (leftIndices: int[]) (leftValues: 'a[]) (rightIndices: int[]) (rightValues: 'a[]) (mask: Mask1D option) (semiring: Semiring<'a>) : OpenCLEvaluation = opencl { - let! allIndices, allValues = Merge.runForVector leftIndices leftValues rightIndices rightValues mask - - let (BinaryOp append) = semiring.PlusMonoid.Append - let! rawPositions = PreparePositions.runForVector allIndices allValues append - return! SetPositions.runForVector allIndices allValues rawPositions - } - - let sparse (leftIndices: int[]) (leftValues: 'a[]) (rightIndices: int[]) (rightValues: 'a[]) (mask: Mask1D option) (semiring: Semiring<'a>) : OpenCLEvaluation = - if leftValues.Length = 0 then - opencl { - let! resultIndices = Copy.run rightIndices - let! resultValues = Copy.run rightValues - - return resultIndices, resultValues - } - elif rightIndices.Length = 0 then - opencl { - let! resultIndices = Copy.run leftIndices - let! resultValues = Copy.run leftValues - - return resultIndices, resultValues - } - else sparseNotEmpty leftIndices leftValues rightIndices rightValues mask semiring + else + runNonEmpty matrixLeft matrixRight mask semiring diff --git a/src/GraphBLAS-sharp/Backend/Merge.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/Merge.fs similarity index 52% rename from src/GraphBLAS-sharp/Backend/Merge.fs rename to src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/Merge.fs index f3bf10ef..2fbba2dd 100644 --- a/src/GraphBLAS-sharp/Backend/Merge.fs +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/Merge.fs @@ -1,4 +1,4 @@ -namespace GraphBLAS.FSharp.Backend +namespace GraphBLAS.FSharp.Backend.COOMatrix.Utilities open Brahma.OpenCL open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic @@ -6,8 +6,9 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open GraphBLAS.FSharp open GraphBLAS.FSharp.Backend.Common +[] module internal Merge = - let runForMatrix (matrixLeft: COOFormat<'a>) (matrixRight: COOFormat<'a>) (mask: Mask2D option) : OpenCLEvaluation = opencl { + let merge (matrixLeft: COOMatrix<'a>) (matrixRight: COOMatrix<'a>) (mask: Mask2D option) : OpenCLEvaluation = opencl { let workGroupSize = Utils.workGroupSize let firstSide = matrixLeft.Values.Length let secondSide = matrixRight.Values.Length @@ -125,113 +126,3 @@ module internal Merge = return allRows, allColumns, allValues } - - let runForVector (leftIndices: int[]) (leftValues: 'a[]) (rightIndices: int[]) (rightValues: 'a[]) (mask: Mask1D option) : OpenCLEvaluation = opencl { - let workGroupSize = Utils.workGroupSize - let firstSide = leftValues.Length - let secondSide = rightValues.Length - let sumOfSides = firstSide + secondSide - - let merge = - <@ - fun (ndRange: _1D) - (firstIndicesBuffer: int[]) - (firstValuesBuffer: 'a[]) - (secondIndicesBuffer: int[]) - (secondValuesBuffer: 'a[]) - (allIndicesBuffer: int[]) - (allValuesBuffer: 'a[]) -> - - let i = ndRange.GlobalID0 - - let mutable beginIdxLocal = local () - let mutable endIdxLocal = local () - let localID = ndRange.LocalID0 - if localID < 2 then - let mutable x = localID * (workGroupSize - 1) + i - 1 - if x >= sumOfSides then x <- sumOfSides - 1 - let diagonalNumber = x - - let mutable leftEdge = diagonalNumber + 1 - secondSide - if leftEdge < 0 then leftEdge <- 0 - - let mutable rightEdge = firstSide - 1 - if rightEdge > diagonalNumber then rightEdge <- diagonalNumber - - while leftEdge <= rightEdge do - let middleIdx = (leftEdge + rightEdge) / 2 - let firstIndex = firstIndicesBuffer.[middleIdx] - let secondIndex = secondIndicesBuffer.[diagonalNumber - middleIdx] - if firstIndex < secondIndex then leftEdge <- middleIdx + 1 else rightEdge <- middleIdx - 1 - - // Here localID equals either 0 or 1 - if localID = 0 then beginIdxLocal <- leftEdge else endIdxLocal <- leftEdge - barrier () - - let beginIdx = beginIdxLocal - let endIdx = endIdxLocal - let firstLocalLength = endIdx - beginIdx - let mutable x = workGroupSize - firstLocalLength - if endIdx = firstSide then x <- secondSide - i + localID + beginIdx - let secondLocalLength = x - - //First indices are from 0 to firstLocalLength - 1 inclusive - //Second indices are from firstLocalLength to firstLocalLength + secondLocalLength - 1 inclusive - let localIndices = localArray workGroupSize - - if localID < firstLocalLength then - localIndices.[localID] <- firstIndicesBuffer.[beginIdx + localID] - if localID < secondLocalLength then - localIndices.[firstLocalLength + localID] <- secondIndicesBuffer.[i - beginIdx] - barrier () - - if i < sumOfSides then - let mutable leftEdge = localID + 1 - secondLocalLength - if leftEdge < 0 then leftEdge <- 0 - - let mutable rightEdge = firstLocalLength - 1 - if rightEdge > localID then rightEdge <- localID - - while leftEdge <= rightEdge do - let middleIdx = (leftEdge + rightEdge) / 2 - let firstIndex = localIndices.[middleIdx] - let secondIndex = localIndices.[firstLocalLength + localID - middleIdx] - if firstIndex < secondIndex then leftEdge <- middleIdx + 1 else rightEdge <- middleIdx - 1 - - let boundaryX = rightEdge - let boundaryY = localID - leftEdge - - // boundaryX and boundaryY can't be off the right edge of array (only off the left edge) - let isValidX = boundaryX >= 0 - let isValidY = boundaryY >= 0 - - let mutable fstIdx = 0 - if isValidX then fstIdx <- localIndices.[boundaryX] - - let mutable sndIdx = 0 - if isValidY then sndIdx <- localIndices.[firstLocalLength + boundaryY] - - if not isValidX || isValidY && fstIdx < sndIdx then - allIndicesBuffer.[i] <- sndIdx - allValuesBuffer.[i] <- secondValuesBuffer.[i - localID - beginIdx + boundaryY] - else - allIndicesBuffer.[i] <- fstIdx - allValuesBuffer.[i] <- firstValuesBuffer.[beginIdx + boundaryX] - @> - - let allIndices = Array.zeroCreate sumOfSides - let allValues = Array.create sumOfSides Unchecked.defaultof<'a> - - do! RunCommand merge <| fun kernelPrepare -> - let ndRange = _1D(Utils.workSize sumOfSides, workGroupSize) - kernelPrepare - ndRange - leftIndices - leftValues - rightIndices - rightValues - allIndices - allValues - - return allIndices, allValues - } diff --git a/src/GraphBLAS-sharp/Backend/PreparePositions.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/PreparePositions.fs similarity index 50% rename from src/GraphBLAS-sharp/Backend/PreparePositions.fs rename to src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/PreparePositions.fs index e4ee057f..9d20adcf 100644 --- a/src/GraphBLAS-sharp/Backend/PreparePositions.fs +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/PreparePositions.fs @@ -1,4 +1,4 @@ -namespace GraphBLAS.FSharp.Backend +namespace GraphBLAS.FSharp.Backend.COOMatrix.Utilities open Brahma.OpenCL open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic @@ -6,8 +6,9 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open GraphBLAS.FSharp.Backend.Common open Microsoft.FSharp.Quotations +[] module internal PreparePositions = - let runForMatrix (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (plus: Expr<'a -> 'a -> 'a>) : OpenCLEvaluation = opencl { + let preparePositions (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (plus: Expr<'a -> 'a -> 'a>) : OpenCLEvaluation = opencl { let length = allValues.Length let preparePositions = @@ -44,39 +45,3 @@ module internal PreparePositions = return rawPositions } - - let runForVector (allIndices: int[]) (allValues: 'a[]) (plus: Expr<'a -> 'a -> 'a>) : OpenCLEvaluation = opencl { - let length = allValues.Length - - let preparePositions = - <@ - fun (ndRange: _1D) - (allIndicesBuffer: int[]) - (allValuesBuffer: 'a[]) - (rawPositionsBuffer: int[]) -> - - let i = ndRange.GlobalID0 - - if i < length - 1 && allIndicesBuffer.[i] = allIndicesBuffer.[i + 1] then - rawPositionsBuffer.[i] <- 0 - - //Do not drop explicit zeroes - allValuesBuffer.[i + 1] <- (%plus) allValuesBuffer.[i] allValuesBuffer.[i + 1] - - //Drop explicit zeroes - // let localResultBuffer = (%plus) allValuesBuffer.[i] allValuesBuffer.[i + 1] - // if localResultBuffer = zero then rawPositionsBuffer.[i + 1] <- 0 else allValuesBuffer.[i + 1] <- localResultBuffer - @> - - let rawPositions = Array.create length 1 - - do! RunCommand preparePositions <| fun kernelPrepare -> - let ndRange = _1D(Utils.workSize (length - 1), Utils.workGroupSize) - kernelPrepare - ndRange - allIndices - allValues - rawPositions - - return rawPositions - } diff --git a/src/GraphBLAS-sharp/Backend/SetPositions.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs similarity index 54% rename from src/GraphBLAS-sharp/Backend/SetPositions.fs rename to src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs index a43132c9..2e21cf9e 100644 --- a/src/GraphBLAS-sharp/Backend/SetPositions.fs +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs @@ -1,12 +1,13 @@ -namespace GraphBLAS.FSharp.Backend +namespace GraphBLAS.FSharp.Backend.COOMatrix.Utilities open Brahma.OpenCL open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open GraphBLAS.FSharp.Backend.Common +[] module internal SetPositions = - let runForMatrix (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (positions: int[]) : OpenCLEvaluation = opencl { + let setPositions (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (positions: int[]) : OpenCLEvaluation = opencl { let prefixSumArrayLength = positions.Length let setPositions = @@ -54,46 +55,3 @@ module internal SetPositions = return resultRows, resultColumns, resultValues } - - let runForVector (allIndices: int[]) (allValues: 'a[]) (positions: int[]) : OpenCLEvaluation = opencl { - let prefixSumArrayLength = positions.Length - - let setPositions = - <@ - fun (ndRange: _1D) - (allIndicesBuffer: int[]) - (allValuesBuffer: 'a[]) - (prefixSumArrayBuffer: int[]) - (resultIndicesBuffer: int[]) - (resultValuesBuffer: 'a[]) -> - - let i = ndRange.GlobalID0 - - if i = prefixSumArrayLength - 1 || i < prefixSumArrayLength && prefixSumArrayBuffer.[i] <> prefixSumArrayBuffer.[i + 1] then - let index = prefixSumArrayBuffer.[i] - - resultIndicesBuffer.[index] <- allIndicesBuffer.[i] - resultValuesBuffer.[index] <- allValuesBuffer.[i] - @> - - let resultLength = Array.zeroCreate 1 - - do! PrefixSum.run positions resultLength - let! _ = ToHost resultLength - let resultLength = resultLength.[0] - - let resultIndices = Array.zeroCreate resultLength - let resultValues = Array.create resultLength Unchecked.defaultof<'a> - - do! RunCommand setPositions <| fun kernelPrepare -> - let ndRange = _1D(Utils.workSize positions.Length, Utils.workGroupSize) - kernelPrepare - ndRange - allIndices - allValues - positions - resultIndices - resultValues - - return resultIndices, resultValues - } diff --git a/src/GraphBLAS-sharp/Backend/COOVector/EWiseAdd.fs b/src/GraphBLAS-sharp/Backend/COOVector/EWiseAdd.fs new file mode 100644 index 00000000..10b9115b --- /dev/null +++ b/src/GraphBLAS-sharp/Backend/COOVector/EWiseAdd.fs @@ -0,0 +1,37 @@ +namespace GraphBLAS.FSharp.Backend.COOVector + +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend.Common +open GraphBLAS.FSharp.Backend.COOVector.Utilities + +module internal EWiseAdd = + let private runNonEmpty (leftIndices: int[]) (leftValues: 'a[]) (rightIndices: int[]) (rightValues: 'a[]) (mask: Mask1D option) (semiring: ISemiring<'a>) : OpenCLEvaluation = opencl { + let! allIndices, allValues = merge leftIndices leftValues rightIndices rightValues mask + + let (ClosedBinaryOp plus) = semiring.Plus + let! rawPositions = preparePositions allIndices allValues plus + + return! setPositions allIndices allValues rawPositions + } + + let run (leftIndices: int[]) (leftValues: 'a[]) (rightIndices: int[]) (rightValues: 'a[]) (mask: Mask1D option) (semiring: ISemiring<'a>) : OpenCLEvaluation = + if leftValues.Length = 0 then + opencl { + let! resultIndices = Copy.run rightIndices + let! resultValues = Copy.run rightValues + + return resultIndices, resultValues + } + + elif rightIndices.Length = 0 then + opencl { + let! resultIndices = Copy.run leftIndices + let! resultValues = Copy.run leftValues + + return resultIndices, resultValues + } + + else + runNonEmpty leftIndices leftValues rightIndices rightValues mask semiring diff --git a/src/GraphBLAS-sharp/Backend/COOVector/Utilities/Merge.fs b/src/GraphBLAS-sharp/Backend/COOVector/Utilities/Merge.fs new file mode 100644 index 00000000..ed7b3620 --- /dev/null +++ b/src/GraphBLAS-sharp/Backend/COOVector/Utilities/Merge.fs @@ -0,0 +1,119 @@ +namespace GraphBLAS.FSharp.Backend.COOVector.Utilities + +open Brahma.OpenCL +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend.Common + +[] +module internal Merge = + let merge (leftIndices: int[]) (leftValues: 'a[]) (rightIndices: int[]) (rightValues: 'a[]) (mask: Mask1D option) : OpenCLEvaluation = opencl { + let workGroupSize = Utils.workGroupSize + let firstSide = leftValues.Length + let secondSide = rightValues.Length + let sumOfSides = firstSide + secondSide + + let merge = + <@ + fun (ndRange: _1D) + (firstIndicesBuffer: int[]) + (firstValuesBuffer: 'a[]) + (secondIndicesBuffer: int[]) + (secondValuesBuffer: 'a[]) + (allIndicesBuffer: int[]) + (allValuesBuffer: 'a[]) -> + + let i = ndRange.GlobalID0 + + let mutable beginIdxLocal = local () + let mutable endIdxLocal = local () + let localID = ndRange.LocalID0 + if localID < 2 then + let mutable x = localID * (workGroupSize - 1) + i - 1 + if x >= sumOfSides then x <- sumOfSides - 1 + let diagonalNumber = x + + let mutable leftEdge = diagonalNumber + 1 - secondSide + if leftEdge < 0 then leftEdge <- 0 + + let mutable rightEdge = firstSide - 1 + if rightEdge > diagonalNumber then rightEdge <- diagonalNumber + + while leftEdge <= rightEdge do + let middleIdx = (leftEdge + rightEdge) / 2 + let firstIndex = firstIndicesBuffer.[middleIdx] + let secondIndex = secondIndicesBuffer.[diagonalNumber - middleIdx] + if firstIndex < secondIndex then leftEdge <- middleIdx + 1 else rightEdge <- middleIdx - 1 + + // Here localID equals either 0 or 1 + if localID = 0 then beginIdxLocal <- leftEdge else endIdxLocal <- leftEdge + barrier () + + let beginIdx = beginIdxLocal + let endIdx = endIdxLocal + let firstLocalLength = endIdx - beginIdx + let mutable x = workGroupSize - firstLocalLength + if endIdx = firstSide then x <- secondSide - i + localID + beginIdx + let secondLocalLength = x + + //First indices are from 0 to firstLocalLength - 1 inclusive + //Second indices are from firstLocalLength to firstLocalLength + secondLocalLength - 1 inclusive + let localIndices = localArray workGroupSize + + if localID < firstLocalLength then + localIndices.[localID] <- firstIndicesBuffer.[beginIdx + localID] + if localID < secondLocalLength then + localIndices.[firstLocalLength + localID] <- secondIndicesBuffer.[i - beginIdx] + barrier () + + if i < sumOfSides then + let mutable leftEdge = localID + 1 - secondLocalLength + if leftEdge < 0 then leftEdge <- 0 + + let mutable rightEdge = firstLocalLength - 1 + if rightEdge > localID then rightEdge <- localID + + while leftEdge <= rightEdge do + let middleIdx = (leftEdge + rightEdge) / 2 + let firstIndex = localIndices.[middleIdx] + let secondIndex = localIndices.[firstLocalLength + localID - middleIdx] + if firstIndex < secondIndex then leftEdge <- middleIdx + 1 else rightEdge <- middleIdx - 1 + + let boundaryX = rightEdge + let boundaryY = localID - leftEdge + + // boundaryX and boundaryY can't be off the right edge of array (only off the left edge) + let isValidX = boundaryX >= 0 + let isValidY = boundaryY >= 0 + + let mutable fstIdx = 0 + if isValidX then fstIdx <- localIndices.[boundaryX] + + let mutable sndIdx = 0 + if isValidY then sndIdx <- localIndices.[firstLocalLength + boundaryY] + + if not isValidX || isValidY && fstIdx < sndIdx then + allIndicesBuffer.[i] <- sndIdx + allValuesBuffer.[i] <- secondValuesBuffer.[i - localID - beginIdx + boundaryY] + else + allIndicesBuffer.[i] <- fstIdx + allValuesBuffer.[i] <- firstValuesBuffer.[beginIdx + boundaryX] + @> + + let allIndices = Array.zeroCreate sumOfSides + let allValues = Array.create sumOfSides Unchecked.defaultof<'a> + + do! RunCommand merge <| fun kernelPrepare -> + let ndRange = _1D(Utils.workSize sumOfSides, workGroupSize) + kernelPrepare + ndRange + leftIndices + leftValues + rightIndices + rightValues + allIndices + allValues + + return allIndices, allValues + } diff --git a/src/GraphBLAS-sharp/Backend/COOVector/Utilities/PreparePositions.fs b/src/GraphBLAS-sharp/Backend/COOVector/Utilities/PreparePositions.fs new file mode 100644 index 00000000..4101d02f --- /dev/null +++ b/src/GraphBLAS-sharp/Backend/COOVector/Utilities/PreparePositions.fs @@ -0,0 +1,45 @@ +namespace GraphBLAS.FSharp.Backend.COOVector.Utilities + +open Brahma.OpenCL +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open GraphBLAS.FSharp.Backend.Common +open Microsoft.FSharp.Quotations + +[] +module internal PreparePositions = + let preparePositions (allIndices: int[]) (allValues: 'a[]) (plus: Expr<'a -> 'a -> 'a>) : OpenCLEvaluation = opencl { + let length = allValues.Length + + let preparePositions = + <@ + fun (ndRange: _1D) + (allIndicesBuffer: int[]) + (allValuesBuffer: 'a[]) + (rawPositionsBuffer: int[]) -> + + let i = ndRange.GlobalID0 + + if i < length - 1 && allIndicesBuffer.[i] = allIndicesBuffer.[i + 1] then + rawPositionsBuffer.[i] <- 0 + + //Do not drop explicit zeroes + allValuesBuffer.[i + 1] <- (%plus) allValuesBuffer.[i] allValuesBuffer.[i + 1] + + //Drop explicit zeroes + // let localResultBuffer = (%plus) allValuesBuffer.[i] allValuesBuffer.[i + 1] + // if localResultBuffer = zero then rawPositionsBuffer.[i + 1] <- 0 else allValuesBuffer.[i + 1] <- localResultBuffer + @> + + let rawPositions = Array.create length 1 + + do! RunCommand preparePositions <| fun kernelPrepare -> + let ndRange = _1D(Utils.workSize (length - 1), Utils.workGroupSize) + kernelPrepare + ndRange + allIndices + allValues + rawPositions + + return rawPositions + } diff --git a/src/GraphBLAS-sharp/Backend/COOVector/Utilities/SetPositions.fs b/src/GraphBLAS-sharp/Backend/COOVector/Utilities/SetPositions.fs new file mode 100644 index 00000000..835baf14 --- /dev/null +++ b/src/GraphBLAS-sharp/Backend/COOVector/Utilities/SetPositions.fs @@ -0,0 +1,51 @@ +namespace GraphBLAS.FSharp.Backend.COOVector.Utilities + +open Brahma.OpenCL +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open GraphBLAS.FSharp.Backend.Common + +[] +module internal SetPositions = + let setPositions (allIndices: int[]) (allValues: 'a[]) (positions: int[]) : OpenCLEvaluation = opencl { + let prefixSumArrayLength = positions.Length + + let setPositions = + <@ + fun (ndRange: _1D) + (allIndicesBuffer: int[]) + (allValuesBuffer: 'a[]) + (prefixSumArrayBuffer: int[]) + (resultIndicesBuffer: int[]) + (resultValuesBuffer: 'a[]) -> + + let i = ndRange.GlobalID0 + + if i = prefixSumArrayLength - 1 || i < prefixSumArrayLength && prefixSumArrayBuffer.[i] <> prefixSumArrayBuffer.[i + 1] then + let index = prefixSumArrayBuffer.[i] + + resultIndicesBuffer.[index] <- allIndicesBuffer.[i] + resultValuesBuffer.[index] <- allValuesBuffer.[i] + @> + + let resultLength = Array.zeroCreate 1 + + do! PrefixSum.run positions resultLength + let! _ = ToHost resultLength + let resultLength = resultLength.[0] + + let resultIndices = Array.zeroCreate resultLength + let resultValues = Array.create resultLength Unchecked.defaultof<'a> + + do! RunCommand setPositions <| fun kernelPrepare -> + let ndRange = _1D(Utils.workSize positions.Length, Utils.workGroupSize) + kernelPrepare + ndRange + allIndices + allValues + positions + resultIndices + resultValues + + return resultIndices, resultValues + } diff --git a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj index b37b3fad..83a62827 100644 --- a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj +++ b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj @@ -18,21 +18,20 @@ - - + + + + + + + + + + - - - - - - - - - diff --git a/src/GraphBLAS-sharp/GraphblasEvaluation.fs b/src/GraphBLAS-sharp/GraphblasEvaluation.fs index 2758966d..bd73867c 100644 --- a/src/GraphBLAS-sharp/GraphblasEvaluation.fs +++ b/src/GraphBLAS-sharp/GraphblasEvaluation.fs @@ -76,6 +76,14 @@ type GraphblasBuilder() = for elem in sequence do EvalGB.run env (f elem) + member this.TryWith(tryBlock, handler) = + EvalGB <| fun env -> + try + EvalGB.run env tryBlock + with + | e -> + EvalGB.run env (handler e) + [] module GraphblasBuilder = let graphblas = GraphblasBuilder() diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs index 7720484a..36c111be 100644 --- a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs @@ -9,6 +9,7 @@ open TypeShape.Core open Expecto.Logging open Expecto.Logging.Message open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open OpenCL.Net let logger = Log.create "EWiseAddTests" @@ -21,7 +22,7 @@ type OperationCase = let testCases = [ - Utils.avaliableContexts "*" |> Seq.map box + Utils.avaliableContexts "" |> Seq.map box Utils.listOfUnionCases |> Seq.map box Utils.listOfUnionCases |> Seq.map box ] @@ -224,9 +225,9 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> let config = { FsCheckConfig.defaultConfig with arbitrary = [typeof] - maxTest = 50 + maxTest = 10 startSize = 0 - endSize = 1_000_000 + // endSize = 1_000_000 } // https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/language-specification/types#value-types @@ -260,10 +261,22 @@ let testFixtures case = [ case |> checkCorrectnessGeneric case.ClContext (||) (<>) not AnyAll.bool |> testPropertyWithConfig config (getTestName "bool") + + case + |> checkCorrectnessGeneric case.ClContext (||) (<>) not AnyAll.bool + |> testPropertyWithConfigStdGen (355610228, 296870493) config "Correctness on both empty matrices" ] let tests = testCases |> List.filter (fun case -> case.MatrixCase = COO && case.MaskCase = NoMask) + |> List.filter + (fun case -> + let mutable e = ErrorCode.Unknown + let device = case.ClContext.Device + // let platform = Cl.GetDeviceInfo(device, DeviceInfo.Platform, &e).CastTo() + let deviceType = Cl.GetDeviceInfo(device, DeviceInfo.Type, &e).CastTo() + deviceType = DeviceType.Cpu + ) |> List.collect testFixtures |> testList "EWiseAdd tests" From ff5d55cb2cd752acfc9ff911a64e2ae0c220eb4f Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Sun, 28 Mar 2021 14:23:56 +0300 Subject: [PATCH 14/16] Add RemoveDuplicates func; add some constructors --- .../BenchmarksEWiseAdd.fs | 6 +- src/GraphBLAS-sharp/AlgebraicStructures.fs | 24 +- src/GraphBLAS-sharp/Algorithms/BFS.fs | 4 +- .../Algorithms/ShortestPath.fs | 2 +- .../Backend/COOMatrix/EWiseAdd.fs | 1 - .../COOMatrix/Utilities/PreparePositions.fs | 9 +- .../COOMatrix/Utilities/SetPositions.fs | 7 +- src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs | 9 + .../Backend/Common/PrefixSum.fs | 129 +---------- .../Backend/Common/RemoveDuplicates.fs | 50 +++++ src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj | 4 +- src/GraphBLAS-sharp/IO/MtxReader.fs | 206 +++++++++--------- src/GraphBLAS-sharp/Methods/Matrix.fs | 30 ++- src/GraphBLAS-sharp/Methods/Vector.fs | 22 +- src/GraphBLAS-sharp/Objects/Matrix.fs | 2 +- src/GraphBLAS-sharp/Objects/Vector.fs | 9 +- .../OperationsTests/EWiseAddTests.fs | 9 +- 17 files changed, 244 insertions(+), 279 deletions(-) create mode 100644 src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs create mode 100644 src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs diff --git a/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs b/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs index 952b5073..ea458e9e 100644 --- a/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs +++ b/benchmarks/GraphBLAS-sharp.Benchmarks/BenchmarksEWiseAdd.fs @@ -158,7 +158,8 @@ type EWiseAddBenchmarks4Float32() = member this.EWiseAdditionCOOFloat32() = let (ClContext context) = this.OclContext (leftCOO, rightCOO) ||> Matrix.eWiseAdd AddMult.float32 - |> EvalGB.runWithClContext context + |> EvalGB.withClContext context + |> EvalGB.runSync static member InputMatricesProvider = "EWiseAddBenchmarks4Float32.txt" @@ -228,7 +229,8 @@ type EWiseAddBenchmarks4Bool() = member this.EWiseAdditionCOOBool() = let (ClContext context) = this.OclContext (leftCOO, rightCOO) ||> Matrix.eWiseAdd AnyAll.bool - |> EvalGB.runWithClContext context + |> EvalGB.withClContext context + |> EvalGB.runSync static member InputMatricesProvider = "EWiseAddBenchmarks4Bool.txt" diff --git a/src/GraphBLAS-sharp/AlgebraicStructures.fs b/src/GraphBLAS-sharp/AlgebraicStructures.fs index 981a52bf..d3e320f4 100644 --- a/src/GraphBLAS-sharp/AlgebraicStructures.fs +++ b/src/GraphBLAS-sharp/AlgebraicStructures.fs @@ -21,21 +21,19 @@ type ISemiring<'a> = inherit IMonoid<'a> abstract Times: ClosedBinaryOp<'a> -// на самом деле должен быть "зависымым типом" -// (если получает ноль, то Zero, иначе Just x) -// но он будет оборачивать 'a только на стороне F# -// => можно сделать специальный статик коснтруктор для инстансов -// (если так делать, то уже не получится оставить его генерик типом) -// (можно в конструктор передавать проверку на ноль первым параметром, тогда норм) +(* + мотивация: + хотим, чтобы ноль был нулем (даже если он явно в матрице хранится) + и все моноиды, определенные над MonoidicType 'a имели корректную семантику + (если получился 0 и мы сменили моноид, то этот элемент все еще будет нулем в другом моноиде) +*) + [] type MonoidicType<'a> = | Just of 'a | Zero -(* - мотивация - хотим, чтобы ноль был нулем (даже если он в матрице будет хранится) - и все моноиды, определенные над MonoidicType 'a имели корректную семантику - (если получился 0 и мы сменили моноид, то этот элемент все еще будет нудем в другом моноиде) - то избавимся от кастов -*) +module MonoidicType = + let wrap (isZero: 'a -> bool) x = + if isZero x then Zero + else Just x diff --git a/src/GraphBLAS-sharp/Algorithms/BFS.fs b/src/GraphBLAS-sharp/Algorithms/BFS.fs index 0c2cd34a..50dfc57d 100644 --- a/src/GraphBLAS-sharp/Algorithms/BFS.fs +++ b/src/GraphBLAS-sharp/Algorithms/BFS.fs @@ -6,8 +6,8 @@ open GraphBLAS.FSharp module BFS = let levelSingleSource (matrix: Matrix) (source: int) = graphblas { let vertexCount = Matrix.rowCount matrix - let levels = Vector.zeroCreate vertexCount 0 - let frontier = Vector.ofList vertexCount [source, true] + let! levels = Vector.zeroCreate vertexCount + let! frontier = Vector.ofList vertexCount [source, true] let mutable currentLevel = 1 while currentLevel < vertexCount do diff --git a/src/GraphBLAS-sharp/Algorithms/ShortestPath.fs b/src/GraphBLAS-sharp/Algorithms/ShortestPath.fs index 86be3288..f1042302 100644 --- a/src/GraphBLAS-sharp/Algorithms/ShortestPath.fs +++ b/src/GraphBLAS-sharp/Algorithms/ShortestPath.fs @@ -8,7 +8,7 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation module ShortestPath = let singleSource (matrix: Matrix) (source: int) = graphblas { let vertexCount = Matrix.rowCount matrix - let distance = Vector.ofList vertexCount [source, 0.] + let! distance = Vector.ofList vertexCount [source, 0.] for _ = 1 to vertexCount - 1 do let! step = (distance, matrix) ||> Vector.vxm MinAdd.float diff --git a/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs index 3d3140b5..cdefcd8b 100644 --- a/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs @@ -11,7 +11,6 @@ module internal EWiseAdd = let (ClosedBinaryOp plus) = semiring.Plus let! rawPositions = preparePositions allRows allColumns allValues plus - let! resultRows, resultColumns, resultValues = setPositions allRows allColumns allValues rawPositions return { diff --git a/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/PreparePositions.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/PreparePositions.fs index 9d20adcf..941985f8 100644 --- a/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/PreparePositions.fs +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/PreparePositions.fs @@ -8,7 +8,7 @@ open Microsoft.FSharp.Quotations [] module internal PreparePositions = - let preparePositions (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (plus: Expr<'a -> 'a -> 'a>) : OpenCLEvaluation = opencl { + let preparePositions (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (plus: Expr<'a -> 'a -> 'a>) = opencl { let length = allValues.Length let preparePositions = @@ -21,10 +21,11 @@ module internal PreparePositions = let i = ndRange.GlobalID0 - if i < length - 1 && allRowsBuffer.[i] = allRowsBuffer.[i + 1] && allColumnsBuffer.[i] = allColumnsBuffer.[i + 1] then + if i < length - 1 + && allRowsBuffer.[i] = allRowsBuffer.[i + 1] + && allColumnsBuffer.[i] = allColumnsBuffer.[i + 1] + then rawPositionsBuffer.[i] <- 0 - - //Do not drop explicit zeroes allValuesBuffer.[i + 1] <- (%plus) allValuesBuffer.[i] allValuesBuffer.[i + 1] //Drop explicit zeroes diff --git a/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs index 2e21cf9e..0b9745da 100644 --- a/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs @@ -7,7 +7,7 @@ open GraphBLAS.FSharp.Backend.Common [] module internal SetPositions = - let setPositions (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (positions: int[]) : OpenCLEvaluation = opencl { + let setPositions (allRows: int[]) (allColumns: int[]) (allValues: 'a[]) (positions: int[]) = opencl { let prefixSumArrayLength = positions.Length let setPositions = @@ -23,7 +23,10 @@ module internal SetPositions = let i = ndRange.GlobalID0 - if i = prefixSumArrayLength - 1 || i < prefixSumArrayLength && prefixSumArrayBuffer.[i] <> prefixSumArrayBuffer.[i + 1] then + if i = prefixSumArrayLength - 1 + || i < prefixSumArrayLength + && prefixSumArrayBuffer.[i] <> prefixSumArrayBuffer.[i + 1] + then let index = prefixSumArrayBuffer.[i] resultRowsBuffer.[index] <- allRowsBuffer.[i] diff --git a/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs b/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs new file mode 100644 index 00000000..ea5f6327 --- /dev/null +++ b/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs @@ -0,0 +1,9 @@ +namespace GraphBLAS.FSharp.Backend.CSRMatrix + +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Backend.Common + +module internal Mxv = + () diff --git a/src/GraphBLAS-sharp/Backend/Common/PrefixSum.fs b/src/GraphBLAS-sharp/Backend/Common/PrefixSum.fs index 0016f525..16fb056c 100644 --- a/src/GraphBLAS-sharp/Backend/Common/PrefixSum.fs +++ b/src/GraphBLAS-sharp/Backend/Common/PrefixSum.fs @@ -7,7 +7,7 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation // functions in mudule could be named run\get\if\it\t // like mentioned here https://www.reddit.com/r/fsharp/comments/5kvsyk/modules_or_namespaces/dbt0zf7?utm_source=share&utm_medium=web2x&context=3 module internal PrefixSum = - let scan (inputArray: int[]) (inputArrayLength: int) (vertices: int[]) (verticesLength: int) (totalSum: int[]) : OpenCLEvaluation = opencl { + let scan (inputArray: int[]) (inputArrayLength: int) (vertices: int[]) (verticesLength: int) (totalSum: int[]) = opencl { let workGroupSize = Utils.workGroupSize let scan = @@ -62,7 +62,7 @@ module internal PrefixSum = totalSum } - let update (inputArray: int[]) (inputArrayLength: int) (vertices: int[]) (bunchLength: int) : OpenCLEvaluation = opencl { + let update (inputArray: int[]) (inputArrayLength: int) (vertices: int[]) (bunchLength: int) = opencl { let workGroupSize = Utils.workGroupSize let update = @@ -108,126 +108,5 @@ module internal PrefixSum = verticesLength <- (verticesLength - 1) / workGroupSize + 1 } - // let rec v1 (inputArray: int[]) = - // let outputArray = Array.zeroCreate inputArray.Length - - // if inputArray.Length = 1 then - // let fillOutputArray = - // <@ - // fun (ndRange: _1D) - // (inputArrayBuffer: int[]) - // (outputArrayBuffer: int[]) -> - - // let i = ndRange.GlobalID0 - // outputArrayBuffer.[i] <- inputArrayBuffer.[i] - // @> - - // opencl { - // let binder kernelP = - // let ndRange = _1D(outputArray.Length) - // kernelP - // ndRange - // inputArray - // outputArray - // do! RunCommand fillOutputArray binder - // return outputArray - // } - // else - // let intermediateArray = Array.zeroCreate ((inputArray.Length + 1) / 2) - // let inputArrayLength = inputArray.Length - // let intermediateArrayLength = intermediateArray.Length - - // let fillIntermediateArray = - // <@ - // fun (ndRange: _1D) - // (inputArrayBuffer: int[]) - // (intermediateArrayBuffer: int[]) -> - - // let i = ndRange.GlobalID0 - // if i < intermediateArrayLength then - // if 2 * i + 1 < inputArrayLength then - // intermediateArrayBuffer.[i] <- inputArrayBuffer.[2 * i] + inputArrayBuffer.[2 * i + 1] - // else intermediateArrayBuffer.[i] <- inputArrayBuffer.[2 * i] - // @> - - // let fillIntermediateArray = - // opencl { - // let binder kernelP = - // let ndRange = _1D(workSize intermediateArray.Length, workGroupSize) - // kernelP - // ndRange - // inputArray - // intermediateArray - // do! RunCommand fillIntermediateArray binder - // } - - // let fillOutputArray = - // <@ - // fun (ndRange: _1D) - // (auxiliaryPrefixSumArrayBuffer: int[]) - // (inputArrayBuffer: int[]) - // (outputArrayBuffer: int[]) -> - - // let i = ndRange.GlobalID0 - // if i < inputArrayLength then - // let j = (i - 1) / 2 - // if i % 2 = 0 then - // if i = 0 then outputArrayBuffer.[i] <- inputArrayBuffer.[i] - // else outputArrayBuffer.[i] <- auxiliaryPrefixSumArrayBuffer.[j] + inputArrayBuffer.[i] - // else outputArrayBuffer.[i] <- auxiliaryPrefixSumArrayBuffer.[j] - // @> - - // opencl { - // do! fillIntermediateArray - // let! auxiliaryPrefixSumArray = v1 intermediateArray - - // let binder kernelP = - // let ndRange = _1D(workSize inputArray.Length, workGroupSize) - // kernelP - // ndRange - // auxiliaryPrefixSumArray - // inputArray - // outputArray - // do! RunCommand fillOutputArray binder - - // return outputArray - // } - - // let v2 (inputArray: int[]) = - // let firstIntermediateArray = Array.copy inputArray - // let secondIntermediateArray = Array.copy inputArray - // let outputArrayLength = firstIntermediateArray.Length - - // let updateResult = - // <@ - // fun (ndRange: _1D) - // (offset: int) - // (firstIntermediateArrayBuffer: int[]) - // (secondIntermediateArrayBuffer: int[]) -> - - // let i = ndRange.GlobalID0 - // if i < outputArrayLength then - // if i < offset then firstIntermediateArrayBuffer.[i] <- secondIntermediateArrayBuffer.[i] - // else firstIntermediateArrayBuffer.[i] <- secondIntermediateArrayBuffer.[i] + secondIntermediateArrayBuffer.[i - offset] - // @> - - // let binder offset firstIntermediateArray secondIntermediateArray kernelP = - // let ndRange = _1D(workSize outputArrayLength, workGroupSize) - // kernelP - // ndRange - // offset - // firstIntermediateArray - // secondIntermediateArray - - // let swap (a, b) = (b, a) - // let mutable arrays = firstIntermediateArray, secondIntermediateArray - - // opencl { - // let mutable offset = 1 - // while offset < outputArrayLength do - // arrays <- swap arrays - // do! RunCommand updateResult <| (binder offset <|| arrays) - // offset <- offset * 2 - - // return (fst arrays) - // } + // сделать не inplace prefixSum + // если функции вспомогательные, то лучше сделат их private diff --git a/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs b/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs new file mode 100644 index 00000000..92fff5df --- /dev/null +++ b/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs @@ -0,0 +1,50 @@ +namespace GraphBLAS.FSharp.Backend.Common + +open Brahma.OpenCL +open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic + +module internal RemoveDuplicates = + let run (array: 'a[]) = opencl { + let inputLength = array.Length + + let isUniqueBitmap = + <@ + fun (ndRange: _1D) + (inputArray: 'a[]) + (isUniqueBitmap: int[]) -> + + let i = ndRange.GlobalID0 + if i < inputLength - 1 && inputArray.[i] = inputArray.[i + 1] then + isUniqueBitmap.[i] <- 0 + @> + + let setPositions = + <@ + fun (ndRange: _1D) + (inputArray: 'a[]) + (positions: int[]) + (ouputArray: 'a[]) -> + + let i = ndRange.GlobalID0 + if i < inputLength then + let position = positions.[i] - 1 + ouputArray.[position] <- inputArray.[i] + @> + + let bitmap = Array.create inputLength 1 + do! RunCommand isUniqueBitmap <| fun kernelPrepare -> + let ndRange = _1D(Utils.workSize inputLength, Utils.workGroupSize) + kernelPrepare ndRange array bitmap + + let resultLength = Array.zeroCreate 1 + do! PrefixSum.run bitmap resultLength + let! _ = ToHost resultLength + let resultLength = resultLength.[0] + + let outputArray = Array.zeroCreate resultLength + do! RunCommand setPositions <| fun kernelPrepare -> + let ndRange = _1D(Utils.workSize inputLength, Utils.workGroupSize) + kernelPrepare ndRange array bitmap outputArray + + return outputArray + } diff --git a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj index 83a62827..e27337a1 100644 --- a/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj +++ b/src/GraphBLAS-sharp/GraphBLAS-sharp.fsproj @@ -20,6 +20,8 @@ + + @@ -46,4 +48,4 @@ - + \ No newline at end of file diff --git a/src/GraphBLAS-sharp/IO/MtxReader.fs b/src/GraphBLAS-sharp/IO/MtxReader.fs index 44eda56e..dbc6b443 100644 --- a/src/GraphBLAS-sharp/IO/MtxReader.fs +++ b/src/GraphBLAS-sharp/IO/MtxReader.fs @@ -1,105 +1,105 @@ namespace GraphBLAS.FSharp.IO -open System.IO -open GraphBLAS.FSharp -open System - -type MtxShape = - { - Filename: string - Object: string - Format: string - Field: string - Symmetry: string - Size: int[] - } - - member this.RowCount = this.Size.[0] - member this.ColumnCount = this.Size.[1] - - override this.ToString() = - sprintf "%s" <| Path.GetFileNameWithoutExtension this.Filename - -module MtxReader = - let private readShapeWithReader (streamReader: StreamReader) (pathToFile: string) = - let shape = streamReader.ReadLine().Split(' ') - let object = shape.[1] - let format = shape.[2] - let field = shape.[3] - let symmetry = shape.[4] - - while streamReader.Peek() = int '%' do - streamReader.ReadLine() |> ignore - - let size = - streamReader.ReadLine().Split(' ') - |> Array.map int - - { - Filename = pathToFile |> Path.GetFileName - Object = object - Format = format - Field = field - Symmetry = symmetry - Size = size - } - - let readShapeFromFile (pathToFile: string) = - use streamReader = new StreamReader(pathToFile) - readShapeWithReader streamReader pathToFile - - let private readGenericMatrixFromFile (pathToFile: string) : Matrix<'a> = - use streamReader = new StreamReader(pathToFile) - let shape = readShapeWithReader streamReader pathToFile - - let len = - match shape.Format with - | "array" -> shape.Size.[0] * shape.Size.[1] - | "coordinate" -> shape.Size.[2] - | _ -> failwith "Unsupported matrix format" - - let data = - [0 .. len - 1] - |> List.map (fun _ -> streamReader.ReadLine().Split(' ')) - - let makeCOO () = - let pack x y = (uint64 x <<< 32) ||| (uint64 y) - let unpack x = (int ((x &&& 0xFFFFFFFF0000000UL) >>> 32)), (int (x &&& 0xFFFFFFFUL)) - - data - |> Array.ofList - |> Array.Parallel.map - (fun line -> - let value = Convert.ChangeType(line.[2], typeof<'a>) |> unbox<'a> - struct(pack <| int line.[0] <| int line.[1], value) - ) - |> Array.sortBy (fun struct(packedIndex, _) -> packedIndex) - |> - fun data -> - let rows = Array.zeroCreate data.Length - let cols = Array.zeroCreate data.Length - let values = Array.zeroCreate data.Length - - Array.Parallel.iteri (fun i struct(packedIndex, value) -> - let (rowIdx, columnIdx) = unpack packedIndex - // in mtx indecies start at 1 - rows.[i] <- rowIdx - 1 - cols.[i] <- columnIdx - 1 - values.[i] <- value - ) data - - { - Rows = rows - Columns = cols - Values = values - RowCount = shape.RowCount - ColumnCount = shape.ColumnCount - } - - - match shape.Format with - | "array" -> failwith "Unsupported matrix format" - | "coordinate" -> MatrixCOO <| makeCOO () - - let readRealMatrix (pathToFile: string) : Matrix = - readGenericMatrixFromFile pathToFile +// open System.IO +// open GraphBLAS.FSharp +// open System + +// type MtxShape = +// { +// Filename: string +// Object: string +// Format: string +// Field: string +// Symmetry: string +// Size: int[] +// } + +// member this.RowCount = this.Size.[0] +// member this.ColumnCount = this.Size.[1] + +// override this.ToString() = +// sprintf "%s" <| Path.GetFileNameWithoutExtension this.Filename + +// module MtxReader = +// let private readShapeWithReader (streamReader: StreamReader) (pathToFile: string) = +// let shape = streamReader.ReadLine().Split(' ') +// let object = shape.[1] +// let format = shape.[2] +// let field = shape.[3] +// let symmetry = shape.[4] + +// while streamReader.Peek() = int '%' do +// streamReader.ReadLine() |> ignore + +// let size = +// streamReader.ReadLine().Split(' ') +// |> Array.map int + +// { +// Filename = pathToFile |> Path.GetFileName +// Object = object +// Format = format +// Field = field +// Symmetry = symmetry +// Size = size +// } + +// let readShapeFromFile (pathToFile: string) = +// use streamReader = new StreamReader(pathToFile) +// readShapeWithReader streamReader pathToFile + +// let private readGenericMatrixFromFile (pathToFile: string) : Matrix<'a> = +// use streamReader = new StreamReader(pathToFile) +// let shape = readShapeWithReader streamReader pathToFile + +// let len = +// match shape.Format with +// | "array" -> shape.Size.[0] * shape.Size.[1] +// | "coordinate" -> shape.Size.[2] +// | _ -> failwith "Unsupported matrix format" + +// let data = +// [0 .. len - 1] +// |> List.map (fun _ -> streamReader.ReadLine().Split(' ')) + +// let makeCOO () = +// let pack x y = (uint64 x <<< 32) ||| (uint64 y) +// let unpack x = (int ((x &&& 0xFFFFFFFF0000000UL) >>> 32)), (int (x &&& 0xFFFFFFFUL)) + +// data +// |> Array.ofList +// |> Array.Parallel.map +// (fun line -> +// let value = Convert.ChangeType(line.[2], typeof<'a>) |> unbox<'a> +// struct(pack <| int line.[0] <| int line.[1], value) +// ) +// |> Array.sortBy (fun struct(packedIndex, _) -> packedIndex) +// |> +// fun data -> +// let rows = Array.zeroCreate data.Length +// let cols = Array.zeroCreate data.Length +// let values = Array.zeroCreate data.Length + +// Array.Parallel.iteri (fun i struct(packedIndex, value) -> +// let (rowIdx, columnIdx) = unpack packedIndex +// // in mtx indecies start at 1 +// rows.[i] <- rowIdx - 1 +// cols.[i] <- columnIdx - 1 +// values.[i] <- value +// ) data + +// { +// Rows = rows +// Columns = cols +// Values = values +// RowCount = shape.RowCount +// ColumnCount = shape.ColumnCount +// } + + +// match shape.Format with +// | "array" -> failwith "Unsupported matrix format" +// | "coordinate" -> MatrixCOO <| makeCOO () + +// let readRealMatrix (pathToFile: string) : Matrix = +// readGenericMatrixFromFile pathToFile diff --git a/src/GraphBLAS-sharp/Methods/Matrix.fs b/src/GraphBLAS-sharp/Methods/Matrix.fs index 067018e1..18604c4f 100644 --- a/src/GraphBLAS-sharp/Methods/Matrix.fs +++ b/src/GraphBLAS-sharp/Methods/Matrix.fs @@ -10,19 +10,28 @@ module Matrix = constructors *) - let build (rowCount: int) (columnCount: int) (rows: int[]) (columns: int[]) (values: 'a[]) : Matrix<'a> = + let build (rowCount: int) (columnCount: int) (rows: int[]) (columns: int[]) (values: 'a[]) : GraphblasEvaluation> = failwith "Not Implemented yet" - let ofArray2D (isZero: 'a -> bool) (array: 'a[,]) : Matrix<'a> = + let ofTuples (rowCount: int) (columnCount: int) (tuples: MatrixTuples<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let fromFile (pathToMatrix: string) : Matrix<'a> = + let ofList (rowCount: int) (columnCount: int) (elements: (int * int * 'a) list) : GraphblasEvaluation> = failwith "Not Implemented yet" - let init (rowCount: int) (columnCount: int) (initializer: int -> int -> 'a) : Matrix<'a> = + let ofArray2D (array: 'a[,]) : GraphblasEvaluation> = failwith "Not Implemented yet" - let zeroCreate (rowCount: int) (columnCount: int) : Matrix<'a> = + let init (rowCount: int) (columnCount: int) (initializer: int -> int -> 'a) : GraphblasEvaluation> = + failwith "Not Implemented yet" + + let create (rowCount: int) (columnCount: int) (value: 'a) : GraphblasEvaluation> = + failwith "Not Implemented yet" + + let zeroCreate (rowCount: int) (columnCount: int) : GraphblasEvaluation> = + failwith "Not Implemented yet" + + let fromFile (pathToMatrix: string) : GraphblasEvaluation> = failwith "Not Implemented yet" (* @@ -46,7 +55,8 @@ module Matrix = let mask (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let complemented (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let switchTo (matrixType: MatrixType) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let thin (isZero: 'a -> bool) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let switch (matrixType: MatrixType) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let synchronize (matrix: Matrix<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" (* @@ -130,7 +140,7 @@ module Matrix = failwith "Not Implemented yet" (* - operations + closed operations *) let mxm (semiring: ISemiring<'a>) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" @@ -167,6 +177,12 @@ module Matrix = let reduceColsWithMask (monoid: IMonoid<'a>) (mask: Mask1D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let kroneckerWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + (* + unclosed operations + *) + + // Должны принимать либо BinaryOp, либо {|BinaryOp; BinaryOp|} с соответствующей семантикой + // ждём тайпклассов чтобы можно было вызывать synchronize для всех объектов, // для которых он реализован, не привязывая реализацию к классу (как стратегия) [] diff --git a/src/GraphBLAS-sharp/Methods/Vector.fs b/src/GraphBLAS-sharp/Methods/Vector.fs index 2c2d24ef..063b609f 100644 --- a/src/GraphBLAS-sharp/Methods/Vector.fs +++ b/src/GraphBLAS-sharp/Methods/Vector.fs @@ -9,29 +9,26 @@ module Vector = constructors *) - let build (size: int) (indices: int[]) (values: int[]) : Vector<'a> = + let build (size: int) (indices: int[]) (values: int[]) : GraphblasEvaluation> = failwith "Not Implemented yet" - let ofList (size: int) (elements: (int * 'a) list) : Vector<'a> = + let ofTuples (size: int) (tuples: VectorTuples<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let ofArray (isZero: 'a -> bool) (array: 'a[]) : Vector<'a> = + let ofList (size: int) (elements: (int * 'a) list) : GraphblasEvaluation> = failwith "Not Implemented yet" - let init (size: int) (initializer: int -> 'a) : Vector<'a> = + let ofArray (array: 'a[]) : GraphblasEvaluation> = failwith "Not Implemented yet" - // Можно сделать явный метод makeSparse isZero, который бы делал плотные векторы разреженными - let create (size: int) (value: 'a) : Vector<'a> = + let init (size: int) (initializer: int -> 'a) : GraphblasEvaluation> = failwith "Not Implemented yet" - // можно не указывать явный ноль, тк 'a -- структура, для которого есть unchecked.defaultof, - // а массивы с с помощью zeroCreate создать - let zeroCreate (size: int) (zero: 'a) : Vector<'a> = + let create (size: int) (value: 'a) : GraphblasEvaluation> = failwith "Not Implemented yet" - // let makeSparse (isZero: 'a -> bool) (vector: Vector<'a>) : Vector<'a> = - // failwith "Not Implemented yet" + let zeroCreate (size: int) : GraphblasEvaluation> = + failwith "Not Implemented yet" (* methods @@ -45,7 +42,8 @@ module Vector = let tuples (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let mask (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" let complemented (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" - let switchTo (vectorType: VectorType) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let thin (isZero: 'a -> bool) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let switch (vectorType: VectorType) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let synchronize (vector: Vector<'a>) : GraphblasEvaluation = failwith "Not Implemented yet" (* diff --git a/src/GraphBLAS-sharp/Objects/Matrix.fs b/src/GraphBLAS-sharp/Objects/Matrix.fs index 14d4bd89..9237830e 100644 --- a/src/GraphBLAS-sharp/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp/Objects/Matrix.fs @@ -5,7 +5,7 @@ type MatrixType = | CSR | COO -type Matrix<'a> = +type Matrix<'a when 'a : struct> = | MatrixCSR of CSRMatrix<'a> | MatrixCOO of COOMatrix<'a> diff --git a/src/GraphBLAS-sharp/Objects/Vector.fs b/src/GraphBLAS-sharp/Objects/Vector.fs index 69094fbb..129d78ad 100644 --- a/src/GraphBLAS-sharp/Objects/Vector.fs +++ b/src/GraphBLAS-sharp/Objects/Vector.fs @@ -2,11 +2,11 @@ namespace GraphBLAS.FSharp type VectorType = | COO - | Dense + | Bitmap -type Vector<'a> = +type Vector<'a when 'a : struct> = | VectorCOO of COOVector<'a> - | VectorDense of ArrayVector<'a> + | VectorBitmap of BitmapVector<'a> and COOVector<'a> = { @@ -15,8 +15,9 @@ and COOVector<'a> = Values: 'a[] } -and ArrayVector<'a> = +and BitmapVector<'a> = { + Bitmap: bool[] Values: 'a[] } diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs index 36c111be..17d257c0 100644 --- a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs @@ -264,7 +264,14 @@ let testFixtures case = [ case |> checkCorrectnessGeneric case.ClContext (||) (<>) not AnyAll.bool - |> testPropertyWithConfigStdGen (355610228, 296870493) config "Correctness on both empty matrices" + |> testPropertyWithConfigStdGen + (355610228, 296870493) + { FsCheckConfig.defaultConfig with + arbitrary = [typeof] + maxTest = 10 + startSize = 0 + } + "Correctness on both empty matrices" ] let tests = From dec5ba87fc6708115c03683b2851224e84a4f322 Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Sun, 28 Mar 2021 22:32:26 +0300 Subject: [PATCH 15/16] Add half of mxv algo; add fair algebraic structures --- src/GraphBLAS-sharp/AlgebraicStructures.fs | 47 ++++++++- .../Backend/COOMatrix/EWiseAdd.fs | 8 +- .../COOMatrix/Utilities/SetPositions.fs | 2 +- .../COOVector/Utilities/SetPositions.fs | 2 +- src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs | 66 ++++++++++++- src/GraphBLAS-sharp/Backend/Common/Copy.fs | 15 +-- .../Backend/Common/PrefixSum.fs | 59 +++++------- .../Backend/Common/RemoveDuplicates.fs | 2 +- src/GraphBLAS-sharp/GraphblasEvaluation.fs | 4 +- src/GraphBLAS-sharp/Helpers.fs | 25 ----- src/GraphBLAS-sharp/Methods/Matrix.fs | 19 +++- src/GraphBLAS-sharp/Methods/Vector.fs | 5 +- src/GraphBLAS-sharp/Objects/Matrix.fs | 1 + src/GraphBLAS-sharp/Predefined/Monoids/Add.fs | 65 ++++++------- src/GraphBLAS-sharp/Predefined/Monoids/Any.fs | 8 +- src/GraphBLAS-sharp/Predefined/Monoids/Min.fs | 16 ++-- .../Predefined/Semirings/AddMult.fs | 63 ++++++------ .../Predefined/Semirings/AnyAll.fs | 9 +- .../Predefined/Semirings/MinAdd.fs | 9 +- tests/GraphBLAS-sharp.Tests/Common.fs | 59 ++++++++++++ .../GraphBLAS-sharp.Tests.fsproj | 3 +- .../OperationsTests/EWiseAddTests.fs | 96 ++++--------------- .../OperationsTests/MxvTests.fs | 75 +++++++++++++++ 23 files changed, 407 insertions(+), 251 deletions(-) create mode 100644 tests/GraphBLAS-sharp.Tests/OperationsTests/MxvTests.fs diff --git a/src/GraphBLAS-sharp/AlgebraicStructures.fs b/src/GraphBLAS-sharp/AlgebraicStructures.fs index d3e320f4..2c51068c 100644 --- a/src/GraphBLAS-sharp/AlgebraicStructures.fs +++ b/src/GraphBLAS-sharp/AlgebraicStructures.fs @@ -8,19 +8,58 @@ type BinaryOp<'a, 'b, 'c> = BinaryOp of Expr<'a -> 'b -> 'c> type ClosedUnaryOp<'a> = ClosedUnaryOp of Expr<'a -> 'a> type ClosedBinaryOp<'a> = ClosedBinaryOp of Expr<'a -> 'a -> 'a> -// associative closed bin op (magma with associative) +/// Magma with associative (magma is set with closed binary operator) type ISemigroup<'a> = - abstract Plus: ClosedBinaryOp<'a> + abstract Op: ClosedBinaryOp<'a> /// Semigroup with identity type IMonoid<'a> = - inherit ISemigroup<'a> + abstract Plus: ClosedBinaryOp<'a> abstract Zero: 'a +/// Monoid with associative binary operator, +/// for wich Zero is annihilator type ISemiring<'a> = - inherit IMonoid<'a> + abstract Zero: 'a + abstract Plus: ClosedBinaryOp<'a> abstract Times: ClosedBinaryOp<'a> +type Semigroup<'a> = + { + AssociativeOp: ClosedBinaryOp<'a> + } + + interface ISemigroup<'a> with + member this.Op = this.AssociativeOp + +type Monoid<'a> = + { + AssociativeOp: ClosedBinaryOp<'a> + Identity: 'a + } + + interface ISemigroup<'a> with + member this.Op = this.AssociativeOp + + interface IMonoid<'a> with + member this.Plus = this.AssociativeOp + member this.Zero = this.Identity + +type Semiring<'a> = + { + PlusMonoid: Monoid<'a> + TimesSemigroup: Semigroup<'a> + } + + interface IMonoid<'a> with + member this.Zero = this.PlusMonoid.Identity + member this.Plus = this.PlusMonoid.AssociativeOp + + interface ISemiring<'a> with + member this.Times = this.TimesSemigroup.AssociativeOp + member this.Zero = this.PlusMonoid.Identity + member this.Plus = this.PlusMonoid.AssociativeOp + (* мотивация: хотим, чтобы ноль был нулем (даже если он явно в матрице хранится) diff --git a/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs index cdefcd8b..fe9467c0 100644 --- a/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/EWiseAdd.fs @@ -6,10 +6,10 @@ open GraphBLAS.FSharp.Backend.Common open GraphBLAS.FSharp.Backend.COOMatrix.Utilities module internal EWiseAdd = - let private runNonEmpty (matrixLeft: COOMatrix<'a>) (matrixRight: COOMatrix<'a>) (mask: Mask2D option) (semiring: ISemiring<'a>) = opencl { + let private runNonEmpty (matrixLeft: COOMatrix<'a>) (matrixRight: COOMatrix<'a>) (mask: Mask2D option) (monoid: IMonoid<'a>) = opencl { let! allRows, allColumns, allValues = merge matrixLeft matrixRight mask - let (ClosedBinaryOp plus) = semiring.Plus + let (ClosedBinaryOp plus) = monoid.Plus let! rawPositions = preparePositions allRows allColumns allValues plus let! resultRows, resultColumns, resultValues = setPositions allRows allColumns allValues rawPositions @@ -22,7 +22,7 @@ module internal EWiseAdd = } } - let run (matrixLeft: COOMatrix<'a>) (matrixRight: COOMatrix<'a>) (mask: Mask2D option) (semiring: ISemiring<'a>) = + let run (matrixLeft: COOMatrix<'a>) (matrixRight: COOMatrix<'a>) (mask: Mask2D option) (monoid: IMonoid<'a>) = if matrixLeft.Values.Length = 0 then opencl { let! resultRows = Copy.run matrixRight.Rows @@ -54,4 +54,4 @@ module internal EWiseAdd = } else - runNonEmpty matrixLeft matrixRight mask semiring + runNonEmpty matrixLeft matrixRight mask monoid diff --git a/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs index 0b9745da..a1de1517 100644 --- a/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs +++ b/src/GraphBLAS-sharp/Backend/COOMatrix/Utilities/SetPositions.fs @@ -36,7 +36,7 @@ module internal SetPositions = let resultLength = Array.zeroCreate 1 - do! PrefixSum.run positions resultLength + do! PrefixSum.runInplace positions resultLength let! _ = ToHost resultLength let resultLength = resultLength.[0] diff --git a/src/GraphBLAS-sharp/Backend/COOVector/Utilities/SetPositions.fs b/src/GraphBLAS-sharp/Backend/COOVector/Utilities/SetPositions.fs index 835baf14..8599ffae 100644 --- a/src/GraphBLAS-sharp/Backend/COOVector/Utilities/SetPositions.fs +++ b/src/GraphBLAS-sharp/Backend/COOVector/Utilities/SetPositions.fs @@ -30,7 +30,7 @@ module internal SetPositions = let resultLength = Array.zeroCreate 1 - do! PrefixSum.run positions resultLength + do! PrefixSum.runInplace positions resultLength let! _ = ToHost resultLength let resultLength = resultLength.[0] diff --git a/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs b/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs index ea5f6327..8d88af31 100644 --- a/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs +++ b/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs @@ -4,6 +4,70 @@ open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation open GraphBLAS.FSharp open GraphBLAS.FSharp.Backend.Common +open Brahma.OpenCL module internal Mxv = - () + let pcsr (matrix: CSRMatrix<'a>) (vector: BitmapVector<'a>) mask (semiring: ISemiring<'a>) = opencl { + let (ClosedBinaryOp plus) = semiring.Plus + let (ClosedBinaryOp times) = semiring.Times + + let matrixLength = matrix.Values.Length + + let kernel1 = + <@ + fun (ndRange: _1D) + (matrixColumns: int[]) + (matrixValues: 'a[]) + (vectorBitmap: bool[]) + (vectorValues: 'a[]) + (intermediateArray: 'a[]) -> + + let i = ndRange.GlobalID0 + if i < matrixLength && vectorBitmap.[i] then + let value = matrixValues.[i] + let column = matrixColumns.[i] + intermediateArray.[i] <- (%times) value vectorValues.[column] + @> + + let kernel2 = + <@ + fun (ndRange: _1D) + (intermediateArray: 'a[]) + (matrixPtr: int[]) + (outputVector: 'a[]) -> + + let gid = ndRange.GlobalID0 + let lid = ndRange.LocalID0 + + let localPtr = localArray (Utils.workGroupSize + 1) + localPtr.[lid] <- matrixPtr.[gid] + if lid = 0 then + localPtr.[Utils.workGroupSize] <- matrixPtr.[gid + Utils.workGroupSize] + barrier () + @> + + let intermediateArray = Array.zeroCreate<'a> matrixLength + do! RunCommand kernel1 <| fun kernelPrepare -> + let range = _1D(Utils.workSize matrixLength, Utils.workGroupSize) + kernelPrepare + range + matrix.ColumnIndices + matrix.Values + vector.Bitmap + vector.Values + intermediateArray + + let outputVector = Array.zeroCreate<'a> matrix.RowCount + do! RunCommand kernel2 <| fun kernelPrepare -> + let range = _1D(Utils.workSize matrixLength, Utils.workGroupSize) + kernelPrepare + range + intermediateArray + matrix.RowPointers + outputVector + + return { + Bitmap = vector.Bitmap + Values = outputVector + } + } diff --git a/src/GraphBLAS-sharp/Backend/Common/Copy.fs b/src/GraphBLAS-sharp/Backend/Common/Copy.fs index deb2ff0c..7e7ff2ce 100644 --- a/src/GraphBLAS-sharp/Backend/Common/Copy.fs +++ b/src/GraphBLAS-sharp/Backend/Common/Copy.fs @@ -2,10 +2,15 @@ namespace GraphBLAS.FSharp.Backend.Common open Brahma.OpenCL open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Utils -module internal Copy = - let runNotEmpty (inputArray: 'a[]) = opencl { +module internal rec Copy = + let run (inputArray: 'a[]) = + if inputArray.Length = 0 then + opencl { return [||] } + else + runNotEmpty inputArray + + let private runNotEmpty (inputArray: 'a[]) = opencl { let inputArrayLength = inputArray.Length let copy = <@ @@ -21,9 +26,7 @@ module internal Copy = let outputArray = Array.zeroCreate inputArray.Length do! RunCommand copy <| fun kernelPrepare -> - let ndRange = _1D(workSize inputArray.Length, workGroupSize) + let ndRange = _1D(Utils.workSize inputArray.Length, Utils.workGroupSize) kernelPrepare ndRange inputArray outputArray return outputArray } - - let run (inputArray: 'a[]) = if inputArray.Length = 0 then opencl { return [||] } else runNotEmpty inputArray diff --git a/src/GraphBLAS-sharp/Backend/Common/PrefixSum.fs b/src/GraphBLAS-sharp/Backend/Common/PrefixSum.fs index 16fb056c..b3902c7f 100644 --- a/src/GraphBLAS-sharp/Backend/Common/PrefixSum.fs +++ b/src/GraphBLAS-sharp/Backend/Common/PrefixSum.fs @@ -2,12 +2,32 @@ namespace GraphBLAS.FSharp.Backend.Common open Brahma.OpenCL open Brahma.FSharp.OpenCL.WorkflowBuilder.Basic -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation -// functions in mudule could be named run\get\if\it\t -// like mentioned here https://www.reddit.com/r/fsharp/comments/5kvsyk/modules_or_namespaces/dbt0zf7?utm_source=share&utm_medium=web2x&context=3 -module internal PrefixSum = - let scan (inputArray: int[]) (inputArrayLength: int) (vertices: int[]) (verticesLength: int) (totalSum: int[]) = opencl { +module internal rec PrefixSum = + let runInplace (inputArray: int[]) (totalSum: int[]) = opencl { + let workGroupSize = Utils.workGroupSize + + let firstVertices = Array.zeroCreate <| (inputArray.Length - 1) / workGroupSize + 1 + let secondVertices = Array.zeroCreate <| (firstVertices.Length - 1) / workGroupSize + 1 + let mutable verticesArrays = firstVertices, secondVertices + let swap (a, b) = (b, a) + + let mutable verticesLength = (inputArray.Length - 1) / workGroupSize + 1 + let mutable bunchLength = workGroupSize + + do! scan inputArray inputArray.Length (fst verticesArrays) verticesLength totalSum + while verticesLength > 1 do + let fstVertices = fst verticesArrays + let sndVertices = snd verticesArrays + do! scan fstVertices verticesLength sndVertices ((verticesLength - 1) / workGroupSize + 1) totalSum + do! update inputArray inputArray.Length fstVertices bunchLength + + bunchLength <- bunchLength * workGroupSize + verticesArrays <- swap verticesArrays + verticesLength <- (verticesLength - 1) / workGroupSize + 1 + } + + let private scan (inputArray: int[]) (inputArrayLength: int) (vertices: int[]) (verticesLength: int) (totalSum: int[]) = opencl { let workGroupSize = Utils.workGroupSize let scan = @@ -62,7 +82,7 @@ module internal PrefixSum = totalSum } - let update (inputArray: int[]) (inputArrayLength: int) (vertices: int[]) (bunchLength: int) = opencl { + let private update (inputArray: int[]) (inputArrayLength: int) (vertices: int[]) (bunchLength: int) = opencl { let workGroupSize = Utils.workGroupSize let update = @@ -83,30 +103,3 @@ module internal PrefixSum = inputArray vertices } - - // Changes received arrays - let run (inputArray: int[]) (totalSum: int[]) = opencl { - let workGroupSize = Utils.workGroupSize - - let firstVertices = Array.zeroCreate <| (inputArray.Length - 1) / workGroupSize + 1 - let secondVertices = Array.zeroCreate <| (firstVertices.Length - 1) / workGroupSize + 1 - let mutable verticesArrays = firstVertices, secondVertices - let swap (a, b) = (b, a) - - let mutable verticesLength = (inputArray.Length - 1) / workGroupSize + 1 - let mutable bunchLength = workGroupSize - - do! scan inputArray inputArray.Length (fst verticesArrays) verticesLength totalSum - while verticesLength > 1 do - let fstVertices = fst verticesArrays - let sndVertices = snd verticesArrays - do! scan fstVertices verticesLength sndVertices ((verticesLength - 1) / workGroupSize + 1) totalSum - do! update inputArray inputArray.Length fstVertices bunchLength - - bunchLength <- bunchLength * workGroupSize - verticesArrays <- swap verticesArrays - verticesLength <- (verticesLength - 1) / workGroupSize + 1 - } - - // сделать не inplace prefixSum - // если функции вспомогательные, то лучше сделат их private diff --git a/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs b/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs index 92fff5df..c49e75ca 100644 --- a/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs +++ b/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs @@ -37,7 +37,7 @@ module internal RemoveDuplicates = kernelPrepare ndRange array bitmap let resultLength = Array.zeroCreate 1 - do! PrefixSum.run bitmap resultLength + do! PrefixSum.runInplace bitmap resultLength let! _ = ToHost resultLength let resultLength = resultLength.[0] diff --git a/src/GraphBLAS-sharp/GraphblasEvaluation.fs b/src/GraphBLAS-sharp/GraphblasEvaluation.fs index bd73867c..5e3e05bc 100644 --- a/src/GraphBLAS-sharp/GraphblasEvaluation.fs +++ b/src/GraphBLAS-sharp/GraphblasEvaluation.fs @@ -12,9 +12,7 @@ type GraphblasContext = type GraphblasEvaluation<'a> = EvalGB of (GraphblasContext -> 'a) module EvalGB = - let defaultEnv = { - ClContext = OpenCLEvaluationContext() - } + let defaultEnv = { ClContext = OpenCLEvaluationContext() } let private runCl env (OpenCLEvaluation f) = f env diff --git a/src/GraphBLAS-sharp/Helpers.fs b/src/GraphBLAS-sharp/Helpers.fs index a1377113..7acefed3 100644 --- a/src/GraphBLAS-sharp/Helpers.fs +++ b/src/GraphBLAS-sharp/Helpers.fs @@ -1,32 +1,7 @@ namespace GraphBLAS.FSharp -open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation -open OpenCL.Net -open System.Text.RegularExpressions - [] module Helpers = let inline (!>) (x: ^a) : ^b = (^a: (static member op_Implicit : ^a -> ^b) x) let inline (^) f x = f x - -module Utils = - let avaliableContexts (platformRegex: string) = - let mutable e = ErrorCode.Unknown - Cl.GetPlatformIDs &e - |> Array.collect (fun platform -> Cl.GetDeviceIDs(platform, DeviceType.All, &e)) - |> Seq.ofArray - |> Seq.distinctBy (fun device -> Cl.GetDeviceInfo(device, DeviceInfo.Name, &e).ToString()) - |> Seq.filter - (fun device -> - let platform = Cl.GetDeviceInfo(device, DeviceInfo.Platform, &e).CastTo() - let platformName = Cl.GetPlatformInfo(platform, PlatformInfo.Name, &e).ToString() - (Regex platformRegex).IsMatch platformName - ) - |> Seq.map - (fun device -> - let platform = Cl.GetDeviceInfo(device, DeviceInfo.Platform, &e).CastTo() - let platformName = Cl.GetPlatformInfo(platform, PlatformInfo.Name, &e).ToString() - let deviceType = Cl.GetDeviceInfo(device, DeviceInfo.Type, &e).CastTo() - OpenCLEvaluationContext(platformName, deviceType) - ) diff --git a/src/GraphBLAS-sharp/Methods/Matrix.fs b/src/GraphBLAS-sharp/Methods/Matrix.fs index 18604c4f..4a637079 100644 --- a/src/GraphBLAS-sharp/Methods/Matrix.fs +++ b/src/GraphBLAS-sharp/Methods/Matrix.fs @@ -144,14 +144,25 @@ module Matrix = *) let mxm (semiring: ISemiring<'a>) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let mxv (semiring: ISemiring<'a>) (matrix: Matrix<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let eWiseAdd (semiring: ISemiring<'a>) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = + let mxv (semiring: ISemiring<'a>) (matrix: Matrix<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = + let operationResult = + match matrix, vector with + | MatrixCSR matrix, VectorBitmap vector -> + opencl { + let! result = CSRMatrix.Mxv.pcsr matrix vector None semiring + return VectorBitmap result + } + | _ -> failwith "Not Implemented" + + graphblas { return! EvalGB.fromCl operationResult } + + let eWiseAdd (monoid: IMonoid<'a>) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = let operationResult = match leftMatrix, rightMatrix with | MatrixCOO left, MatrixCOO right -> opencl { - let! result = COOMatrix.EWiseAdd.run left right None semiring + let! result = COOMatrix.EWiseAdd.run left right None monoid return MatrixCOO result } | _ -> failwith "Not Implemented" @@ -169,7 +180,7 @@ module Matrix = let mxmWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let mxvWithMask (semiring: ISemiring<'a>) (mask: Mask1D) (matrix: Matrix<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let eWiseAddWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseAddWithMask (monoid: IMonoid<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let eWiseMultWithMask (semiring: ISemiring<'a>) (mask: Mask2D) (leftMatrix: Matrix<'a>) (rightMatrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let applyWithMask (mapper: UnaryOp<'a, 'b>) (mask: Mask2D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let selectWithMask (predicate: UnaryOp) (mask: Mask2D) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" diff --git a/src/GraphBLAS-sharp/Methods/Vector.fs b/src/GraphBLAS-sharp/Methods/Vector.fs index 063b609f..588c0975 100644 --- a/src/GraphBLAS-sharp/Methods/Vector.fs +++ b/src/GraphBLAS-sharp/Methods/Vector.fs @@ -83,14 +83,15 @@ module Vector = *) let vxm (semiring: ISemiring<'a>) (vector: Vector<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let eWiseAdd (semiring: ISemiring<'a>) (mask: Mask1D option) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseAdd (monoid: IMonoid<'a>) (mask: Mask1D option) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let eWiseMult (semiring: ISemiring<'a>) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let apply (mapper: UnaryOp<'a, 'b>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let select (predicate: UnaryOp<'a, bool>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let reduce (monoid: IMonoid<'a>) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let vxmWithMask (semiring: ISemiring<'a>) (mask: Mask1D) (vector: Vector<'a>) (matrix: Matrix<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" - let eWiseAddWithMask (semiring: ISemiring<'a>) (mask: Mask1D) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseAddWithMask (monoid: IMonoid<'a>) (mask: Mask1D) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" + let eWiseMultWithMask (semiring: ISemiring<'a>) (mask: Mask1D) (leftVector: Vector<'a>) (rightVector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let applyWithMask (mapper: UnaryOp<'a, 'b>) (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" let selectWithMask (predicate: UnaryOp<'a, bool>) (mask: Mask1D) (vector: Vector<'a>) : GraphblasEvaluation> = failwith "Not Implemented yet" diff --git a/src/GraphBLAS-sharp/Objects/Matrix.fs b/src/GraphBLAS-sharp/Objects/Matrix.fs index 9237830e..b35d039b 100644 --- a/src/GraphBLAS-sharp/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp/Objects/Matrix.fs @@ -11,6 +11,7 @@ type Matrix<'a when 'a : struct> = and CSRMatrix<'a> = { + RowCount: int ColumnCount: int RowPointers: int[] ColumnIndices: int[] diff --git a/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs b/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs index 8a2e2a9f..9dd3dc88 100644 --- a/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs +++ b/src/GraphBLAS-sharp/Predefined/Monoids/Add.fs @@ -3,52 +3,51 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module Add = - let int = - { new IMonoid with - member this.Zero = 0 - member this.Plus = ClosedBinaryOp <@ (+) @> + let int: Monoid = + { + AssociativeOp = ClosedBinaryOp <@ (+) @> + Identity = 0 } - let float = - { new IMonoid with - member this.Zero = 0. - member this.Plus = ClosedBinaryOp <@ (+) @> + let float: Monoid = + { + AssociativeOp = ClosedBinaryOp <@ (+) @> + Identity = 0. } - let float32 = - { new IMonoid with - member this.Zero = 0.f - member this.Plus = ClosedBinaryOp <@ (+) @> + let float32: Monoid = + { + AssociativeOp = ClosedBinaryOp <@ (+) @> + Identity = 0.f } - let sbyte = - { new IMonoid with - member this.Zero = 0y - member this.Plus = ClosedBinaryOp <@ (+) @> + let sbyte: Monoid = + { + AssociativeOp = ClosedBinaryOp <@ (+) @> + Identity = 0y } - let byte = - { new IMonoid with - member this.Zero = 0uy - member this.Plus = ClosedBinaryOp <@ (+) @> + let byte: Monoid = + { + AssociativeOp = ClosedBinaryOp <@ (+) @> + Identity = 0uy } - let int16 = - { new IMonoid with - member this.Zero = 0s - member this.Plus = ClosedBinaryOp <@ (+) @> + let int16: Monoid = + { + AssociativeOp = ClosedBinaryOp <@ (+) @> + Identity = 0s } - let uint16 = - { new IMonoid with - member this.Zero = 0us - member this.Plus = ClosedBinaryOp <@ (+) @> + let uint16: Monoid = + { + AssociativeOp = ClosedBinaryOp <@ (+) @> + Identity = 0us } - let monoidicFloat = - { new IMonoid> with - member this.Zero = Zero - member this.Plus = + let monoidicFloat: Monoid> = + { + AssociativeOp = <@ fun x y -> match x, y with @@ -59,4 +58,6 @@ module Add = | Zero, Just y -> Just y | Zero, Zero -> Zero @> |> ClosedBinaryOp + + Identity = Zero } diff --git a/src/GraphBLAS-sharp/Predefined/Monoids/Any.fs b/src/GraphBLAS-sharp/Predefined/Monoids/Any.fs index c17ad46b..cf8c7980 100644 --- a/src/GraphBLAS-sharp/Predefined/Monoids/Any.fs +++ b/src/GraphBLAS-sharp/Predefined/Monoids/Any.fs @@ -3,8 +3,8 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module Any = - let bool = - { new IMonoid with - member this.Zero = false - member this.Plus = ClosedBinaryOp <@ ( || ) @> + let bool: Monoid = + { + AssociativeOp = ClosedBinaryOp <@ (||) @> + Identity = false } diff --git a/src/GraphBLAS-sharp/Predefined/Monoids/Min.fs b/src/GraphBLAS-sharp/Predefined/Monoids/Min.fs index 0f73c28e..c69fd809 100644 --- a/src/GraphBLAS-sharp/Predefined/Monoids/Min.fs +++ b/src/GraphBLAS-sharp/Predefined/Monoids/Min.fs @@ -3,14 +3,14 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module Min = - let int = - { new IMonoid with - member this.Zero = System.Int32.MaxValue - member this.Plus = ClosedBinaryOp <@ fun x y -> System.Math.Min(x, y) @> + let int: Monoid = + { + AssociativeOp = ClosedBinaryOp <@ fun x y -> System.Math.Min(x, y) @> + Identity = System.Int32.MaxValue } - let float = - { new IMonoid with - member this.Zero = System.Double.PositiveInfinity - member this.Plus = ClosedBinaryOp <@ fun x y -> System.Math.Min(x, y) @> + let float: Monoid = + { + AssociativeOp = ClosedBinaryOp <@ fun x y -> System.Math.Min(x, y) @> + Identity = System.Double.PositiveInfinity } diff --git a/src/GraphBLAS-sharp/Predefined/Semirings/AddMult.fs b/src/GraphBLAS-sharp/Predefined/Semirings/AddMult.fs index c06d0e9f..f0d01598 100644 --- a/src/GraphBLAS-sharp/Predefined/Semirings/AddMult.fs +++ b/src/GraphBLAS-sharp/Predefined/Semirings/AddMult.fs @@ -3,51 +3,44 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module AddMult = - let int = - { new ISemiring with - member this.Zero = Add.int.Zero - member this.Plus = Add.int.Plus - member this.Times = ClosedBinaryOp <@ (*) @> + let int: Semiring = + { + PlusMonoid = Add.int + TimesSemigroup = { AssociativeOp = ClosedBinaryOp <@ (*) @> } } - let float = - { new ISemiring with - member this.Zero = Add.float.Zero - member this.Plus = Add.float.Plus - member this.Times = ClosedBinaryOp <@ (*) @> + let float: Semiring = + { + PlusMonoid = Add.float + TimesSemigroup = { AssociativeOp = ClosedBinaryOp <@ (*) @> } } - let float32 = - { new ISemiring with - member this.Zero = Add.float32.Zero - member this.Plus = Add.float32.Plus - member this.Times = ClosedBinaryOp <@ (*) @> + let float32: Semiring = + { + PlusMonoid = Add.float32 + TimesSemigroup = { AssociativeOp = ClosedBinaryOp <@ (*) @> } } - let sbyte = - { new ISemiring with - member this.Zero = Add.sbyte.Zero - member this.Plus = Add.sbyte.Plus - member this.Times = ClosedBinaryOp <@ (*) @> + let sbyte: Semiring = + { + PlusMonoid = Add.sbyte + TimesSemigroup = { AssociativeOp = ClosedBinaryOp <@ (*) @> } } - let byte = - { new ISemiring with - member this.Zero = Add.byte.Zero - member this.Plus = Add.byte.Plus - member this.Times = ClosedBinaryOp <@ (*) @> + let byte: Semiring = + { + PlusMonoid = Add.byte + TimesSemigroup = { AssociativeOp = ClosedBinaryOp <@ (*) @> } } - let int16 = - { new ISemiring with - member this.Zero = Add.int16.Zero - member this.Plus = Add.int16.Plus - member this.Times = ClosedBinaryOp <@ (*) @> + let int16: Semiring = + { + PlusMonoid = Add.int16 + TimesSemigroup = { AssociativeOp = ClosedBinaryOp <@ (*) @> } } - let uint16 = - { new ISemiring with - member this.Zero = Add.uint16.Zero - member this.Plus = Add.uint16.Plus - member this.Times = ClosedBinaryOp <@ (*) @> + let uint16: Semiring = + { + PlusMonoid = Add.uint16 + TimesSemigroup = { AssociativeOp = ClosedBinaryOp <@ (*) @> } } diff --git a/src/GraphBLAS-sharp/Predefined/Semirings/AnyAll.fs b/src/GraphBLAS-sharp/Predefined/Semirings/AnyAll.fs index 3941acf9..bd57b906 100644 --- a/src/GraphBLAS-sharp/Predefined/Semirings/AnyAll.fs +++ b/src/GraphBLAS-sharp/Predefined/Semirings/AnyAll.fs @@ -3,9 +3,8 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module AnyAll = - let bool = - { new ISemiring with - member this.Zero = Any.bool.Zero - member this.Plus = Any.bool.Plus - member this.Times = ClosedBinaryOp <@ ( && ) @> + let bool: Semiring = + { + PlusMonoid = Any.bool + TimesSemigroup = { AssociativeOp = ClosedBinaryOp <@ (&&) @> } } diff --git a/src/GraphBLAS-sharp/Predefined/Semirings/MinAdd.fs b/src/GraphBLAS-sharp/Predefined/Semirings/MinAdd.fs index 2e0d443d..56590f66 100644 --- a/src/GraphBLAS-sharp/Predefined/Semirings/MinAdd.fs +++ b/src/GraphBLAS-sharp/Predefined/Semirings/MinAdd.fs @@ -3,9 +3,8 @@ namespace GraphBLAS.FSharp.Predefined open GraphBLAS.FSharp module MinAdd = - let float = - { new ISemiring with - member this.Zero = Min.float.Zero - member this.Plus = Min.float.Plus - member this.Times = ClosedBinaryOp <@ (+) @> + let float: Semiring = + { + PlusMonoid = Min.float + TimesSemigroup = { AssociativeOp = ClosedBinaryOp <@ (+) @> } } diff --git a/tests/GraphBLAS-sharp.Tests/Common.fs b/tests/GraphBLAS-sharp.Tests/Common.fs index 0aefd725..667080f2 100644 --- a/tests/GraphBLAS-sharp.Tests/Common.fs +++ b/tests/GraphBLAS-sharp.Tests/Common.fs @@ -5,8 +5,14 @@ open System open GraphBLAS.FSharp open Microsoft.FSharp.Reflection open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open OpenCL.Net +open Expecto.Logging +open Expecto.Logging.Message +open System.Text.RegularExpressions module Generators = + let logger = Log.create "Generators" + let dimension2DGenerator = Gen.sized <| fun size -> Gen.choose (1, size |> float |> sqrt |> int) @@ -17,6 +23,30 @@ module Generators = Gen.choose (1, size |> float |> sqrt |> int) |> Gen.three + let genericSparseGenerator zero valuesGen handler = + let maxSparsity = 100 + let sparsityGen = Gen.choose (0, maxSparsity) + let genWithSparsity sparseValuesGenProvider = + gen { + let! sparsity = sparsityGen + + logger.debug ( + eventX "Sparcity is {sp} of {ms}" + >> setField "sp" sparsity + >> setField "ms" maxSparsity + ) + + return! sparseValuesGenProvider sparsity + } + + genWithSparsity <| fun sparsity -> + [ + (maxSparsity - sparsity, valuesGen) + (sparsity, Gen.constant zero) + ] + |> Gen.frequency + |> handler + // generate non-empty matrices let pairOfMatricesOfEqualSizeGenerator (valuesGenerator: Gen<'a>) = gen { @@ -27,6 +57,15 @@ module Generators = } |> Gen.filter (fun (matrixA, matrixB) -> matrixA.Length <> 0 && matrixB.Length <> 0) + let pairOfMatrixAndVectorOfEqualSizeGenerator (valuesGenerator: Gen<'a>) = + gen { + let! (nrows, ncols) = dimension2DGenerator + let! matrix = valuesGenerator |> Gen.array2DOfDim (nrows, ncols) + let! vector = valuesGenerator |> Gen.arrayOfLength ncols + return (matrix, vector) + } + |> Gen.filter (fun (matrix, vector) -> matrix.Length <> 0 && vector.Length <> 0) + module Utils = let rec cartesian listOfLists = match listOfLists with @@ -41,3 +80,23 @@ module Utils = FSharpType.GetUnionCases typeof<'a> |> Array.map (fun caseInfo -> FSharpValue.MakeUnion(caseInfo, [||]) :?> 'a) |> List.ofArray + + let avaliableContexts (platformRegex: string) = + let mutable e = ErrorCode.Unknown + Cl.GetPlatformIDs &e + |> Array.collect (fun platform -> Cl.GetDeviceIDs(platform, DeviceType.All, &e)) + |> Seq.ofArray + |> Seq.distinctBy (fun device -> Cl.GetDeviceInfo(device, DeviceInfo.Name, &e).ToString()) + |> Seq.filter + (fun device -> + let platform = Cl.GetDeviceInfo(device, DeviceInfo.Platform, &e).CastTo() + let platformName = Cl.GetPlatformInfo(platform, PlatformInfo.Name, &e).ToString() + (Regex platformRegex).IsMatch platformName + ) + |> Seq.map + (fun device -> + let platform = Cl.GetDeviceInfo(device, DeviceInfo.Platform, &e).CastTo() + let platformName = Cl.GetPlatformInfo(platform, PlatformInfo.Name, &e).ToString() + let deviceType = Cl.GetDeviceInfo(device, DeviceInfo.Type, &e).CastTo() + OpenCLEvaluationContext(platformName, deviceType) + ) diff --git a/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj b/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj index 2e0bb548..5adeb7a6 100644 --- a/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj +++ b/tests/GraphBLAS-sharp.Tests/GraphBLAS-sharp.Tests.fsproj @@ -9,8 +9,9 @@ + - + \ No newline at end of file diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs index 17d257c0..44a23115 100644 --- a/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/EWiseAddTests.fs @@ -36,103 +36,47 @@ let testCases = } type PairOfSparseMatricesOfEqualSize() = - static let MaxSparcity = 100 - static let SparsityGen = Gen.choose (0, MaxSparcity) - static let GenericSparseGen valueGenProvider = - gen { - let! sparsity = SparsityGen - logger.debug ( - eventX "Sparcity is {sp} of {ms}" - >> setField "sp" sparsity - >> setField "ms" MaxSparcity - ) - - return! valueGenProvider sparsity - } - static member IntType() = - fun sparsity -> - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.frequency [ - (MaxSparcity - sparsity, Arb.generate) - (sparsity, Gen.constant 0) - ] - ) - |> GenericSparseGen + Generators.pairOfMatricesOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0 Arb.generate |> Arb.fromGen static member FloatType() = - fun sparsity -> - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.frequency [ - (MaxSparcity - sparsity, Arb.Default.NormalFloat() |> Arb.toGen |> Gen.map float) - (sparsity, Gen.constant 0.) - ] - ) - |> GenericSparseGen + Generators.pairOfMatricesOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0. (Arb.Default.NormalFloat() |> Arb.toGen |> Gen.map float) |> Arb.fromGen static member SByteType() = - fun sparsity -> - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.frequency [ - (MaxSparcity - sparsity, Arb.generate) - (sparsity, Gen.constant 0y) - ] - ) - |> GenericSparseGen + Generators.pairOfMatricesOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0y Arb.generate |> Arb.fromGen static member ByteType() = - fun sparsity -> - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.frequency [ - (MaxSparcity - sparsity, Arb.generate) - (sparsity, Gen.constant 0uy) - ] - ) - |> GenericSparseGen + Generators.pairOfMatricesOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0uy Arb.generate |> Arb.fromGen static member Int16Type() = - fun sparsity -> - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.frequency [ - (MaxSparcity - sparsity, Arb.generate) - (sparsity, Gen.constant 0s) - ] - ) - |> GenericSparseGen + Generators.pairOfMatricesOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0s Arb.generate |> Arb.fromGen static member UInt16Type() = - fun sparsity -> - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.frequency [ - (MaxSparcity - sparsity, Arb.generate) - (sparsity, Gen.constant 0us) - ] - ) - |> GenericSparseGen + Generators.pairOfMatricesOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0us Arb.generate |> Arb.fromGen static member BoolType() = - fun sparsity -> - Generators.pairOfMatricesOfEqualSizeGenerator ( - Gen.frequency [ - (MaxSparcity - sparsity, Arb.generate) - (sparsity, Gen.constant false) - ] - ) - |> GenericSparseGen + Generators.pairOfMatricesOfEqualSizeGenerator + |> Generators.genericSparseGenerator false Arb.generate |> Arb.fromGen -let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> +let checkCorrectnessGeneric<'a when 'a : struct> (oclContext: OpenCLEvaluationContext) (sum: 'a -> 'a -> 'a) (diff: 'a -> 'a -> 'a) (isZero: 'a -> bool) - (semiring: ISemiring<'a>) + (monoid: IMonoid<'a>) (case: OperationCase) (matrixA: 'a[,], matrixB: 'a[,]) = @@ -182,7 +126,7 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> ) graphblas { - let! result = Matrix.eWiseAdd semiring left right + let! result = Matrix.eWiseAdd monoid left right let! tuples = Matrix.tuples result do! MatrixTuples.synchronize tuples return tuples @@ -222,13 +166,13 @@ let checkCorrectnessGeneric<'a when 'a : struct and 'a : equality> "There should be no difference between expected and received values" |> Expect.all difference isZero -let config = { - FsCheckConfig.defaultConfig with +let config = + { FsCheckConfig.defaultConfig with arbitrary = [typeof] maxTest = 10 startSize = 0 // endSize = 1_000_000 -} + } // https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/language-specification/types#value-types let testFixtures case = [ diff --git a/tests/GraphBLAS-sharp.Tests/OperationsTests/MxvTests.fs b/tests/GraphBLAS-sharp.Tests/OperationsTests/MxvTests.fs new file mode 100644 index 00000000..64713f6f --- /dev/null +++ b/tests/GraphBLAS-sharp.Tests/OperationsTests/MxvTests.fs @@ -0,0 +1,75 @@ +module Mxv + +open Expecto +open FsCheck +open GraphBLAS.FSharp +open GraphBLAS.FSharp.Tests +open GraphBLAS.FSharp.Predefined +open TypeShape.Core +open Expecto.Logging +open Expecto.Logging.Message +open Brahma.FSharp.OpenCL.WorkflowBuilder.Evaluation +open OpenCL.Net + +let logger = Log.create "MxvTests" + +type OperationCase = + { + ClContext: OpenCLEvaluationContext + MatrixCase: MatrixType + VectorCase: VectorType + MaskCase: MaskType + } + +let testCases = + [ + Utils.avaliableContexts "" |> Seq.map box + Utils.listOfUnionCases |> Seq.map box + Utils.listOfUnionCases |> Seq.map box + Utils.listOfUnionCases |> Seq.map box + ] + |> List.map List.ofSeq + |> Utils.cartesian + |> List.map ^fun list -> + { + ClContext = unbox list.[0] + MatrixCase = unbox list.[1] + VectorCase = unbox list.[2] + MaskCase = unbox list.[3] + } + +type PairOfSparseMatrixAndVectorOfEqualSize() = + static member IntType() = + Generators.pairOfMatrixAndVectorOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0 Arb.generate + |> Arb.fromGen + + static member FloatType() = + Generators.pairOfMatrixAndVectorOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0. (Arb.Default.NormalFloat() |> Arb.toGen |> Gen.map float) + |> Arb.fromGen + + static member SByteType() = + Generators.pairOfMatrixAndVectorOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0y Arb.generate + |> Arb.fromGen + + static member ByteType() = + Generators.pairOfMatrixAndVectorOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0uy Arb.generate + |> Arb.fromGen + + static member Int16Type() = + Generators.pairOfMatrixAndVectorOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0s Arb.generate + |> Arb.fromGen + + static member UInt16Type() = + Generators.pairOfMatrixAndVectorOfEqualSizeGenerator + |> Generators.genericSparseGenerator 0us Arb.generate + |> Arb.fromGen + + static member BoolType() = + Generators.pairOfMatrixAndVectorOfEqualSizeGenerator + |> Generators.genericSparseGenerator false Arb.generate + |> Arb.fromGen From 805aa5ff166b2260ca56894bcb5c4ad83d16fa02 Mon Sep 17 00:00:00 2001 From: Dmitriy Panfilyonok Date: Sun, 28 Mar 2021 23:58:23 +0300 Subject: [PATCH 16/16] Fix sync for MatrixTuples --- src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs | 1 + .../Backend/Common/RemoveDuplicates.fs | 12 ++++++------ src/GraphBLAS-sharp/Methods/Matrix.fs | 9 +++++---- src/GraphBLAS-sharp/Objects/Matrix.fs | 11 ++++++++++- src/GraphBLAS-sharp/Objects/Vector.fs | 9 +++++++++ 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs b/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs index 8d88af31..a96ab295 100644 --- a/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs +++ b/src/GraphBLAS-sharp/Backend/CSRMatrix/Mxv.fs @@ -7,6 +7,7 @@ open GraphBLAS.FSharp.Backend.Common open Brahma.OpenCL module internal Mxv = + // not finished let pcsr (matrix: CSRMatrix<'a>) (vector: BitmapVector<'a>) mask (semiring: ISemiring<'a>) = opencl { let (ClosedBinaryOp plus) = semiring.Plus let (ClosedBinaryOp times) = semiring.Times diff --git a/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs b/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs index c49e75ca..c546e121 100644 --- a/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs +++ b/src/GraphBLAS-sharp/Backend/Common/RemoveDuplicates.fs @@ -7,7 +7,7 @@ module internal RemoveDuplicates = let run (array: 'a[]) = opencl { let inputLength = array.Length - let isUniqueBitmap = + let getUniqueBitmap = <@ fun (ndRange: _1D) (inputArray: 'a[]) @@ -32,9 +32,9 @@ module internal RemoveDuplicates = @> let bitmap = Array.create inputLength 1 - do! RunCommand isUniqueBitmap <| fun kernelPrepare -> - let ndRange = _1D(Utils.workSize inputLength, Utils.workGroupSize) - kernelPrepare ndRange array bitmap + do! RunCommand getUniqueBitmap <| fun kernelPrepare -> + let range = _1D(Utils.workSize inputLength, Utils.workGroupSize) + kernelPrepare range array bitmap let resultLength = Array.zeroCreate 1 do! PrefixSum.runInplace bitmap resultLength @@ -43,8 +43,8 @@ module internal RemoveDuplicates = let outputArray = Array.zeroCreate resultLength do! RunCommand setPositions <| fun kernelPrepare -> - let ndRange = _1D(Utils.workSize inputLength, Utils.workGroupSize) - kernelPrepare ndRange array bitmap outputArray + let range = _1D(Utils.workSize inputLength, Utils.workGroupSize) + kernelPrepare range array bitmap outputArray return outputArray } diff --git a/src/GraphBLAS-sharp/Methods/Matrix.fs b/src/GraphBLAS-sharp/Methods/Matrix.fs index 4a637079..eed1d90c 100644 --- a/src/GraphBLAS-sharp/Methods/Matrix.fs +++ b/src/GraphBLAS-sharp/Methods/Matrix.fs @@ -48,7 +48,7 @@ module Matrix = let tuples (matrix: Matrix<'a>) : GraphblasEvaluation> = let matrixTuples = match matrix with - | MatrixCOO coo -> COOMatrix.GetTuples.from coo + | MatrixCOO matrix -> COOMatrix.GetTuples.from matrix | _ -> failwith "Not Implemented" graphblas { return! EvalGB.fromCl matrixTuples } @@ -200,9 +200,10 @@ module Matrix = module MatrixTuples = let synchronize (matrixTuples: MatrixTuples<'a>) = opencl { - let! _ = ToHost matrixTuples.RowIndices - let! _ = ToHost matrixTuples.ColumnIndices - let! _ = ToHost matrixTuples.Values + let! rows = if matrixTuples.RowIndices.Length = 0 then opencl { return [||] } else ToHost matrixTuples.RowIndices + let! cols = if matrixTuples.ColumnIndices.Length = 0 then opencl { return [||] } else ToHost matrixTuples.ColumnIndices + let! vals = if matrixTuples.Values.Length = 0 then opencl { return [||] } else ToHost matrixTuples.Values + return () } |> EvalGB.fromCl diff --git a/src/GraphBLAS-sharp/Objects/Matrix.fs b/src/GraphBLAS-sharp/Objects/Matrix.fs index b35d039b..a7972ef9 100644 --- a/src/GraphBLAS-sharp/Objects/Matrix.fs +++ b/src/GraphBLAS-sharp/Objects/Matrix.fs @@ -30,6 +30,15 @@ and COOMatrix<'a> = Values: 'a[] } + override this.ToString() = + [ + sprintf "COO Matrix %ix%i \n" this.RowCount this.ColumnCount + sprintf "RowIndices: %A \n" this.Rows + sprintf "ColumnIndices: %A \n" this.Columns + sprintf "Values: %A \n" this.Values + ] + |> String.concat "" + static member FromTuples(rowCount: int, columnCount: int, rows: int[], columns: int[], values: 'a[]) = { RowCount = rowCount @@ -44,7 +53,7 @@ and COOMatrix<'a> = array |> Seq.cast<'a> |> Seq.mapi (fun idx v -> (idx / Array2D.length2 array, idx % Array2D.length2 array, v)) - |> Seq.filter (fun (i, j, v) -> not <| isZero v) + |> Seq.filter (fun (_, _, v) -> not <| isZero v) |> Array.ofSeq |> Array.unzip3 diff --git a/src/GraphBLAS-sharp/Objects/Vector.fs b/src/GraphBLAS-sharp/Objects/Vector.fs index 129d78ad..167393f7 100644 --- a/src/GraphBLAS-sharp/Objects/Vector.fs +++ b/src/GraphBLAS-sharp/Objects/Vector.fs @@ -15,6 +15,15 @@ and COOVector<'a> = Values: 'a[] } + override this.ToString() = + [ + sprintf "Sparse Vector\n" + sprintf "Size: %i \n" this.Size + sprintf "Indices: %A \n" this.Indices + sprintf "Values: %A \n" this.Values + ] + |> String.concat "" + and BitmapVector<'a> = { Bitmap: bool[]