diff --git a/QuadTree.Tests/QuadTree.Tests.fsproj b/QuadTree.Tests/QuadTree.Tests.fsproj index e0cd2e3..9d6d3aa 100644 --- a/QuadTree.Tests/QuadTree.Tests.fsproj +++ b/QuadTree.Tests/QuadTree.Tests.fsproj @@ -8,6 +8,8 @@ + + diff --git a/QuadTree.Tests/Tests.LinearAlgebra.fs b/QuadTree.Tests/Tests.LinearAlgebra.fs new file mode 100644 index 0000000..7b6196c --- /dev/null +++ b/QuadTree.Tests/Tests.LinearAlgebra.fs @@ -0,0 +1,237 @@ +module LinearAlgebra.Tests + +open System +open Xunit + +open Matrix +open Vector +open Common + +(* +2,2,2,2 +* +N,1,1,N +3,2,2,3 +N,N,1,2 +N,N,3,N += +6,6,14,10 +*) +[] +let ``Simple vxm. All sizes are power of two.`` () = + let m = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(UserValue(Some(2))) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(UserValue(Some(3))) + ), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(UserValue(None)) + ) + ) + + let store = Matrix.Storage(4UL, 4UL, tree) + SparseMatrix(4UL, 4UL, 9UL, store) + + let v = + let tree = Vector.btree.Leaf(UserValue(Some(2))) + + let store = Vector.Storage(4UL, tree) + SparseVector(4UL, 4UL, store) + + let op_add x y = + match (x, y) with + | Some(a), Some(b) -> Some(a + b) + | Some(a), _ + | _, Some(a) -> Some(a) + | _ -> None + + let op_mult x y = + match (x, y) with + | Some(a), Some(b) -> Some(a * b) + | _ -> None + + let expected = + let tree = + Vector.btree.Node( + Vector.btree.Leaf(UserValue(Some(6))), + Vector.btree.Node(Vector.btree.Leaf(UserValue(Some(14))), Vector.btree.Leaf(UserValue(Some(10)))) + ) + + let store = Vector.Storage(4UL, tree) + Result.Success(SparseVector(4UL, 4UL, store)) + + let actual = LinearAlgebra.vxm op_add op_mult v m + + let eq = actual = expected + + Assert.True(eq) + +(* +2,2,2,D +* +N,1,1,N +3,2,2,3 +N,N,1,2 +D,D,D,D += +6,6,8,10 +*) +[] +let ``Simple vxm. 3 * (3x4)`` () = + let m = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(UserValue(Some(2))) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(UserValue(Some(3))) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy) + ) + ) + + let store = Matrix.Storage(4UL, 4UL, tree) + SparseMatrix(3UL, 4UL, 8UL, store) + + let v = + let tree = + Vector.btree.Node( + Vector.btree.Leaf(UserValue(Some(2))), + Vector.btree.Node(Vector.btree.Leaf(UserValue(Some(2))), Vector.btree.Leaf(Dummy)) + ) + + let store = Vector.Storage(4UL, tree) + SparseVector(3UL, 3UL, store) + + let op_add x y = + match (x, y) with + | Some(a), Some(b) -> Some(a + b) + | Some(a), _ + | _, Some(a) -> Some(a) + | _ -> None + + let op_mult x y = + match (x, y) with + | Some(a), Some(b) -> Some(a * b) + | _ -> None + + let expected = + let tree = + Vector.btree.Node( + Vector.btree.Leaf(UserValue(Some(6))), + Vector.btree.Node(Vector.btree.Leaf(UserValue(Some(8))), Vector.btree.Leaf(UserValue(Some(10)))) + ) + + let store = Vector.Storage(4UL, tree) + Result.Success(SparseVector(4UL, 4UL, store)) + + let actual = LinearAlgebra.vxm op_add op_mult v m + + let eq = actual = expected + + Assert.True(eq) + + +(* +2,2,2,2 +* +N,1,1,D +3,2,2,D +N,N,1,D +N,N,3,D += +6,6,14,D +*) +[] +let ``Simple vxm. 4 * (4x3).`` () = + let m = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(UserValue(Some(2))) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(Dummy) + ), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(Dummy) + ) + ) + + let store = Matrix.Storage(4UL, 4UL, tree) + SparseMatrix(4UL, 3UL, 7UL, store) + + let v = + let tree = Vector.btree.Leaf(UserValue(Some(2))) + + let store = Vector.Storage(4UL, tree) + SparseVector(4UL, 4UL, store) + + let op_add x y = + match (x, y) with + | Some(a), Some(b) -> Some(a + b) + | Some(a), _ + | _, Some(a) -> Some(a) + | _ -> None + + let op_mult x y = + match (x, y) with + | Some(a), Some(b) -> Some(a * b) + | _ -> None + + let expected = + let tree = + Vector.btree.Node( + Vector.btree.Leaf(UserValue(Some(6))), + Vector.btree.Node(Vector.btree.Leaf(UserValue(Some(14))), Vector.btree.Leaf(Dummy)) + ) + + let store = Vector.Storage(4UL, tree) + Result.Success(SparseVector(3UL, 3UL, store)) + + let actual = LinearAlgebra.vxm op_add op_mult v m + + let eq = actual = expected + + Assert.True(eq) diff --git a/QuadTree.Tests/Tests.Matrix.fs b/QuadTree.Tests/Tests.Matrix.fs new file mode 100644 index 0000000..90b678d --- /dev/null +++ b/QuadTree.Tests/Tests.Matrix.fs @@ -0,0 +1,228 @@ +module Matrix.Tests + +open System +open Xunit + +open Matrix +open Common + +let printMatrix (matrix: SparseMatrix<_>) = + printfn "Matrix:" + printfn " Rows: %A" matrix.nrows + printfn " Columns: %A" matrix.ncols + printfn " Nvals: %A" matrix.nvals + printfn " Storage:" + printfn " vSize: %A" matrix.storage.vSize + printfn " hSize: %A" matrix.storage.hSize + printfn " Data: %A" matrix.storage.data + + +(* +N,1,1,N +3,2,2,3 +N,N,1,2 +N,N,3,N ++ +1,1,2,2 +1,1,2,2 +3,3,N,N +3,3,N,N += +N,2,3,N +4,3,4,5 +N,N,N,N +N,N,N,N +*) +[] +let ``Simple Matrix.map2. Square where number of cols and rows are power of two.`` () = + let m1 = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(UserValue(Some(2))) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(UserValue(Some(3))) + ), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(UserValue(None)) + ) + ) + + let store = Storage(4UL, 4UL, tree) + SparseMatrix(4UL, 4UL, 9UL, store) + + let m2 = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(UserValue(None)) + ) + + let store = Storage(4UL, 4UL, tree) + SparseMatrix(4UL, 4UL, 12UL, store) + + let f x y = + match (x, y) with + | Some(a), Some(b) -> Some(a + b) + | _ -> None + + let expected = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(UserValue(Some(4))), + Matrix.qtree.Leaf(UserValue(Some(3))) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(4))), + Matrix.qtree.Leaf(UserValue(Some(5))) + ), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(None)) + ) + + let store = Storage(4UL, 4UL, tree) + Result.Success(SparseMatrix(4UL, 4UL, 6UL, store)) + + let actual = Matrix.map2 m1 m2 f + + let eq = actual = expected + + Assert.True(eq) + +(* +N,1,1,D +3,2,2,D +N,N,1,D +D,D,D,D ++ +1,1,2,D +1,1,2,D +3,3,N,D +D,D,D,D += +N,2,3,D +4,3,4,D +N,N,N,D +D,D,D,D +*) +[] +let ``Simple Matrix.map2. Square where number of cols and rows are not power of two.`` () = + let m1 = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(UserValue(Some(2))) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(Dummy) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy) + ) + ) + + let store = Storage(4UL, 4UL, tree) + SparseMatrix(3UL, 3UL, 6UL, store) + + let m2 = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(1))), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(Dummy) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy) + ) + ) + + let store = Storage(4UL, 4UL, tree) + SparseMatrix(3UL, 3UL, 8UL, store) + + let f x y = + match (x, y) with + | Some(a), Some(b) -> Some(a + b) + | _ -> None + + let expected = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(Some(2))), + Matrix.qtree.Leaf(UserValue(Some(4))), + Matrix.qtree.Leaf(UserValue(Some(3))) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(Some(3))), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(UserValue(Some(4))), + Matrix.qtree.Leaf(Dummy) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy) + ), + Matrix.qtree.Node( + Matrix.qtree.Leaf(UserValue(None)), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy), + Matrix.qtree.Leaf(Dummy) + ) + ) + + let store = Storage(4UL, 4UL, tree) + Result.Success(SparseMatrix(3UL, 3UL, 5UL, store)) + + let actual = Matrix.map2 m1 m2 f + + let eq = actual = expected + + Assert.True(eq) diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index 55f3b77..1f3f32f 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -15,12 +15,12 @@ let printVector (vector: SparseVector<_>) = printfn " Data: %A" vector.storage.data [] -let ``Simple map2`` () = +let ``Simple Vector.map2. Length is power of two.`` () = let v1 = let tree = Vector.btree.Node( - Vector.btree.Node(Vector.btree.Leaf(Some(1)), Vector.btree.Leaf(None)), - Vector.btree.Leaf(Some(2)) + Vector.btree.Node(Vector.btree.Leaf(UserValue(Some(1))), Vector.btree.Leaf(UserValue(None))), + Vector.btree.Leaf(UserValue(Some(2))) ) let store = Storage(8UL, tree) @@ -29,8 +29,8 @@ let ``Simple map2`` () = let v2 = let tree = Vector.btree.Node( - Vector.btree.Node(Vector.btree.Leaf(Some(2)), Vector.btree.Leaf(None)), - Vector.btree.Node(Vector.btree.Leaf(None), Vector.btree.Leaf(Some(1))) + Vector.btree.Node(Vector.btree.Leaf(UserValue(Some(2))), Vector.btree.Leaf(UserValue(None))), + Vector.btree.Node(Vector.btree.Leaf(UserValue(None)), Vector.btree.Leaf(UserValue(Some(1)))) ) let store = Storage(8UL, tree) @@ -44,8 +44,8 @@ let ``Simple map2`` () = let expected = let tree = Vector.btree.Node( - Vector.btree.Node(Vector.btree.Leaf(Some(3)), Vector.btree.Leaf(None)), - Vector.btree.Node(Vector.btree.Leaf(None), Vector.btree.Leaf(Some(3))) + Vector.btree.Node(Vector.btree.Leaf(UserValue(Some(3))), Vector.btree.Leaf(UserValue(None))), + Vector.btree.Node(Vector.btree.Leaf(UserValue(None)), Vector.btree.Leaf(UserValue(Some(3)))) ) let store = Storage(8UL, tree) @@ -56,3 +56,47 @@ let ``Simple map2`` () = let eq = actual = expected Assert.True(eq) + + +[] +let ``Simple Vector.map2. Length is not power of two.`` () = + let v1 = + let tree = + Vector.btree.Node( + Vector.btree.Node(Vector.btree.Leaf(UserValue(Some(1))), Vector.btree.Leaf(UserValue(None))), + Vector.btree.Node(Vector.btree.Leaf(UserValue(None)), Vector.btree.Leaf(Dummy)) + ) + + let store = Storage(8UL, tree) + SparseVector(6UL, 2UL, store) + + let v2 = + let tree = + Vector.btree.Node( + Vector.btree.Node(Vector.btree.Leaf(UserValue(Some(2))), Vector.btree.Leaf(UserValue(None))), + Vector.btree.Node(Vector.btree.Leaf(UserValue(None)), Vector.btree.Leaf(Dummy)) + ) + + let store = Storage(8UL, tree) + SparseVector(6UL, 2UL, store) + + let f x y = + match (x, y) with + | Some(a), Some(b) -> Some(a + b) + | _ -> None + + let expected = + let tree = + Vector.btree.Node( + Vector.btree.Node(Vector.btree.Leaf(UserValue(Some(3))), Vector.btree.Leaf(UserValue(None))), + Vector.btree.Node(Vector.btree.Leaf(UserValue(None)), Vector.btree.Leaf(Dummy)) + ) + + let store = Storage(8UL, tree) + Result.Success(SparseVector(6UL, 2UL, store)) + + let actual = Vector.map2 v1 v2 f + + let eq = actual = expected + + Assert.True(eq) diff --git a/QuadTree/Common.fs b/QuadTree/Common.fs index 0cbc45f..0d57192 100644 --- a/QuadTree/Common.fs +++ b/QuadTree/Common.fs @@ -3,6 +3,10 @@ module Common [] type nvals +type 'value treeValue = + | Dummy + | UserValue of 'value + type BinSearchTree<'value> = | Leaf of 'value diff --git a/QuadTree/LinearAlgebra.fs b/QuadTree/LinearAlgebra.fs index ac4d176..db5aada 100644 --- a/QuadTree/LinearAlgebra.fs +++ b/QuadTree/LinearAlgebra.fs @@ -1,27 +1,85 @@ module LinearAlgebra -open Vector -open Matrix +open Common -let rec multScalar op_add (x: uint) y = - if x = 1u then +type Error<'value1, 'value2, 'value3> = + | InconsistentStructureOfStorages of Vector.btree> * Matrix.qtree> + | InconsistentSizeOfArguments of Vector.SparseVector<'value1> * Matrix.SparseMatrix<'value2> + | VectorAdditionProblem of Vector.Error<'value3, 'value3> + +let rec multScalar op_add (x: uint64) y = + if x = 1UL then y else - let v = multScalar op_add (x / 2u) y + let v = multScalar op_add (x / 2UL) y let res = op_add v v - if x % 2u = 0u then res else op_add res v + if x % 2UL = 0UL then res else op_add res v + + +let vxm op_add op_mult (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseMatrix<'b>) = + + let rec inner (size: uint64) vector matrix = + let _do x1 x2 y1 y2 y3 y4 = + let new_size = size / 2UL + + match (inner new_size x1 y1), (inner new_size x1 y2), (inner new_size x2 y3), (inner new_size x2 y4) with + | Result.Success((t1, nvals1)), + Result.Success((t2, nvals2)), + Result.Success((t3, nvals3)), + Result.Success((t4, nvals4)) -> + let data_length = (uint64 new_size) * 1UL + let v1 = Vector.SparseVector(data_length, nvals1, (Vector.Storage(new_size, t1))) + let v2 = Vector.SparseVector(data_length, nvals2, (Vector.Storage(new_size, t2))) + let v3 = Vector.SparseVector(data_length, nvals3, (Vector.Storage(new_size, t3))) + let v4 = Vector.SparseVector(data_length, nvals4, (Vector.Storage(new_size, t4))) + + let vAdd v1 (v2: Vector.SparseVector<_>) = + match v2.storage.data with + | Vector.Leaf(Dummy) -> Result.Success(v1) + | _ -> Vector.map2 v1 v2 op_add + + let z1 = vAdd v1 v3 + let z2 = vAdd v2 v4 + + match (z1, z2) with + | Result.Success(v1), Result.Success(v2) -> + Result.Success((Vector.mkNode v1.storage.data v2.storage.data), v1.nvals + v2.nvals) + | Result.Failure(e), _ + | _, Result.Failure(e) -> Result.Failure(VectorAdditionProblem(e)) + + | Result.Failure(e), _, _, _ + | _, Result.Failure(e), _, _ + | _, _, Result.Failure(e), _ + | _, _, _, Result.Failure(e) -> Result.Failure(e) + + match (vector, matrix) with + | Vector.btree.Leaf(UserValue(v1)), Matrix.qtree.Leaf(UserValue(v2)) -> + let res = multScalar op_add (uint64 size) (op_mult v1 v2) + + let nnz = + match res with + | None -> 0UL + | _ -> (uint64 size) * 1UL + + Result.Success(Vector.btree.Leaf(UserValue(res)), nnz) + + | Vector.btree.Leaf(UserValue(_)), Matrix.qtree.Node(y1, y2, y3, y4) -> _do vector vector y1 y2 y3 y4 + | Vector.btree.Node(x1, x2), Matrix.qtree.Leaf(UserValue(_)) -> _do x1 x2 matrix matrix matrix matrix + | Vector.btree.Node(x1, x2), Matrix.qtree.Node(y1, y2, y3, y4) -> _do x1 x2 y1 y2 y3 y4 + + | Vector.btree.Leaf(Dummy), Matrix.qtree.Leaf(Dummy) + | _, Matrix.qtree.Leaf(Dummy) -> Result.Success(Vector.btree.Leaf(Dummy), 0UL) + | (x, y) -> Result.Failure <| Error.InconsistentStructureOfStorages(x, y) -let vxm op_add op_mult (vector: SparseVector<'a>) (matrix: SparseMatrix<'b>) = if uint64 vector.length = uint64 matrix.nrows then - let inner len vector matrix = - match (vector, matrix) with - | btree.Leaf(v1), qtree.Leaf(v2) -> - let v = op_mult v1 v2 - btree.Leaf(multScalar op_add len v), len - | btree.Leaf(v1), Node(t1, t2, t3, t4) -> - //let new_t1, nvals1 = inner (len/2u) vector - failwith "Unfinished..." - - Result.Failure "TODO..." + match inner vector.storage.size vector.storage.data matrix.storage.data with + | Result.Failure x -> Result.Failure x + | Result.Success(storage, nvals) -> + (Vector.SparseVector( + (uint64 matrix.ncols) * 1UL, + nvals, + (Vector.Storage((uint64 matrix.storage.hSize) * 1UL, storage)) + )) + |> Result.Success else - Result.Failure "The length of the vector must be equals to the number of rows of the matrix." + (Error.InconsistentSizeOfArguments(vector, matrix)) |> Result.Failure diff --git a/QuadTree/Matrix.fs b/QuadTree/Matrix.fs index dfb273a..4133f60 100644 --- a/QuadTree/Matrix.fs +++ b/QuadTree/Matrix.fs @@ -1,33 +1,45 @@ module Matrix open Common + (* | x1 | x2 | ---------- | x3 | x4 | *) -type qtree<'value> = //when 'TCell: equality> = +type qtree<'value> = | Node of qtree<'value> * qtree<'value> * qtree<'value> * qtree<'value> - | Leaf of 'value + | Leaf of treeValue<'value> +[] +type ncols [] -type columnId +type nrows [] -type rowId +type storageVSize +[] +type storageHSize [] -type SparseMatrix<'value> = - - val nrows: uint - - val ncols: uint +type Storage<'value> = + val vSize: uint64 + val hSize: uint64 + val data: qtree<'value> - val nvals: uint + new(_vSize, _hSize, _data) = + { vSize = _vSize + hSize = _hSize + data = _data } - val storage: qtree> +[] +type SparseMatrix<'value> = + val nrows: uint64 + val ncols: uint64 + val nvals: uint64 + val storage: Storage> new(_nrows, _ncols, _nvals, _storage) = { nrows = _nrows @@ -35,20 +47,71 @@ type SparseMatrix<'value> = nvals = _nvals storage = _storage } +type Error<'value1, 'value2> = + | InconsistentStructureOfStorages of qtree> * qtree> + | InconsistentSizeOfArguments of SparseMatrix<'value1> * SparseMatrix<'value2> -let fromCoo size (coo: List * uint * 'value>) = - let groupedByColumns = - List.groupBy (fun (i, j, v) -> i) coo - |> List.sortBy fst - |> List.map (fun (x, l) -> x, List.sortBy (fun (_, j, _) -> j) l) - - 0 let mkNode x1 x2 x3 x4 = match (x1, x2, x3, x4) with | Leaf(v1), Leaf(v2), Leaf(v3), Leaf(v4) when v1 = v2 && v2 = v3 && v3 = v4 -> Leaf(v1) | _ -> Node(x1, x2, x3, x4) +let map2 (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = + let rec inner (vSize: uint64) (hSize: uint64) matrix1 matrix2 = + let _do x1 x2 x3 x4 y1 y2 y3 y4 = + let new_vSize = vSize / 2UL + let new_hSize = hSize / 2UL + + match + (inner new_vSize new_hSize x1 y1), + (inner new_vSize new_hSize x2 y2), + (inner new_vSize new_hSize x3 y3), + (inner new_vSize new_hSize x4 y4) + with + | Result.Success((new_t1, nvals1)), + Result.Success((new_t2, nvals2)), + Result.Success((new_t3, nvals3)), + Result.Success((new_t4, nvals4)) -> + ((mkNode new_t1 new_t2 new_t3 new_t4), nvals1 + nvals2 + nvals3 + nvals4) + |> Result.Success + | Result.Failure(e), _, _, _ + | _, Result.Failure(e), _, _ + | _, _, Result.Failure(e), _ + | _, _, _, Result.Failure(e) -> Result.Failure(e) + + match (matrix1, matrix2) with + | Leaf(Dummy), Leaf(Dummy) -> Result.Success(Leaf(Dummy), 0UL) + | Leaf(UserValue(v1)), Leaf(UserValue(v2)) -> + let res = f v1 v2 + + let nnz = + match res with + | None -> 0UL + | _ -> (uint64 vSize) * (uint64 hSize) * 1UL + + (Leaf(UserValue(res)), nnz) |> Result.Success + + | Node(x1, x2, x3, x4), Node(y1, y2, y3, y4) -> _do x1 x2 x3 x4 y1 y2 y3 y4 + | Node(x1, x2, x3, x4), Leaf(v) -> _do x1 x2 x3 x4 matrix2 matrix2 matrix2 matrix2 + | Leaf(v), Node(x1, x2, x3, x4) -> _do matrix1 matrix1 matrix1 matrix1 x1 x2 x3 x4 + | (x, y) -> Result.Failure <| Error.InconsistentStructureOfStorages(x, y) + + if matrix1.nrows = matrix2.nrows && matrix1.ncols = matrix2.ncols then + match inner matrix1.storage.vSize matrix1.storage.hSize matrix1.storage.data matrix2.storage.data with + | Result.Failure x -> Result.Failure x + | Result.Success(storage, nvals) -> + (SparseMatrix( + matrix1.nrows, + matrix1.ncols, + nvals, + (Storage(matrix1.storage.vSize, matrix1.storage.hSize, storage)) + )) + |> Result.Success + else + (Error.InconsistentSizeOfArguments(matrix1, matrix2)) |> Result.Failure + + (* let rec map (op: 'TCell1 -> 'TCell2) (m1:Matrix<'TCell1>) = match m1 with @@ -57,23 +120,6 @@ let rec map (op: 'TCell1 -> 'TCell2) (m1:Matrix<'TCell1>) = | Node (s,x1,x2,x3,x4) -> mkNode s (map op x1) (map op x2) (map op x3) (map op x4) -let map2 (op: 'TCell1 -> 'TCell2 -> 'TCell3) (m1:Matrix<'TCell1>) (m2:Matrix<'TCell2>) = - let rec go m1 m2 = - match (m1, m2) with - | Leaf(s,v1), Leaf(_,v2) -> - Leaf (s, op v1 v2) - | Node (s,x1,x2,x3,x4), Node (_,y1,y2,y3,y4) -> - mkNode s (go x1 y1) (go x2 y2) (go x3 y3) (go x4 y4) - | Node (s,x1,x2,x3,x4), Leaf (_,v) -> - let l = Leaf(s / 2u,v) - mkNode s (go x1 l) (go x2 l) (go x3 l) (go x4 l) - | Leaf (_,v), Node (s,x1,x2,x3,x4) -> - let l = Leaf(s / 2u,v) - mkNode s (go l x1) (go l x2) (go l x3) (go l x4) - - if m1.Size = m2.Size - then go m1 m2 - else failwith $"Matrices should be of equals size, but m1.Size = {m1.Size} and m2.Size = {m2.Size}" let multScalar opAdd (x:uint) y = if x = 1u diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index 002d54a..35c945b 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -3,7 +3,7 @@ module Vector open Common type 'value btree = - | Leaf of 'value + | Leaf of 'value treeValue | Node of 'value btree * 'value btree [] @@ -29,16 +29,9 @@ type SparseVector<'value> = nvals = _nvals storage = _storage } -(*let nvals (vector:SparseVector<'a>) = - let compute - match vector.nvals with - | Some(i) -> i - | None -> +type Error<'value1, 'value2> = InconsistentSizeOfArguments of SparseVector<'value1> * SparseVector<'value2> + -let nvals vector = - match vector with - | SparseVector(_,nvals,_) -> nvals - *) (* let foldValues state f tree = match tree with @@ -53,37 +46,39 @@ let mkNode t1 t2 = let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = let len1 = vector1.length + let rec inner (size: uint64) vector1 vector2 = + match (vector1, vector2) with + | Node(t1, t2), Leaf(_) -> + let new_t1, nvals1 = inner (size / 2UL) t1 vector2 + let new_t2, nvals2 = inner (size / 2UL) t2 vector2 + (mkNode new_t1 new_t2), nvals1 + nvals2 + | Leaf(_), Node(t1, t2) -> + let new_t1, nvals1 = inner (size / 2UL) vector1 t1 + let new_t2, nvals2 = inner (size / 2UL) vector1 t2 + (mkNode new_t1 new_t2), nvals1 + nvals2 + | Node(t1, t2), Node(t3, t4) -> + let new_t1, nvals1 = inner (size / 2UL) t1 t3 + let new_t2, nvals2 = inner (size / 2UL) t2 t4 + (mkNode new_t1 new_t2), nvals1 + nvals2 + | Leaf(Dummy), Leaf(Dummy) -> Leaf(Dummy), 0UL + | Leaf(UserValue(v1)), Leaf(UserValue(v2)) -> + let res = f v1 v2 + + let nnz = + match res with + | None -> 0UL + | _ -> (uint64 size) * 1UL + + Leaf(UserValue(res)), nnz + if len1 = vector2.length then - let rec inner (size: uint64) vector1 vector2 = - match (vector1, vector2) with - | Node(t1, t2), Leaf(_) -> - let new_t1, nvals1 = inner (size / 2UL) t1 vector2 - let new_t2, nvals2 = inner (size / 2UL) t2 vector2 - (mkNode new_t1 new_t2), nvals1 + nvals2 - | Leaf(_), Node(t1, t2) -> - let new_t1, nvals1 = inner (size / 2UL) vector1 t1 - let new_t2, nvals2 = inner (size / 2UL) vector1 t2 - (mkNode new_t1 new_t2), nvals1 + nvals2 - | Node(t1, t2), Node(t3, t4) -> - let new_t1, nvals1 = inner (size / 2UL) t1 t3 - let new_t2, nvals2 = inner (size / 2UL) t2 t4 - (mkNode new_t1 new_t2), nvals1 + nvals2 - | Leaf(v1), Leaf(v2) -> - let res = f v1 v2 - - let nnz = - match res with - | None -> 0UL - | _ -> (uint64 size) * 1UL - - Leaf(res), nnz let storage, nvals = inner vector1.storage.size vector1.storage.data vector2.storage.data Result.Success(SparseVector(len1, nvals, (Storage(vector1.storage.size, storage)))) else - Result.Failure "The length of the vector1 must be equals to the length of the vector2." + Result.Failure <| Error.InconsistentSizeOfArguments(vector1, vector2) let mask (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = map2 vector1 vector2 (fun v1 v2 -> if f v2 then v1 else None)