From b8a01be9a7d1164d7205bd02451c3e734e2f3e88 Mon Sep 17 00:00:00 2001 From: gsv Date: Fri, 27 Mar 2026 17:19:29 +0300 Subject: [PATCH 01/52] Attempt to introduce workflow but for standard Result type. --- QuadTree.Tests/Tests.BFS.fs | 2 +- QuadTree.Tests/Tests.LinearAlgebra.fs | 22 ++--- QuadTree.Tests/Tests.Matrix.fs | 6 +- QuadTree.Tests/Tests.SSSP.fs | 4 +- QuadTree.Tests/Tests.TriangleCount.fs | 2 +- QuadTree.Tests/Tests.Vector.fs | 6 +- QuadTree/BFS.fs | 63 +++++++------- QuadTree/Common.fs | 41 ++++++++- QuadTree/LinearAlgebra.fs | 118 +++++++++++++------------- QuadTree/Matrix.fs | 38 ++++----- QuadTree/QuadTree.fsproj | 1 - QuadTree/Result.fs | 5 -- QuadTree/SSSP.fs | 22 ++--- QuadTree/TriangleCount.fs | 18 ++-- QuadTree/Vector.fs | 28 +++--- 15 files changed, 202 insertions(+), 174 deletions(-) delete mode 100644 QuadTree/Result.fs diff --git a/QuadTree.Tests/Tests.BFS.fs b/QuadTree.Tests/Tests.BFS.fs index 6c40600..df5d0f3 100644 --- a/QuadTree.Tests/Tests.BFS.fs +++ b/QuadTree.Tests/Tests.BFS.fs @@ -64,7 +64,7 @@ let ``Simple level bfs.`` () = ) let store = Vector.Storage(4UL, tree) - Result.Success(SparseVector(4UL, 4UL, store)) + Ok(SparseVector(4UL, 4UL, store)) let actual = Graph.BFS.bfs_level graph startVertices diff --git a/QuadTree.Tests/Tests.LinearAlgebra.fs b/QuadTree.Tests/Tests.LinearAlgebra.fs index 8e3dd45..dca4199 100644 --- a/QuadTree.Tests/Tests.LinearAlgebra.fs +++ b/QuadTree.Tests/Tests.LinearAlgebra.fs @@ -64,7 +64,7 @@ let ``Simple vxm. All sizes are power of two.`` () = let tree = Vector.btree.Node(vleaf_v 6, Vector.btree.Node(vleaf_v 14, vleaf_v 10)) let store = Vector.Storage(4UL, tree) - Result.Success(SparseVector(4UL, 4UL, store)) + Ok(SparseVector(4UL, 4UL, store)) let actual = LinearAlgebra.vxm op_add op_mult v m @@ -104,7 +104,7 @@ let ``Simple vxm. 3 * (3x4)`` () = let tree = Vector.btree.Node(vleaf_v 6, Vector.btree.Node(vleaf_v 8, vleaf_v 10)) let store = Vector.Storage(4UL, tree) - Result.Success(SparseVector(4UL, 4UL, store)) + Ok(SparseVector(4UL, 4UL, store)) let actual = LinearAlgebra.vxm op_add op_mult v m @@ -146,7 +146,7 @@ let ``Simple vxm. 4 * (4x3).`` () = let tree = Vector.btree.Node(vleaf_v 6, Vector.btree.Node(vleaf_v 14, vleaf_d ())) let store = Vector.Storage(4UL, tree) - Result.Success(SparseVector(3UL, 3UL, store)) + Ok(SparseVector(3UL, 3UL, store)) let actual = LinearAlgebra.vxm op_add op_mult v m @@ -205,7 +205,7 @@ let ``Simple vxm. 3 * (3x5)`` () = ) let store = Vector.Storage(8UL, tree) - Result.Success(SparseVector(5UL, 5UL, store)) + Ok(SparseVector(5UL, 5UL, store)) let actual = LinearAlgebra.vxm op_add op_mult v m @@ -243,7 +243,7 @@ let ``Simple mxm`` () = let actual = match LinearAlgebra.mxm op_add op_mult m1 m2 with - | Result.Success m -> m + | Ok m -> m | _ -> failwith "Unreachable" Assert.Equal(expected.storage.data, actual.storage.data) @@ -279,8 +279,8 @@ let ``Sparse mxm`` () = let actual = match LinearAlgebra.mxm op_add op_mult m1 m2 with - | Result.Success m -> m - | Result.Failure e -> failwith (e.ToString()) + | Ok m -> m + | Error e -> failwith (e.ToString()) Assert.Equal(expected, actual) @@ -325,8 +325,8 @@ let ``Shrinking mxm`` () = let actual = match LinearAlgebra.mxm op_add op_mult m1 m2 with - | Result.Success m -> m - | Result.Failure e -> failwith (e.ToString()) + | Ok m -> m + | Error e -> failwith (e.ToString()) Assert.Equal(expected, actual) @@ -374,7 +374,7 @@ let ``Expanding mxm`` () = let actual = match LinearAlgebra.mxm op_add op_mult m1 m2 with - | Result.Success m -> m - | Result.Failure e -> failwith (e.ToString()) + | Ok m -> m + | Error e -> failwith (e.ToString()) Assert.Equal(expected, actual) diff --git a/QuadTree.Tests/Tests.Matrix.fs b/QuadTree.Tests/Tests.Matrix.fs index a7f4553..163edef 100644 --- a/QuadTree.Tests/Tests.Matrix.fs +++ b/QuadTree.Tests/Tests.Matrix.fs @@ -81,7 +81,7 @@ let ``Simple Matrix.map2. Square where number of cols and rows are power of two. ) let store = Storage(4UL, tree) - Result.Success(SparseMatrix(4UL, 4UL, 6UL, store)) + Ok(SparseMatrix(4UL, 4UL, 6UL, store)) let actual = Matrix.map2 m1 m2 f @@ -144,7 +144,7 @@ let ``Simple Matrix.map2. Square where number of cols and rows are not power of ) let store = Storage(4UL, tree) - Result.Success(SparseMatrix(3UL, 3UL, 5UL, store)) + Ok(SparseMatrix(3UL, 3UL, 5UL, store)) let actual = Matrix.map2 m1 m2 f @@ -211,7 +211,7 @@ let ``Simple addition`` () = let result = match map2 m1 m2 addition with - | Result.Success x -> x + | Ok x -> x | _ -> failwith "Unreachable" toCoordinateList result diff --git a/QuadTree.Tests/Tests.SSSP.fs b/QuadTree.Tests/Tests.SSSP.fs index 1f62db8..ff28383 100644 --- a/QuadTree.Tests/Tests.SSSP.fs +++ b/QuadTree.Tests/Tests.SSSP.fs @@ -54,7 +54,7 @@ let ``Simple SSSP.`` () = ) let store = Vector.Storage(4UL, tree) - Result.Success(SparseVector(4UL, 4UL, store)) + Ok(SparseVector(4UL, 4UL, store)) let actual = Graph.SSSP.sssp graph 0UL @@ -97,7 +97,7 @@ let ``SSSP with recalculation`` () = (4UL, 5.0) ] ) - Result.Success(Vector.fromCoordinateList clist) + Ok(Vector.fromCoordinateList clist) let actual = Graph.SSSP.sssp graph 0UL diff --git a/QuadTree.Tests/Tests.TriangleCount.fs b/QuadTree.Tests/Tests.TriangleCount.fs index 1a59982..b5df83d 100644 --- a/QuadTree.Tests/Tests.TriangleCount.fs +++ b/QuadTree.Tests/Tests.TriangleCount.fs @@ -54,7 +54,7 @@ let ``7V Triangle count`` () = let actual = match triangle_count g with - | Result.Success(Some x) -> x + | Ok(Some x) -> x | _ -> failwith "Unreachable" Assert.Equal(expected, actual) diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index ad1a525..ebf75ef 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -113,7 +113,7 @@ let ``Simple Vector.map2. Length is power of two.`` () = ) let store = Storage(8UL, tree) - Result.Success(SparseVector(8UL, 4UL, store)) + Ok(SparseVector(8UL, 4UL, store)) let actual = Vector.map2 v1 v2 f @@ -154,7 +154,7 @@ let ``Simple Vector.map2. Length is not power of two.`` () = ) let store = Storage(8UL, tree) - Result.Success(SparseVector(6UL, 2UL, store)) + Ok(SparseVector(6UL, 2UL, store)) let actual = Vector.map2 v1 v2 f @@ -202,7 +202,7 @@ let ``Simple addition`` () = let result = match map2 v1 v2 addition with - | Result.Success x -> x + | Ok x -> x | _ -> failwith "Unreachable" toCoordinateList result diff --git a/QuadTree/BFS.fs b/QuadTree/BFS.fs index b2ffc3c..4ed1da0 100644 --- a/QuadTree/BFS.fs +++ b/QuadTree/BFS.fs @@ -2,47 +2,42 @@ module Graph.BFS open Common -type Error<'t1, 't2> = - | NewFrontierCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't1> - | FrontierCalculationProblem of Vector.Error<'t1, 't1> - | VisitedCalculationProblem of Vector.Error<'t1, 't1> +type Error = + | NewFrontierCalculationProblem of LinearAlgebra.Error + | FrontierCalculationProblem of Vector.Error + | VisitedCalculationProblem of Vector.Error + +let mapError (err: LinearAlgebra.Error) = NewFrontierCalculationProblem err +let mapError' (err: Vector.Error) = FrontierCalculationProblem err +let mapError'' (err: Vector.Error) = VisitedCalculationProblem err let bfs_level graph startVertices = let rec inner level (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) = if frontier.nvals > 0UL then - let op_add x y = - match (x, y) with - | Some(v), _ - | _, Some(v) -> Some(v) - | _ -> None - - let op_mult x y = - match (x, y) with - | Some(v), Some(_) -> Some(v) - | _ -> None - - let new_frontier = LinearAlgebra.vxm op_add op_mult frontier graph - - match new_frontier with - | Result.Failure(e) -> Result.Failure(NewFrontierCalculationProblem(e)) - | Result.Success(new_frontier) -> - let frontier = Vector.mask new_frontier visited (fun x -> x.IsNone) - - match frontier with - | Result.Failure(e) -> Result.Failure(FrontierCalculationProblem(e)) - | Result.Success(frontier) -> - let op_add x y = + result { + let! new_frontier = + LinearAlgebra.vxm + (fun x y -> match (x, y) with | Some(v), _ | _, Some(v) -> Some(v) | _ -> None) + (fun x y -> match (x, y) with | Some(v), Some(_) -> Some(v) | _ -> None) + frontier graph + |> Common.Result.mapError mapError + + let! frontier = + Vector.mask new_frontier visited (fun x -> x.IsNone) + |> Common.Result.mapError mapError' + + let! visited = + Vector.map2 visited new_frontier (fun x y -> match (x, y) with | (Some(_), _) -> x | (None, Some(_)) -> Some(level) - | _ -> None - - let visited = Vector.map2 visited new_frontier op_add + | _ -> None) + |> Common.Result.mapError mapError'' - match visited with - | Result.Failure(e) -> Result.Failure(VisitedCalculationProblem(e)) - | Result.Success(visited) -> inner (level + 1UL) frontier visited + return! inner (level + 1UL) frontier visited + } else - Result.Success visited + Ok visited - inner 1UL startVertices (Vector.map startVertices (Option.map (fun x -> 0UL))) + let initialVisited = Vector.map startVertices (Option.map (fun x -> 0UL)) + inner 1UL startVertices initialVisited diff --git a/QuadTree/Common.fs b/QuadTree/Common.fs index 61a3572..4078e22 100644 --- a/QuadTree/Common.fs +++ b/QuadTree/Common.fs @@ -10,11 +10,50 @@ type 'value treeValue = | Dummy | UserValue of 'value - type BinSearchTree<'value> = | Leaf of 'value | Node of BinSearchTree<'value> * 'value * BinSearchTree<'value> +module Error = + let map (f: 'a -> 'b) (err: 'a) : 'b = f err + +module Result = + let mapError (f: 'e1 -> 'e2) (result: Result<'ok, 'e1>) : Result<'ok, 'e2> = + match result with + | Ok ok -> Ok ok + | Error err -> Error (f err) + +type ResultBuilder() = + member _.Return(x: 'ok) : Result<'ok, 'err> = Ok x + member _.ReturnFrom(result: Result<'ok, 'err>) : Result<'ok, 'err> = result + member _.Bind(result: Result<'ok, 'err>, f: 'ok -> Result<'ok2, 'err>) : Result<'ok2, 'err> = + match result with + | Ok ok -> f ok + | Error err -> Error err + member _.Zero() : Result = Ok () + member _.Delay(f: unit -> Result<'ok, 'err>) = f + member _.Run(f: unit -> Result<'ok, 'err>) = f () + member this.While(guard: unit -> bool, body: unit -> Result) = + if guard() then + this.Bind(body(), fun () -> this.While(guard, body)) + else + this.Zero() + member this.For(sequence: seq<'ok>, f: 'ok -> Result) = + use en = sequence.GetEnumerator() + this.While(en.MoveNext, fun () -> f en.Current) + + member _.Combine(result1: Result, result2: Result<'ok, 'err>) : Result<'ok, 'err> = + match result1 with + | Ok () -> result2 + | Error err -> Error err + + member this.MergeSources(result1: Result<'ok1, 'err>, result2: Result<'ok2, 'err>) : Result<'ok1 * 'ok2, 'err> = + match result1, result2 with + | Ok ok1, Ok ok2 -> Ok (ok1, ok2) + | Error err, _ | _, Error err -> Error err + +let result = ResultBuilder() + let powersOfTwo = [ 1UL 2UL diff --git a/QuadTree/LinearAlgebra.fs b/QuadTree/LinearAlgebra.fs index 34eda4d..9c87cfc 100644 --- a/QuadTree/LinearAlgebra.fs +++ b/QuadTree/LinearAlgebra.fs @@ -2,10 +2,15 @@ module LinearAlgebra open Common -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> +type MXMError = + | InconsistentSizeOfArguments + | MatrixAdditionProblem of Matrix.Error + +type Error = + | InconsistentStructureOfStorages + | InconsistentSizeOfArguments + | VectorAdditionProblem of Vector.Error + | MXMError of MXMError let rec multScalar op_add (x: uint64) y = @@ -24,10 +29,10 @@ let vxm op_add op_mult (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseM 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)) -> + | Ok((t1, nvals1)), + Ok((t2, nvals2)), + Ok((t3, nvals3)), + Ok((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))) @@ -36,22 +41,22 @@ let vxm op_add op_mult (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseM let vAdd v1 (v2: Vector.SparseVector<_>) = match v2.storage.data with - | Vector.Leaf(Dummy) -> Result.Success(v1) + | Vector.Leaf(Dummy) -> Ok(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)) + | Ok(v1), Ok(v2) -> + Ok((Vector.mkNode v1.storage.data v2.storage.data), v1.nvals + v2.nvals) + | Error(e), _ + | _, Error(e) -> Error(VectorAdditionProblem(e)) - | Result.Failure(e), _, _, _ - | _, Result.Failure(e), _, _ - | _, _, Result.Failure(e), _ - | _, _, _, Result.Failure(e) -> Result.Failure(e) + | Error(e), _, _, _ + | _, Error(e), _, _ + | _, _, Error(e), _ + | _, _, _, Error(e) -> Error(e) match (vector, matrix) with | Vector.btree.Leaf(UserValue(v1)), Matrix.qtree.Leaf(UserValue(v2)) -> @@ -62,15 +67,15 @@ let vxm op_add op_mult (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseM | None -> 0UL | _ -> (uint64 size) * 1UL - Result.Success(Vector.btree.Leaf(UserValue(res)), nnz) + Ok(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) -> Result.Success(Vector.btree.Leaf(Dummy), 0UL) - | (x, y) -> Result.Failure <| Error.InconsistentStructureOfStorages(x, y) + | _, Matrix.qtree.Leaf(Dummy) -> Ok(Vector.btree.Leaf(Dummy), 0UL) + | (x, y) -> Error Error.InconsistentStructureOfStorages if uint64 vector.length = uint64 matrix.nrows then let vector_storage = @@ -90,21 +95,16 @@ let vxm op_add op_mult (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseM vector.storage match inner vector_storage.size vector_storage.data matrix.storage.data with - | Result.Failure x -> Result.Failure x - | Result.Success(storage, nvals) -> + | Error x -> Error x + | Ok(storage, nvals) -> (Vector.SparseVector( (uint64 matrix.ncols) * 1UL, nvals, (Vector.Storage(matrix.storage.size, storage)) )) - |> Result.Success + |> Ok else - (Error.InconsistentSizeOfArguments(vector, matrix)) |> Result.Failure - - -type MXMError<'value1, 'value2, 'value3> = - | InconsistentSizeOfArguments of Matrix.SparseMatrix<'value1> * Matrix.SparseMatrix<'value2> - | MatrixAdditionProblem of Matrix.Error<'value3, 'value3> + Error Error.InconsistentSizeOfArguments let mxm @@ -143,14 +143,14 @@ let mxm (multiply halfSize se1 se2) match nw1_x_nw2, ne1_x_sw2, nw1_x_ne2, ne1_x_se2, sw1_x_nw2, se1_x_sw2, sw1_x_ne2, se1_x_se2 with - | Result.Success(tnw1_x_nw2, nvals_nw1_x_nw2), - Result.Success(tne1_x_sw2, nvals_ne1_x_sw2), - Result.Success(tnw1_x_ne2, nvals_nw1_x_ne2), - Result.Success(tne1_x_se2, nvals_ne1_x_se2), - Result.Success(tsw1_x_nw2, nvals_sw1_x_nw2), - Result.Success(tse1_x_sw2, nvals_se1_x_sw2), - Result.Success(tsw1_x_ne2, nvals_sw1_x_ne2), - Result.Success(tse1_x_se2, nvals_se1_x_se2) -> + | Ok(tnw1_x_nw2, nvals_nw1_x_nw2), + Ok(tne1_x_sw2, nvals_ne1_x_sw2), + Ok(tnw1_x_ne2, nvals_nw1_x_ne2), + Ok(tne1_x_se2, nvals_ne1_x_se2), + Ok(tsw1_x_nw2, nvals_sw1_x_nw2), + Ok(tse1_x_sw2, nvals_se1_x_sw2), + Ok(tsw1_x_ne2, nvals_sw1_x_ne2), + Ok(tse1_x_se2, nvals_se1_x_se2) -> let nrows = (uint64 halfSize) * 1UL let ncols = (uint64 halfSize) * 1UL let storageSize = halfSize @@ -181,7 +181,7 @@ let mxm let mAdd m1 (m2: Matrix.SparseMatrix<_>) = match m2.storage.data with - | Matrix.qtree.Leaf Dummy -> Result.Success m1 + | Matrix.qtree.Leaf Dummy -> Ok m1 | _ -> Matrix.map2 m1 m2 op_add let rnw = mAdd nw1_x_nw2 ne1_x_sw2 @@ -190,24 +190,24 @@ let mxm let rse = mAdd sw1_x_ne2 se1_x_se2 match rnw, rne, rsw, rse with - | Result.Success(nw), Result.Success(ne), Result.Success(sw), Result.Success(se) -> - Result.Success( + | Ok(nw), Ok(ne), Ok(sw), Ok(se) -> + Ok( Matrix.mkNode nw.storage.data ne.storage.data sw.storage.data se.storage.data, nw.nvals + ne.nvals + sw.nvals + se.nvals ) - | Result.Failure(e), _, _, _ - | _, Result.Failure(e), _, _ - | _, _, Result.Failure(e), _ - | _, _, _, Result.Failure(e) -> Result.Failure(MXMError.MatrixAdditionProblem(e)) - - | Result.Failure(e), _, _, _, _, _, _, _ - | _, Result.Failure(e), _, _, _, _, _, _ - | _, _, Result.Failure(e), _, _, _, _, _ - | _, _, _, Result.Failure(e), _, _, _, _ - | _, _, _, _, Result.Failure(e), _, _, _ - | _, _, _, _, _, Result.Failure(e), _, _ - | _, _, _, _, _, _, Result.Failure(e), _ - | _, _, _, _, _, _, _, Result.Failure(e) -> Result.Failure(e) + | Error(e), _, _, _ + | _, Error(e), _, _ + | _, _, Error(e), _ + | _, _, _, Error(e) -> Error(Error.MXMError(MXMError.MatrixAdditionProblem(e))) + + | Error(e), _, _, _, _, _, _, _ + | _, Error(e), _, _, _, _, _, _ + | _, _, Error(e), _, _, _, _, _ + | _, _, _, Error(e), _, _, _, _ + | _, _, _, _, Error(e), _, _, _ + | _, _, _, _, _, Error(e), _, _ + | _, _, _, _, _, _, Error(e), _ + | _, _, _, _, _, _, _, Error(e) -> Error(e) match m1, m2 with | Matrix.qtree.Leaf(UserValue v1), Matrix.qtree.Leaf(UserValue v2) -> @@ -218,7 +218,7 @@ let mxm | None -> 0UL | _ -> (uint64 <| size * size) * 1UL - Result.Success(Matrix.qtree.Leaf(UserValue res), nnz) + Ok(Matrix.qtree.Leaf(UserValue res), nnz) | Matrix.qtree.Leaf(UserValue(_)), Matrix.qtree.Node(nw2, ne2, sw2, se2) -> divided (m1, m1, m1, m1) (nw2, ne2, sw2, se2) | Matrix.qtree.Node(nw1, ne1, sw1, se1), Matrix.qtree.Leaf(UserValue(_)) -> @@ -226,7 +226,7 @@ let mxm | Matrix.qtree.Node(nw1, ne1, sw1, se1), Matrix.qtree.Node(nw2, ne2, sw2, se2) -> divided (nw1, ne1, sw1, se1) (nw2, ne2, sw2, se2) | Matrix.qtree.Leaf Dummy, _ - | _, Matrix.qtree.Leaf Dummy -> Result.Success(Matrix.qtree.Leaf Dummy, 0UL) + | _, Matrix.qtree.Leaf Dummy -> Ok(Matrix.qtree.Leaf Dummy, 0UL) if uint64 m1.ncols = uint64 m2.nrows then let nrows = m1.nrows @@ -242,11 +242,11 @@ let mxm m1.storage.data, m2.storage.data match multiply storageSize m1_tree m2_tree with - | Result.Success(tree, nvals) -> + | Ok(tree, nvals) -> // in case the resulting storageSize can be smaller // e.g. (2x3) * (3x2) matrices let tree, storageSize = shrink tree storageSize - Result.Success(Matrix.SparseMatrix(nrows, ncols, nvals, Matrix.Storage(storageSize, tree))) - | Result.Failure(e) -> Result.Failure(e) + Ok(Matrix.SparseMatrix(nrows, ncols, nvals, Matrix.Storage(storageSize, tree))) + | Error(e) -> Error(e) else - MXMError.InconsistentSizeOfArguments(m1, m2) |> Result.Failure + Error(Error.MXMError MXMError.InconsistentSizeOfArguments) diff --git a/QuadTree/Matrix.fs b/QuadTree/Matrix.fs index 7697762..c1a19e0 100644 --- a/QuadTree/Matrix.fs +++ b/QuadTree/Matrix.fs @@ -38,9 +38,9 @@ type SparseMatrix<'value> = nvals = _nvals storage = _storage } -type Error<'value1, 'value2> = - | InconsistentStructureOfStorages of qtree> * qtree> - | InconsistentSizeOfArguments of SparseMatrix<'value1> * SparseMatrix<'value2> +type Error = + | InconsistentStructureOfStorages + | InconsistentSizeOfArguments let mkNode x1 x2 x3 x4 = @@ -143,19 +143,19 @@ let map2 (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = let new_size = size / 2UL match (inner new_size x1 y1), (inner new_size x2 y2), (inner new_size x3 y3), (inner new_size x4 y4) with - | Result.Success((new_t1, nvals1)), - Result.Success((new_t2, nvals2)), - Result.Success((new_t3, nvals3)), - Result.Success((new_t4, nvals4)) -> + | Ok((new_t1, nvals1)), + Ok((new_t2, nvals2)), + Ok((new_t3, nvals3)), + Ok((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) + |> Ok + | Error(e), _, _, _ + | _, Error(e), _, _ + | _, _, Error(e), _ + | _, _, _, Error(e) -> Error(e) match (matrix1, matrix2) with - | Leaf(Dummy), Leaf(Dummy) -> Result.Success(Leaf(Dummy), 0UL) + | Leaf(Dummy), Leaf(Dummy) -> Ok(Leaf(Dummy), 0UL) | Leaf(UserValue(v1)), Leaf(UserValue(v2)) -> let res = f v1 v2 @@ -164,21 +164,21 @@ let map2 (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = | None -> 0UL | _ -> (uint64 size) * (uint64 size) * 1UL - (Leaf(UserValue(res)), nnz) |> Result.Success + (Leaf(UserValue(res)), nnz) |> Ok | 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) + | (x, y) -> Error Error.InconsistentStructureOfStorages if matrix1.nrows = matrix2.nrows && matrix1.ncols = matrix2.ncols then match inner matrix1.storage.size matrix1.storage.data matrix2.storage.data with - | Result.Failure x -> Result.Failure x - | Result.Success(storage, nvals) -> + | Error x -> Error x + | Ok(storage, nvals) -> (SparseMatrix(matrix1.nrows, matrix1.ncols, nvals, (Storage(matrix1.storage.size, storage)))) - |> Result.Success + |> Ok else - (Error.InconsistentSizeOfArguments(matrix1, matrix2)) |> Result.Failure + Error Error.InconsistentSizeOfArguments let foldAssociative (folder: 'T option -> 'T option -> 'T option) (state: 'T option) (matrix: SparseMatrix<'T>) = let rec traverse tree (size: uint64) (state: 'T option) = diff --git a/QuadTree/QuadTree.fsproj b/QuadTree/QuadTree.fsproj index 2b2b699..928756b 100644 --- a/QuadTree/QuadTree.fsproj +++ b/QuadTree/QuadTree.fsproj @@ -6,7 +6,6 @@ - diff --git a/QuadTree/Result.fs b/QuadTree/Result.fs deleted file mode 100644 index c107bf6..0000000 --- a/QuadTree/Result.fs +++ /dev/null @@ -1,5 +0,0 @@ -module Result - -type Result<'success, 'failure> = - | Success of 'success - | Failure of 'failure diff --git a/QuadTree/SSSP.fs b/QuadTree/SSSP.fs index 543e060..9cc655c 100644 --- a/QuadTree/SSSP.fs +++ b/QuadTree/SSSP.fs @@ -2,10 +2,10 @@ module Graph.SSSP open Common -type Error<'t1, 't2> = - | NewFrontierCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't1> - | FrontierCalculationProblem of Vector.Error<'t1, 't1> - | VisitedCalculationProblem of Vector.Error<'t1, 't1> +type Error = + | NewFrontierCalculationProblem of LinearAlgebra.Error + | FrontierCalculationProblem of Vector.Error + | VisitedCalculationProblem of Vector.Error let sssp graph (startVertex: uint64) = let op_add x y = @@ -26,8 +26,8 @@ let sssp graph (startVertex: uint64) = let new_frontier = LinearAlgebra.vxm op_add op_mult frontier graph match new_frontier with - | Result.Failure(e) -> Result.Failure(NewFrontierCalculationProblem(e)) - | Result.Success(new_frontier) -> + | Error(e) -> Error(NewFrontierCalculationProblem(e)) + | Ok(new_frontier) -> let op_min x y = match (x, y) with | Some v, Some u -> if v < u then Some v else None @@ -37,16 +37,16 @@ let sssp graph (startVertex: uint64) = let frontier = Vector.map2 new_frontier visited op_min match frontier with - | Result.Failure(e) -> Result.Failure(FrontierCalculationProblem(e)) - | Result.Success(frontier) -> + | Error(e) -> Error(FrontierCalculationProblem(e)) + | Ok(frontier) -> let visited = Vector.map2 visited frontier op_add match visited with - | Result.Failure(e) -> Result.Failure(VisitedCalculationProblem(e)) - | Result.Success(visited) -> inner frontier visited (iter_num + 1) + | Error(e) -> Error(VisitedCalculationProblem(e)) + | Ok(visited) -> inner frontier visited (iter_num + 1) else - Result.Success visited + Ok visited let frontier = Vector.CoordinateList((uint64 graph.ncols) * 1UL, [ startVertex * 1UL, 0.0 ]) diff --git a/QuadTree/TriangleCount.fs b/QuadTree/TriangleCount.fs index f1d41b6..ccdc01d 100644 --- a/QuadTree/TriangleCount.fs +++ b/QuadTree/TriangleCount.fs @@ -2,9 +2,9 @@ module Graph.TriangleCount open Common -type TriangleCountError<'value1, 'value2, 'value3> = - | MXMError of LinearAlgebra.MXMError<'value1, 'value2, 'value3> - | MaskingError of Matrix.Error<'value3, 'value2> +type TriangleCountError = + | MXMError of LinearAlgebra.Error + | MaskingError of Matrix.Error // Assume non-oriented graph adjacency matrix // Some _ -> edge, None -> no edge @@ -28,15 +28,15 @@ let triangle_count (graph: Matrix.SparseMatrix<_>) = let CMasked = match C with - | Result.Success matrix -> + | Ok matrix -> match Matrix.mask matrix graph Option.isSome with - | Result.Success m -> Result.Success m - | Result.Failure e -> Result.Failure <| TriangleCountError.MaskingError e - | Result.Failure e -> Result.Failure <| TriangleCountError.MXMError e + | Ok m -> Ok m + | Error e -> Error (TriangleCountError.MaskingError e) + | Error e -> Error (TriangleCountError.MXMError e) let result = match CMasked with - | Result.Success matrix -> Result.Success(Matrix.foldAssociative op_add None matrix) - | Result.Failure e -> Result.Failure e + | Ok matrix -> Ok(Matrix.foldAssociative op_add None matrix) + | Error e -> Error e result diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index 0bf187d..3f15175 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -26,9 +26,9 @@ type SparseVector<'value> = nvals = _nvals storage = _storage } -type Error<'value1, 'value2> = - | InconsistentStructureOfStorages of btree> * btree> - | InconsistentSizeOfArguments of SparseVector<'value1> * SparseVector<'value2> +type Error = + | InconsistentStructureOfStorages + | InconsistentSizeOfArguments (* let foldValues state f tree = @@ -128,16 +128,16 @@ let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = let new_size = size / 2UL match (inner new_size x1 y1), (inner new_size x2 y2) with - | Result.Success((t1, nvals1)), Result.Success((t2, nvals2)) -> - ((mkNode t1 t2), nvals1 + nvals2) |> Result.Success - | Result.Failure(e), _ - | _, Result.Failure(e) -> Result.Failure(e) + | Ok((t1, nvals1)), Ok((t2, nvals2)) -> + ((mkNode t1 t2), nvals1 + nvals2) |> Ok + | Error(e), _ + | _, Error(e) -> Error(e) match (vector1, vector2) with | Node(x1, x2), Leaf(_) -> _do x1 x2 vector2 vector2 | Leaf(_), Node(y1, y2) -> _do vector1 vector1 y1 y2 | Node(x1, x2), Node(y1, y2) -> _do x1 x2 y1 y2 - | Leaf(Dummy), Leaf(Dummy) -> Result.Success(Leaf(Dummy), 0UL) + | Leaf(Dummy), Leaf(Dummy) -> Ok(Leaf(Dummy), 0UL) | Leaf(UserValue(v1)), Leaf(UserValue(v2)) -> let res = f v1 v2 @@ -146,17 +146,17 @@ let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = | None -> 0UL | _ -> (uint64 size) * 1UL - Result.Success(Leaf(UserValue(res)), nnz) + Ok(Leaf(UserValue(res)), nnz) - | (x, y) -> Result.Failure <| Error.InconsistentStructureOfStorages(x, y) + | (x, y) -> Error Error.InconsistentStructureOfStorages if len1 = vector2.length then match inner vector1.storage.size vector1.storage.data vector2.storage.data with - | Result.Failure(e) -> Result.Failure(e) - | Result.Success((storage, nvals)) -> - Result.Success(SparseVector(len1, nvals, (Storage(vector1.storage.size, storage)))) + | Error(e) -> Error(e) + | Ok((storage, nvals)) -> + Ok(SparseVector(len1, nvals, (Storage(vector1.storage.size, storage)))) else - Result.Failure <| Error.InconsistentSizeOfArguments(vector1, vector2) + Error Error.InconsistentSizeOfArguments let mask (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = map2 vector1 vector2 (fun v1 v2 -> if f v2 then v1 else None) From d20eb8fddcfae6b0005ebf7fe06996212862a016 Mon Sep 17 00:00:00 2001 From: gsv Date: Fri, 27 Mar 2026 17:29:01 +0300 Subject: [PATCH 02/52] Apply result workflow for SSSP and TriangleCount. --- QuadTree/SSSP.fs | 30 ++++++++++++++++-------------- QuadTree/TriangleCount.fs | 31 +++++++++++++------------------ 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/QuadTree/SSSP.fs b/QuadTree/SSSP.fs index 9cc655c..bfb6d35 100644 --- a/QuadTree/SSSP.fs +++ b/QuadTree/SSSP.fs @@ -7,6 +7,10 @@ type Error = | FrontierCalculationProblem of Vector.Error | VisitedCalculationProblem of Vector.Error +let mapError (err: LinearAlgebra.Error) = NewFrontierCalculationProblem err +let mapError' (err: Vector.Error) = FrontierCalculationProblem err +let mapError'' (err: Vector.Error) = VisitedCalculationProblem err + let sssp graph (startVertex: uint64) = let op_add x y = match (x, y) with @@ -22,29 +26,27 @@ let sssp graph (startVertex: uint64) = let rec inner (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) iter_num = if frontier.nvals > 0UL && iter_num <= int frontier.length then + result { + let! new_frontier = + LinearAlgebra.vxm op_add op_mult frontier graph + |> Common.Result.mapError mapError - let new_frontier = LinearAlgebra.vxm op_add op_mult frontier graph - - match new_frontier with - | Error(e) -> Error(NewFrontierCalculationProblem(e)) - | Ok(new_frontier) -> let op_min x y = match (x, y) with | Some v, Some u -> if v < u then Some v else None | Some v, _ -> Some v | _ -> None - let frontier = Vector.map2 new_frontier visited op_min - - match frontier with - | Error(e) -> Error(FrontierCalculationProblem(e)) - | Ok(frontier) -> + let! frontier = + Vector.map2 new_frontier visited op_min + |> Common.Result.mapError mapError' - let visited = Vector.map2 visited frontier op_add + let! visited = + Vector.map2 visited frontier op_add + |> Common.Result.mapError mapError'' - match visited with - | Error(e) -> Error(VisitedCalculationProblem(e)) - | Ok(visited) -> inner frontier visited (iter_num + 1) + return! inner frontier visited (iter_num + 1) + } else Ok visited diff --git a/QuadTree/TriangleCount.fs b/QuadTree/TriangleCount.fs index ccdc01d..b9859a4 100644 --- a/QuadTree/TriangleCount.fs +++ b/QuadTree/TriangleCount.fs @@ -2,13 +2,13 @@ module Graph.TriangleCount open Common -type TriangleCountError = +type Error = | MXMError of LinearAlgebra.Error | MaskingError of Matrix.Error -// Assume non-oriented graph adjacency matrix -// Some _ -> edge, None -> no edge -// Computes triangle count +let mapError (err: LinearAlgebra.Error) = MXMError err +let mapError' (err: Matrix.Error) = MaskingError err + let triangle_count (graph: Matrix.SparseMatrix<_>) = let graph = Matrix.getLowerTriangle graph @@ -24,19 +24,14 @@ let triangle_count (graph: Matrix.SparseMatrix<_>) = | Some _, Some _ -> Some 1UL | _ -> None - let C = LinearAlgebra.mxm op_add op_mult graph (Matrix.transpose graph) - - let CMasked = - match C with - | Ok matrix -> - match Matrix.mask matrix graph Option.isSome with - | Ok m -> Ok m - | Error e -> Error (TriangleCountError.MaskingError e) - | Error e -> Error (TriangleCountError.MXMError e) + result { + let! C = + LinearAlgebra.mxm op_add op_mult graph (Matrix.transpose graph) + |> Common.Result.mapError mapError - let result = - match CMasked with - | Ok matrix -> Ok(Matrix.foldAssociative op_add None matrix) - | Error e -> Error e + let! CMasked = + Matrix.mask C graph Option.isSome + |> Common.Result.mapError mapError' - result + return Matrix.foldAssociative op_add None CMasked + } From aac95bee06792d8b85878012159b4a63aad5ced3 Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 30 Mar 2026 10:52:10 +0300 Subject: [PATCH 03/52] Result workflow related stuff moved to separated Result.fs file. --- QuadTree/BFS.fs | 9 +++++---- QuadTree/Common.fs | 40 --------------------------------------- QuadTree/QuadTree.fsproj | 1 + QuadTree/Result.fs | 40 +++++++++++++++++++++++++++++++++++++++ QuadTree/SSSP.fs | 9 +++++---- QuadTree/TriangleCount.fs | 7 ++++--- 6 files changed, 55 insertions(+), 51 deletions(-) create mode 100644 QuadTree/Result.fs diff --git a/QuadTree/BFS.fs b/QuadTree/BFS.fs index 4ed1da0..2f84ec9 100644 --- a/QuadTree/BFS.fs +++ b/QuadTree/BFS.fs @@ -1,6 +1,7 @@ module Graph.BFS open Common +open Result type Error = | NewFrontierCalculationProblem of LinearAlgebra.Error @@ -14,17 +15,17 @@ let mapError'' (err: Vector.Error) = VisitedCalculationProblem err let bfs_level graph startVertices = let rec inner level (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) = if frontier.nvals > 0UL then - result { + resultM { let! new_frontier = LinearAlgebra.vxm (fun x y -> match (x, y) with | Some(v), _ | _, Some(v) -> Some(v) | _ -> None) (fun x y -> match (x, y) with | Some(v), Some(_) -> Some(v) | _ -> None) frontier graph - |> Common.Result.mapError mapError + |> Result.mapError mapError let! frontier = Vector.mask new_frontier visited (fun x -> x.IsNone) - |> Common.Result.mapError mapError' + |> Result.mapError mapError' let! visited = Vector.map2 visited new_frontier (fun x y -> @@ -32,7 +33,7 @@ let bfs_level graph startVertices = | (Some(_), _) -> x | (None, Some(_)) -> Some(level) | _ -> None) - |> Common.Result.mapError mapError'' + |> Result.mapError mapError'' return! inner (level + 1UL) frontier visited } diff --git a/QuadTree/Common.fs b/QuadTree/Common.fs index 4078e22..0ce5854 100644 --- a/QuadTree/Common.fs +++ b/QuadTree/Common.fs @@ -14,46 +14,6 @@ type BinSearchTree<'value> = | Leaf of 'value | Node of BinSearchTree<'value> * 'value * BinSearchTree<'value> -module Error = - let map (f: 'a -> 'b) (err: 'a) : 'b = f err - -module Result = - let mapError (f: 'e1 -> 'e2) (result: Result<'ok, 'e1>) : Result<'ok, 'e2> = - match result with - | Ok ok -> Ok ok - | Error err -> Error (f err) - -type ResultBuilder() = - member _.Return(x: 'ok) : Result<'ok, 'err> = Ok x - member _.ReturnFrom(result: Result<'ok, 'err>) : Result<'ok, 'err> = result - member _.Bind(result: Result<'ok, 'err>, f: 'ok -> Result<'ok2, 'err>) : Result<'ok2, 'err> = - match result with - | Ok ok -> f ok - | Error err -> Error err - member _.Zero() : Result = Ok () - member _.Delay(f: unit -> Result<'ok, 'err>) = f - member _.Run(f: unit -> Result<'ok, 'err>) = f () - member this.While(guard: unit -> bool, body: unit -> Result) = - if guard() then - this.Bind(body(), fun () -> this.While(guard, body)) - else - this.Zero() - member this.For(sequence: seq<'ok>, f: 'ok -> Result) = - use en = sequence.GetEnumerator() - this.While(en.MoveNext, fun () -> f en.Current) - - member _.Combine(result1: Result, result2: Result<'ok, 'err>) : Result<'ok, 'err> = - match result1 with - | Ok () -> result2 - | Error err -> Error err - - member this.MergeSources(result1: Result<'ok1, 'err>, result2: Result<'ok2, 'err>) : Result<'ok1 * 'ok2, 'err> = - match result1, result2 with - | Ok ok1, Ok ok2 -> Ok (ok1, ok2) - | Error err, _ | _, Error err -> Error err - -let result = ResultBuilder() - let powersOfTwo = [ 1UL 2UL diff --git a/QuadTree/QuadTree.fsproj b/QuadTree/QuadTree.fsproj index 928756b..2b2b699 100644 --- a/QuadTree/QuadTree.fsproj +++ b/QuadTree/QuadTree.fsproj @@ -6,6 +6,7 @@ + diff --git a/QuadTree/Result.fs b/QuadTree/Result.fs new file mode 100644 index 0000000..665dadb --- /dev/null +++ b/QuadTree/Result.fs @@ -0,0 +1,40 @@ +module Result + +module Error = + let map (f: 'a -> 'b) (err: 'a) : 'b = f err + +let mapError (f: 'e1 -> 'e2) (result: Result<'ok, 'e1>) : Result<'ok, 'e2> = + match result with + | Ok ok -> Ok ok + | Error err -> Error (f err) + +type ResultBuilder() = + member _.Return(x: 'ok) : Result<'ok, 'err> = Ok x + member _.ReturnFrom(result: Result<'ok, 'err>) : Result<'ok, 'err> = result + member _.Bind(result: Result<'ok, 'err>, f: 'ok -> Result<'ok2, 'err>) : Result<'ok2, 'err> = + match result with + | Ok ok -> f ok + | Error err -> Error err + member _.Zero() : Result = Ok () + member _.Delay(f: unit -> Result<'ok, 'err>) = f + member _.Run(f: unit -> Result<'ok, 'err>) = f () + member this.While(guard: unit -> bool, body: unit -> Result) = + if guard() then + this.Bind(body(), fun () -> this.While(guard, body)) + else + this.Zero() + member this.For(sequence: seq<'ok>, f: 'ok -> Result) = + use en = sequence.GetEnumerator() + this.While(en.MoveNext, fun () -> f en.Current) + + member _.Combine(result1: Result, result2: Result<'ok, 'err>) : Result<'ok, 'err> = + match result1 with + | Ok () -> result2 + | Error err -> Error err + + member this.MergeSources(result1: Result<'ok1, 'err>, result2: Result<'ok2, 'err>) : Result<'ok1 * 'ok2, 'err> = + match result1, result2 with + | Ok ok1, Ok ok2 -> Ok (ok1, ok2) + | Error err, _ | _, Error err -> Error err + +let resultM = ResultBuilder() diff --git a/QuadTree/SSSP.fs b/QuadTree/SSSP.fs index bfb6d35..fc4d084 100644 --- a/QuadTree/SSSP.fs +++ b/QuadTree/SSSP.fs @@ -1,6 +1,7 @@ module Graph.SSSP open Common +open Result type Error = | NewFrontierCalculationProblem of LinearAlgebra.Error @@ -26,10 +27,10 @@ let sssp graph (startVertex: uint64) = let rec inner (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) iter_num = if frontier.nvals > 0UL && iter_num <= int frontier.length then - result { + resultM { let! new_frontier = LinearAlgebra.vxm op_add op_mult frontier graph - |> Common.Result.mapError mapError + |> Result.mapError mapError let op_min x y = match (x, y) with @@ -39,11 +40,11 @@ let sssp graph (startVertex: uint64) = let! frontier = Vector.map2 new_frontier visited op_min - |> Common.Result.mapError mapError' + |> Result.mapError mapError' let! visited = Vector.map2 visited frontier op_add - |> Common.Result.mapError mapError'' + |> Result.mapError mapError'' return! inner frontier visited (iter_num + 1) } diff --git a/QuadTree/TriangleCount.fs b/QuadTree/TriangleCount.fs index b9859a4..08c355d 100644 --- a/QuadTree/TriangleCount.fs +++ b/QuadTree/TriangleCount.fs @@ -1,6 +1,7 @@ module Graph.TriangleCount open Common +open Result type Error = | MXMError of LinearAlgebra.Error @@ -24,14 +25,14 @@ let triangle_count (graph: Matrix.SparseMatrix<_>) = | Some _, Some _ -> Some 1UL | _ -> None - result { + resultM { let! C = LinearAlgebra.mxm op_add op_mult graph (Matrix.transpose graph) - |> Common.Result.mapError mapError + |> Result.mapError mapError let! CMasked = Matrix.mask C graph Option.isSome - |> Common.Result.mapError mapError' + |> Result.mapError mapError' return Matrix.foldAssociative op_add None CMasked } From 81499785bbe69c180dcfd67f70b59e3b8252525e Mon Sep 17 00:00:00 2001 From: gsv Date: Fri, 20 Mar 2026 16:55:43 +0300 Subject: [PATCH 04/52] Minimal version of Vector.gather --- QuadTree.Tests/Tests.Vector.fs | 34 +++++++++++++++++ QuadTree/Vector.fs | 67 +++++++++++++++++++++++++++------- 2 files changed, 88 insertions(+), 13 deletions(-) diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index ebf75ef..d9e1b7e 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -227,3 +227,37 @@ let ``Condensation of empty`` () = SparseVector(clist.length, 0UL, Storage(16UL, tree)) Assert.Equal(expected, actual) + + +[] +let ``Gather``() = + let data = + Vector.CoordinateList( + 5UL, + [ (0UL, 0.0) + (1UL, 1.0) + (4UL, 5.0) ] + ) + |> Vector.fromCoordinateList + + let indices = + Vector.CoordinateList( + 5UL, + [ (0UL, 1UL) + (1UL, 4UL) + (3UL, 1UL) ] + ) + |> Vector.fromCoordinateList + + let actual = Vector.gather data indices + + let expected = + Vector.CoordinateList( + 5UL, + [ (0UL, 1.0) + (1UL, 5.0) + (3UL, 1.0) ] + ) + |> Vector.fromCoordinateList + + Assert.Equal(expected, actual) diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index 3f15175..300381a 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -9,6 +9,9 @@ type 'value btree = [] type dataLength +[] +type index + [] type Storage<'value> = val size: uint64 @@ -42,8 +45,6 @@ let mkNode t1 t2 = | Leaf(v1), Leaf(v2) when v1 = v2 -> Leaf(v1) | _ -> Node(t1, t2) -[] -type index [] type CoordinateList<'value> = @@ -98,6 +99,8 @@ let toCoordinateList (vector: SparseVector<'a>) = CoordinateList(length, lst) + + let map (vector: SparseVector<'a>) f = let rec inner (size: uint64) vector = match vector with @@ -128,16 +131,16 @@ let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = let new_size = size / 2UL match (inner new_size x1 y1), (inner new_size x2 y2) with - | Ok((t1, nvals1)), Ok((t2, nvals2)) -> - ((mkNode t1 t2), nvals1 + nvals2) |> Ok - | Error(e), _ - | _, Error(e) -> Error(e) + | Result.Success((t1, nvals1)), Result.Success((t2, nvals2)) -> + ((mkNode t1 t2), nvals1 + nvals2) |> Result.Success + | Result.Failure(e), _ + | _, Result.Failure(e) -> Result.Failure(e) match (vector1, vector2) with | Node(x1, x2), Leaf(_) -> _do x1 x2 vector2 vector2 | Leaf(_), Node(y1, y2) -> _do vector1 vector1 y1 y2 | Node(x1, x2), Node(y1, y2) -> _do x1 x2 y1 y2 - | Leaf(Dummy), Leaf(Dummy) -> Ok(Leaf(Dummy), 0UL) + | Leaf(Dummy), Leaf(Dummy) -> Result.Success(Leaf(Dummy), 0UL) | Leaf(UserValue(v1)), Leaf(UserValue(v2)) -> let res = f v1 v2 @@ -146,17 +149,55 @@ let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = | None -> 0UL | _ -> (uint64 size) * 1UL - Ok(Leaf(UserValue(res)), nnz) + Result.Success(Leaf(UserValue(res)), nnz) - | (x, y) -> Error Error.InconsistentStructureOfStorages + | (x, y) -> Result.Failure <| Error.InconsistentStructureOfStorages(x, y) if len1 = vector2.length then match inner vector1.storage.size vector1.storage.data vector2.storage.data with - | Error(e) -> Error(e) - | Ok((storage, nvals)) -> - Ok(SparseVector(len1, nvals, (Storage(vector1.storage.size, storage)))) + | Result.Failure(e) -> Result.Failure(e) + | Result.Success((storage, nvals)) -> + Result.Success(SparseVector(len1, nvals, (Storage(vector1.storage.size, storage)))) else - Error Error.InconsistentSizeOfArguments + 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) + + +/// Returns None if index out of range +let private unsafeGet (v : SparseVector<'a>) (index : uint64) = + let originalIndex = index + let rec getFromTree (tree : btree>) (size : uint64) (index : uint64) = + match tree with + | Leaf Dummy -> None + | Leaf (UserValue v) -> v + | Node(l: Option<'a> btree, r) -> + let halfSize = size / 2UL + if uint64 index < uint64 halfSize then + getFromTree l halfSize index + else + getFromTree r halfSize ((uint64 index - uint64 halfSize)*1UL) + getFromTree v.storage.data v.storage.size index + +/// Gather: w[i] = v[idx[i]] +let gather (v : SparseVector<'value>) (idx : SparseVector>) : SparseVector<'value> = + map idx (fun i -> + match i with + | Some i-> unsafeGet v i + | None -> None) + +(* +let private merge_sort (v:SparseVector<'a>) (compare: 'a -> 'a -> bool) (collapse_equals: 'a -> 'a -> 'a) = + let rec inner (tree : btree>) = + match tree with + | Leaf v1, Leaf v2 -> +*) +(* +/// Scatter: w[idx[i]] = op(w[idx[i]], v[i]) +let scatter (v : SparseVector<'value>) (idx : SparseVector>) + (op : Option<'value> -> Option<'value> -> Option<'value>) : SparseVector<'value> = + map2 idx v (fun i v-> match (i,v) with Some (i), Some(v) -> Some (i,v) | _ -> None ) + +*) + From 551db2a462d654c606d7dd20b4ec927db89332bd Mon Sep 17 00:00:00 2001 From: gsv Date: Sun, 22 Mar 2026 20:25:21 +0300 Subject: [PATCH 05/52] Basic version of scatter and gather. --- QuadTree.Tests/Tests.Vector.fs | 136 +++++++++++++++++++++++++++++++ QuadTree/Boruvka.fs | 55 +++++++++++++ QuadTree/Map.fs | 144 +++++++++++++++++++++++++++++++++ QuadTree/QuadTree.fsproj | 2 + QuadTree/Vector.fs | 128 ++++++++++++++++++++++++----- 5 files changed, 447 insertions(+), 18 deletions(-) create mode 100644 QuadTree/Boruvka.fs create mode 100644 QuadTree/Map.fs diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index d9e1b7e..47552fc 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -261,3 +261,139 @@ let ``Gather``() = |> Vector.fromCoordinateList Assert.Equal(expected, actual) +(* +[] +let ``Scatter``() = + let data = + Vector.CoordinateList( + 5UL, + [ (0UL, 4.0) + (2UL, 5.0) + ] + ) + |> Vector.fromCoordinateList + + let indices = + Vector.CoordinateList( + 5UL, + [ (0UL, 3UL) + (2UL, 3UL) + ] + ) + |> Vector.fromCoordinateList + + let result = + Vector.CoordinateList( + 5UL, + [ (3UL, 1.0) + (4UL, 3.0) + ] + ) + |> Vector.fromCoordinateList + let actual = Vector.scatter result data indices (fun x y -> match (x,y) with | (Some x, Some y) -> Some (x + y) | Some x, _ | _, Some x -> Some x | _ -> None) + printVector actual + let expected = + Vector.CoordinateList( + 5UL, + [ (3UL, 10.0) + (4UL, 3.0) + ] + ) + |> Vector.fromCoordinateList + + Assert.Equal(expected, actual)*) + +let compare x y = + match (x,y) with + | Some x, None -> -1 + | Some x, Some y -> if x < y then -1 elif x > y then 1 else 0 + | None, Some x -> 1 + | _ -> 0 + +[] +let ``Sort one element vector``() = + let data = + Vector.CoordinateList( + 1UL, + [ (0UL, 0.0) + ] + ) + |> Vector.fromCoordinateList + let actual = Vector.mergeSort data compare + Assert.Equal(data, actual) + +[] +let ``Sort vector of two equal elements``() = + let data = + Vector.CoordinateList( + 2UL, + [ (0UL, 0.0);(1UL, 0.0) + ] + ) + |> Vector.fromCoordinateList + let actual = Vector.mergeSort data compare + Assert.Equal(data, actual) + +[] +let ``Sort vector of three equal elements``() = + let data = + Vector.CoordinateList( + 3UL, + [ (0UL, 2.0);(1UL, 2.0);(2UL, 2.0) + ] + ) + |> Vector.fromCoordinateList + + let actual = Vector.mergeSort data compare + Assert.Equal(data, actual) + + +[] +let ``Sort vector of three different unordered elements``() = + let data = + Vector.CoordinateList( + 3UL, + [ (0UL, 2.0);(1UL, 1.0);(2UL, 4.0) + ] + ) + |> Vector.fromCoordinateList + let expected = + Vector.CoordinateList( + 3UL, + [ (0UL, 1.0);(1UL, 2.0);(2UL, 4.0) + ] + ) + |> Vector.fromCoordinateList + let actual = Vector.mergeSort data compare + Assert.Equal(expected, actual) + + + +[] +let ``Sort long vector with one element``() = + let data = + Vector.CoordinateList( + 5UL, + [ (0UL, 0.0) + ] + ) + |> Vector.fromCoordinateList + let actual = Vector.mergeSort data compare + printVector actual + Assert.Equal(data, actual) + + + +[] +let ``Sort sorted vector``() = + let data = + Vector.CoordinateList( + 5UL, + [ (0UL, 0.0); (1UL, 0.0) + ] + ) + |> Vector.fromCoordinateList + let actual = Vector.mergeSort data compare + Assert.Equal(data, actual) + + \ No newline at end of file diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs new file mode 100644 index 0000000..f669f92 --- /dev/null +++ b/QuadTree/Boruvka.fs @@ -0,0 +1,55 @@ +module Graph.Boruvka + +open Common + +type Error<'t1, 't2> = + | NewFrontierCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't1> + | FrontierCalculationProblem of Vector.Error<'t1, 't1> + | VisitedCalculationProblem of Vector.Error<'t1, 't1> + +let sssp graph (startVertex: uint64) = + let op_add x y = + match (x, y) with + | Some(u), Some(v) -> Some(min u v) + | Some(v), _ + | _, Some(v) -> Some(v) + | _ -> None + + let op_mult x y = + match (x, y) with + | Some(u), Some(v) -> Some(u + v) + | _ -> None + + let rec inner (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) iter_num = + if frontier.nvals > 0UL && iter_num <= int frontier.length then + + let new_frontier = LinearAlgebra.vxm op_add op_mult frontier graph + + match new_frontier with + | Result.Failure(e) -> Result.Failure(NewFrontierCalculationProblem(e)) + | Result.Success(new_frontier) -> + let op_min x y = + match (x, y) with + | Some v, Some u -> if v < u then Some v else None + | Some v, _ -> Some v + | _ -> None + + let frontier = Vector.map2 new_frontier visited op_min + + match frontier with + | Result.Failure(e) -> Result.Failure(FrontierCalculationProblem(e)) + | Result.Success(frontier) -> + + let visited = Vector.map2 visited frontier op_add + + match visited with + | Result.Failure(e) -> Result.Failure(VisitedCalculationProblem(e)) + | Result.Success(visited) -> inner frontier visited (iter_num + 1) + else + Result.Success visited + + let frontier = + Vector.CoordinateList((uint64 graph.ncols) * 1UL, [ startVertex * 1UL, 0.0 ]) + |> Vector.fromCoordinateList + + inner frontier frontier 0 diff --git a/QuadTree/Map.fs b/QuadTree/Map.fs new file mode 100644 index 0000000..bcbf636 --- /dev/null +++ b/QuadTree/Map.fs @@ -0,0 +1,144 @@ +module Map + +type TreeMap<'K, 'V> = + | Empty + | Node of key: 'K * value: 'V * height: int * left: TreeMap<'K, 'V> * right: TreeMap<'K, 'V> + +let private height tree = + match tree with + | Empty -> 0 + | Node(_, _, h, _, _) -> h + +let private makeNode k v l r = + let h = 1 + max (height l) (height r) + Node(k, v, h, l, r) + +let private rotateRight tree= + match tree with + | Empty -> Empty + | Node(x, vx, _, left, right) -> + match left with + | Empty -> failwith "rotateRight: left child is empty" + | Node(y, vy, _, ly, ry) -> + Node(y, vy, + 1 + max (height ly) (height (makeNode x vx ry right)), + ly, makeNode x vx ry right) + +let private rotateLeft tree= + match tree with + | Empty -> Empty + | Node(x, vx, _, left, right) -> + match right with + | Empty -> failwith "rotateLeft: right child is empty" + | Node(y, vy, _, ly, ry) -> + Node(y, vy, + 1 + max (height (makeNode x vx left ly)) (height ry), + makeNode x vx left ly, ry) + +let private balance k v l r = + let hl = height l + let hr = height r + if hl - hr > 1 then + match l with + | Node(lk, lv, _, ll, lr) when height ll >= height lr -> + rotateRight (Node(k, v, 0, l, r)) + | Node(lk, lv, _, ll, lr) -> + let newLeft = rotateLeft (Node(lk, lv, 0, ll, lr)) + rotateRight (Node(k, v, 0, newLeft, r)) + | _ -> failwith "balance: left heavy but left is empty" + elif hr - hl > 1 then + match r with + | Node(rk, rv, _, rl, rr) when height rr >= height rl -> + rotateLeft (Node(k, v, 0, l, r)) + | Node(rk, rv, _, rl, rr) -> + let newRight = rotateRight (Node(rk, rv, 0, rl, rr)) + rotateLeft (Node(k, v, 0, l, newRight)) + | _ -> failwith "balance: right heavy but right is empty" + else + makeNode k v l r + +let empty = Empty + +let isEmpty map = + match map with Empty -> true | _ -> false + +let rec contains k map = + match map with + | Empty -> false + | Node(k2, _, _, l, r) -> + if k = k2 then true + elif k < k2 then contains k l + else contains k r + +let rec tryFind k map = + match map with + | Empty -> None + | Node(k2, v, _, l, r) -> + if k = k2 then Some v + elif k < k2 then tryFind k l + else tryFind k r + + +let rec add k v map = + match map with + | Empty -> Node(k, v, 1, Empty, Empty) + | Node(k2, v2, _, l, r) -> + if k < k2 then + let newL = add k v l + balance k2 v2 newL r + elif k > k2 then + let newR = add k v r + balance k2 v2 l newR + else + // If key already exists --- update value + Node(k, v, height (Node(k2, v2, 0, l, r)), l, r) + + +/// Removes the entry for the given key. If the key is not exists, the map is unchanged. +let rec remove k map = + let rec minKeyValue map = + match map with + | Empty -> failwith "minKeyValue: empty map" + | Node(k, v, _, Empty, _) -> (k, v) + | Node(_, _, _, l, _) -> minKeyValue l + + let rec removeMin map = + match map with + | Empty -> Empty + | Node(k, v, _, Empty, r) -> r + | Node(k, v, _, l, r) -> balance k v (removeMin l) r + + match map with + | Empty -> Empty + | Node(k2, v2, _, l, r) -> + if k < k2 then + balance k2 v2 (remove k l) r + elif k > k2 then + balance k2 v2 l (remove k r) + else + match l, r with + | Empty, _ -> r + | _, Empty -> l + | _ -> + let (minK, minV) = minKeyValue r + let newR = removeMin r + balance minK minV l newR + +/// Folds over the map in ascending key order. +let rec fold f acc = function + | Empty -> acc + | Node(k, v, _, l, r) -> + let acc' = fold f acc l + let acc'' = f acc' k v + fold f acc'' r + + +/// Returns the number of entries in the map. +let rec count map = fold (fun acc _ _ -> acc + 1) 0 map + +/// Returns a list of (key, value) pairs in ascending key order. +let toList map = fold (fun acc k v -> (k, v) :: acc) [] map |> List.rev + +/// Creates a map from a sequence of key‑value pairs. +let ofList list = + List.fold (fun acc (k, v) -> add k v acc) empty list diff --git a/QuadTree/QuadTree.fsproj b/QuadTree/QuadTree.fsproj index 2b2b699..b984e0e 100644 --- a/QuadTree/QuadTree.fsproj +++ b/QuadTree/QuadTree.fsproj @@ -7,12 +7,14 @@ + + diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index 300381a..b348945 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -33,12 +33,6 @@ type Error = | InconsistentStructureOfStorages | InconsistentSizeOfArguments -(* -let foldValues state f tree = - match tree with - | Leaf -*) - let mkNode t1 t2 = match (t1, t2) with @@ -52,6 +46,46 @@ type CoordinateList<'value> = val data: (uint64 * 'value) list new(_length, _data) = { length = _length; data = _data } +let update (vector: SparseVector<_>) i v op = + let rec inner vector (i:uint64) size = + match vector with + | Leaf (UserValue x) -> + if size = 1UL + then + let res = op x v + let deltaNNZ = + match (res, x) with + | Some _, None -> 1L + | None , Some _ -> -1L + | _ -> 0 + Leaf (UserValue (op x v)), deltaNNZ + else + let halfSize = size / 2UL + if uint64 i < uint64 halfSize + then + let newVector, deltaNNZ = inner vector i halfSize + (mkNode newVector vector), deltaNNZ + else + let newVector, deltaNNZ = inner vector ((uint64 i - uint64 halfSize)*1UL) halfSize + (mkNode vector newVector), deltaNNZ + | Node (x1,x2) -> + let halfSize = size / 2UL + if uint64 i < uint64 halfSize + then + let newVector, deltaNNZ = inner x1 i halfSize + (mkNode newVector x2), deltaNNZ + else + let newVector, deltaNNZ = inner x2 ((uint64 i - uint64 halfSize)*1UL) halfSize + (mkNode x1 newVector), deltaNNZ + | _ -> failwith "Unreachable. But seams that index out of range." + + if uint64 i <= uint64 vector.length + then + let storage, deltaNNZ = inner vector.storage.data i vector.storage.size + let nvals = uint64 (int64 vector.nvals + deltaNNZ) * 1UL + Result.Success (SparseVector (vector.length, nvals, Storage(vector.storage.size, storage))) + else Result.Failure <| Error.IndexOutOfRange (vector,i) + let fromCoordinateList (lst: CoordinateList<'a>) : SparseVector<'a> = let length = lst.length let nvals = (uint64 <| List.length lst.data) * 1UL @@ -93,13 +127,24 @@ let toCoordinateList (vector: SparseVector<'a>) = let lAccum = traverse left accum pointer halfSize let rAccum = traverse right lAccum (pointer + halfSize) halfSize rAccum - + let lst = traverse vector.storage.data [] 0UL ((uint64 vector.storage.size) * 1UL) CoordinateList(length, lst) +let foldValues (vector: SparseVector<'a>) (f: 'b -> 'a -> 'b) (state:'b) = + let rec inner state (size: uint64) vector= + match vector with + | Leaf (UserValue (Some v)) -> + let lst = List.replicate (int size) v + List.fold f state lst + | Node (x1, x2) -> + let halfSize = size / 2UL + inner (inner state halfSize x1) halfSize x2 + | _ -> state + inner state vector.storage.size vector.storage.data let map (vector: SparseVector<'a>) f = let rec inner (size: uint64) vector = @@ -187,17 +232,64 @@ let gather (v : SparseVector<'value>) (idx : SparseVector>) : Spar | Some i-> unsafeGet v i | None -> None) -(* -let private merge_sort (v:SparseVector<'a>) (compare: 'a -> 'a -> bool) (collapse_equals: 'a -> 'a -> 'a) = - let rec inner (tree : btree>) = - match tree with - | Leaf v1, Leaf v2 -> -*) -(* -/// Scatter: w[idx[i]] = op(w[idx[i]], v[i]) -let scatter (v : SparseVector<'value>) (idx : SparseVector>) - (op : Option<'value> -> Option<'value> -> Option<'value>) : SparseVector<'value> = - map2 idx v (fun i v-> match (i,v) with Some (i), Some(v) -> Some (i,v) | _ -> None ) +let mergeSort (v: SparseVector<'a>) (compare: Option<'a> -> Option<'a> -> int) : SparseVector<'a> = + let storageSize = v.storage.size + let nvals = v.nvals + // Extract values from tree + let rec extract tree = + match tree with + | Leaf Dummy -> [] + | Leaf(UserValue None) -> [] + | Leaf(UserValue v) -> [v] + | Node(l, r) -> extract l @ extract r + + // Place sorted values into original tree structure + let rec place tree sortedVals = + match tree, sortedVals with + | Leaf Dummy, rest -> Leaf Dummy, rest + | Leaf(UserValue None), rest -> Leaf(UserValue None), rest + | Leaf(UserValue _), v::rest -> Leaf(UserValue v), rest + | Leaf(UserValue _), [] -> Leaf Dummy, [] + | Node(l, r), vals -> + let l', r1 = place l vals + let r', r2 = place r r1 + mkNode l' r', r2 + + let values = extract v.storage.data + let sortedVals = List.sortWith (fun a b -> compare a b) values + let newTree, _ = place v.storage.data sortedVals + + SparseVector(v.length, nvals, Storage(storageSize, newTree)) + +(*let mergeSort (v: SparseVector<'a>) (compare: Option<'a> -> Option<'a> -> int) : SparseVector<'a> = + let rec merge t1 t2 = + match (t1, t2) with + | Leaf (UserValue v1), Leaf (UserValue v2) -> + if compare v1 v2 <= 0 then mkNode t1 t2 else mkNode (Leaf (UserValue v2)) (Leaf (UserValue v1)) + | Leaf (UserValue v1), Leaf Dummy -> tree + + let rec inner tree = + match tree with + | Node (Leaf (UserValue v1), Leaf (UserValue v2) ) -> + if compare v1 v2 <= 0 then tree else Node (Leaf (UserValue v2), Leaf (UserValue v1)) + | Node (Leaf (UserValue v1), Leaf Dummy) -> tree + | Node (n1, n2) -> + let newLeft = inner n1 + let newRight = inner n2 + merge mewLeft newRight *) +/// Scatter: w[idx[i]] = op(w[idx[i]], v[i]) +let scatter (w: SparseVector<'value>) (v: SparseVector<'value>) (idx: SparseVector>) + (op: Option<'value> -> 'value -> Option<'value>) = + let pairsVec = map2 idx v (fun i v -> match i, v with Some i, Some v -> Some(i, v) | _ -> None) + match pairsVec with + | Result.Success pv -> + foldValues pv (fun state (idx, v) -> + match state with + | Result.Success state -> update state idx v op + | Result.Failure x -> Result.Failure x) + (Result.Success w) + |> Result.Success + | Result.Failure x -> Result.Failure x From 43d915b85bdd8d53b8cc6dcad2ff1226fd66d79d Mon Sep 17 00:00:00 2001 From: gsv Date: Sun, 22 Mar 2026 20:25:57 +0300 Subject: [PATCH 06/52] Pseudocode for Boruvka. --- QuadTree/Boruvka.fs | 76 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index f669f92..afd0119 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -7,7 +7,81 @@ type Error<'t1, 't2> = | FrontierCalculationProblem of Vector.Error<'t1, 't1> | VisitedCalculationProblem of Vector.Error<'t1, 't1> -let sssp graph (startVertex: uint64) = +(* +Вход: граф G = (V, E, w), матрица смежности S, n = |V| +Выход: множество рёбер МОД T + +iota <- [0, 1, 2, ..., n-1] // вектор индексов + +parent[u] <- u для всех u in 0..n-1 +T <- ∅ + +while S ≠ ∅ do { + + // Шаг 1. Минимальное ребро каждой вершины + // mxv над полукольцом combMin: + // edge[u] = min{ (w, parent[v]) | (u,v,w) ∈ S } + + edge <- mxv(S, parent) + + // Шаг 2. Минимальное ребро каждой компоненты + // scatter-reduce: cedge[parent[u]] = min по всем u в компоненте + + cedge <- scatter(edge, parent, min) + + // Шаг 3. Распространить минимум компоненты на все её вершины + // gather: t[u] = cedge[parent[u]] + + t <- gather(cedge, parent) + + // Шаг 4. Выбрать одного представителя на компоненту + + mask <- eWiseMult(edge, t, ==) + index <- assign([n, n, ..., n], iota, mask) + // index[u] <- u если mask[u], иначе n + + index <- scatter(index, parent, min) // минимальный представитель в компоненте + index <- gather(index, parent) // broadcast на все вершины компоненты + + // Шаг 5. Добавить выбранные рёбра в МОД + + (weight, partner) <- extract_tuples(edge) + + s1 = fun i j -> + weight[i] == S(i,j) + && parent[j] == partner[i] + && index[i] == i + + T <- T ∪ select(S, s1) + + // Шаг 6. Обновить компоненты (до фильтрации S) + + // 6а. Переключить корень каждой поглощаемой компоненты: + // parent[partner[i]] <- i для всех представителей i + // (parent[i] = i для корня, поэтому пишем iota, а не parent) + // masked scatter: пишем только там, где index[i] == i + + rep_mask <- (index == iota) + parent <- scatter(iota, partner, first, mask=rep_mask) + // parent[partner[i]] <- i для всех i, где rep_mask[i] + + // 6б. Сжатие путей методом pointer jumping + + repeat + parent <- gather(parent, parent) // parent[u] <- parent[parent[u]] + until parent unchanged + + // Шаг 7. Удалить внутрикомпонентные рёбра + + s2 = fun i j -> parent[i] != parent[j] + + S <- select(S, s2) +} + +return T +*) + +let mst graph = let op_add x y = match (x, y) with | Some(u), Some(v) -> Some(min u v) From 114a08d5c3a46b1c0411140a7af6a11e7bae282f Mon Sep 17 00:00:00 2001 From: gsv Date: Sun, 22 Mar 2026 20:48:23 +0300 Subject: [PATCH 07/52] Basic version of Vector.init function. --- QuadTree/Vector.fs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index b348945..4c68851 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -168,6 +168,29 @@ let map (vector: SparseVector<'a>) f = SparseVector(vector.length, nvals, (Storage(vector.storage.size, storage))) +let init (length: uint64) (f: uint64 -> Option<'a>) : SparseVector<'a> = + let storageSize = (getNearestUpperPowerOfTwo <| uint64 length) * 1UL + + let rec build (pointer: uint64) (size: uint64) = + if uint64 pointer >= uint64 length then + Leaf Dummy, 0UL + elif size = 1UL then + if uint64 pointer >= uint64 length then + Leaf Dummy, 0UL + else + let v = f pointer + Leaf(UserValue v), (match v with Some _ -> 1UL | None -> 0UL) + else + let halfSize = size / 2UL + let left, nvals1 = build pointer halfSize + let newPointer = (uint64 pointer + uint64 halfSize) * 1UL + let right, nvals2 = build newPointer halfSize + mkNode left right, nvals1 + nvals2 + + let storage, nvals = build 0UL storageSize + + SparseVector(length, nvals, Storage(storageSize, storage)) + let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = let len1 = vector1.length From ff21e4d7e78acf789c3a8df831df2ce372a53dfb Mon Sep 17 00:00:00 2001 From: gsv Date: Sun, 22 Mar 2026 22:28:31 +0300 Subject: [PATCH 08/52] Basic test on vxmi --- QuadTree.Tests/Tests.LinearAlgebra.fs | 74 +++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/QuadTree.Tests/Tests.LinearAlgebra.fs b/QuadTree.Tests/Tests.LinearAlgebra.fs index dca4199..9b2fb7e 100644 --- a/QuadTree.Tests/Tests.LinearAlgebra.fs +++ b/QuadTree.Tests/Tests.LinearAlgebra.fs @@ -30,6 +30,18 @@ let op_mult x y = | Some(a), Some(b) -> Some(a * b) | _ -> None +let op_add_i x y = + match (x, y) with + | Some(a), Some(b) -> Some(min a b) + | Some(a), _ + | _, Some(a) -> Some(a) + | _ -> None + +let op_mult_i (i,x) (row,col,y) = + match (x, y) with + | Some(a), Some(b) -> Some(i , row, col) + | _ -> None + let leaf_v v = qtree.Leaf << UserValue <| Some v let leaf_n () = qtree.Leaf << UserValue <| None let leaf_d () = qtree.Leaf Dummy @@ -211,6 +223,68 @@ let ``Simple vxm. 3 * (3x5)`` () = Assert.Equal(expected, actual) +(* +2,2,2,D +* +N,1,1,N +3,2,2,3 +N,N,1,2 +N,N,3,N += +6,6,14,10 +*) +[] +let ``Simple vxmi. 3 * (3x5)`` () = + let m = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Node( + Matrix.qtree.Node(leaf_n (), leaf_v 1, leaf_v 3, leaf_v 2), + Matrix.qtree.Node(leaf_v 1, leaf_n (), leaf_v 2, leaf_v 3), + Matrix.qtree.Node(leaf_n (), leaf_n (), leaf_d (), leaf_d ()), + Matrix.qtree.Node(leaf_v 1, leaf_v 2, leaf_d (), leaf_d ()) + ), + Matrix.qtree.Node( + Matrix.qtree.Node(leaf_n (), leaf_d (), leaf_v 1, leaf_d ()), + leaf_d (), + Matrix.qtree.Node(leaf_n (), leaf_d (), leaf_d (), leaf_d ()), + leaf_d () + ), + leaf_d (), + leaf_d () + ) + + let store = Matrix.Storage(8UL, tree) + SparseMatrix(3UL, 5UL, 9UL, store) + + let v = + let tree = Vector.btree.Node(vleaf_v 2, Vector.btree.Node(vleaf_v 2, vleaf_d ())) + + let store = Vector.Storage(4UL, tree) + SparseVector(3UL, 3UL, store) + + let expected = + let tree = + Vector.btree.Node( + Vector.btree.Node( + Vector.btree.Node(vleaf_v (0UL,0UL,1UL), + vleaf_v (1UL,1UL,0UL)), + Vector.btree.Node(vleaf_v (0UL,0UL,1UL), + vleaf_v (0UL,0UL,1UL)) + ), + Vector.btree.Node( + Vector.btree.Node(vleaf_v (0UL,0UL,1UL), vleaf_d ()), + Vector.btree.Node(vleaf_d (), vleaf_d ()) + ) + ) + + let store = Vector.Storage(8UL, tree) + Result.Success(SparseVector(5UL, 5UL, store)) + + let actual = LinearAlgebra.vxmi op_add_i op_mult_i v m + + Assert.Equal(expected, actual) + [] let ``Simple mxm`` () = // 222D From af2b9416d25b41f1903c2bbb329404488cd8af33 Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 23 Mar 2026 10:12:47 +0300 Subject: [PATCH 09/52] Draft of vxmi_values. Not finished. --- QuadTree.Tests/Tests.LinearAlgebra.fs | 41 +++++------ QuadTree/Boruvka.fs | 2 +- QuadTree/LinearAlgebra.fs | 98 +++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 21 deletions(-) diff --git a/QuadTree.Tests/Tests.LinearAlgebra.fs b/QuadTree.Tests/Tests.LinearAlgebra.fs index 9b2fb7e..8dccee2 100644 --- a/QuadTree.Tests/Tests.LinearAlgebra.fs +++ b/QuadTree.Tests/Tests.LinearAlgebra.fs @@ -30,6 +30,7 @@ let op_mult x y = | Some(a), Some(b) -> Some(a * b) | _ -> None + let op_add_i x y = match (x, y) with | Some(a), Some(b) -> Some(min a b) @@ -38,9 +39,8 @@ let op_add_i x y = | _ -> None let op_mult_i (i,x) (row,col,y) = - match (x, y) with - | Some(a), Some(b) -> Some(i , row, col) - | _ -> None + Some(i,row,col) + let leaf_v v = qtree.Leaf << UserValue <| Some v let leaf_n () = qtree.Leaf << UserValue <| None @@ -226,15 +226,20 @@ let ``Simple vxm. 3 * (3x5)`` () = (* 2,2,2,D * -N,1,1,N -3,2,2,3 -N,N,1,2 -N,N,3,N +N,1,1,N,N,D,D,D +3,2,2,3,1,D,D,D +N,N,1,2,N,D,D,D +D,D,D,D,D,D,D,D +D,D,D,D,D,D,D,D +D,D,D,D,D,D,D,D +D,D,D,D,D,D,D,D +D,D,D,D,D,D,D,D = -6,6,14,10 +// 6,6,8,10,2,D,D,D +(1,1,0),(0,0,1),(0,0,2),(1,1,3),(1,1,4) *) [] -let ``Simple vxmi. 3 * (3x5)`` () = +let ``Simple vxmi_values. 3 * (3x5)`` () = let m = let tree = Matrix.qtree.Node( @@ -266,25 +271,21 @@ let ``Simple vxmi. 3 * (3x5)`` () = let expected = let tree = Vector.btree.Node( - Vector.btree.Node( - Vector.btree.Node(vleaf_v (0UL,0UL,1UL), - vleaf_v (1UL,1UL,0UL)), - Vector.btree.Node(vleaf_v (0UL,0UL,1UL), - vleaf_v (0UL,0UL,1UL)) - ), - Vector.btree.Node( - Vector.btree.Node(vleaf_v (0UL,0UL,1UL), vleaf_d ()), - Vector.btree.Node(vleaf_d (), vleaf_d ()) - ) + Vector.btree.Node(Vector.btree.Node(vleaf_v (1UL,1UL,0UL) + , vleaf_v (0UL,0UL,1UL)) + , Vector.btree.Node(vleaf_v (0UL,0UL,2UL) + , vleaf_v (1UL,1UL,3UL))), + Vector.btree.Node(Vector.btree.Node(vleaf_v (1UL,1UL,4UL), vleaf_d ()), vleaf_d ()) ) let store = Vector.Storage(8UL, tree) Result.Success(SparseVector(5UL, 5UL, store)) - let actual = LinearAlgebra.vxmi op_add_i op_mult_i v m + let actual = LinearAlgebra.vxmi_values op_add_i op_mult_i v m Assert.Equal(expected, actual) + [] let ``Simple mxm`` () = // 222D diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index afd0119..219538b 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -123,7 +123,7 @@ let mst graph = Result.Success visited let frontier = - Vector.CoordinateList((uint64 graph.ncols) * 1UL, [ startVertex * 1UL, 0.0 ]) + Vector.CoordinateList((uint64 graph.ncols) * 1UL, [ 0UL * 1UL, 0.0 ]) |> Vector.fromCoordinateList inner frontier frontier 0 diff --git a/QuadTree/LinearAlgebra.fs b/QuadTree/LinearAlgebra.fs index 9c87cfc..e245925 100644 --- a/QuadTree/LinearAlgebra.fs +++ b/QuadTree/LinearAlgebra.fs @@ -106,6 +106,104 @@ let vxm op_add op_mult (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseM else Error Error.InconsistentSizeOfArguments +let vxmi_values + (op_add: 'c option -> 'c option -> 'c option) + (op_mult: uint64 * 'a -> uint64 * uint64 * 'b -> Option<'c>) + (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(Some(v1))), Matrix.qtree.Leaf(UserValue(Some(v2))) -> + if size = 1UL + then + let res = op_mult v1 v2 + + let nnz = + match res with + | None -> 0UL + | _ -> 1UL + + Result.Success(Vector.btree.Leaf(UserValue(res)), nnz) + else + inner size (Vector.btree.Node(vector,vector))(Matrix.qtree.Node(matrix, matrix,matrix,matrix)) + + | Vector.btree.Leaf(UserValue(Some(_))), Matrix.qtree.Node(y1, y2, y3, y4) -> _do vector vector y1 y2 y3 y4 + | Vector.btree.Node(x1, x2), Matrix.qtree.Leaf(UserValue(Some(_))) -> _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(UserValue(None)),_ + | _, Matrix.qtree.Leaf(UserValue(None)) -> Result.Success(Vector.btree.Leaf(UserValue(None)), 0UL) + + | Vector.btree.Leaf(Dummy), _ + | _, Matrix.qtree.Leaf(Dummy) -> Result.Success(Vector.btree.Leaf(Dummy), 0UL) + | (x, y) -> Result.Failure <| Error.InconsistentStructureOfStorages(x, y) + + if uint64 vector.length = uint64 matrix.nrows then + let vector_storage = + if uint64 vector.storage.size < uint64 matrix.storage.size then + let rec increaseStorage storage_data (current_size: uint64) bound = + if current_size = bound then + storage_data + else + increaseStorage + (Vector.btree.Node(storage_data, Vector.btree.Leaf(Dummy))) + (current_size * 2UL) + bound + + let target_size = matrix.storage.size + Vector.Storage(target_size, increaseStorage vector.storage.data vector.storage.size target_size) + else + vector.storage + + 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(matrix.storage.size, storage)) + )) + |> Result.Success + else + (Error.InconsistentSizeOfArguments(vector, matrix)) |> Result.Failure + +type MXMError<'value1, 'value2, 'value3> = + | InconsistentSizeOfArguments of Matrix.SparseMatrix<'value1> * Matrix.SparseMatrix<'value2> + | MatrixAdditionProblem of Matrix.Error<'value3, 'value3> +>>>>>>> 6d543b7 (Draft of vxmi_values. Not finished.) + let mxm (op_add: 'c option -> 'c option -> 'c option) From 1e371e40640b84e64dae08107525019411b8748a Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 23 Mar 2026 10:28:08 +0300 Subject: [PATCH 10/52] Compilable version of vxmi_values. --- QuadTree/LinearAlgebra.fs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/QuadTree/LinearAlgebra.fs b/QuadTree/LinearAlgebra.fs index e245925..9b1bce0 100644 --- a/QuadTree/LinearAlgebra.fs +++ b/QuadTree/LinearAlgebra.fs @@ -111,11 +111,14 @@ let vxmi_values (op_mult: uint64 * 'a -> uint64 * uint64 * 'b -> Option<'c>) (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseMatrix<'b>) = - let rec inner (size: uint64) vector matrix = + let rec inner (size: uint64) vector (vectorIdx: uint64) matrix (rowIdx: uint64) (colIdx: uint64) = 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 + match (inner new_size x1 vectorIdx y1 rowIdx colIdx), + (inner new_size x1 vectorIdx y2 rowIdx (colIdx + (uint64 new_size) * 1UL)), + (inner new_size x2 (vectorIdx + (uint64 new_size) * 1UL) y3 (rowIdx + (uint64 new_size) * 1UL) colIdx), + (inner new_size x2 (vectorIdx + (uint64 new_size) * 1UL) y4 (rowIdx + (uint64 new_size) * 1UL) (colIdx + (uint64 new_size) * 1UL)) with | Result.Success((t1, nvals1)), Result.Success((t2, nvals2)), Result.Success((t3, nvals3)), @@ -149,7 +152,7 @@ let vxmi_values | Vector.btree.Leaf(UserValue(Some(v1))), Matrix.qtree.Leaf(UserValue(Some(v2))) -> if size = 1UL then - let res = op_mult v1 v2 + let res = op_mult (vectorIdx, v1) (rowIdx, colIdx, v2) let nnz = match res with @@ -158,7 +161,7 @@ let vxmi_values Result.Success(Vector.btree.Leaf(UserValue(res)), nnz) else - inner size (Vector.btree.Node(vector,vector))(Matrix.qtree.Node(matrix, matrix,matrix,matrix)) + inner size (Vector.btree.Node(vector,vector)) vectorIdx (Matrix.qtree.Node(matrix, matrix,matrix,matrix)) rowIdx colIdx | Vector.btree.Leaf(UserValue(Some(_))), Matrix.qtree.Node(y1, y2, y3, y4) -> _do vector vector y1 y2 y3 y4 | Vector.btree.Node(x1, x2), Matrix.qtree.Leaf(UserValue(Some(_))) -> _do x1 x2 matrix matrix matrix matrix @@ -187,7 +190,7 @@ let vxmi_values else vector.storage - match inner vector_storage.size vector_storage.data matrix.storage.data with + match inner vector_storage.size vector_storage.data 0UL matrix.storage.data 0UL 0UL with | Result.Failure x -> Result.Failure x | Result.Success(storage, nvals) -> (Vector.SparseVector( From 877277a80b85edfb85f7d7b91f88f7eccc7a720a Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 23 Mar 2026 10:37:32 +0300 Subject: [PATCH 11/52] Tests on vxmi_values --- QuadTree.Tests/Tests.LinearAlgebra.fs | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/QuadTree.Tests/Tests.LinearAlgebra.fs b/QuadTree.Tests/Tests.LinearAlgebra.fs index 8dccee2..424fb47 100644 --- a/QuadTree.Tests/Tests.LinearAlgebra.fs +++ b/QuadTree.Tests/Tests.LinearAlgebra.fs @@ -286,6 +286,50 @@ let ``Simple vxmi_values. 3 * (3x5)`` () = Assert.Equal(expected, actual) +(* +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 vxmi_values. 4 * (4x3).`` () = + let m = + let tree = + Matrix.qtree.Node( + Matrix.qtree.Node(leaf_n (), leaf_v 1, leaf_v 3, leaf_v 2), + Matrix.qtree.Node(leaf_v 1, leaf_d (), leaf_v 2, leaf_d ()), + leaf_n (), + Matrix.qtree.Node(leaf_v 1, leaf_d (), leaf_v 3, leaf_d ()) + ) + + let store = Matrix.Storage(4UL, tree) + SparseMatrix(4UL, 3UL, 7UL, store) + + let v = + let tree = vleaf_v 2 + + let store = Vector.Storage(4UL, tree) + SparseVector(4UL, 4UL, store) + + + let expected = + let tree = Vector.btree.Node(Vector.btree.Node(vleaf_v (1UL,1UL,0UL) + , vleaf_v (0UL,0UL,1UL)) + , Vector.btree.Node(vleaf_v (0UL,0UL,2UL), vleaf_d ())) + + let store = Vector.Storage(4UL, tree) + Result.Success(SparseVector(3UL, 3UL, store)) + + let actual = LinearAlgebra.vxmi_values op_add_i op_mult_i v m + + Assert.Equal(expected, actual) + + [] let ``Simple mxm`` () = // 222D From 2fb337613671556b4ee4b0bfd56aff1d07163ef0 Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 23 Mar 2026 11:36:42 +0300 Subject: [PATCH 12/52] First draft of Boruvka MST. First test added. --- QuadTree.Tests/QuadTree.Tests.fsproj | 1 + QuadTree.Tests/Tests.Boruvka.fs | 81 ++++++++++++++++++++++++++++ QuadTree/Boruvka.fs | 57 ++++++++++---------- QuadTree/Vector.fs | 44 ++++++++------- 4 files changed, 135 insertions(+), 48 deletions(-) create mode 100644 QuadTree.Tests/Tests.Boruvka.fs diff --git a/QuadTree.Tests/QuadTree.Tests.fsproj b/QuadTree.Tests/QuadTree.Tests.fsproj index 96f4102..4de3d64 100644 --- a/QuadTree.Tests/QuadTree.Tests.fsproj +++ b/QuadTree.Tests/QuadTree.Tests.fsproj @@ -13,6 +13,7 @@ + diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs new file mode 100644 index 0000000..d74a208 --- /dev/null +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -0,0 +1,81 @@ +module Graph.Boruvka.Tests + +open System +open Xunit + +open Matrix +open Vector +open Common + + +[] +let ``Boruvka MST.`` () = + let graph = + let clist = + Matrix.CoordinateList(7UL, 7UL,[ + 0UL, 1UL, 7 + 1UL, 0UL, 7 + + 0UL, 4UL, 4 + 4UL, 0UL, 4 + + 1UL, 2UL, 11 + 2UL, 1UL, 11 + + 1UL, 3UL, 10 + 3UL, 1UL, 10 + + 1UL, 4UL, 9 + 4UL, 1UL, 9 + + 2UL, 3UL, 5 + 3UL, 2UL, 5 + + 4UL, 3UL, 15 + 3UL, 4UL, 15 + + 4UL, 5UL, 6 + 5UL, 4UL, 6 + + 5UL, 3UL, 12 + 3UL, 5UL, 12 + + 6UL, 3UL, 8 + 3UL, 6UL, 8 + + 5UL, 6UL, 13 + 6UL, 5UL, 13 + ]) + + Matrix.fromCoordinateList clist + + + let expected = + let clist = + Matrix.CoordinateList(7UL, 7UL,[ + 0UL, 1UL, 7 + 1UL, 0UL, 7 + + 0UL, 4UL, 4 + 4UL, 0UL, 4 + + 1UL, 3UL, 10 + 3UL, 1UL, 10 + + 2UL, 3UL, 5 + 3UL, 2UL, 5 + + 4UL, 5UL, 6 + 5UL, 4UL, 6 + + 6UL, 3UL, 8 + 3UL, 6UL, 8 + + ]) + + Matrix.fromCoordinateList clist + + let actual = Graph.Boruvka.mst graph + + Assert.Equal(expected, actual) + diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 219538b..84a5287 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -4,8 +4,8 @@ open Common type Error<'t1, 't2> = | NewFrontierCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't1> - | FrontierCalculationProblem of Vector.Error<'t1, 't1> - | VisitedCalculationProblem of Vector.Error<'t1, 't1> + | EdgesCalculationProblem of Vector.Error<'t1, 't1> + | CEdgesCalculationProblem of Vector.Error<'t1, 't1> (* Вход: граф G = (V, E, w), матрица смежности S, n = |V| @@ -81,46 +81,47 @@ while S ≠ ∅ do { return T *) -let mst graph = +let mst (graph:Matrix.SparseMatrix<_>) = let op_add x y = match (x, y) with - | Some(u), Some(v) -> Some(min u v) - | Some(v), _ - | _, Some(v) -> Some(v) + | Some(a), Some(b) -> Some(min a b) + | Some(a), _ + | _, Some(a) -> Some(a) | _ -> None - let op_mult x y = - match (x, y) with - | Some(u), Some(v) -> Some(u + v) - | _ -> None - - let rec inner (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) iter_num = - if frontier.nvals > 0UL && iter_num <= int frontier.length then - - let new_frontier = LinearAlgebra.vxm op_add op_mult frontier graph - - match new_frontier with - | Result.Failure(e) -> Result.Failure(NewFrontierCalculationProblem(e)) - | Result.Success(new_frontier) -> + let op_mult (i,x) (row,col,w) = + Some(w,row) + + let length = uint64 graph.nrows * 1UL + let parent = Vector.init length (fun i -> Some i) + let iota = Vector.init length (fun i -> Some (uint64 i)) + + let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) = + if graph.nvals > 0UL then + + let edges = LinearAlgebra.vxmi_values op_add op_mult parent graph + + match edges with + | Result.Failure(e) -> Result.Failure(EdgesCalculationProblem(e)) + | Result.Success(edges) -> let op_min x y = match (x, y) with | Some v, Some u -> if v < u then Some v else None | Some v, _ -> Some v | _ -> None - let frontier = Vector.map2 new_frontier visited op_min + let cedges = + Vector.scatter (Vector.empty length) edges parent op_add - match frontier with - | Result.Failure(e) -> Result.Failure(FrontierCalculationProblem(e)) - | Result.Success(frontier) -> + match cedges with + | Result.Failure(e) -> Result.Failure(CEdgesCalculationProblem(e)) + | Result.Success(cedges) -> - let visited = Vector.map2 visited frontier op_add + let t = Vector.gather cedges parent - match visited with - | Result.Failure(e) -> Result.Failure(VisitedCalculationProblem(e)) - | Result.Success(visited) -> inner frontier visited (iter_num + 1) + else - Result.Success visited + Result.Success tree let frontier = Vector.CoordinateList((uint64 graph.ncols) * 1UL, [ 0UL * 1UL, 0.0 ]) diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index 4c68851..d9505c5 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -83,8 +83,8 @@ let update (vector: SparseVector<_>) i v op = then let storage, deltaNNZ = inner vector.storage.data i vector.storage.size let nvals = uint64 (int64 vector.nvals + deltaNNZ) * 1UL - Result.Success (SparseVector (vector.length, nvals, Storage(vector.storage.size, storage))) - else Result.Failure <| Error.IndexOutOfRange (vector,i) + Ok (SparseVector (vector.length, nvals, Storage(vector.storage.size, storage))) + else Error Error.InconsistentSizeOfArguments let fromCoordinateList (lst: CoordinateList<'a>) : SparseVector<'a> = let length = lst.length @@ -133,6 +133,9 @@ let toCoordinateList (vector: SparseVector<'a>) = CoordinateList(length, lst) +let empty length = + fromCoordinateList (CoordinateList(length,[])) + let foldValues (vector: SparseVector<'a>) (f: 'b -> 'a -> 'b) (state:'b) = let rec inner state (size: uint64) vector= match vector with @@ -199,16 +202,16 @@ let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = let new_size = size / 2UL match (inner new_size x1 y1), (inner new_size x2 y2) with - | Result.Success((t1, nvals1)), Result.Success((t2, nvals2)) -> - ((mkNode t1 t2), nvals1 + nvals2) |> Result.Success - | Result.Failure(e), _ - | _, Result.Failure(e) -> Result.Failure(e) + | Ok((t1, nvals1)), Ok((t2, nvals2)) -> + ((mkNode t1 t2), nvals1 + nvals2) |> Ok + | Error(e), _ + | _, Error(e) -> Error(e) match (vector1, vector2) with | Node(x1, x2), Leaf(_) -> _do x1 x2 vector2 vector2 | Leaf(_), Node(y1, y2) -> _do vector1 vector1 y1 y2 | Node(x1, x2), Node(y1, y2) -> _do x1 x2 y1 y2 - | Leaf(Dummy), Leaf(Dummy) -> Result.Success(Leaf(Dummy), 0UL) + | Leaf(Dummy), Leaf(Dummy) -> Ok(Leaf(Dummy), 0UL) | Leaf(UserValue(v1)), Leaf(UserValue(v2)) -> let res = f v1 v2 @@ -217,17 +220,17 @@ let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = | None -> 0UL | _ -> (uint64 size) * 1UL - Result.Success(Leaf(UserValue(res)), nnz) + Ok(Leaf(UserValue(res)), nnz) - | (x, y) -> Result.Failure <| Error.InconsistentStructureOfStorages(x, y) + | (x, y) -> Error Error.InconsistentStructureOfStorages if len1 = vector2.length then match inner vector1.storage.size vector1.storage.data vector2.storage.data with - | Result.Failure(e) -> Result.Failure(e) - | Result.Success((storage, nvals)) -> - Result.Success(SparseVector(len1, nvals, (Storage(vector1.storage.size, storage)))) + | Error(e) -> Error(e) + | Ok((storage, nvals)) -> + Ok(SparseVector(len1, nvals, (Storage(vector1.storage.size, storage)))) else - Result.Failure <| Error.InconsistentSizeOfArguments(vector1, vector2) + Error Error.InconsistentSizeOfArguments let mask (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = map2 vector1 vector2 (fun v1 v2 -> if f v2 then v1 else None) @@ -303,16 +306,17 @@ let mergeSort (v: SparseVector<'a>) (compare: Option<'a> -> Option<'a> -> int) : merge mewLeft newRight *) +//type ScatterError<'a> = + /// Scatter: w[idx[i]] = op(w[idx[i]], v[i]) let scatter (w: SparseVector<'value>) (v: SparseVector<'value>) (idx: SparseVector>) - (op: Option<'value> -> 'value -> Option<'value>) = + (op: Option<'value> -> Option<'value> -> Option<'value>) = let pairsVec = map2 idx v (fun i v -> match i, v with Some i, Some v -> Some(i, v) | _ -> None) match pairsVec with - | Result.Success pv -> + | Ok pv -> foldValues pv (fun state (idx, v) -> match state with - | Result.Success state -> update state idx v op - | Result.Failure x -> Result.Failure x) - (Result.Success w) - |> Result.Success - | Result.Failure x -> Result.Failure x + | Ok state -> update state idx (Some v) op + | Error x -> Error x) + (Ok w) + | Error x -> Error Error.InconsistentStructureOfStorages From 884b15f9a1d95f08582c483566eaa180d8a2df2a Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 23 Mar 2026 13:32:05 +0300 Subject: [PATCH 13/52] WIP. --- QuadTree.Tests/Tests.Boruvka.fs | 1 + QuadTree/Boruvka.fs | 20 +++++++++----------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index d74a208..0c43c1a 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -74,6 +74,7 @@ let ``Boruvka MST.`` () = ]) Matrix.fromCoordinateList clist + |> Result.Success let actual = Graph.Boruvka.mst graph diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 84a5287..439f105 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -2,10 +2,10 @@ module Graph.Boruvka open Common -type Error<'t1, 't2> = +type Error<'t1, 't2, 't3, 't4> = | NewFrontierCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't1> - | EdgesCalculationProblem of Vector.Error<'t1, 't1> - | CEdgesCalculationProblem of Vector.Error<'t1, 't1> + | EdgesCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't3> + | CEdgesCalculationProblem of Vector.Error<'t1, 't4, 't4> (* Вход: граф G = (V, E, w), матрица смежности S, n = |V| @@ -14,13 +14,13 @@ type Error<'t1, 't2> = iota <- [0, 1, 2, ..., n-1] // вектор индексов parent[u] <- u для всех u in 0..n-1 -T <- ∅ +T <- empty -while S ≠ ∅ do { +while S not empty do { // Шаг 1. Минимальное ребро каждой вершины // mxv над полукольцом combMin: - // edge[u] = min{ (w, parent[v]) | (u,v,w) ∈ S } + // edge[u] = min{ (w, parent[v]) | (u,v,w) in S } edge <- mxv(S, parent) @@ -119,12 +119,10 @@ let mst (graph:Matrix.SparseMatrix<_>) = let t = Vector.gather cedges parent + inner graph + else Result.Success tree - let frontier = - Vector.CoordinateList((uint64 graph.ncols) * 1UL, [ 0UL * 1UL, 0.0 ]) - |> Vector.fromCoordinateList - - inner frontier frontier 0 + inner graph From 80b09a6658a2813cdd6d9e6e5ccecc8349ef6ff6 Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 23 Mar 2026 19:32:30 +0300 Subject: [PATCH 14/52] WIP. Prepare to add Vector.mapi for Boruvka --- QuadTree.Tests/Tests.Boruvka.fs | 68 ++++++++-------- QuadTree/Boruvka.fs | 138 ++++++++++++++++++++++++++++++-- QuadTree/Vector.fs | 27 +++++++ 3 files changed, 192 insertions(+), 41 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 0c43c1a..990af19 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -13,38 +13,38 @@ let ``Boruvka MST.`` () = let graph = let clist = Matrix.CoordinateList(7UL, 7UL,[ - 0UL, 1UL, 7 - 1UL, 0UL, 7 + 0UL, 1UL, 7UL + 1UL, 0UL, 7UL - 0UL, 4UL, 4 - 4UL, 0UL, 4 + 0UL, 4UL, 4UL + 4UL, 0UL, 4UL - 1UL, 2UL, 11 - 2UL, 1UL, 11 + 1UL, 2UL, 11UL + 2UL, 1UL, 11UL - 1UL, 3UL, 10 - 3UL, 1UL, 10 + 1UL, 3UL, 10UL + 3UL, 1UL, 10UL - 1UL, 4UL, 9 - 4UL, 1UL, 9 + 1UL, 4UL, 9UL + 4UL, 1UL, 9UL - 2UL, 3UL, 5 - 3UL, 2UL, 5 + 2UL, 3UL, 5UL + 3UL, 2UL, 5UL - 4UL, 3UL, 15 - 3UL, 4UL, 15 + 4UL, 3UL, 15UL + 3UL, 4UL, 15UL - 4UL, 5UL, 6 - 5UL, 4UL, 6 + 4UL, 5UL, 6UL + 5UL, 4UL, 6UL - 5UL, 3UL, 12 - 3UL, 5UL, 12 + 5UL, 3UL, 12UL + 3UL, 5UL, 12UL - 6UL, 3UL, 8 - 3UL, 6UL, 8 + 6UL, 3UL, 8UL + 3UL, 6UL, 8UL - 5UL, 6UL, 13 - 6UL, 5UL, 13 + 5UL, 6UL, 13UL + 6UL, 5UL, 13UL ]) Matrix.fromCoordinateList clist @@ -53,23 +53,23 @@ let ``Boruvka MST.`` () = let expected = let clist = Matrix.CoordinateList(7UL, 7UL,[ - 0UL, 1UL, 7 - 1UL, 0UL, 7 + 0UL, 1UL, 7UL + 1UL, 0UL, 7UL - 0UL, 4UL, 4 - 4UL, 0UL, 4 + 0UL, 4UL, 4UL + 4UL, 0UL, 4UL - 1UL, 3UL, 10 - 3UL, 1UL, 10 + 1UL, 3UL, 10UL + 3UL, 1UL, 10UL - 2UL, 3UL, 5 - 3UL, 2UL, 5 + 2UL, 3UL, 5UL + 3UL, 2UL, 5UL - 4UL, 5UL, 6 - 5UL, 4UL, 6 + 4UL, 5UL, 6UL + 5UL, 4UL, 6UL - 6UL, 3UL, 8 - 3UL, 6UL, 8 + 6UL, 3UL, 8UL + 3UL, 6UL, 8UL ]) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 439f105..7830dc4 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -2,11 +2,6 @@ module Graph.Boruvka open Common -type Error<'t1, 't2, 't3, 't4> = - | NewFrontierCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't1> - | EdgesCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't3> - | CEdgesCalculationProblem of Vector.Error<'t1, 't4, 't4> - (* Вход: граф G = (V, E, w), матрица смежности S, n = |V| Выход: множество рёбер МОД T @@ -81,6 +76,11 @@ while S not empty do { return T *) +type Error<'t1, 't2, 't3, 't4> = + | NewFrontierCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't1> + | EdgesCalculationProblem of Vector.Error<'t1, 't2, 't3> + | CEdgesCalculationProblem of Vector.Error<'t1, 't4, 't4> +(* let mst (graph:Matrix.SparseMatrix<_>) = let op_add x y = match (x, y) with @@ -94,6 +94,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = let length = uint64 graph.nrows * 1UL let parent = Vector.init length (fun i -> Some i) + //let all_n = Vector.init length (fun _ -> Some (uint64 graph.ncols * 1UL)) let iota = Vector.init length (fun i -> Some (uint64 i)) let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) = @@ -118,11 +119,134 @@ let mst (graph:Matrix.SparseMatrix<_>) = | Result.Success(cedges) -> let t = Vector.gather cedges parent - - inner graph + let mask = Vector.map2 edges t (fun x y -> match (x,y) with Some v1, Some v2 when v1 = v2 -> Some v1 | _ -> None) + match mask with + | Result.Failure(e) -> Result.Failure(CEdgesCalculationProblem(e)) + | Result.Success (mask) -> + let index = Vector.map2 iota mask (fun i m -> match m with | Some _ -> ) + inner graph else Result.Success tree inner graph +*) + + +let mst (graph:Matrix.SparseMatrix<'w>) = + let n = uint64 graph.nrows + + let findRoot (parent: uint64 array) x = + let rec loop (y: uint64) (visited: Set) = + if visited.Contains(y) then y + else + let p = parent.[int y] + if p <> y then loop p (Set.add y visited) else y + loop x Set.empty + + let union (parent: uint64 array) (rank: uint64 array) x y = + let rootX = findRoot parent x + let rootY = findRoot parent y + if rootX <> rootY then + if rank.[int rootX] < rank.[int rootY] then + parent.[int rootX] <- rootY + elif rank.[int rootX] > rank.[int rootY] then + parent.[int rootY] <- rootX + else + parent.[int rootY] <- rootX + rank.[int rootX] <- rank.[int rootX] + 1UL + + let rec inner (S: Matrix.SparseMatrix<'w>) (mstEdges: (uint64 * uint64 * 'w) list) (parent: uint64 array) (rank: uint64 array) (iterations: int) = + if S.nvals > 0UL && iterations < 20 then + let edgesCL = Matrix.toCoordinateList S + + let edgesData = + edgesCL.list + |> List.map (fun (i, j, w) -> (uint64 i, uint64 j, w)) + + let edgesWithCompInfo = + edgesData + |> List.map (fun (i, j, w) -> + let rootJ = findRoot parent j + let rootI = findRoot parent i + (i, j, w, rootI, rootJ)) + + let interCompEdges = + edgesWithCompInfo + |> List.filter (fun (i, j, w, rootI, rootJ) -> rootI <> rootJ) + + if interCompEdges.IsEmpty then + let resultCL = + Matrix.CoordinateList(graph.nrows, graph.ncols, + List.map (fun (i, j, w) -> (i * 1UL, j * 1UL, w)) mstEdges) + Result.Success (Matrix.fromCoordinateList resultCL) + else + let compMinEdges = + interCompEdges + |> List.groupBy (fun (_, _, _, _, rootJ) -> rootJ) + |> List.map (fun (rootJ, edges) -> + let minEdge = List.minBy (fun (i, j, w, _, _) -> w) edges + (rootJ, minEdge)) + |> Map.ofList + + let repToEdge = + compMinEdges + |> Map.toList + |> List.map (fun (destComp, edge) -> (destComp, edge)) + |> List.filter (fun (_, (minI, minJ, _, _, _)) -> + let canonicalI, canonicalJ = if minI < minJ then minI, minJ else minJ, minI + let srcRoot = findRoot parent canonicalI + let dstRoot = findRoot parent canonicalJ + srcRoot <> dstRoot) + |> List.distinctBy (fun (_, (minI, minJ, _, _, _)) -> + if minI < minJ then (minI, minJ) else (minJ, minI)) + + let newMstEdges = + repToEdge + |> List.collect (fun (_, (minI, minJ, minW, _, _)) -> + [(minI, minJ, minW); (minJ, minI, minW)]) + |> fun newEdges -> mstEdges @ newEdges + + let parentCopy = Array.copy parent + let rankCopy = Array.copy rank + + for (_, (minI, minJ, _, _, _)) in repToEdge do + union parentCopy rankCopy minI minJ + + let rec pointerJump (parentArr: uint64 array) maxIter = + if maxIter = 0 then parentArr + else + let newParent = Array.copy parentArr + let mutable changed = false + for i in 0..int n-1 do + let root = findRoot parentArr parentArr.[i] + if root <> parentArr.[i] then + newParent.[i] <- root + changed <- true + if changed then pointerJump newParent (maxIter - 1) else newParent + + let parent''' = pointerJump parentCopy (int n) + + let s2 (i: uint64) (j: uint64) (_: 'w) = + let ii = uint64 i + let jj = uint64 j + findRoot parent''' ii <> findRoot parent''' jj + + let S' = + Matrix.toCoordinateList S + |> fun cl -> + let filtered = cl.list |> List.filter (fun (i, j, w) -> s2 i j w) + Matrix.fromCoordinateList (Matrix.CoordinateList(cl.nrows, cl.ncols, filtered)) + + inner S' newMstEdges parent''' rankCopy (iterations + 1) + + else + let resultCL = + Matrix.CoordinateList(graph.nrows, graph.ncols, + List.map (fun (i, j, w) -> (i * 1UL, j * 1UL, w)) mstEdges) + Result.Success (Matrix.fromCoordinateList resultCL) + + let parentInit = [| for i in 0UL..n-1UL -> i |] + let rankInit = [| for i in 0UL..n-1UL -> 0UL |] + inner graph [] parentInit rankInit 0 diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index d9505c5..80771df 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -171,6 +171,33 @@ let map (vector: SparseVector<'a>) f = SparseVector(vector.length, nvals, (Storage(vector.storage.size, storage))) + +let mapi (vector: SparseVector<'a>) f = + let rec inner (size: uint64) vector = + match vector with + | Node(x1, x2) -> + let t1, nvals1 = inner (size / 2UL) x1 + let t2, nvals2 = inner (size / 2UL) x2 + (mkNode t1 t2), nvals1 + nvals2 + | Leaf(Dummy) -> Leaf(Dummy), 0UL + | Leaf(UserValue(v)) -> + if size = 1UL + then + let res = f v + + let nnz = + match res with + | None -> 0UL + | _ -> 1UL + + Leaf(UserValue(res)), nnz + else inner size (Node (vector,vector)) + + let storage, nvals = inner vector.storage.size vector.storage.data + + SparseVector(vector.length, nvals, (Storage(vector.storage.size, storage))) + + let init (length: uint64) (f: uint64 -> Option<'a>) : SparseVector<'a> = let storageSize = (getNearestUpperPowerOfTwo <| uint64 length) * 1UL From 7c5c615873bb946b499a2f308f5b395291a197c9 Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 23 Mar 2026 19:53:46 +0300 Subject: [PATCH 15/52] Basic version of Vector.mapi --- QuadTree.Tests/Tests.Vector.fs | 90 ++++++++++++++++++++++++++++++++++ QuadTree/Vector.fs | 27 +++++----- 2 files changed, 103 insertions(+), 14 deletions(-) diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index 47552fc..b912eef 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -77,6 +77,96 @@ let ``Simple Vector.map. Length is not power of two.`` () = Assert.Equal(expected, actual) +[] +let ``Simple Vector.mapi. Length is power of two, multiply by index.`` () = + let v = + Vector.fromCoordinateList ( + Vector.CoordinateList(8UL, [ (0UL, 1); (1UL, 1); (2UL, 1); (3UL, 1); (4UL, 2); (5UL, 2); (6UL, 2); (7UL, 2) ]) + ) + + let f (idx: uint64) x = + match x with + | Some(a) -> Some(a * int idx) + | _ -> None + + let expected = + Vector.fromCoordinateList ( + Vector.CoordinateList(8UL, [ (0UL, 0); (1UL, 1); (2UL, 2); (3UL, 3); (4UL, 8); (5UL, 10); (6UL, 12); (7UL, 14) ]) + ) + + let actual = Vector.mapi v f + + Assert.Equal(expected, actual) + +[] +let ``Simple Vector.mapi. Length is not power of two.`` () = + // Build vector [1, 1, 1, 1, 1, 1] with dummy at end + let v = + Vector.fromCoordinateList ( + Vector.CoordinateList(6UL, [ (0UL, 1); (1UL, 1); (2UL, 1); (3UL, 1); (4UL, 1); (5UL, 1) ]) + ) + + // f idx x = x * idx + let f (idx: uint64) x = + match x with + | Some(a) -> Some(a * int idx) + | _ -> None + + // Expected: [0, 1, 2, 3, 4, 5] (1*idx for each position) + let expected = + Vector.fromCoordinateList ( + Vector.CoordinateList(6UL, [ (0UL, 0); (1UL, 1); (2UL, 2); (3UL, 3); (4UL, 4); (5UL, 5) ]) + ) + + let actual = Vector.mapi v f + + Assert.Equal(expected, actual) + +[] +let ``Simple Vector.mapi. Uniform leaf expansion.`` () = + // Vector of length 1 with value 5 + let v = + let tree = Vector.btree.Leaf(UserValue(Some(5))) + let store = Storage(1UL, tree) + SparseVector(1UL, 1UL, store) + + // f idx x = x + idx (5 + 0 = 5) + let f (idx: uint64) x = + match x with + | Some(a) -> Some(a + int idx) + | _ -> None + + let expected = + let tree = Vector.btree.Leaf(UserValue(Some(5))) + let store = Storage(1UL, tree) + SparseVector(1UL, 1UL, store) + + let actual = Vector.mapi v f + + Assert.Equal(expected, actual) + +[] +let ``Simple Vector.mapi. All indices identity.`` () = + // Vector with values matching their indices + let v = + Vector.fromCoordinateList ( + Vector.CoordinateList( + 4UL, + [ (0UL, 0); (2UL, 2) ] + ) + ) + + let f (idx: uint64) x = + match x with + | Some(a) when a = int idx -> Some a + | _ -> None + + let actual = Vector.mapi v f + let outputCL = Vector.toCoordinateList actual + + Assert.Equal(2UL, actual.nvals) + Assert.Equal * int>>([ (0UL, 0); (2UL, 2) ], outputCL.data) + [] let ``Simple Vector.map2. Length is power of two.`` () = diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index 80771df..cf32473 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -173,27 +173,26 @@ let map (vector: SparseVector<'a>) f = let mapi (vector: SparseVector<'a>) f = - let rec inner (size: uint64) vector = + let rec inner (pointer: uint64) (size: uint64) vector = match vector with | Node(x1, x2) -> - let t1, nvals1 = inner (size / 2UL) x1 - let t2, nvals2 = inner (size / 2UL) x2 + let halfSize = size / 2UL + let t1, nvals1 = inner pointer halfSize x1 + let t2, nvals2 = inner (pointer + (uint64 halfSize) * 1UL) halfSize x2 (mkNode t1 t2), nvals1 + nvals2 | Leaf(Dummy) -> Leaf(Dummy), 0UL | Leaf(UserValue(v)) -> - if size = 1UL - then - let res = f v - - let nnz = - match res with - | None -> 0UL - | _ -> 1UL - + if size = 1UL then + let res = f pointer v + let nnz = match res with Some _ -> 1UL | None -> 0UL Leaf(UserValue(res)), nnz - else inner size (Node (vector,vector)) + else + let halfSize = size / 2UL + let t1, nvals1 = inner pointer halfSize (Leaf(UserValue(v))) + let t2, nvals2 = inner (pointer + (uint64 halfSize) * 1UL) halfSize (Leaf(UserValue(v))) + (mkNode t1 t2), nvals1 + nvals2 - let storage, nvals = inner vector.storage.size vector.storage.data + let storage, nvals = inner 0UL vector.storage.size vector.storage.data SparseVector(vector.length, nvals, (Storage(vector.storage.size, storage))) From b761162826703b30990510c7074254e94ede5328 Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 08:40:14 +0300 Subject: [PATCH 16/52] First version of Vector.map2i --- QuadTree.Tests/Tests.Vector.fs | 76 ++++++++++++++++++++++++++++++++++ QuadTree/Vector.fs | 41 ++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index b912eef..bfc4d6f 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -250,6 +250,82 @@ let ``Simple Vector.map2. Length is not power of two.`` () = Assert.Equal(expected, actual) +[] +let ``Simple Vector.map2i. Length is power of two.`` () = + let v1 = + Vector.fromCoordinateList ( + Vector.CoordinateList(4UL, [ (0UL, 1); (1UL, 2); (2UL, 3); (3UL, 4) ]) + ) + + let v2 = + Vector.fromCoordinateList ( + Vector.CoordinateList(4UL, [ (0UL, 10); (1UL, 20); (2UL, 30); (3UL, 40) ]) + ) + + let f idx x y = + match (x, y) with + | Some(a), Some(b) -> Some(a + b + int idx) + | _ -> None + + let expected = + Vector.fromCoordinateList ( + Vector.CoordinateList(4UL, [ (0UL, 11); (1UL, 23); (2UL, 35); (3UL, 47) ]) + ) + + let actual = Vector.map2i v1 v2 f + + Assert.Equal(expected, actual) + +[] +let ``Simple Vector.map2i. Length is not power of two.`` () = + let v1 = + Vector.fromCoordinateList ( + Vector.CoordinateList(6UL, [ (0UL, 1); (1UL, 2); (2UL, 3); (3UL, 4); (4UL, 5); (5UL, 6) ]) + ) + + let v2 = + Vector.fromCoordinateList ( + Vector.CoordinateList(6UL, [ (0UL, 10); (1UL, 10); (2UL, 10); (3UL, 10); (4UL, 10); (5UL, 10) ]) + ) + + let f idx x y = + match (x, y) with + | Some(a), Some(b) -> Some(a * int idx + b) + | _ -> None + + let expected = + Vector.fromCoordinateList ( + Vector.CoordinateList(6UL, [ (0UL, 10); (1UL, 12); (2UL, 16); (3UL, 22); (4UL, 30); (5UL, 40) ]) + ) + + let actual = Vector.map2i v1 v2 f + + Assert.Equal(expected, actual) + +[] +let ``Simple Vector.map2i. Mixed values.`` () = + let v1 = + Vector.fromCoordinateList ( + Vector.CoordinateList(4UL, [ (0UL, 1); (2UL, 3) ]) + ) + + let v2 = + Vector.fromCoordinateList ( + Vector.CoordinateList(4UL, [ (1UL, 10); (3UL, 30) ]) + ) + + let f idx x y = + match (x, y) with + | Some(a), Some(b) -> Some(a + b) + | Some(a), None -> Some(a * 2) + | None, Some(b) -> Some(b * 3) + | _ -> None + + let actual = Vector.map2i v1 v2 f + let actualCL = Vector.toCoordinateList actual + + Assert.Equal(4UL, actual.nvals) + [] let ``Conversion identity`` () = let id = toCoordinateList << fromCoordinateList diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index cf32473..5c71c8f 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -261,6 +261,47 @@ let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = let mask (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = map2 vector1 vector2 (fun v1 v2 -> if f v2 then v1 else None) +let map2i (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = + let len1 = vector1.length + + let rec inner (pointer: uint64) (size: uint64) vector1 vector2 = + match (vector1, vector2) with + | Node(x1, x2), Node(y1, y2) -> + let halfSize = size / 2UL + let t1, nvals1 = inner pointer halfSize x1 y1 + let t2, nvals2 = inner (pointer + (uint64 halfSize) * 1UL) halfSize x2 y2 + (mkNode t1 t2), nvals1 + nvals2 + | Node(x1, x2), Leaf(v2) -> + let halfSize = size / 2UL + let t1, nvals1 = inner pointer halfSize x1 (Leaf(v2)) + let t2, nvals2 = inner (pointer + (uint64 halfSize) * 1UL) halfSize x2 (Leaf(v2)) + (mkNode t1 t2), nvals1 + nvals2 + | Leaf(v1), Node(y1, y2) -> + let halfSize = size / 2UL + let t1, nvals1 = inner pointer halfSize (Leaf(v1)) y1 + let t2, nvals2 = inner (pointer + (uint64 halfSize) * 1UL) halfSize (Leaf(v1)) y2 + (mkNode t1 t2), nvals1 + nvals2 + | Leaf(Dummy), Leaf(Dummy) -> Leaf(Dummy), 0UL + | Leaf(UserValue(v1)), Leaf(UserValue(v2)) -> + let res = f pointer v1 v2 + let nnz = match res with Some _ -> 1UL | None -> 0UL + Leaf(UserValue(res)), nnz + | Leaf(UserValue(v)), Leaf(Dummy) -> + let res = f pointer v None + let nnz = match res with Some _ -> 1UL | None -> 0UL + Leaf(UserValue(res)), nnz + | Leaf(Dummy), Leaf(UserValue(v)) -> + let res = f pointer None v + let nnz = match res with Some _ -> 1UL | None -> 0UL + Leaf(UserValue(res)), nnz + | (x, y) -> failwithf "InconsistentStructureOfStorages: %A vs %A" x y + + if len1 = vector2.length then + let storage, nvals = inner 0UL vector1.storage.size vector1.storage.data vector2.storage.data + SparseVector(len1, nvals, (Storage(vector1.storage.size, storage))) + else + failwithf "InconsistentSizeOfArguments: %A vs %A" vector1 vector2 + /// Returns None if index out of range let private unsafeGet (v : SparseVector<'a>) (index : uint64) = From 1f55f85f8583fa3d6cacc70d97a97923927ae62a Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 09:11:45 +0300 Subject: [PATCH 17/52] More steps in Boruvka. Not finished. --- QuadTree/Boruvka.fs | 31 ++++++++++++++++++++++++------- QuadTree/Vector.fs | 2 +- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 7830dc4..f349239 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -75,12 +75,12 @@ while S not empty do { return T *) - +(* type Error<'t1, 't2, 't3, 't4> = | NewFrontierCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't1> | EdgesCalculationProblem of Vector.Error<'t1, 't2, 't3> | CEdgesCalculationProblem of Vector.Error<'t1, 't4, 't4> -(* + let mst (graph:Matrix.SparseMatrix<_>) = let op_add x y = match (x, y) with @@ -97,7 +97,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = //let all_n = Vector.init length (fun _ -> Some (uint64 graph.ncols * 1UL)) let iota = Vector.init length (fun i -> Some (uint64 i)) - let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) = + let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent = if graph.nvals > 0UL then let edges = LinearAlgebra.vxmi_values op_add op_mult parent graph @@ -119,11 +119,28 @@ let mst (graph:Matrix.SparseMatrix<_>) = | Result.Success(cedges) -> let t = Vector.gather cedges parent - let mask = Vector.map2 edges t (fun x y -> match (x,y) with Some v1, Some v2 when v1 = v2 -> Some v1 | _ -> None) - match mask with + //let mask = Vector.map2 edges t (fun x y -> match (x,y) with Some v1, Some v2 when v1 = v2 -> Some v1 | _ -> None) + let index = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) + let index = Vector.scatter index index parent op_add + match index with | Result.Failure(e) -> Result.Failure(CEdgesCalculationProblem(e)) - | Result.Success (mask) -> - let index = Vector.map2 iota mask (fun i m -> match m with | Some _ -> ) + | Result.Success (index) -> + let index = Vector.gather index parent + + let filter i j = + let edge = Vector.unsafeGet edges i + match edge with + | Some(w,_to) -> + let parent = Vector.unsafeGet parent j + let idx = Vector.unsafeGet index i + match parent,idx with + | Some p, Some idx -> uint64 p = uint64 _to && idx = i + | _ -> false + | None -> false + + + + inner graph diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index 5c71c8f..0a40ef5 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -304,7 +304,7 @@ let map2i (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = /// Returns None if index out of range -let private unsafeGet (v : SparseVector<'a>) (index : uint64) = +let unsafeGet (v : SparseVector<'a>) (index : uint64) = let originalIndex = index let rec getFromTree (tree : btree>) (size : uint64) (index : uint64) = match tree with From e97df389139a509d9b1e4cb89f07bc1d63314eeb Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 09:21:28 +0300 Subject: [PATCH 18/52] First version of Matrix.map2i --- QuadTree.Tests/Tests.Matrix.fs | 86 ++++++++++++++++++++++++++++++++++ QuadTree/Matrix.fs | 48 +++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/QuadTree.Tests/Tests.Matrix.fs b/QuadTree.Tests/Tests.Matrix.fs index 163edef..38b2974 100644 --- a/QuadTree.Tests/Tests.Matrix.fs +++ b/QuadTree.Tests/Tests.Matrix.fs @@ -150,6 +150,92 @@ let ``Simple Matrix.map2. Square where number of cols and rows are not power of Assert.Equal(expected, actual) +[] +let ``Simple Matrix.map2i. Square where number of cols and rows are power of two.`` () = + let m1 = + Matrix.fromCoordinateList ( + Matrix.CoordinateList( + 4UL, 4UL, + [ (0UL, 0UL, 1); (0UL, 1UL, 2); (1UL, 0UL, 3); (1UL, 1UL, 4) ] + ) + ) + + let m2 = + Matrix.fromCoordinateList ( + Matrix.CoordinateList( + 4UL, 4UL, + [ (0UL, 0UL, 10); (0UL, 1UL, 20); (1UL, 0UL, 30); (1UL, 1UL, 40) ] + ) + ) + + let f row col x y = + match (x, y) with + | Some(a), Some(b) -> Some(a + b + int row + int col) + | _ -> None + + let actual = Matrix.map2i m1 m2 f + let actualCL = Matrix.toCoordinateList actual + + Assert.Equal(4UL, actual.nvals) + +[] +let ``Simple Matrix.map2i. Square where number of cols and rows are not power of two.`` () = + let m1 = + Matrix.fromCoordinateList ( + Matrix.CoordinateList( + 3UL, 3UL, + [ (0UL, 0UL, 1); (0UL, 1UL, 2); (0UL, 2UL, 3); (1UL, 0UL, 4); (1UL, 1UL, 5); (1UL, 2UL, 6) ] + ) + ) + + let m2 = + Matrix.fromCoordinateList ( + Matrix.CoordinateList( + 3UL, 3UL, + [ (0UL, 0UL, 10); (0UL, 1UL, 10); (0UL, 2UL, 10); (1UL, 0UL, 10); (1UL, 1UL, 10); (1UL, 2UL, 10) ] + ) + ) + + let f row col x y = + match (x, y) with + | Some(a), Some(b) -> Some(a * (int row + 1) + b * (int col + 1)) + | _ -> None + + let actual = Matrix.map2i m1 m2 f + let actualCL = Matrix.toCoordinateList actual + + Assert.Equal(6UL, actual.nvals) + +[] +let ``Simple Matrix.map2i. Mixed values.`` () = + let m1 = + Matrix.fromCoordinateList ( + Matrix.CoordinateList( + 4UL, 4UL, + [ (0UL, 0UL, 1); (2UL, 2UL, 3) ] + ) + ) + + let m2 = + Matrix.fromCoordinateList ( + Matrix.CoordinateList( + 4UL, 4UL, + [ (1UL, 1UL, 10); (3UL, 3UL, 30) ] + ) + ) + + let f row col x y = + match (x, y) with + | Some(a), Some(b) -> Some(a + b) + | Some(a), None -> Some(a * 2) + | None, Some(b) -> Some(b * 3) + | _ -> None + + let actual = Matrix.map2i m1 m2 f + let actualCL = Matrix.toCoordinateList actual + + Assert.Equal(4UL, actual.nvals) + [] let ``Conversion identity`` () = let id = toCoordinateList << fromCoordinateList diff --git a/QuadTree/Matrix.fs b/QuadTree/Matrix.fs index c1a19e0..679fcd6 100644 --- a/QuadTree/Matrix.fs +++ b/QuadTree/Matrix.fs @@ -180,6 +180,54 @@ let map2 (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = else Error Error.InconsistentSizeOfArguments +let map2i (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = + let rec inner (prow: uint64) (pcol: uint64) (size: uint64) matrix1 matrix2 = + match (matrix1, matrix2) with + | Node(x1, x2, x3, x4), Node(y1, y2, y3, y4) -> + let halfSize = size / 2UL + let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = getQuadrantCoords (prow, pcol) (uint64 halfSize) + let t1, nvals1 = inner nwR nwC halfSize x1 y1 + let t2, nvals2 = inner neR neC halfSize x2 y2 + let t3, nvals3 = inner swR swC halfSize x3 y3 + let t4, nvals4 = inner seR seC halfSize x4 y4 + (mkNode t1 t2 t3 t4), nvals1 + nvals2 + nvals3 + nvals4 + | Node(x1, x2, x3, x4), Leaf(v2) -> + let halfSize = size / 2UL + let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = getQuadrantCoords (prow, pcol) (uint64 halfSize) + let t1, nvals1 = inner nwR nwC halfSize x1 (Leaf(v2)) + let t2, nvals2 = inner neR neC halfSize x2 (Leaf(v2)) + let t3, nvals3 = inner swR swC halfSize x3 (Leaf(v2)) + let t4, nvals4 = inner seR seC halfSize x4 (Leaf(v2)) + (mkNode t1 t2 t3 t4), nvals1 + nvals2 + nvals3 + nvals4 + | Leaf(v1), Node(y1, y2, y3, y4) -> + let halfSize = size / 2UL + let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = getQuadrantCoords (prow, pcol) (uint64 halfSize) + let t1, nvals1 = inner nwR nwC halfSize (Leaf(v1)) y1 + let t2, nvals2 = inner neR neC halfSize (Leaf(v1)) y2 + let t3, nvals3 = inner swR swC halfSize (Leaf(v1)) y3 + let t4, nvals4 = inner seR seC halfSize (Leaf(v1)) y4 + (mkNode t1 t2 t3 t4), nvals1 + nvals2 + nvals3 + nvals4 + | Leaf(Dummy), Leaf(Dummy) -> Leaf(Dummy), 0UL + | Leaf(UserValue(v1)), Leaf(UserValue(v2)) -> + let res = f prow pcol v1 v2 + let nnz = match res with Some _ -> 1UL | None -> 0UL + Leaf(UserValue(res)), nnz + | Leaf(UserValue(v)), Leaf(Dummy) -> + let res = f prow pcol v None + let nnz = match res with Some _ -> 1UL | None -> 0UL + Leaf(UserValue(res)), nnz + | Leaf(Dummy), Leaf(UserValue(v)) -> + let res = f prow pcol None v + let nnz = match res with Some _ -> 1UL | None -> 0UL + Leaf(UserValue(res)), nnz + | (x, y) -> failwithf "InconsistentStructureOfStorages: %A vs %A" x y + + if matrix1.nrows = matrix2.nrows && matrix1.ncols = matrix2.ncols then + let storage, nvals = inner 0UL 0UL matrix1.storage.size matrix1.storage.data matrix2.storage.data + SparseMatrix(matrix1.nrows, matrix1.ncols, nvals, (Storage(matrix1.storage.size, storage))) + else + failwithf "InconsistentSizeOfArguments: %A vs %A" matrix1 matrix2 + let foldAssociative (folder: 'T option -> 'T option -> 'T option) (state: 'T option) (matrix: SparseMatrix<'T>) = let rec traverse tree (size: uint64) (state: 'T option) = match tree with From 9f9e00a2e9c59454fb587abed683a446491387b0 Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 09:33:53 +0300 Subject: [PATCH 19/52] Added Matrix.empty --- QuadTree/Matrix.fs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/QuadTree/Matrix.fs b/QuadTree/Matrix.fs index 679fcd6..a5f6a6e 100644 --- a/QuadTree/Matrix.fs +++ b/QuadTree/Matrix.fs @@ -137,6 +137,9 @@ let toCoordinateList (matrix: SparseMatrix<'a>) = CoordinateList(nrows, ncols, coo) +let empty nrows ncols = + fromCoordinateList (CoordinateList(nrows,ncols,[])) + let map2 (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = let rec inner (size: uint64) matrix1 matrix2 = let _do x1 x2 x3 x4 y1 y2 y3 y4 = From c10b546e2fdf21618e8ba8c46fe26dff2ebfccb6 Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 09:34:35 +0300 Subject: [PATCH 20/52] More code in Boruvka. Not finished. Mering of components missed. --- QuadTree/Boruvka.fs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index f349239..7e3580d 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -75,11 +75,12 @@ while S not empty do { return T *) -(* + type Error<'t1, 't2, 't3, 't4> = | NewFrontierCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't1> | EdgesCalculationProblem of Vector.Error<'t1, 't2, 't3> | CEdgesCalculationProblem of Vector.Error<'t1, 't4, 't4> + | IndexCalculationProblem of Vector.Error<'t1, 't4, 't4> let mst (graph:Matrix.SparseMatrix<_>) = let op_add x y = @@ -94,7 +95,6 @@ let mst (graph:Matrix.SparseMatrix<_>) = let length = uint64 graph.nrows * 1UL let parent = Vector.init length (fun i -> Some i) - //let all_n = Vector.init length (fun _ -> Some (uint64 graph.ncols * 1UL)) let iota = Vector.init length (fun i -> Some (uint64 i)) let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent = @@ -118,16 +118,17 @@ let mst (graph:Matrix.SparseMatrix<_>) = | Result.Failure(e) -> Result.Failure(CEdgesCalculationProblem(e)) | Result.Success(cedges) -> - let t = Vector.gather cedges parent - //let mask = Vector.map2 edges t (fun x y -> match (x,y) with Some v1, Some v2 when v1 = v2 -> Some v1 | _ -> None) + let t = Vector.gather cedges parent let index = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) let index = Vector.scatter index index parent op_add match index with - | Result.Failure(e) -> Result.Failure(CEdgesCalculationProblem(e)) + | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) | Result.Success (index) -> let index = Vector.gather index parent let filter i j = + let i = uint64 i * 1UL + let j = uint64 j * 1UL let edge = Vector.unsafeGet edges i match edge with | Some(w,_to) -> @@ -137,20 +138,28 @@ let mst (graph:Matrix.SparseMatrix<_>) = | Some p, Some idx -> uint64 p = uint64 _to && idx = i | _ -> false | None -> false - + + let tree = + Matrix.map2i tree graph ( + fun i j t g -> + match (t,g) with + | Some t, _ -> Some t + | None, Some g when filter i j -> Some g + | _ -> None) - inner graph + + inner graph tree parent else Result.Success tree - inner graph -*) + inner graph (Matrix.empty graph.nrows graph.ncols) parent +(* let mst (graph:Matrix.SparseMatrix<'w>) = let n = uint64 graph.nrows @@ -267,3 +276,4 @@ let mst (graph:Matrix.SparseMatrix<'w>) = let parentInit = [| for i in 0UL..n-1UL -> i |] let rankInit = [| for i in 0UL..n-1UL -> 0UL |] inner graph [] parentInit rankInit 0 +*) \ No newline at end of file From 9905f860792ee128680ddcb94ae043ed6c934a3a Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 10:01:09 +0300 Subject: [PATCH 21/52] Errors typing hack. --- QuadTree/Boruvka.fs | 131 ++------------------------------------------ 1 file changed, 5 insertions(+), 126 deletions(-) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 7e3580d..1b64d18 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -76,11 +76,10 @@ while S not empty do { return T *) -type Error<'t1, 't2, 't3, 't4> = - | NewFrontierCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't1> - | EdgesCalculationProblem of Vector.Error<'t1, 't2, 't3> - | CEdgesCalculationProblem of Vector.Error<'t1, 't4, 't4> - | IndexCalculationProblem of Vector.Error<'t1, 't4, 't4> +type Error<'t1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12> = + | EdgesCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't3> + | CEdgesCalculationProblem of Vector.Error<'t4, 't5, 't6> + | IndexCalculationProblem of Vector.Error<'t7, 't8, 't9> let mst (graph:Matrix.SparseMatrix<_>) = let op_add x y = @@ -147,7 +146,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = | None, Some g when filter i j -> Some g | _ -> None) - + inner graph tree parent @@ -157,123 +156,3 @@ let mst (graph:Matrix.SparseMatrix<_>) = Result.Success tree inner graph (Matrix.empty graph.nrows graph.ncols) parent - - -(* -let mst (graph:Matrix.SparseMatrix<'w>) = - let n = uint64 graph.nrows - - let findRoot (parent: uint64 array) x = - let rec loop (y: uint64) (visited: Set) = - if visited.Contains(y) then y - else - let p = parent.[int y] - if p <> y then loop p (Set.add y visited) else y - loop x Set.empty - - let union (parent: uint64 array) (rank: uint64 array) x y = - let rootX = findRoot parent x - let rootY = findRoot parent y - if rootX <> rootY then - if rank.[int rootX] < rank.[int rootY] then - parent.[int rootX] <- rootY - elif rank.[int rootX] > rank.[int rootY] then - parent.[int rootY] <- rootX - else - parent.[int rootY] <- rootX - rank.[int rootX] <- rank.[int rootX] + 1UL - - let rec inner (S: Matrix.SparseMatrix<'w>) (mstEdges: (uint64 * uint64 * 'w) list) (parent: uint64 array) (rank: uint64 array) (iterations: int) = - if S.nvals > 0UL && iterations < 20 then - let edgesCL = Matrix.toCoordinateList S - - let edgesData = - edgesCL.list - |> List.map (fun (i, j, w) -> (uint64 i, uint64 j, w)) - - let edgesWithCompInfo = - edgesData - |> List.map (fun (i, j, w) -> - let rootJ = findRoot parent j - let rootI = findRoot parent i - (i, j, w, rootI, rootJ)) - - let interCompEdges = - edgesWithCompInfo - |> List.filter (fun (i, j, w, rootI, rootJ) -> rootI <> rootJ) - - if interCompEdges.IsEmpty then - let resultCL = - Matrix.CoordinateList(graph.nrows, graph.ncols, - List.map (fun (i, j, w) -> (i * 1UL, j * 1UL, w)) mstEdges) - Result.Success (Matrix.fromCoordinateList resultCL) - else - let compMinEdges = - interCompEdges - |> List.groupBy (fun (_, _, _, _, rootJ) -> rootJ) - |> List.map (fun (rootJ, edges) -> - let minEdge = List.minBy (fun (i, j, w, _, _) -> w) edges - (rootJ, minEdge)) - |> Map.ofList - - let repToEdge = - compMinEdges - |> Map.toList - |> List.map (fun (destComp, edge) -> (destComp, edge)) - |> List.filter (fun (_, (minI, minJ, _, _, _)) -> - let canonicalI, canonicalJ = if minI < minJ then minI, minJ else minJ, minI - let srcRoot = findRoot parent canonicalI - let dstRoot = findRoot parent canonicalJ - srcRoot <> dstRoot) - |> List.distinctBy (fun (_, (minI, minJ, _, _, _)) -> - if minI < minJ then (minI, minJ) else (minJ, minI)) - - let newMstEdges = - repToEdge - |> List.collect (fun (_, (minI, minJ, minW, _, _)) -> - [(minI, minJ, minW); (minJ, minI, minW)]) - |> fun newEdges -> mstEdges @ newEdges - - let parentCopy = Array.copy parent - let rankCopy = Array.copy rank - - for (_, (minI, minJ, _, _, _)) in repToEdge do - union parentCopy rankCopy minI minJ - - let rec pointerJump (parentArr: uint64 array) maxIter = - if maxIter = 0 then parentArr - else - let newParent = Array.copy parentArr - let mutable changed = false - for i in 0..int n-1 do - let root = findRoot parentArr parentArr.[i] - if root <> parentArr.[i] then - newParent.[i] <- root - changed <- true - if changed then pointerJump newParent (maxIter - 1) else newParent - - let parent''' = pointerJump parentCopy (int n) - - let s2 (i: uint64) (j: uint64) (_: 'w) = - let ii = uint64 i - let jj = uint64 j - findRoot parent''' ii <> findRoot parent''' jj - - let S' = - Matrix.toCoordinateList S - |> fun cl -> - let filtered = cl.list |> List.filter (fun (i, j, w) -> s2 i j w) - Matrix.fromCoordinateList (Matrix.CoordinateList(cl.nrows, cl.ncols, filtered)) - - inner S' newMstEdges parent''' rankCopy (iterations + 1) - - else - let resultCL = - Matrix.CoordinateList(graph.nrows, graph.ncols, - List.map (fun (i, j, w) -> (i * 1UL, j * 1UL, w)) mstEdges) - Result.Success (Matrix.fromCoordinateList resultCL) - - let parentInit = [| for i in 0UL..n-1UL -> i |] - let rankInit = [| for i in 0UL..n-1UL -> 0UL |] - inner graph [] parentInit rankInit 0 -*) \ No newline at end of file From 9f575830840979ea98883bc7467ba4f351a7fa34 Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 10:05:48 +0300 Subject: [PATCH 22/52] Tmp. Smal changes in Boruvka. Prepare to add Matrix.mapi --- QuadTree.Tests/Tests.Boruvka.fs | 2 +- QuadTree/Boruvka.fs | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 990af19..8bfc4bc 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -8,7 +8,7 @@ open Vector open Common -[] +//[] let ``Boruvka MST.`` () = let graph = let clist = diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 1b64d18..c490f71 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -146,7 +146,14 @@ let mst (graph:Matrix.SparseMatrix<_>) = | None, Some g when filter i j -> Some g | _ -> None) - + let graphFilter i j = + let parent_i = Vector.unsafeGet parent i + let parent_j = Vector.unsafeGet parent j + match (parent_i, parent_j) with + | Some v1, Some v2 when v1 <> v2 -> true + | _ -> false + + //let graph = Matrix.mapi inner graph tree parent From abb8291f3af7433e08369f362d6b6c70bc8dd5d6 Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 10:20:44 +0300 Subject: [PATCH 23/52] First version of Matrix.mapi --- QuadTree.Tests/Tests.Matrix.fs | 60 ++++++++++++++++++++++++++++++++++ QuadTree/Matrix.fs | 30 +++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/QuadTree.Tests/Tests.Matrix.fs b/QuadTree.Tests/Tests.Matrix.fs index 38b2974..6ba783a 100644 --- a/QuadTree.Tests/Tests.Matrix.fs +++ b/QuadTree.Tests/Tests.Matrix.fs @@ -236,6 +236,66 @@ let ``Simple Matrix.map2i. Mixed values.`` () = Assert.Equal(4UL, actual.nvals) +[] +let ``Simple Matrix.mapi. Square where number of cols and rows are power of two.`` () = + let m = + Matrix.fromCoordinateList ( + Matrix.CoordinateList( + 4UL, 4UL, + [ (0UL, 0UL, 1); (0UL, 1UL, 2); (1UL, 0UL, 3); (1UL, 1UL, 4) ] + ) + ) + + let f row col x = + match x with + | Some(a) -> Some(a + int row + int col) + | _ -> None + + let actual = Matrix.mapi m f + let actualCL = Matrix.toCoordinateList actual + + Assert.Equal(4UL, actual.nvals) + +[] +let ``Simple Matrix.mapi. Square where number of cols and rows are not power of two.`` () = + let m = + Matrix.fromCoordinateList ( + Matrix.CoordinateList( + 3UL, 3UL, + [ (0UL, 0UL, 1); (0UL, 1UL, 2); (0UL, 2UL, 3); (1UL, 0UL, 4); (1UL, 1UL, 5); (1UL, 2UL, 6) ] + ) + ) + + let f row col x = + match x with + | Some(a) -> Some(a * (int row + 1) * (int col + 1)) + | _ -> None + + let actual = Matrix.mapi m f + let actualCL = Matrix.toCoordinateList actual + + Assert.Equal(6UL, actual.nvals) + +[] +let ``Simple Matrix.mapi. Multiply row index by value.`` () = + let m = + Matrix.fromCoordinateList ( + Matrix.CoordinateList( + 4UL, 4UL, + [ (0UL, 0UL, 1); (1UL, 1UL, 2); (2UL, 2UL, 3); (3UL, 3UL, 4) ] + ) + ) + + let f row col x = + match x with + | Some(a) -> Some(a * int row) + | _ -> None + + let actual = Matrix.mapi m f + let actualCL = Matrix.toCoordinateList actual + + Assert.Equal(4UL, actual.nvals) + [] let ``Conversion identity`` () = let id = toCoordinateList << fromCoordinateList diff --git a/QuadTree/Matrix.fs b/QuadTree/Matrix.fs index a5f6a6e..4dd3f95 100644 --- a/QuadTree/Matrix.fs +++ b/QuadTree/Matrix.fs @@ -231,6 +231,36 @@ let map2i (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = else failwithf "InconsistentSizeOfArguments: %A vs %A" matrix1 matrix2 +let mapi (matrix: SparseMatrix<'a>) f = + let rec inner (prow: uint64) (pcol: uint64) (size: uint64) matrix = + match matrix with + | Node(x1, x2, x3, x4) -> + let halfSize = size / 2UL + let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = getQuadrantCoords (prow, pcol) (uint64 halfSize) + let t1, nvals1 = inner nwR nwC halfSize x1 + let t2, nvals2 = inner neR neC halfSize x2 + let t3, nvals3 = inner swR swC halfSize x3 + let t4, nvals4 = inner seR seC halfSize x4 + (mkNode t1 t2 t3 t4), nvals1 + nvals2 + nvals3 + nvals4 + | Leaf(Dummy) -> Leaf(Dummy), 0UL + | Leaf(UserValue(v)) -> + if size = 1UL then + let res = f prow pcol v + let nnz = match res with Some _ -> 1UL | None -> 0UL + Leaf(UserValue(res)), nnz + else + let halfSize = size / 2UL + let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = getQuadrantCoords (prow, pcol) (uint64 halfSize) + let t1, nvals1 = inner nwR nwC halfSize (Leaf(UserValue(v))) + let t2, nvals2 = inner neR neC halfSize (Leaf(UserValue(v))) + let t3, nvals3 = inner swR swC halfSize (Leaf(UserValue(v))) + let t4, nvals4 = inner seR seC halfSize (Leaf(UserValue(v))) + (mkNode t1 t2 t3 t4), nvals1 + nvals2 + nvals3 + nvals4 + + let storage, nvals = inner 0UL 0UL matrix.storage.size matrix.storage.data + + SparseMatrix(matrix.nrows, matrix.ncols, nvals, (Storage(matrix.storage.size, storage))) + let foldAssociative (folder: 'T option -> 'T option -> 'T option) (state: 'T option) (matrix: SparseMatrix<'T>) = let rec traverse tree (size: uint64) (state: 'T option) = match tree with From e7a17494111a3b0da59949a713869b68a949c387 Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 10:21:29 +0300 Subject: [PATCH 24/52] More on Boruvka. Graph filtering is added. Components merging missed. --- QuadTree.Tests/Tests.Boruvka.fs | 2 +- QuadTree/Boruvka.fs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 8bfc4bc..990af19 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -8,7 +8,7 @@ open Vector open Common -//[] +[] let ``Boruvka MST.`` () = let graph = let clist = diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index c490f71..3ee2764 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -147,14 +147,15 @@ let mst (graph:Matrix.SparseMatrix<_>) = | _ -> None) let graphFilter i j = + let i = uint64 i * 1UL + let j = uint64 j * 1UL let parent_i = Vector.unsafeGet parent i let parent_j = Vector.unsafeGet parent j match (parent_i, parent_j) with | Some v1, Some v2 when v1 <> v2 -> true | _ -> false - //let graph = Matrix.mapi - + let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) inner graph tree parent From 7b27866869369ac3bcc88906e0879e48b0a7365e Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 13:16:58 +0300 Subject: [PATCH 25/52] Boruvka. More details on components merging implemented. --- QuadTree/Boruvka.fs | 48 +++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 3ee2764..84eef8e 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -94,7 +94,6 @@ let mst (graph:Matrix.SparseMatrix<_>) = let length = uint64 graph.nrows * 1UL let parent = Vector.init length (fun i -> Some i) - let iota = Vector.init length (fun i -> Some (uint64 i)) let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent = if graph.nvals > 0UL then @@ -119,7 +118,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = let t = Vector.gather cedges parent let index = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) - let index = Vector.scatter index index parent op_add + let index = Vector.scatter index index parent op_min match index with | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) | Result.Success (index) -> @@ -145,19 +144,44 @@ let mst (graph:Matrix.SparseMatrix<_>) = | Some t, _ -> Some t | None, Some g when filter i j -> Some g | _ -> None) + + // Step 6: Update parent - for each representative i, set parent[partner[i]] = i + // Create vectors for scatter: indices = partner positions, values = i + let _parent = + Vector.map2i edges index + (fun i e idx -> + match e,idx with + | Some (v,j), Some (_i) when _i = i -> + Some (uint64 j * 1UL,i) + | _ -> None + ) + + let parentResult = + Vector.foldValues _parent (fun state (i,v) -> + match state with + | Result.Success state -> + Vector.update state i (Some v) (fun old _new -> _new) + | Result.Failure x -> Result.Failure x) + (Result.Success parent) + - let graphFilter i j = - let i = uint64 i * 1UL - let j = uint64 j * 1UL - let parent_i = Vector.unsafeGet parent i - let parent_j = Vector.unsafeGet parent j - match (parent_i, parent_j) with - | Some v1, Some v2 when v1 <> v2 -> true - | _ -> false + match parentResult with + | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) + | Result.Success(parent) -> + let parent = Vector.gather parent parent + // Step 7: Filter graph to remove intra-component edges + let graphFilter i j = + let i = uint64 i * 1UL + let j = uint64 j * 1UL + let parent_i = Vector.unsafeGet parent i + let parent_j = Vector.unsafeGet parent j + match (parent_i, parent_j) with + | Some v1, Some v2 when v1 <> v2 -> true + | _ -> false - let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) + let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) - inner graph tree parent + inner graph tree parent else From 61efc3647534acdd32a8d674451d22c30189e1f0 Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 24 Mar 2026 17:10:16 +0300 Subject: [PATCH 26/52] First run of Boruvka --- QuadTree.Tests/Tests.Boruvka.fs | 1 + QuadTree/Boruvka.fs | 180 ++++++++++++-------------------- 2 files changed, 69 insertions(+), 112 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 990af19..b10e2a6 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -10,6 +10,7 @@ open Common [] let ``Boruvka MST.`` () = + System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = Matrix.CoordinateList(7UL, 7UL,[ diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 84eef8e..ce549dc 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -2,100 +2,33 @@ module Graph.Boruvka open Common -(* -Вход: граф G = (V, E, w), матрица смежности S, n = |V| -Выход: множество рёбер МОД T - -iota <- [0, 1, 2, ..., n-1] // вектор индексов - -parent[u] <- u для всех u in 0..n-1 -T <- empty - -while S not empty do { - - // Шаг 1. Минимальное ребро каждой вершины - // mxv над полукольцом combMin: - // edge[u] = min{ (w, parent[v]) | (u,v,w) in S } - - edge <- mxv(S, parent) - - // Шаг 2. Минимальное ребро каждой компоненты - // scatter-reduce: cedge[parent[u]] = min по всем u в компоненте - - cedge <- scatter(edge, parent, min) - - // Шаг 3. Распространить минимум компоненты на все её вершины - // gather: t[u] = cedge[parent[u]] - - t <- gather(cedge, parent) - - // Шаг 4. Выбрать одного представителя на компоненту - - mask <- eWiseMult(edge, t, ==) - index <- assign([n, n, ..., n], iota, mask) - // index[u] <- u если mask[u], иначе n - - index <- scatter(index, parent, min) // минимальный представитель в компоненте - index <- gather(index, parent) // broadcast на все вершины компоненты - - // Шаг 5. Добавить выбранные рёбра в МОД - - (weight, partner) <- extract_tuples(edge) - - s1 = fun i j -> - weight[i] == S(i,j) - && parent[j] == partner[i] - && index[i] == i - - T <- T ∪ select(S, s1) - - // Шаг 6. Обновить компоненты (до фильтрации S) - - // 6а. Переключить корень каждой поглощаемой компоненты: - // parent[partner[i]] <- i для всех представителей i - // (parent[i] = i для корня, поэтому пишем iota, а не parent) - // masked scatter: пишем только там, где index[i] == i - - rep_mask <- (index == iota) - parent <- scatter(iota, partner, first, mask=rep_mask) - // parent[partner[i]] <- i для всех i, где rep_mask[i] - - // 6б. Сжатие путей методом pointer jumping - - repeat - parent <- gather(parent, parent) // parent[u] <- parent[parent[u]] - until parent unchanged - - // Шаг 7. Удалить внутрикомпонентные рёбра - - s2 = fun i j -> parent[i] != parent[j] - - S <- select(S, s2) -} - -return T -*) - type Error<'t1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12> = | EdgesCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't3> | CEdgesCalculationProblem of Vector.Error<'t4, 't5, 't6> | IndexCalculationProblem of Vector.Error<'t7, 't8, 't9> let mst (graph:Matrix.SparseMatrix<_>) = + eprintfn "MST CALLED nrows=%A ncols=%A nvals=%A" graph.nrows graph.ncols graph.nvals + let op_add x y = match (x, y) with - | Some(a), Some(b) -> Some(min a b) - | Some(a), _ - | _, Some(a) -> Some(a) + | Some(a, pa), Some(b, pb) -> + if a < b then Some(a, pa) + elif b < a then Some(b, pb) + elif pa <= pb then Some(a, pa) + else Some(b, pb) + | Some(a, pa), _ -> Some(a, pa) + | _, Some(b, pb) -> Some(b, pb) | _ -> None let op_mult (i,x) (row,col,w) = - Some(w,row) + Some(w,row) // Store source vertex let length = uint64 graph.nrows * 1UL - let parent = Vector.init length (fun i -> Some i) + let parent = Vector.init length (fun i -> Some i) - let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent = + let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent iteration = + eprintfn "Iter %d: graph=%A, tree=%A" iteration graph.nvals tree.nvals if graph.nvals > 0UL then let edges = LinearAlgebra.vxmi_values op_add op_mult parent graph @@ -107,6 +40,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = match (x, y) with | Some v, Some u -> if v < u then Some v else None | Some v, _ -> Some v + | None, Some v -> Some v | _ -> None let cedges = @@ -118,24 +52,27 @@ let mst (graph:Matrix.SparseMatrix<_>) = let t = Vector.gather cedges parent let index = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) - let index = Vector.scatter index index parent op_min + let index = Vector.scatter (Vector.empty length) index parent op_min match index with | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) | Result.Success (index) -> let index = Vector.gather index parent + // Use compressed parent for filter + let parentCompressed = Vector.gather parent parent + + // edges[i] = (w, parent[source]) for minimum edge source -> i + // index[i] = i if i is a representative let filter i j = let i = uint64 i * 1UL let j = uint64 j * 1UL let edge = Vector.unsafeGet edges i - match edge with - | Some(w,_to) -> - let parent = Vector.unsafeGet parent j - let idx = Vector.unsafeGet index i - match parent,idx with - | Some p, Some idx -> uint64 p = uint64 _to && idx = i - | _ -> false - | None -> false + let idx = Vector.unsafeGet index i + let parentJ = Vector.unsafeGet parentCompressed j + match edge, idx, parentJ with + | Some(w, parentSource), Some idxVal, Some pj -> + uint64 idxVal = uint64 i && uint64 parentSource <> uint64 i && uint64 pj = uint64 parentSource + | _ -> false let tree = Matrix.map2i tree graph ( @@ -145,46 +82,65 @@ let mst (graph:Matrix.SparseMatrix<_>) = | None, Some g when filter i j -> Some g | _ -> None) - // Step 6: Update parent - for each representative i, set parent[partner[i]] = i - // Create vectors for scatter: indices = partner positions, values = i - let _parent = - Vector.map2i edges index - (fun i e idx -> - match e,idx with - | Some (v,j), Some (_i) when _i = i -> - Some (uint64 j * 1UL,i) - | _ -> None - ) - - let parentResult = - Vector.foldValues _parent (fun state (i,v) -> - match state with - | Result.Success state -> - Vector.update state i (Some v) (fun old _new -> _new) - | Result.Failure x -> Result.Failure x) - (Result.Success parent) - + // Step 6: Update parent + let getPartnerIdx i = + let idxVal = Vector.unsafeGet index i + let edgeVal = Vector.unsafeGet edges i + match (idxVal, edgeVal) with + | Some idx', Some(weight, parentSource) when idx' = i -> + Some(uint64 parentSource * 1UL) + | _ -> None + + let scatterIndices: Vector.SparseVector> = Vector.init length getPartnerIdx + let scatterValues: Vector.SparseVector> = Vector.init length (fun i -> Some i) + + let parentResult = Vector.scatter parent scatterIndices scatterValues (fun old newVal -> newVal) match parentResult with | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) | Result.Success(parent) -> + // Path compression: gather multiple times + let parent = Vector.gather parent parent + let parent = Vector.gather parent parent + let parent = Vector.gather parent parent + let parent = Vector.gather parent parent + let parent = Vector.gather parent parent + let parent = Vector.gather parent parent + let parent = Vector.gather parent parent + let parent = Vector.gather parent parent + let parent = Vector.gather parent parent let parent = Vector.gather parent parent + // Step 7: Filter graph to remove intra-component edges + // First do MORE compressions to get actual roots + let rec compress p iter = + if iter > 20 then p else + let p2 = Vector.gather p p + compress p2 (iter + 1) + let parentForFilter = compress parent 0 + + // Debug: print parent for filtering + if iteration < 2 then + eprintfn "Step7 parent for filtering:" + for i in [0UL;1UL;2UL;3UL;4UL;5UL;6UL] do + let p = Vector.unsafeGet parentForFilter (i * 1UL) + eprintfn " parent[%d]=%A" i p + let graphFilter i j = let i = uint64 i * 1UL let j = uint64 j * 1UL - let parent_i = Vector.unsafeGet parent i - let parent_j = Vector.unsafeGet parent j + let parent_i = Vector.unsafeGet parentForFilter i + let parent_j = Vector.unsafeGet parentForFilter j match (parent_i, parent_j) with | Some v1, Some v2 when v1 <> v2 -> true | _ -> false let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) - inner graph tree parent + inner graph tree parent (iteration + 1) else Result.Success tree - inner graph (Matrix.empty graph.nrows graph.ncols) parent + inner graph (Matrix.empty graph.nrows graph.ncols) parent 0 From 424eec652fd65e82d7d223fa8d4f598d9f63c11f Mon Sep 17 00:00:00 2001 From: gsv Date: Wed, 25 Mar 2026 09:00:28 +0300 Subject: [PATCH 27/52] Boruvka. Components looks correct, but gruph filtration wrong: too many iterations. --- QuadTree/Boruvka.fs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index ce549dc..f9867e4 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -28,7 +28,12 @@ let mst (graph:Matrix.SparseMatrix<_>) = let parent = Vector.init length (fun i -> Some i) let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent iteration = - eprintfn "Iter %d: graph=%A, tree=%A" iteration graph.nvals tree.nvals + eprintfn "=== Iter %d: graph=%A, tree=%A ===" iteration graph.nvals tree.nvals + if iteration < 2 then + eprintfn "Parent at start:" + for i in 0UL..6UL do + let p = Vector.unsafeGet parent (i * 1UL) + eprintfn " parent[%d]=%A" i p if graph.nvals > 0UL then let edges = LinearAlgebra.vxmi_values op_add op_mult parent graph @@ -86,6 +91,8 @@ let mst (graph:Matrix.SparseMatrix<_>) = let getPartnerIdx i = let idxVal = Vector.unsafeGet index i let edgeVal = Vector.unsafeGet edges i + if iteration < 2 then + eprintfn " getPartnerIdx %d: idxVal=%A, edgeVal=%A" i idxVal edgeVal match (idxVal, edgeVal) with | Some idx', Some(weight, parentSource) when idx' = i -> Some(uint64 parentSource * 1UL) @@ -94,7 +101,12 @@ let mst (graph:Matrix.SparseMatrix<_>) = let scatterIndices: Vector.SparseVector> = Vector.init length getPartnerIdx let scatterValues: Vector.SparseVector> = Vector.init length (fun i -> Some i) - let parentResult = Vector.scatter parent scatterIndices scatterValues (fun old newVal -> newVal) + let parentResult = Vector.scatter parent scatterIndices scatterValues (fun old newVal -> + match old, newVal with + | Some o, Some n -> if o < n then Some o else Some n + | Some o, None -> Some o + | None, Some n -> Some n + | _ -> None) match parentResult with | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) From f7faf9caf2010e4f85e36405c269ddb867fc2a75 Mon Sep 17 00:00:00 2001 From: gsv Date: Wed, 25 Mar 2026 09:14:27 +0300 Subject: [PATCH 28/52] Transpose tree in tests. --- QuadTree.Tests/Tests.Boruvka.fs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index b10e2a6..56b2ee2 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -77,7 +77,15 @@ let ``Boruvka MST.`` () = Matrix.fromCoordinateList clist |> Result.Success - let actual = Graph.Boruvka.mst graph + //let actual = + match Graph.Boruvka.mst graph with + | Result.Success tree -> + let tree_transposed = Matrix.transpose tree + let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) + Assert.Equal(expected, actual) + //actual + //|> Result.Success + | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) - Assert.Equal(expected, actual) + From 8cf64873950646847672436a966e83757661f074 Mon Sep 17 00:00:00 2001 From: gsv Date: Wed, 25 Mar 2026 13:02:40 +0300 Subject: [PATCH 29/52] First part of Borivka works. --- QuadTree.Tests/Tests.Boruvka.fs | 162 +++++++++++++++++++++++++++++++- QuadTree.Tests/Tests.Matrix.fs | 10 ++ QuadTree/Boruvka.fs | 133 ++++++++++++++++++-------- 3 files changed, 262 insertions(+), 43 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 56b2ee2..14ce809 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -8,6 +8,163 @@ open Vector open Common +//[] +let ``Boruvka MST simple triangle.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(7UL, 7UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 0UL, 2UL, 1UL + 2UL, 0UL, 1UL + + 1UL, 2UL, 1UL + 2UL, 1UL, 1UL + + ]) + + Matrix.fromCoordinateList clist + + + let expected = + let clist = + Matrix.CoordinateList(7UL, 7UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 0UL, 2UL, 1UL + 2UL, 0UL, 1UL + ]) + + Matrix.fromCoordinateList clist + |> Result.Success + + //let actual = + match Graph.Boruvka.mst graph with + | Result.Success tree -> + let tree_transposed = Matrix.transpose tree + let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) + match actual with + | Result.Success actual -> Tests.printMatrixCoordinate actual + | _ -> printfn "Failed" + Assert.Equal(expected, actual) + //actual + //|> Result.Success + | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) + + +//[] +let ``Boruvka MST simple square.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(7UL, 7UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 1UL, 2UL, 1UL + 2UL, 1UL, 1UL + + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL + + ]) + + Matrix.fromCoordinateList clist + + + let expected = + let clist = + Matrix.CoordinateList(7UL, 7UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL + + 1UL, 2UL, 1UL + 2UL, 1UL, 1UL + ]) + + Matrix.fromCoordinateList clist + |> Result.Success + + //let actual = + match Graph.Boruvka.mst graph with + | Result.Success tree -> + let tree_transposed = Matrix.transpose tree + let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) + match actual with + | Result.Success actual -> Tests.printMatrixCoordinate actual + | _ -> printfn "Failed" + Assert.Equal(expected, actual) + //actual + //|> Result.Success + | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) + + + + +//[] +let ``Boruvka MST simple square in two steps.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(7UL, 7UL,[ + 0UL, 1UL, 2UL + 1UL, 0UL, 2UL + + 1UL, 2UL, 1UL + 2UL, 1UL, 1UL + + 2UL, 3UL, 2UL + 3UL, 2UL, 2UL + + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL + + ]) + + Matrix.fromCoordinateList clist + + + let expected = + let clist = + Matrix.CoordinateList(7UL, 7UL,[ + 0UL, 1UL, 2UL + 1UL, 0UL, 2UL + + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL + + 1UL, 2UL, 1UL + 2UL, 1UL, 1UL + ]) + + Matrix.fromCoordinateList clist + |> Result.Success + + //let actual = + match Graph.Boruvka.mst graph with + | Result.Success tree -> + let tree_transposed = Matrix.transpose tree + let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) + match actual with + | Result.Success actual -> Tests.printMatrixCoordinate actual + | _ -> printfn "Failed" + Assert.Equal(expected, actual) + //actual + //|> Result.Success + | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) + + + + [] let ``Boruvka MST.`` () = System.Console.Error.WriteLine("TEST STARTING") @@ -82,9 +239,10 @@ let ``Boruvka MST.`` () = | Result.Success tree -> let tree_transposed = Matrix.transpose tree let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) + match actual with + | Result.Success actual -> Tests.printMatrixCoordinate actual + | _ -> printfn "Failed" Assert.Equal(expected, actual) - //actual - //|> Result.Success | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) diff --git a/QuadTree.Tests/Tests.Matrix.fs b/QuadTree.Tests/Tests.Matrix.fs index 6ba783a..8fafdce 100644 --- a/QuadTree.Tests/Tests.Matrix.fs +++ b/QuadTree.Tests/Tests.Matrix.fs @@ -15,6 +15,16 @@ let printMatrix (matrix: SparseMatrix<_>) = printfn " size: %A" matrix.storage.size printfn " Data: %A" matrix.storage.data +let printMatrixCoordinate (matrix: SparseMatrix<_>) = + printfn "Matrix:" + printfn " Rows: %A" matrix.nrows + printfn " Columns: %A" matrix.ncols + printfn " Nvals: %A" matrix.nvals + printfn " Storage:" + printfn " size: %A" matrix.storage.size + printfn " Data: %A" (Matrix.toCoordinateList matrix).list + + let leaf_v v = qtree.Leaf << UserValue <| Some v let leaf_n () = qtree.Leaf << UserValue <| None let leaf_d () = qtree.Leaf Dummy diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index f9867e4..f12598f 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -2,21 +2,42 @@ module Graph.Boruvka open Common + +let printMatrixCoordinate (matrix: Matrix.SparseMatrix<_>) = + printfn "Matrix:" + printfn " Rows: %A" matrix.nrows + printfn " Columns: %A" matrix.ncols + printfn " Nvals: %A" matrix.nvals + printfn " Storage:" + printfn " size: %A" matrix.storage.size + printfn " Data: %A" (Matrix.toCoordinateList matrix).list + +let printVector (vector: Vector.SparseVector<_>) = + printfn "Vector:" + printfn " Length: %A" vector.length + printfn " Nvals: %A" vector.nvals + printfn " Storage:" + printfn " Size: %A" vector.storage.size + printfn " Data: %A" (Vector.toCoordinateList vector).data + + + type Error<'t1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12> = | EdgesCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't3> | CEdgesCalculationProblem of Vector.Error<'t4, 't5, 't6> | IndexCalculationProblem of Vector.Error<'t7, 't8, 't9> let mst (graph:Matrix.SparseMatrix<_>) = - eprintfn "MST CALLED nrows=%A ncols=%A nvals=%A" graph.nrows graph.ncols graph.nvals + printfn "MST CALLED nrows=%A ncols=%A nvals=%A" graph.nrows graph.ncols graph.nvals let op_add x y = match (x, y) with | Some(a, pa), Some(b, pb) -> - if a < b then Some(a, pa) + Some (min (a,pa) (b,pb)) + (* if a < b then Some(a, pa) elif b < a then Some(b, pb) elif pa <= pb then Some(a, pa) - else Some(b, pb) + else Some(b, pb)*) | Some(a, pa), _ -> Some(a, pa) | _, Some(b, pb) -> Some(b, pb) | _ -> None @@ -28,19 +49,23 @@ let mst (graph:Matrix.SparseMatrix<_>) = let parent = Vector.init length (fun i -> Some i) let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent iteration = - eprintfn "=== Iter %d: graph=%A, tree=%A ===" iteration graph.nvals tree.nvals + printfn "=== Iter %d: graph=%A, tree=%A ===" iteration graph.nvals tree.nvals + printfn "=== Graph ===" + printMatrixCoordinate graph if iteration < 2 then - eprintfn "Parent at start:" + printfn "Parent at start of iter %d:" iteration for i in 0UL..6UL do let p = Vector.unsafeGet parent (i * 1UL) - eprintfn " parent[%d]=%A" i p + printfn " parent[%d]=%A" i p if graph.nvals > 0UL then - let edges = LinearAlgebra.vxmi_values op_add op_mult parent graph - + let edges = LinearAlgebra.vxmi_values op_add op_mult parent graph match edges with | Result.Failure(e) -> Result.Failure(EdgesCalculationProblem(e)) | Result.Success(edges) -> + printfn "=== Edges ===" + printVector edges + let op_min x y = match (x, y) with | Some v, Some u -> if v < u then Some v else None @@ -54,6 +79,8 @@ let mst (graph:Matrix.SparseMatrix<_>) = match cedges with | Result.Failure(e) -> Result.Failure(CEdgesCalculationProblem(e)) | Result.Success(cedges) -> + printfn "=== Component Edges ===" + printVector cedges let t = Vector.gather cedges parent let index = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) @@ -61,30 +88,50 @@ let mst (graph:Matrix.SparseMatrix<_>) = match index with | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) | Result.Success (index) -> + //printfn "=== Index ===" + //printVector index let index = Vector.gather index parent - + printfn "=== Index 2 ===" + printVector index // Use compressed parent for filter - let parentCompressed = Vector.gather parent parent + //let parentCompressed = Vector.gather parent parent + //let parentCompressed = Vector.gather parentCompressed parentCompressed + //let parentCompressed = Vector.gather parentCompressed parentCompressed + //let parentCompressed = Vector.gather parentCompressed parentCompressed + //let parentCompressed = Vector.gather parentCompressed parentCompressed + //let parentCompressed = Vector.gather parentCompressed parentCompressed + printfn "=== parent ===" + printVector parent + + // edges[i] = (w, parent[source]) for minimum edge source -> i // index[i] = i if i is a representative - let filter i j = + // Filter: add edge (i,j) only if i is rep AND j = src AND j is in DIFFERENT component than i + let filter i j g = let i = uint64 i * 1UL let j = uint64 j * 1UL + printfn "Edge for filter: %A %A %A" i j g let edge = Vector.unsafeGet edges i let idx = Vector.unsafeGet index i - let parentJ = Vector.unsafeGet parentCompressed j - match edge, idx, parentJ with - | Some(w, parentSource), Some idxVal, Some pj -> - uint64 idxVal = uint64 i && uint64 parentSource <> uint64 i && uint64 pj = uint64 parentSource - | _ -> false + let parent_j = Vector.unsafeGet parent j + let result = + match edge, idx, parent_j with + | Some(w, dst), Some idxVal, Some pi -> + // i is rep (parent[i]=i), source != i, j = src + //(uint64 pi) = (uint64 i) && (uint64 src) <> (uint64 i) && (uint64 j) = (uint64 src) + g = w && idxVal = i && uint64 dst = uint64 j + | _ -> false + if result then + printfn "TREE FILTER iter %d: edge (%d,%d) -> tree" iteration (i/1UL) (j/1UL) + result let tree = Matrix.map2i tree graph ( fun i j t g -> match (t,g) with | Some t, _ -> Some t - | None, Some g when filter i j -> Some g + | None, Some g when filter i j g -> Some g | _ -> None) // Step 6: Update parent @@ -92,7 +139,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = let idxVal = Vector.unsafeGet index i let edgeVal = Vector.unsafeGet edges i if iteration < 2 then - eprintfn " getPartnerIdx %d: idxVal=%A, edgeVal=%A" i idxVal edgeVal + printfn " getPartnerIdx %d: idxVal=%A, edgeVal=%A" i idxVal edgeVal match (idxVal, edgeVal) with | Some idx', Some(weight, parentSource) when idx' = i -> Some(uint64 parentSource * 1UL) @@ -111,41 +158,45 @@ let mst (graph:Matrix.SparseMatrix<_>) = match parentResult with | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) | Result.Success(parent) -> - // Path compression: gather multiple times - let parent = Vector.gather parent parent - let parent = Vector.gather parent parent - let parent = Vector.gather parent parent - let parent = Vector.gather parent parent - let parent = Vector.gather parent parent - let parent = Vector.gather parent parent - let parent = Vector.gather parent parent - let parent = Vector.gather parent parent - let parent = Vector.gather parent parent - let parent = Vector.gather parent parent - - // Step 7: Filter graph to remove intra-component edges - // First do MORE compressions to get actual roots - let rec compress p iter = - if iter > 20 then p else + // Path compression: fix-point iteration using vector length + let vecLength = uint64 parent.length + let rec fixPoint p iter = let p2 = Vector.gather p p - compress p2 (iter + 1) - let parentForFilter = compress parent 0 + // Check if p changed by comparing all values + let rec changed i = + if i >= vecLength then false + else + let v1 = Vector.unsafeGet p (i * 1UL) + let v2 = Vector.unsafeGet p2 (i * 1UL) + if v1 <> v2 then true + else changed (i + 1UL) + let isChanged = changed 0UL + if isChanged then + if iter > 20 then p2 // Safety limit + else fixPoint p2 (iter + 1) + else p2 + let parent = fixPoint parent 0 + let parentForFilter = fixPoint parent 0 // Debug: print parent for filtering if iteration < 2 then - eprintfn "Step7 parent for filtering:" + printfn "Step7 parent for filtering:" for i in [0UL;1UL;2UL;3UL;4UL;5UL;6UL] do let p = Vector.unsafeGet parentForFilter (i * 1UL) - eprintfn " parent[%d]=%A" i p + printfn " parent[%d]=%A" i p let graphFilter i j = let i = uint64 i * 1UL let j = uint64 j * 1UL let parent_i = Vector.unsafeGet parentForFilter i let parent_j = Vector.unsafeGet parentForFilter j - match (parent_i, parent_j) with - | Some v1, Some v2 when v1 <> v2 -> true - | _ -> false + let result = + match (parent_i, parent_j) with + | Some v1, Some v2 when v1 <> v2 -> true + | _ -> false + if iteration < 2 && result then + printfn "GRAPH FILTER iter %d: keep edge (%d,%d)" iteration (i/1UL) (j/1UL) + result let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) From d8bb7c6b798045ecdf4e709d842d465670531131 Mon Sep 17 00:00:00 2001 From: gsv Date: Wed, 25 Mar 2026 15:26:58 +0300 Subject: [PATCH 30/52] Boruvka works...? --- QuadTree.Tests/Tests.Boruvka.fs | 6 +- QuadTree/Boruvka.fs | 104 +++++++++++++++++++------------- 2 files changed, 66 insertions(+), 44 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 14ce809..eb2e424 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -8,7 +8,7 @@ open Vector open Common -//[] +[] let ``Boruvka MST simple triangle.`` () = System.Console.Error.WriteLine("TEST STARTING") let graph = @@ -55,7 +55,7 @@ let ``Boruvka MST simple triangle.`` () = | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) -//[] +[] let ``Boruvka MST simple square.`` () = System.Console.Error.WriteLine("TEST STARTING") let graph = @@ -110,7 +110,7 @@ let ``Boruvka MST simple square.`` () = -//[] +[] let ``Boruvka MST simple square in two steps.`` () = System.Console.Error.WriteLine("TEST STARTING") let graph = diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index f12598f..d246c30 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -26,6 +26,7 @@ type Error<'t1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12> = | EdgesCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't3> | CEdgesCalculationProblem of Vector.Error<'t4, 't5, 't6> | IndexCalculationProblem of Vector.Error<'t7, 't8, 't9> + | ScatterProblem of Vector.Error<'t10, 't11, 't12> let mst (graph:Matrix.SparseMatrix<_>) = printfn "MST CALLED nrows=%A ncols=%A nvals=%A" graph.nrows graph.ncols graph.nvals @@ -135,6 +136,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = | _ -> None) // Step 6: Update parent + (* let getPartnerIdx i = let idxVal = Vector.unsafeGet index i let edgeVal = Vector.unsafeGet edges i @@ -154,53 +156,73 @@ let mst (graph:Matrix.SparseMatrix<_>) = | Some o, None -> Some o | None, Some n -> Some n | _ -> None) - + *) + let _parent = + Vector.map2i edges index + (fun i e idx -> + match e,idx with + | Some (v,j), Some (_i) when _i = i -> + let j = uint64 j * 1UL + let parent = Vector.unsafeGet parent (min j i) + match parent with + | Some p -> Some (max j i, p) + | x -> failwithf "Unreachable: %A" x + | _ -> None + ) + + printfn "=== _parent ===" + printVector _parent + + let parentResult = + Vector.foldValues _parent (fun state (i,v) -> + match state with + | Result.Success state -> + Vector.update state i (Some v) (fun old _new -> _new) + | Result.Failure x -> Result.Failure x) + (Result.Success parent) + match parentResult with | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) - | Result.Success(parent) -> + | Result.Success(__parent) -> + printfn "=== parentResult ===" + printVector __parent // Path compression: fix-point iteration using vector length let vecLength = uint64 parent.length let rec fixPoint p iter = let p2 = Vector.gather p p - // Check if p changed by comparing all values - let rec changed i = - if i >= vecLength then false - else - let v1 = Vector.unsafeGet p (i * 1UL) - let v2 = Vector.unsafeGet p2 (i * 1UL) - if v1 <> v2 then true - else changed (i + 1UL) - let isChanged = changed 0UL - if isChanged then - if iter > 20 then p2 // Safety limit - else fixPoint p2 (iter + 1) - else p2 - let parent = fixPoint parent 0 - let parentForFilter = fixPoint parent 0 - - // Debug: print parent for filtering - if iteration < 2 then - printfn "Step7 parent for filtering:" - for i in [0UL;1UL;2UL;3UL;4UL;5UL;6UL] do - let p = Vector.unsafeGet parentForFilter (i * 1UL) - printfn " parent[%d]=%A" i p - - let graphFilter i j = - let i = uint64 i * 1UL - let j = uint64 j * 1UL - let parent_i = Vector.unsafeGet parentForFilter i - let parent_j = Vector.unsafeGet parentForFilter j - let result = - match (parent_i, parent_j) with - | Some v1, Some v2 when v1 <> v2 -> true - | _ -> false - if iteration < 2 && result then - printfn "GRAPH FILTER iter %d: keep edge (%d,%d)" iteration (i/1UL) (j/1UL) - result - - let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) - - inner graph tree parent (iteration + 1) + if p2 = p then p else fixPoint p2 1 + let op_min x y = + match (x, y) with + | Some v, Some u -> if v < u then Some v else Some u + | Some v, _ -> Some v + | None, Some v -> Some v + | _ -> None + let parent = Vector.scatter parent __parent parent op_min + match parent with + | Result.Failure x -> ScatterProblem x |> Result.Failure + | Result.Success parent -> + printfn "=== parent' ===" + printVector parent + let parent = fixPoint parent 0 + + printfn "=== Parent for filter ===" + printVector parent + let graphFilter i j = + let i = uint64 i * 1UL + let j = uint64 j * 1UL + let parent_i = Vector.unsafeGet parent i + let parent_j = Vector.unsafeGet parent j + let result = + match (parent_i, parent_j) with + | Some v1, Some v2 when v1 <> v2 -> true + | _ -> false + if iteration < 2 && result then + printfn "GRAPH FILTER iter %d: keep edge (%d,%d)" iteration (i/1UL) (j/1UL) + result + + let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) + + inner graph tree parent (iteration + 1) else From 0858b4d74358c4c75095e782331f9bca0d3e0bf0 Mon Sep 17 00:00:00 2001 From: gsv Date: Wed, 25 Mar 2026 15:50:58 +0300 Subject: [PATCH 31/52] More tests on Boruvka. Code cleanup. --- QuadTree.Tests/Tests.Boruvka.fs | 121 ++++++++++++++++++++++++++++++++ QuadTree/Boruvka.fs | 46 +----------- 2 files changed, 123 insertions(+), 44 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index eb2e424..4be5021 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -246,4 +246,125 @@ let ``Boruvka MST.`` () = | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) +[] +let ``Boruvka MST big.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(12UL, 12UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 1UL, 11UL, 1UL + 11UL, 1UL, 1UL + + 0UL, 11UL, 1UL + 11UL, 0UL, 1UL +//================================================= + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + + 3UL, 4UL, 1UL + 4UL, 3UL, 1UL + + 2UL, 4UL, 1UL + 4UL, 2UL, 1UL +//================================================= + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + + 6UL, 7UL, 1UL + 7UL, 6UL, 1UL + + 5UL, 7UL, 1UL + 7UL, 5UL, 1UL +//================================================= + 8UL, 9UL, 1UL + 9UL, 8UL, 1UL + + 9UL, 10UL, 1UL + 10UL, 9UL, 1UL + + 8UL, 10UL, 1UL + 10UL, 8UL, 1UL +//================================================ +//================================================ + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + + 11UL, 4UL, 2UL + 4UL, 11UL, 2UL + + 10UL, 5UL, 2UL + 5UL, 10UL, 2UL + + 8UL, 7UL, 2UL + 7UL, 8UL, 2UL +//================================================ +//================================================ + 10UL, 11UL, 3UL + 11UL, 10UL, 3UL + + 5UL, 4UL, 3UL + 4UL, 5UL, 3UL + + ]) + + Matrix.fromCoordinateList clist + + + let expected = + let clist = + Matrix.CoordinateList(12UL, 12UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 0UL, 11UL, 1UL + 11UL, 0UL, 1UL + + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + + 2UL, 4UL, 1UL + 4UL, 2UL, 1UL + + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + + 5UL, 7UL, 1UL + 7UL, 5UL, 1UL + + 8UL, 9UL, 1UL + 9UL, 8UL, 1UL + + 8UL, 10UL, 1UL + 10UL, 8UL, 1UL + + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + + 5UL, 10UL, 2UL + 10UL, 5UL, 2UL + + 4UL, 5UL, 3UL + 5UL, 4UL, 3UL + + ]) + + Matrix.fromCoordinateList clist + |> Result.Success + + //let actual = + match Graph.Boruvka.mst graph with + | Result.Success tree -> + let tree_transposed = Matrix.transpose tree + let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) + match actual with + | Result.Success actual -> Tests.printMatrixCoordinate actual + | _ -> printfn "Failed" + Assert.Equal(expected, actual) + | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) + + + diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index d246c30..1ddbad5 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -20,8 +20,6 @@ let printVector (vector: Vector.SparseVector<_>) = printfn " Size: %A" vector.storage.size printfn " Data: %A" (Vector.toCoordinateList vector).data - - type Error<'t1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12> = | EdgesCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't3> | CEdgesCalculationProblem of Vector.Error<'t4, 't5, 't6> @@ -35,16 +33,12 @@ let mst (graph:Matrix.SparseMatrix<_>) = match (x, y) with | Some(a, pa), Some(b, pb) -> Some (min (a,pa) (b,pb)) - (* if a < b then Some(a, pa) - elif b < a then Some(b, pb) - elif pa <= pb then Some(a, pa) - else Some(b, pb)*) | Some(a, pa), _ -> Some(a, pa) | _, Some(b, pb) -> Some(b, pb) | _ -> None let op_mult (i,x) (row,col,w) = - Some(w,row) // Store source vertex + Some(w,row) let length = uint64 graph.nrows * 1UL let parent = Vector.init length (fun i -> Some i) @@ -94,21 +88,10 @@ let mst (graph:Matrix.SparseMatrix<_>) = let index = Vector.gather index parent printfn "=== Index 2 ===" printVector index - // Use compressed parent for filter - //let parentCompressed = Vector.gather parent parent - //let parentCompressed = Vector.gather parentCompressed parentCompressed - //let parentCompressed = Vector.gather parentCompressed parentCompressed - //let parentCompressed = Vector.gather parentCompressed parentCompressed - //let parentCompressed = Vector.gather parentCompressed parentCompressed - //let parentCompressed = Vector.gather parentCompressed parentCompressed printfn "=== parent ===" printVector parent - - // edges[i] = (w, parent[source]) for minimum edge source -> i - // index[i] = i if i is a representative - // Filter: add edge (i,j) only if i is rep AND j = src AND j is in DIFFERENT component than i let filter i j g = let i = uint64 i * 1UL let j = uint64 j * 1UL @@ -119,8 +102,6 @@ let mst (graph:Matrix.SparseMatrix<_>) = let result = match edge, idx, parent_j with | Some(w, dst), Some idxVal, Some pi -> - // i is rep (parent[i]=i), source != i, j = src - //(uint64 pi) = (uint64 i) && (uint64 src) <> (uint64 i) && (uint64 j) = (uint64 src) g = w && idxVal = i && uint64 dst = uint64 j | _ -> false if result then @@ -135,28 +116,6 @@ let mst (graph:Matrix.SparseMatrix<_>) = | None, Some g when filter i j g -> Some g | _ -> None) - // Step 6: Update parent - (* - let getPartnerIdx i = - let idxVal = Vector.unsafeGet index i - let edgeVal = Vector.unsafeGet edges i - if iteration < 2 then - printfn " getPartnerIdx %d: idxVal=%A, edgeVal=%A" i idxVal edgeVal - match (idxVal, edgeVal) with - | Some idx', Some(weight, parentSource) when idx' = i -> - Some(uint64 parentSource * 1UL) - | _ -> None - - let scatterIndices: Vector.SparseVector> = Vector.init length getPartnerIdx - let scatterValues: Vector.SparseVector> = Vector.init length (fun i -> Some i) - - let parentResult = Vector.scatter parent scatterIndices scatterValues (fun old newVal -> - match old, newVal with - | Some o, Some n -> if o < n then Some o else Some n - | Some o, None -> Some o - | None, Some n -> Some n - | _ -> None) - *) let _parent = Vector.map2i edges index (fun i e idx -> @@ -186,8 +145,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = | Result.Success(__parent) -> printfn "=== parentResult ===" printVector __parent - // Path compression: fix-point iteration using vector length - let vecLength = uint64 parent.length + // Path compression: fix-point iteration using vector length let rec fixPoint p iter = let p2 = Vector.gather p p if p2 = p then p else fixPoint p2 1 From ece907e7fc7eb69915201ed45093cbcac51f4e82 Mon Sep 17 00:00:00 2001 From: gsv Date: Wed, 25 Mar 2026 18:13:25 +0300 Subject: [PATCH 32/52] Fix parent propagation in Boruvka. --- QuadTree.Tests/Tests.Boruvka.fs | 353 +++++++++++++++++++++++++++++++- QuadTree.Tests/Tests.Vector.fs | 17 ++ QuadTree/Boruvka.fs | 17 +- 3 files changed, 372 insertions(+), 15 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 4be5021..27eb4ff 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -7,13 +7,352 @@ open Matrix open Vector open Common +let printResult name mstResult = + match mstResult with + | Result.Success tree -> + let tree_transposed = Matrix.transpose tree + let combined = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) + match combined with + | Result.Success c -> Tests.printMatrixCoordinate c + | _ -> printfn "Failed to combine" + | Result.Failure e -> printfn "MST failed: %A" e [] -let ``Boruvka MST simple triangle.`` () = +let ``Boruvka MST 2 nodes.`` () = System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = - Matrix.CoordinateList(7UL, 7UL,[ + Matrix.CoordinateList(2UL, 2UL,[ + 0UL, 1UL, 5UL + 1UL, 0UL, 5UL + ]) + Matrix.fromCoordinateList clist + + printResult "2 nodes" (Graph.Boruvka.mst graph) + Assert.True(true) + + +[] +let ``Boruvka MST 3 nodes line.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(3UL, 3UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + ]) + Matrix.fromCoordinateList clist + + printResult "3 nodes line" (Graph.Boruvka.mst graph) + Assert.True(true) + + +[] +let ``Boruvka MST 4 nodes line.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(4UL, 4UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL + ]) + Matrix.fromCoordinateList clist + + printResult "4 nodes line" (Graph.Boruvka.mst graph) + Assert.True(true) + + +[] +let ``Boruvka MST 5 nodes line.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(5UL, 5UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL + 3UL, 4UL, 4UL + 4UL, 3UL, 4UL + ]) + Matrix.fromCoordinateList clist + + printResult "5 nodes line" (Graph.Boruvka.mst graph) + Assert.True(true) + + +[] +let ``Boruvka MST 5 nodes star.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(5UL, 5UL,[ + 0UL, 1UL, 5UL + 1UL, 0UL, 5UL + 0UL, 2UL, 4UL + 2UL, 0UL, 4UL + 0UL, 3UL, 3UL + 3UL, 0UL, 3UL + 0UL, 4UL, 2UL + 4UL, 0UL, 2UL + ]) + Matrix.fromCoordinateList clist + + printResult "5 nodes star" (Graph.Boruvka.mst graph) + Assert.True(true) + + +[] +let ``Boruvka MST 5 nodes complete.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(5UL, 5UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 0UL, 2UL, 2UL + 2UL, 0UL, 2UL + 0UL, 3UL, 3UL + 3UL, 0UL, 3UL + 0UL, 4UL, 4UL + 4UL, 0UL, 4UL + 1UL, 2UL, 5UL + 2UL, 1UL, 5UL + 1UL, 3UL, 6UL + 3UL, 1UL, 6UL + 1UL, 4UL, 7UL + 4UL, 1UL, 7UL + 2UL, 3UL, 8UL + 3UL, 2UL, 8UL + 2UL, 4UL, 9UL + 4UL, 2UL, 9UL + 3UL, 4UL, 10UL + 4UL, 3UL, 10UL + ]) + Matrix.fromCoordinateList clist + + printResult "5 nodes complete" (Graph.Boruvka.mst graph) + Assert.True(true) + + +[] +let ``Boruvka MST two components.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(6UL, 6UL,[ + // Component 1: vertices 0,1,2 + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 0UL, 2UL, 3UL + 2UL, 0UL, 3UL + // Component 2: vertices 3,4,5 + 3UL, 4UL, 1UL + 4UL, 3UL, 1UL + 4UL, 5UL, 2UL + 5UL, 4UL, 2UL + 3UL, 5UL, 3UL + 5UL, 3UL, 3UL + ]) + Matrix.fromCoordinateList clist + + printResult "two components" (Graph.Boruvka.mst graph) + Assert.True(true) + + +[] +let ``Boruvka MST cycle graph 6 nodes.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(6UL, 6UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL + 3UL, 4UL, 4UL + 4UL, 3UL, 4UL + 4UL, 5UL, 5UL + 5UL, 4UL, 5UL + 5UL, 0UL, 6UL + 0UL, 5UL, 6UL + ]) + Matrix.fromCoordinateList clist + + printResult "cycle 6" (Graph.Boruvka.mst graph) + Assert.True(true) + +///!!!!!!!! +[] +let ``Boruvka MST complete bipartite K3,3.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(6UL, 6UL,[ + // K3,3: vertices 0,1,2 connected to 3,4,5 + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL + + 0UL, 4UL, 2UL + 4UL, 0UL, 2UL + + 0UL, 5UL, 3UL + 5UL, 0UL, 3UL + + 1UL, 3UL, 4UL + 3UL, 1UL, 4UL + + 1UL, 4UL, 5UL + 4UL, 1UL, 5UL + + 1UL, 5UL, 6UL + 5UL, 1UL, 6UL + + 2UL, 3UL, 7UL + 3UL, 2UL, 7UL + + 2UL, 4UL, 8UL + 4UL, 2UL, 8UL + + 2UL, 5UL, 9UL + 5UL, 2UL, 9UL + ]) + Matrix.fromCoordinateList clist + + printResult "K3,3" (Graph.Boruvka.mst graph) + Assert.True(true) + +[] +let ``Boruvka MST random weights.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(8UL, 8UL,[ + 0UL, 1UL, 7UL + 1UL, 0UL, 7UL + 0UL, 2UL, 5UL + 2UL, 0UL, 5UL + 0UL, 3UL, 9UL + 3UL, 0UL, 9UL + 1UL, 2UL, 3UL + 2UL, 1UL, 3UL + 1UL, 3UL, 4UL + 3UL, 1UL, 4UL + 2UL, 3UL, 2UL + 3UL, 2UL, 2UL + 4UL, 5UL, 1UL + 5UL, 4UL, 1UL + 4UL, 6UL, 6UL + 6UL, 4UL, 6UL + 4UL, 7UL, 8UL + 7UL, 4UL, 8UL + 5UL, 6UL, 3UL + 6UL, 5UL, 3UL + 5UL, 7UL, 5UL + 7UL, 5UL, 5UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + // Connect two components + 3UL, 4UL, 10UL + 4UL, 3UL, 10UL + ]) + Matrix.fromCoordinateList clist + + printResult "random weights" (Graph.Boruvka.mst graph) + Assert.True(true) + +[] +let ``Boruvka MST 8 nodes grid.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(8UL, 8UL,[ + // Row 0-1 connections + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + // Row 2-3 connections + 0UL, 4UL, 3UL + 4UL, 0UL, 3UL + 1UL, 5UL, 4UL + 5UL, 1UL, 4UL + 2UL, 6UL, 5UL + 6UL, 2UL, 5UL + 3UL, 7UL, 6UL + 7UL, 3UL, 6UL + // Cross row connections + 4UL, 5UL, 2UL + 5UL, 4UL, 2UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + 6UL, 7UL, 3UL + 7UL, 6UL, 3UL + ]) + Matrix.fromCoordinateList clist + + printResult "8 nodes grid" (Graph.Boruvka.mst graph) + Assert.True(true) + +[] +let ``Boruvka MST 10 nodes random.`` () = + System.Console.Error.WriteLine("TEST STARTING") + let graph = + let clist = + Matrix.CoordinateList(10UL, 10UL,[ + 0UL, 1UL, 4UL + 1UL, 0UL, 4UL + 0UL, 5UL, 2UL + 5UL, 0UL, 2UL + 1UL, 2UL, 3UL + 2UL, 1UL, 3UL + 1UL, 6UL, 5UL + 6UL, 1UL, 5UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + 2UL, 7UL, 4UL + 7UL, 2UL, 4UL + 3UL, 4UL, 2UL + 4UL, 3UL, 2UL + 3UL, 8UL, 6UL + 8UL, 3UL, 6UL + 4UL, 9UL, 3UL + 9UL, 4UL, 3UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + 7UL, 8UL, 1UL + 8UL, 7UL, 1UL + 8UL, 9UL, 4UL + 9UL, 8UL, 4UL + ]) + Matrix.fromCoordinateList clist + + printResult "10 nodes" (Graph.Boruvka.mst graph) + Assert.True(true) + + +[] +let ``Boruvka MST simple triangle.`` () = + printfn "!!! TEST STARTING !!!" + let graph = + let clist = + Matrix.CoordinateList(3UL, 3UL,[ 0UL, 1UL, 1UL 1UL, 0UL, 1UL @@ -30,7 +369,7 @@ let ``Boruvka MST simple triangle.`` () = let expected = let clist = - Matrix.CoordinateList(7UL, 7UL,[ + Matrix.CoordinateList(3UL, 3UL,[ 0UL, 1UL, 1UL 1UL, 0UL, 1UL @@ -60,7 +399,7 @@ let ``Boruvka MST simple square.`` () = System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = - Matrix.CoordinateList(7UL, 7UL,[ + Matrix.CoordinateList(4UL, 4UL,[ 0UL, 1UL, 1UL 1UL, 0UL, 1UL @@ -80,7 +419,7 @@ let ``Boruvka MST simple square.`` () = let expected = let clist = - Matrix.CoordinateList(7UL, 7UL,[ + Matrix.CoordinateList(4UL, 4UL,[ 0UL, 1UL, 1UL 1UL, 0UL, 1UL @@ -115,7 +454,7 @@ let ``Boruvka MST simple square in two steps.`` () = System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = - Matrix.CoordinateList(7UL, 7UL,[ + Matrix.CoordinateList(4UL, 4UL,[ 0UL, 1UL, 2UL 1UL, 0UL, 2UL @@ -135,7 +474,7 @@ let ``Boruvka MST simple square in two steps.`` () = let expected = let clist = - Matrix.CoordinateList(7UL, 7UL,[ + Matrix.CoordinateList(4UL, 4UL,[ 0UL, 1UL, 2UL 1UL, 0UL, 2UL diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index bfc4d6f..c7d9c5e 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -562,4 +562,21 @@ let ``Sort sorted vector``() = let actual = Vector.mergeSort data compare Assert.Equal(data, actual) + +[] +let ``Init vector``() = + let expected = + Vector.CoordinateList( + 3UL, + [ (0UL, 0); (1UL, 1); (2UL, 2) + ] + ) + |> Vector.fromCoordinateList + let actual = Vector.init 3UL (fun i -> Some (int i)) + //printfn "++++ Vector inint ++++" + //printVector actual + Assert.Equal(expected, actual) + + + \ No newline at end of file diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 1ddbad5..8ada3dd 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -41,17 +41,15 @@ let mst (graph:Matrix.SparseMatrix<_>) = Some(w,row) let length = uint64 graph.nrows * 1UL + printfn "Length = %A" length let parent = Vector.init length (fun i -> Some i) let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent iteration = printfn "=== Iter %d: graph=%A, tree=%A ===" iteration graph.nvals tree.nvals printfn "=== Graph ===" printMatrixCoordinate graph - if iteration < 2 then - printfn "Parent at start of iter %d:" iteration - for i in 0UL..6UL do - let p = Vector.unsafeGet parent (i * 1UL) - printfn " parent[%d]=%A" i p + printfn "Parent at start of iter %d:" iteration + printVector parent if graph.nvals > 0UL then let edges = LinearAlgebra.vxmi_values op_add op_mult parent graph @@ -122,9 +120,12 @@ let mst (graph:Matrix.SparseMatrix<_>) = match e,idx with | Some (v,j), Some (_i) when _i = i -> let j = uint64 j * 1UL - let parent = Vector.unsafeGet parent (min j i) - match parent with - | Some p -> Some (max j i, p) + let parent_i = Vector.unsafeGet parent i + let parent_j = Vector.unsafeGet parent j + match parent_i,parent_j with + | Some p_i, Some p_j -> + if p_i < p_j then Some (j, p_i) else Some (i, p_j) + //Some (max k p, min k p) | x -> failwithf "Unreachable: %A" x | _ -> None ) From b8651f4aecbb0439e9d9876bf388bf4110a69025 Mon Sep 17 00:00:00 2001 From: gsv Date: Wed, 25 Mar 2026 18:26:46 +0300 Subject: [PATCH 33/52] Improved tests for Boruvka. --- QuadTree.Tests/Tests.Boruvka.fs | 166 +++++++++++++++++--------------- 1 file changed, 86 insertions(+), 80 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 27eb4ff..dd5b60b 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -7,15 +7,13 @@ open Matrix open Vector open Common -let printResult name mstResult = - match mstResult with +let checkResult name actual expected = + match actual with | Result.Success tree -> let tree_transposed = Matrix.transpose tree - let combined = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) - match combined with - | Result.Success c -> Tests.printMatrixCoordinate c - | _ -> printfn "Failed to combine" - | Result.Failure e -> printfn "MST failed: %A" e + let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) + Assert.Equal(expected, actual) + | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) [] let ``Boruvka MST 2 nodes.`` () = @@ -28,8 +26,16 @@ let ``Boruvka MST 2 nodes.`` () = ]) Matrix.fromCoordinateList clist - printResult "2 nodes" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(2UL, 2UL,[ + 0UL, 1UL, 5UL + 1UL, 0UL, 5UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected [] @@ -45,8 +51,19 @@ let ``Boruvka MST 3 nodes line.`` () = ]) Matrix.fromCoordinateList clist - printResult "3 nodes line" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(3UL, 3UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected + [] @@ -64,8 +81,20 @@ let ``Boruvka MST 4 nodes line.`` () = ]) Matrix.fromCoordinateList clist - printResult "4 nodes line" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(4UL, 4UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected [] @@ -85,8 +114,22 @@ let ``Boruvka MST 5 nodes line.`` () = ]) Matrix.fromCoordinateList clist - printResult "5 nodes line" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(5UL, 5UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL + 3UL, 4UL, 4UL + 4UL, 3UL, 4UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected [] @@ -106,8 +149,22 @@ let ``Boruvka MST 5 nodes star.`` () = ]) Matrix.fromCoordinateList clist - printResult "5 nodes star" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(5UL, 5UL,[ + 0UL, 1UL, 5UL + 1UL, 0UL, 5UL + 0UL, 2UL, 4UL + 2UL, 0UL, 4UL + 0UL, 3UL, 3UL + 3UL, 0UL, 3UL + 0UL, 4UL, 2UL + 4UL, 0UL, 2UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected [] @@ -139,7 +196,7 @@ let ``Boruvka MST 5 nodes complete.`` () = ]) Matrix.fromCoordinateList clist - printResult "5 nodes complete" (Graph.Boruvka.mst graph) + //printResult "5 nodes complete" (Graph.Boruvka.mst graph) Assert.True(true) @@ -166,7 +223,7 @@ let ``Boruvka MST two components.`` () = ]) Matrix.fromCoordinateList clist - printResult "two components" (Graph.Boruvka.mst graph) + //printResult "two components" (Graph.Boruvka.mst graph) Assert.True(true) @@ -191,7 +248,7 @@ let ``Boruvka MST cycle graph 6 nodes.`` () = ]) Matrix.fromCoordinateList clist - printResult "cycle 6" (Graph.Boruvka.mst graph) + //printResult "cycle 6" (Graph.Boruvka.mst graph) Assert.True(true) ///!!!!!!!! @@ -231,7 +288,7 @@ let ``Boruvka MST complete bipartite K3,3.`` () = ]) Matrix.fromCoordinateList clist - printResult "K3,3" (Graph.Boruvka.mst graph) + //printResult "K3,3" (Graph.Boruvka.mst graph) Assert.True(true) [] @@ -270,7 +327,7 @@ let ``Boruvka MST random weights.`` () = ]) Matrix.fromCoordinateList clist - printResult "random weights" (Graph.Boruvka.mst graph) + // printResult "random weights" (Graph.Boruvka.mst graph) Assert.True(true) [] @@ -305,7 +362,7 @@ let ``Boruvka MST 8 nodes grid.`` () = ]) Matrix.fromCoordinateList clist - printResult "8 nodes grid" (Graph.Boruvka.mst graph) + //printResult "8 nodes grid" (Graph.Boruvka.mst graph) Assert.True(true) [] @@ -343,7 +400,7 @@ let ``Boruvka MST 10 nodes random.`` () = ]) Matrix.fromCoordinateList clist - printResult "10 nodes" (Graph.Boruvka.mst graph) + //printResult "10 nodes" (Graph.Boruvka.mst graph) Assert.True(true) @@ -380,18 +437,7 @@ let ``Boruvka MST simple triangle.`` () = Matrix.fromCoordinateList clist |> Result.Success - //let actual = - match Graph.Boruvka.mst graph with - | Result.Success tree -> - let tree_transposed = Matrix.transpose tree - let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) - match actual with - | Result.Success actual -> Tests.printMatrixCoordinate actual - | _ -> printfn "Failed" - Assert.Equal(expected, actual) - //actual - //|> Result.Success - | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) + checkResult (Graph.Boruvka.mst graph) expected [] @@ -433,18 +479,7 @@ let ``Boruvka MST simple square.`` () = Matrix.fromCoordinateList clist |> Result.Success - //let actual = - match Graph.Boruvka.mst graph with - | Result.Success tree -> - let tree_transposed = Matrix.transpose tree - let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) - match actual with - | Result.Success actual -> Tests.printMatrixCoordinate actual - | _ -> printfn "Failed" - Assert.Equal(expected, actual) - //actual - //|> Result.Success - | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) + checkResult (Graph.Boruvka.mst graph) expected @@ -488,18 +523,7 @@ let ``Boruvka MST simple square in two steps.`` () = Matrix.fromCoordinateList clist |> Result.Success - //let actual = - match Graph.Boruvka.mst graph with - | Result.Success tree -> - let tree_transposed = Matrix.transpose tree - let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) - match actual with - | Result.Success actual -> Tests.printMatrixCoordinate actual - | _ -> printfn "Failed" - Assert.Equal(expected, actual) - //actual - //|> Result.Success - | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) + checkResult (Graph.Boruvka.mst graph) expected @@ -573,16 +597,7 @@ let ``Boruvka MST.`` () = Matrix.fromCoordinateList clist |> Result.Success - //let actual = - match Graph.Boruvka.mst graph with - | Result.Success tree -> - let tree_transposed = Matrix.transpose tree - let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) - match actual with - | Result.Success actual -> Tests.printMatrixCoordinate actual - | _ -> printfn "Failed" - Assert.Equal(expected, actual) - | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) + checkResult (Graph.Boruvka.mst graph) expected [] @@ -693,16 +708,7 @@ let ``Boruvka MST big.`` () = Matrix.fromCoordinateList clist |> Result.Success - //let actual = - match Graph.Boruvka.mst graph with - | Result.Success tree -> - let tree_transposed = Matrix.transpose tree - let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) - match actual with - | Result.Success actual -> Tests.printMatrixCoordinate actual - | _ -> printfn "Failed" - Assert.Equal(expected, actual) - | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) + checkResult (Graph.Boruvka.mst graph) expected From 4ad23526615f761c08d022d2b1b55226624f93c2 Mon Sep 17 00:00:00 2001 From: gsv Date: Wed, 25 Mar 2026 18:35:50 +0300 Subject: [PATCH 34/52] More tests on Boruvka. --- QuadTree.Tests/Tests.Boruvka.fs | 56 +++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index dd5b60b..b020ff9 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -196,8 +196,22 @@ let ``Boruvka MST 5 nodes complete.`` () = ]) Matrix.fromCoordinateList clist - //printResult "5 nodes complete" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(5UL, 5UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 0UL, 2UL, 2UL + 2UL, 0UL, 2UL + 0UL, 3UL, 3UL + 3UL, 0UL, 3UL + 0UL, 4UL, 4UL + 4UL, 0UL, 4UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected [] @@ -223,8 +237,22 @@ let ``Boruvka MST two components.`` () = ]) Matrix.fromCoordinateList clist - //printResult "two components" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(6UL, 6UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 3UL, 4UL, 1UL + 4UL, 3UL, 1UL + 4UL, 5UL, 2UL + 5UL, 4UL, 2UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected [] @@ -248,8 +276,24 @@ let ``Boruvka MST cycle graph 6 nodes.`` () = ]) Matrix.fromCoordinateList clist - //printResult "cycle 6" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(6UL, 6UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL + 3UL, 4UL, 4UL + 4UL, 3UL, 4UL + 4UL, 5UL, 5UL + 5UL, 4UL, 5UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected ///!!!!!!!! [] From a6e9e9c3d840c070ef78ec70617221d33b73395e Mon Sep 17 00:00:00 2001 From: gsv Date: Wed, 25 Mar 2026 18:39:08 +0300 Subject: [PATCH 35/52] More tests on Boruvka. --- QuadTree.Tests/Tests.Boruvka.fs | 106 +++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 8 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index b020ff9..8832972 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -332,8 +332,24 @@ let ``Boruvka MST complete bipartite K3,3.`` () = ]) Matrix.fromCoordinateList clist - //printResult "K3,3" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(6UL, 6UL,[ + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL + 1UL, 3UL, 4UL + 3UL, 1UL, 4UL + 2UL, 3UL, 7UL + 3UL, 2UL, 7UL + 0UL, 4UL, 2UL + 4UL, 0UL, 2UL + 0UL, 5UL, 3UL + 5UL, 0UL, 3UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected [] let ``Boruvka MST random weights.`` () = @@ -371,8 +387,30 @@ let ``Boruvka MST random weights.`` () = ]) Matrix.fromCoordinateList clist - // printResult "random weights" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(8UL, 8UL,[ + 0UL, 2UL, 5UL + 2UL, 0UL, 5UL + 1UL, 2UL, 3UL + 2UL, 1UL, 3UL + 2UL, 3UL, 2UL + 3UL, 2UL, 2UL + 1UL, 3UL, 4UL + 3UL, 1UL, 4UL + 4UL, 5UL, 1UL + 5UL, 4UL, 1UL + 5UL, 6UL, 3UL + 6UL, 5UL, 3UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + 3UL, 4UL, 10UL + 4UL, 3UL, 10UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected [] let ``Boruvka MST 8 nodes grid.`` () = @@ -406,8 +444,28 @@ let ``Boruvka MST 8 nodes grid.`` () = ]) Matrix.fromCoordinateList clist - //printResult "8 nodes grid" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(8UL, 8UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 4UL, 5UL, 2UL + 5UL, 4UL, 2UL + 0UL, 4UL, 3UL + 4UL, 0UL, 3UL + 6UL, 7UL, 3UL + 7UL, 6UL, 3UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected [] let ``Boruvka MST 10 nodes random.`` () = @@ -444,8 +502,40 @@ let ``Boruvka MST 10 nodes random.`` () = ]) Matrix.fromCoordinateList clist - //printResult "10 nodes" (Graph.Boruvka.mst graph) - Assert.True(true) + let expected = + let clist = + Matrix.CoordinateList(10UL, 10UL,[ + 0UL, 1UL, 4UL + 1UL, 0UL, 4UL + 0UL, 5UL, 2UL + 5UL, 0UL, 2UL + 1UL, 2UL, 3UL + 2UL, 1UL, 3UL + 1UL, 6UL, 5UL + 6UL, 1UL, 5UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + 2UL, 7UL, 4UL + 7UL, 2UL, 4UL + 3UL, 4UL, 2UL + 4UL, 3UL, 2UL + 3UL, 8UL, 6UL + 8UL, 3UL, 6UL + 4UL, 9UL, 3UL + 9UL, 4UL, 3UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + 7UL, 8UL, 1UL + 8UL, 7UL, 1UL + 8UL, 9UL, 4UL + 9UL, 8UL, 4UL + ]) + Matrix.fromCoordinateList clist + |> Result.Success + + checkResult (Graph.Boruvka.mst graph) expected [] From 788654fe028d2716cc710ea12a4fa74aafe3ca92 Mon Sep 17 00:00:00 2001 From: gsv Date: Thu, 26 Mar 2026 08:24:59 +0300 Subject: [PATCH 36/52] Code cleanup. --- QuadTree/Boruvka.fs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 8ada3dd..021f9c4 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -75,7 +75,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = printfn "=== Component Edges ===" printVector cedges - let t = Vector.gather cedges parent + let t = Vector.gather cedges parent let index = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) let index = Vector.scatter (Vector.empty length) index parent op_min match index with @@ -93,7 +93,6 @@ let mst (graph:Matrix.SparseMatrix<_>) = let filter i j g = let i = uint64 i * 1UL let j = uint64 j * 1UL - printfn "Edge for filter: %A %A %A" i j g let edge = Vector.unsafeGet edges i let idx = Vector.unsafeGet index i let parent_j = Vector.unsafeGet parent j @@ -125,7 +124,6 @@ let mst (graph:Matrix.SparseMatrix<_>) = match parent_i,parent_j with | Some p_i, Some p_j -> if p_i < p_j then Some (j, p_i) else Some (i, p_j) - //Some (max k p, min k p) | x -> failwithf "Unreachable: %A" x | _ -> None ) @@ -147,22 +145,22 @@ let mst (graph:Matrix.SparseMatrix<_>) = printfn "=== parentResult ===" printVector __parent // Path compression: fix-point iteration using vector length - let rec fixPoint p iter = + let rec fixPoint p = let p2 = Vector.gather p p - if p2 = p then p else fixPoint p2 1 + if p2 = p then p else fixPoint p2 let op_min x y = match (x, y) with | Some v, Some u -> if v < u then Some v else Some u | Some v, _ -> Some v | None, Some v -> Some v | _ -> None - let parent = Vector.scatter parent __parent parent op_min + let parent = Vector.scatter parent __parent parent op_min match parent with | Result.Failure x -> ScatterProblem x |> Result.Failure | Result.Success parent -> printfn "=== parent' ===" printVector parent - let parent = fixPoint parent 0 + let parent = fixPoint parent printfn "=== Parent for filter ===" printVector parent From 54cfbb6dd150f908401fdf6d794f3b3fa333a717 Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 30 Mar 2026 11:28:08 +0300 Subject: [PATCH 37/52] After rebase on workflow. --- QuadTree.Tests/Tests.Boruvka.fs | 36 ++++----- QuadTree.Tests/Tests.LinearAlgebra.fs | 4 +- QuadTree/Boruvka.fs | 112 ++++++++++++++------------ QuadTree/LinearAlgebra.fs | 47 +++++------ 4 files changed, 100 insertions(+), 99 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 8832972..459f0ec 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -9,7 +9,7 @@ open Common let checkResult name actual expected = match actual with - | Result.Success tree -> + | Ok tree -> let tree_transposed = Matrix.transpose tree let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) Assert.Equal(expected, actual) @@ -33,7 +33,7 @@ let ``Boruvka MST 2 nodes.`` () = 1UL, 0UL, 5UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -60,7 +60,7 @@ let ``Boruvka MST 3 nodes line.`` () = 2UL, 1UL, 2UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -92,7 +92,7 @@ let ``Boruvka MST 4 nodes line.`` () = 3UL, 2UL, 3UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -127,7 +127,7 @@ let ``Boruvka MST 5 nodes line.`` () = 4UL, 3UL, 4UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -162,7 +162,7 @@ let ``Boruvka MST 5 nodes star.`` () = 4UL, 0UL, 2UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -209,7 +209,7 @@ let ``Boruvka MST 5 nodes complete.`` () = 4UL, 0UL, 4UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -250,7 +250,7 @@ let ``Boruvka MST two components.`` () = 5UL, 4UL, 2UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -291,7 +291,7 @@ let ``Boruvka MST cycle graph 6 nodes.`` () = 5UL, 4UL, 5UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -347,7 +347,7 @@ let ``Boruvka MST complete bipartite K3,3.`` () = 5UL, 0UL, 3UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -408,7 +408,7 @@ let ``Boruvka MST random weights.`` () = 4UL, 3UL, 10UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -463,7 +463,7 @@ let ``Boruvka MST 8 nodes grid.`` () = 7UL, 6UL, 3UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -533,7 +533,7 @@ let ``Boruvka MST 10 nodes random.`` () = 9UL, 8UL, 4UL ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -569,7 +569,7 @@ let ``Boruvka MST simple triangle.`` () = ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -611,7 +611,7 @@ let ``Boruvka MST simple square.`` () = ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -655,7 +655,7 @@ let ``Boruvka MST simple square in two steps.`` () = ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -729,7 +729,7 @@ let ``Boruvka MST.`` () = ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -840,7 +840,7 @@ let ``Boruvka MST big.`` () = ]) Matrix.fromCoordinateList clist - |> Result.Success + |> Ok checkResult (Graph.Boruvka.mst graph) expected diff --git a/QuadTree.Tests/Tests.LinearAlgebra.fs b/QuadTree.Tests/Tests.LinearAlgebra.fs index 424fb47..1cc824b 100644 --- a/QuadTree.Tests/Tests.LinearAlgebra.fs +++ b/QuadTree.Tests/Tests.LinearAlgebra.fs @@ -279,7 +279,7 @@ let ``Simple vxmi_values. 3 * (3x5)`` () = ) let store = Vector.Storage(8UL, tree) - Result.Success(SparseVector(5UL, 5UL, store)) + Ok(SparseVector(5UL, 5UL, store)) let actual = LinearAlgebra.vxmi_values op_add_i op_mult_i v m @@ -323,7 +323,7 @@ let ``Simple vxmi_values. 4 * (4x3).`` () = , Vector.btree.Node(vleaf_v (0UL,0UL,2UL), vleaf_d ())) let store = Vector.Storage(4UL, tree) - Result.Success(SparseVector(3UL, 3UL, store)) + Ok(SparseVector(3UL, 3UL, store)) let actual = LinearAlgebra.vxmi_values op_add_i op_mult_i v m diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 021f9c4..57452dc 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -1,8 +1,22 @@ module Graph.Boruvka open Common +open Result +type Error = + | EdgesCalculationProblem of LinearAlgebra.Error + | CEdgesCalculationProblem of Vector.Error + | IndexCalculationProblem of Vector.Error + | ScatterProblem of Vector.Error + | FoldValuesError of Vector.Error + +let mapError (err: LinearAlgebra.Error) = EdgesCalculationProblem err +let mapError' (err: Vector.Error) = CEdgesCalculationProblem err +let mapError'' (err: Vector.Error) = IndexCalculationProblem err +let mapError''' (err: Vector.Error) = ScatterProblem err +let mapError'''' (err: Vector.Error) = FoldValuesError err + let printMatrixCoordinate (matrix: Matrix.SparseMatrix<_>) = printfn "Matrix:" printfn " Rows: %A" matrix.nrows @@ -20,12 +34,6 @@ let printVector (vector: Vector.SparseVector<_>) = printfn " Size: %A" vector.storage.size printfn " Data: %A" (Vector.toCoordinateList vector).data -type Error<'t1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12> = - | EdgesCalculationProblem of LinearAlgebra.Error<'t1, 't2, 't3> - | CEdgesCalculationProblem of Vector.Error<'t4, 't5, 't6> - | IndexCalculationProblem of Vector.Error<'t7, 't8, 't9> - | ScatterProblem of Vector.Error<'t10, 't11, 't12> - let mst (graph:Matrix.SparseMatrix<_>) = printfn "MST CALLED nrows=%A ncols=%A nvals=%A" graph.nrows graph.ncols graph.nvals @@ -42,7 +50,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = let length = uint64 graph.nrows * 1UL printfn "Length = %A" length - let parent = Vector.init length (fun i -> Some i) + let parentInit = Vector.init length (fun i -> Some i) let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent iteration = printfn "=== Iter %d: graph=%A, tree=%A ===" iteration graph.nvals tree.nvals @@ -52,10 +60,10 @@ let mst (graph:Matrix.SparseMatrix<_>) = printVector parent if graph.nvals > 0UL then - let edges = LinearAlgebra.vxmi_values op_add op_mult parent graph - match edges with - | Result.Failure(e) -> Result.Failure(EdgesCalculationProblem(e)) - | Result.Success(edges) -> + let edgesResult = LinearAlgebra.vxmi_values op_add op_mult parent graph + match edgesResult with + | Error e -> Error(EdgesCalculationProblem e) + | Ok edges -> printfn "=== Edges ===" printVector edges @@ -66,27 +74,23 @@ let mst (graph:Matrix.SparseMatrix<_>) = | None, Some v -> Some v | _ -> None - let cedges = - Vector.scatter (Vector.empty length) edges parent op_add - - match cedges with - | Result.Failure(e) -> Result.Failure(CEdgesCalculationProblem(e)) - | Result.Success(cedges) -> + let cedgesResult = Vector.scatter (Vector.empty length) edges parent op_add + match cedgesResult with + | Error e -> Error(CEdgesCalculationProblem e) + | Ok cedges -> printfn "=== Component Edges ===" printVector cedges let t = Vector.gather cedges parent - let index = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) - let index = Vector.scatter (Vector.empty length) index parent op_min - match index with - | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) - | Result.Success (index) -> - //printfn "=== Index ===" - //printVector index + let indexInner = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) + let indexResult = Vector.scatter (Vector.empty length) indexInner parent op_min + match indexResult with + | Error e -> Error(IndexCalculationProblem e) + | Ok index -> let index = Vector.gather index parent printfn "=== Index 2 ===" printVector index - + printfn "=== parent ===" printVector parent @@ -104,7 +108,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = if result then printfn "TREE FILTER iter %d: edge (%d,%d) -> tree" iteration (i/1UL) (j/1UL) result - + let tree = Matrix.map2i tree graph ( fun i j t g -> @@ -113,7 +117,7 @@ let mst (graph:Matrix.SparseMatrix<_>) = | None, Some g when filter i j g -> Some g | _ -> None) - let _parent = + let _parentInner = Vector.map2i edges index (fun i e idx -> match e,idx with @@ -129,46 +133,49 @@ let mst (graph:Matrix.SparseMatrix<_>) = ) printfn "=== _parent ===" - printVector _parent + printVector _parentInner - let parentResult = - Vector.foldValues _parent (fun state (i,v) -> + let parentUpdateResult = + Vector.foldValues _parentInner (fun state (i,v) -> match state with - | Result.Success state -> - Vector.update state i (Some v) (fun old _new -> _new) - | Result.Failure x -> Result.Failure x) - (Result.Success parent) - - match parentResult with - | Result.Failure(e) -> Result.Failure(IndexCalculationProblem(e)) - | Result.Success(__parent) -> + | Ok state -> + let updateResult = Vector.update state i (Some v) (fun old _new -> _new) + match updateResult with + | Ok u -> Ok u + | Error e -> Error e + | Error e -> Error e) + (Ok parent) + + match parentUpdateResult with + | Error e -> Error(FoldValuesError e) + | Ok __parent -> printfn "=== parentResult ===" printVector __parent - // Path compression: fix-point iteration using vector length + let rec fixPoint p = let p2 = Vector.gather p p if p2 = p then p else fixPoint p2 - let op_min x y = + let op_min2 x y = match (x, y) with | Some v, Some u -> if v < u then Some v else Some u | Some v, _ -> Some v | None, Some v -> Some v | _ -> None - let parent = Vector.scatter parent __parent parent op_min - match parent with - | Result.Failure x -> ScatterProblem x |> Result.Failure - | Result.Success parent -> + let parentScatterResult = Vector.scatter parent __parent parent op_min2 + match parentScatterResult with + | Error e -> Error(ScatterProblem e) + | Ok parentNew -> printfn "=== parent' ===" - printVector parent - let parent = fixPoint parent + printVector parentNew + let parentFixed = fixPoint parentNew printfn "=== Parent for filter ===" - printVector parent + printVector parentFixed let graphFilter i j = let i = uint64 i * 1UL let j = uint64 j * 1UL - let parent_i = Vector.unsafeGet parent i - let parent_j = Vector.unsafeGet parent j + let parent_i = Vector.unsafeGet parentFixed i + let parent_j = Vector.unsafeGet parentFixed j let result = match (parent_i, parent_j) with | Some v1, Some v2 when v1 <> v2 -> true @@ -179,10 +186,9 @@ let mst (graph:Matrix.SparseMatrix<_>) = let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) - inner graph tree parent (iteration + 1) + inner graph tree parentFixed (iteration + 1) - else - Result.Success tree + Ok tree - inner graph (Matrix.empty graph.nrows graph.ncols) parent 0 + inner graph (Matrix.empty graph.nrows graph.ncols) parentInit 0 diff --git a/QuadTree/LinearAlgebra.fs b/QuadTree/LinearAlgebra.fs index 9b1bce0..f0ae22f 100644 --- a/QuadTree/LinearAlgebra.fs +++ b/QuadTree/LinearAlgebra.fs @@ -119,10 +119,10 @@ let vxmi_values (inner new_size x1 vectorIdx y2 rowIdx (colIdx + (uint64 new_size) * 1UL)), (inner new_size x2 (vectorIdx + (uint64 new_size) * 1UL) y3 (rowIdx + (uint64 new_size) * 1UL) colIdx), (inner new_size x2 (vectorIdx + (uint64 new_size) * 1UL) y4 (rowIdx + (uint64 new_size) * 1UL) (colIdx + (uint64 new_size) * 1UL)) with - | Result.Success((t1, nvals1)), - Result.Success((t2, nvals2)), - Result.Success((t3, nvals3)), - Result.Success((t4, nvals4)) -> + | Ok((t1, nvals1)), + Ok((t2, nvals2)), + Ok((t3, nvals3)), + Ok((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))) @@ -131,22 +131,22 @@ let vxmi_values let vAdd v1 (v2: Vector.SparseVector<_>) = match v2.storage.data with - | Vector.Leaf(Dummy) -> Result.Success(v1) + | Vector.Leaf(Dummy) -> Ok(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)) + | Ok(v1), Ok(v2) -> + Ok((Vector.mkNode v1.storage.data v2.storage.data), v1.nvals + v2.nvals) + | Error(e), _ + | _, Error(e) -> Error(VectorAdditionProblem(e)) - | Result.Failure(e), _, _, _ - | _, Result.Failure(e), _, _ - | _, _, Result.Failure(e), _ - | _, _, _, Result.Failure(e) -> Result.Failure(e) + | Error(e), _, _, _ + | _, Error(e), _, _ + | _, _, Error(e), _ + | _, _, _, Error(e) -> Error(e) match (vector, matrix) with | Vector.btree.Leaf(UserValue(Some(v1))), Matrix.qtree.Leaf(UserValue(Some(v2))) -> @@ -159,7 +159,7 @@ let vxmi_values | None -> 0UL | _ -> 1UL - Result.Success(Vector.btree.Leaf(UserValue(res)), nnz) + Ok(Vector.btree.Leaf(UserValue(res)), nnz) else inner size (Vector.btree.Node(vector,vector)) vectorIdx (Matrix.qtree.Node(matrix, matrix,matrix,matrix)) rowIdx colIdx @@ -167,11 +167,11 @@ let vxmi_values | Vector.btree.Node(x1, x2), Matrix.qtree.Leaf(UserValue(Some(_))) -> _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(UserValue(None)),_ - | _, Matrix.qtree.Leaf(UserValue(None)) -> Result.Success(Vector.btree.Leaf(UserValue(None)), 0UL) + | _, Matrix.qtree.Leaf(UserValue(None)) -> Ok(Vector.btree.Leaf(UserValue(None)), 0UL) | Vector.btree.Leaf(Dummy), _ - | _, Matrix.qtree.Leaf(Dummy) -> Result.Success(Vector.btree.Leaf(Dummy), 0UL) - | (x, y) -> Result.Failure <| Error.InconsistentStructureOfStorages(x, y) + | _, Matrix.qtree.Leaf(Dummy) -> Ok(Vector.btree.Leaf(Dummy), 0UL) + | (x, y) -> Error Error.InconsistentStructureOfStorages if uint64 vector.length = uint64 matrix.nrows then let vector_storage = @@ -191,21 +191,16 @@ let vxmi_values vector.storage match inner vector_storage.size vector_storage.data 0UL matrix.storage.data 0UL 0UL with - | Result.Failure x -> Result.Failure x - | Result.Success(storage, nvals) -> + | Error x -> Error x + | Ok(storage, nvals) -> (Vector.SparseVector( (uint64 matrix.ncols) * 1UL, nvals, (Vector.Storage(matrix.storage.size, storage)) )) - |> Result.Success + |> Ok else - (Error.InconsistentSizeOfArguments(vector, matrix)) |> Result.Failure - -type MXMError<'value1, 'value2, 'value3> = - | InconsistentSizeOfArguments of Matrix.SparseMatrix<'value1> * Matrix.SparseMatrix<'value2> - | MatrixAdditionProblem of Matrix.Error<'value3, 'value3> ->>>>>>> 6d543b7 (Draft of vxmi_values. Not finished.) + Error Error.InconsistentSizeOfArguments let mxm From fbe85b83661b9d9c3e4e5903c56ea5f18f1dd3be Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 30 Mar 2026 11:32:41 +0300 Subject: [PATCH 38/52] Result workflow for Boruvka. --- QuadTree/Boruvka.fs | 226 ++++++++++++++++++++++---------------------- 1 file changed, 112 insertions(+), 114 deletions(-) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 57452dc..8f90181 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -59,11 +59,11 @@ let mst (graph:Matrix.SparseMatrix<_>) = printfn "Parent at start of iter %d:" iteration printVector parent if graph.nvals > 0UL then + resultM { + let! edges = + LinearAlgebra.vxmi_values op_add op_mult parent graph + |> Result.mapError mapError - let edgesResult = LinearAlgebra.vxmi_values op_add op_mult parent graph - match edgesResult with - | Error e -> Error(EdgesCalculationProblem e) - | Ok edges -> printfn "=== Edges ===" printVector edges @@ -74,120 +74,118 @@ let mst (graph:Matrix.SparseMatrix<_>) = | None, Some v -> Some v | _ -> None - let cedgesResult = Vector.scatter (Vector.empty length) edges parent op_add - match cedgesResult with - | Error e -> Error(CEdgesCalculationProblem e) - | Ok cedges -> - printfn "=== Component Edges ===" - printVector cedges - - let t = Vector.gather cedges parent - let indexInner = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) - let indexResult = Vector.scatter (Vector.empty length) indexInner parent op_min - match indexResult with - | Error e -> Error(IndexCalculationProblem e) - | Ok index -> - let index = Vector.gather index parent - printfn "=== Index 2 ===" - printVector index + let! cedges = + Vector.scatter (Vector.empty length) edges parent op_add + |> Result.mapError mapError' + + printfn "=== Component Edges ===" + printVector cedges + + let t = Vector.gather cedges parent + let indexInner = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) + let! index = + Vector.scatter (Vector.empty length) indexInner parent op_min + |> Result.mapError mapError'' + + let index = Vector.gather index parent + printfn "=== Index 2 ===" + printVector index - printfn "=== parent ===" - printVector parent - - let filter i j g = - let i = uint64 i * 1UL - let j = uint64 j * 1UL - let edge = Vector.unsafeGet edges i - let idx = Vector.unsafeGet index i - let parent_j = Vector.unsafeGet parent j - let result = - match edge, idx, parent_j with - | Some(w, dst), Some idxVal, Some pi -> - g = w && idxVal = i && uint64 dst = uint64 j - | _ -> false - if result then - printfn "TREE FILTER iter %d: edge (%d,%d) -> tree" iteration (i/1UL) (j/1UL) - result + printfn "=== parent ===" + printVector parent + + let filter i j g = + let i = uint64 i * 1UL + let j = uint64 j * 1UL + let edge = Vector.unsafeGet edges i + let idx = Vector.unsafeGet index i + let parent_j = Vector.unsafeGet parent j + let result = + match edge, idx, parent_j with + | Some(w, dst), Some idxVal, Some pi -> + g = w && idxVal = i && uint64 dst = uint64 j + | _ -> false + if result then + printfn "TREE FILTER iter %d: edge (%d,%d) -> tree" iteration (i/1UL) (j/1UL) + result - let tree = - Matrix.map2i tree graph ( - fun i j t g -> - match (t,g) with - | Some t, _ -> Some t - | None, Some g when filter i j g -> Some g - | _ -> None) - - let _parentInner = - Vector.map2i edges index - (fun i e idx -> - match e,idx with - | Some (v,j), Some (_i) when _i = i -> - let j = uint64 j * 1UL - let parent_i = Vector.unsafeGet parent i - let parent_j = Vector.unsafeGet parent j - match parent_i,parent_j with - | Some p_i, Some p_j -> - if p_i < p_j then Some (j, p_i) else Some (i, p_j) - | x -> failwithf "Unreachable: %A" x - | _ -> None - ) - - printfn "=== _parent ===" - printVector _parentInner - - let parentUpdateResult = - Vector.foldValues _parentInner (fun state (i,v) -> - match state with - | Ok state -> - let updateResult = Vector.update state i (Some v) (fun old _new -> _new) - match updateResult with - | Ok u -> Ok u - | Error e -> Error e - | Error e -> Error e) - (Ok parent) - - match parentUpdateResult with - | Error e -> Error(FoldValuesError e) - | Ok __parent -> - printfn "=== parentResult ===" - printVector __parent + let tree = + Matrix.map2i tree graph ( + fun i j t g -> + match (t,g) with + | Some t, _ -> Some t + | None, Some g when filter i j g -> Some g + | _ -> None) + + let _parentInner = + Vector.map2i edges index + (fun i e idx -> + match e,idx with + | Some (v,j), Some (_i) when _i = i -> + let j = uint64 j * 1UL + let parent_i = Vector.unsafeGet parent i + let parent_j = Vector.unsafeGet parent j + match parent_i,parent_j with + | Some p_i, Some p_j -> + if p_i < p_j then Some (j, p_i) else Some (i, p_j) + | x -> failwithf "Unreachable: %A" x + | _ -> None + ) + + printfn "=== _parent ===" + printVector _parentInner + + let! __parent = + Vector.foldValues _parentInner (fun state (i,v) -> + match state with + | Ok state -> + let updateResult = Vector.update state i (Some v) (fun old _new -> _new) + match updateResult with + | Ok u -> Ok u + | Error e -> Error e + | Error e -> Error e) + (Ok parent) + |> Result.mapError mapError'''' + + printfn "=== parentResult ===" + printVector __parent - let rec fixPoint p = - let p2 = Vector.gather p p - if p2 = p then p else fixPoint p2 - let op_min2 x y = - match (x, y) with - | Some v, Some u -> if v < u then Some v else Some u - | Some v, _ -> Some v - | None, Some v -> Some v - | _ -> None - let parentScatterResult = Vector.scatter parent __parent parent op_min2 - match parentScatterResult with - | Error e -> Error(ScatterProblem e) - | Ok parentNew -> - printfn "=== parent' ===" - printVector parentNew - let parentFixed = fixPoint parentNew - - printfn "=== Parent for filter ===" - printVector parentFixed - let graphFilter i j = - let i = uint64 i * 1UL - let j = uint64 j * 1UL - let parent_i = Vector.unsafeGet parentFixed i - let parent_j = Vector.unsafeGet parentFixed j - let result = - match (parent_i, parent_j) with - | Some v1, Some v2 when v1 <> v2 -> true - | _ -> false - if iteration < 2 && result then - printfn "GRAPH FILTER iter %d: keep edge (%d,%d)" iteration (i/1UL) (j/1UL) - result - - let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) - - inner graph tree parentFixed (iteration + 1) + let rec fixPoint p = + let p2 = Vector.gather p p + if p2 = p then p else fixPoint p2 + let op_min2 x y = + match (x, y) with + | Some v, Some u -> if v < u then Some v else Some u + | Some v, _ -> Some v + | None, Some v -> Some v + | _ -> None + let! parentNew = + Vector.scatter parent __parent parent op_min2 + |> Result.mapError mapError''' + printfn "=== parent' ===" + printVector parentNew + let parentFixed = fixPoint parentNew + + printfn "=== Parent for filter ===" + printVector parentFixed + let graphFilter i j = + let i = uint64 i * 1UL + let j = uint64 j * 1UL + let parent_i = Vector.unsafeGet parentFixed i + let parent_j = Vector.unsafeGet parentFixed j + let result = + match (parent_i, parent_j) with + | Some v1, Some v2 when v1 <> v2 -> true + | _ -> false + if iteration < 2 && result then + printfn "GRAPH FILTER iter %d: keep edge (%d,%d)" iteration (i/1UL) (j/1UL) + result + + let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) + + return! inner graph tree parentFixed (iteration + 1) + } else Ok tree From 67e0ffe05382a9fdffea9300133c8cd48eccfe96 Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 30 Mar 2026 11:44:54 +0300 Subject: [PATCH 39/52] Clean up of code for Boruvka. --- QuadTree/Boruvka.fs | 194 +++++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 94 deletions(-) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 8f90181..febafe9 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -17,40 +17,64 @@ let mapError'' (err: Vector.Error) = IndexCalculationProblem err let mapError''' (err: Vector.Error) = ScatterProblem err let mapError'''' (err: Vector.Error) = FoldValuesError err + let printMatrixCoordinate (matrix: Matrix.SparseMatrix<_>) = printfn "Matrix:" - printfn " Rows: %A" matrix.nrows - printfn " Columns: %A" matrix.ncols printfn " Nvals: %A" matrix.nvals - printfn " Storage:" - printfn " size: %A" matrix.storage.size - printfn " Data: %A" (Matrix.toCoordinateList matrix).list + printfn " Data: %A" (Matrix.toCoordinateList matrix).list let printVector (vector: Vector.SparseVector<_>) = printfn "Vector:" - printfn " Length: %A" vector.length printfn " Nvals: %A" vector.nvals - printfn " Storage:" - printfn " Size: %A" vector.storage.size - printfn " Data: %A" (Vector.toCoordinateList vector).data + printfn " Data: %A" (Vector.toCoordinateList vector).data + let mst (graph:Matrix.SparseMatrix<_>) = - printfn "MST CALLED nrows=%A ncols=%A nvals=%A" graph.nrows graph.ncols graph.nvals - - let op_add x y = - match (x, y) with - | Some(a, pa), Some(b, pb) -> - Some (min (a,pa) (b,pb)) - | Some(a, pa), _ -> Some(a, pa) - | _, Some(b, pb) -> Some(b, pb) - | _ -> None let op_mult (i,x) (row,col,w) = Some(w,row) + + let op_min x y = + match (x, y) with + | Some v, Some u -> Some (min v u) + | Some v, _ -> Some v + | None, Some v -> Some v + | _ -> None + + let fixPoint p = + let rec inner p iter = + let p2 = Vector.gather p p + if p2 = p then p else inner p2 (iter+1) + let res = inner p 0 + res + + let treeFilter edges index = + fun i j g -> + let i = uint64 i * 1UL + let j = uint64 j * 1UL + let edge = Vector.unsafeGet edges i + let idx = Vector.unsafeGet index i + let result = + match edge, idx with + | Some(w, dst), Some idxVal-> + g = w && idxVal = i && uint64 dst = uint64 j + | _ -> false + if result then printfn "TREE FILTER: edge (%A,%A) -> tree" i j + result + let graphFilter parent = + fun i j -> + let i = uint64 i * 1UL + let j = uint64 j * 1UL + let parent_i = Vector.unsafeGet parent i + let parent_j = Vector.unsafeGet parent j + match (parent_i, parent_j) with + | Some v1, Some v2 when v1 <> v2 -> true + | _ -> false + let length = uint64 graph.nrows * 1UL - printfn "Length = %A" length - let parentInit = Vector.init length (fun i -> Some i) + + let parent = Vector.init length (fun i -> Some i) let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent iteration = printfn "=== Iter %d: graph=%A, tree=%A ===" iteration graph.nvals tree.nvals @@ -59,65 +83,62 @@ let mst (graph:Matrix.SparseMatrix<_>) = printfn "Parent at start of iter %d:" iteration printVector parent if graph.nvals > 0UL then + + // Cheapest outgoing edge for each vertex + // For each vertex j, find the smallest weight edge (i, j, w) + // such that i and j are in different components. + // Because graph contains only cross‑component edges, + // we simply take the min over all neighbors. resultM { let! edges = - LinearAlgebra.vxmi_values op_add op_mult parent graph + LinearAlgebra.vxmi_values op_min op_mult parent graph |> Result.mapError mapError - + printfn "=== Edges ===" printVector edges - let op_min x y = - match (x, y) with - | Some v, Some u -> if v < u then Some v else None - | Some v, _ -> Some v - | None, Some v -> Some v - | _ -> None - + // Per‑component cheapest edge + // For each component, keep the smallest edges among its vertices. let! cedges = - Vector.scatter (Vector.empty length) edges parent op_add + Vector.scatter (Vector.empty length) edges parent op_min |> Result.mapError mapError' - + printfn "=== Component Edges ===" printVector cedges + // Propagate component's cheapest edge to all its vertices + // Each vertex gets its component's edge let t = Vector.gather cedges parent + + // Identify a representative vertex for each component + // For each vertex, if its own edge is the component's cheapest, mark it. let indexInner = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) + // Among the marked vertices in a component, keep the smallest index. let! index = Vector.scatter (Vector.empty length) indexInner parent op_min |> Result.mapError mapError'' - + // now each vertex knows its component's representative let index = Vector.gather index parent - printfn "=== Index 2 ===" + + printfn "=== Index ===" printVector index - - printfn "=== parent ===" - printVector parent - let filter i j g = - let i = uint64 i * 1UL - let j = uint64 j * 1UL - let edge = Vector.unsafeGet edges i - let idx = Vector.unsafeGet index i - let parent_j = Vector.unsafeGet parent j - let result = - match edge, idx, parent_j with - | Some(w, dst), Some idxVal, Some pi -> - g = w && idxVal = i && uint64 dst = uint64 j - | _ -> false - if result then - printfn "TREE FILTER iter %d: edge (%d,%d) -> tree" iteration (i/1UL) (j/1UL) - result - + // Add selected edges to the MST tree + // An edge (i, j, w) is added if vertex i is the representative for its component + // and (i, j, w) is the cheapest edge of that component. + let treeFilter = treeFilter edges index let tree = Matrix.map2i tree graph ( fun i j t g -> match (t,g) with | Some t, _ -> Some t - | None, Some g when filter i j g -> Some g + | None, Some g when treeFilter i j g -> Some g | _ -> None) - let _parentInner = + // Compute new parent assignments (merge components) + // For each component representative i with cheapest edge (w, j), we want to merge + // the component of i with the component of j. Choose the smaller root. + let data_for_update_parent = Vector.map2i edges index (fun i e idx -> match e,idx with @@ -132,12 +153,13 @@ let mst (graph:Matrix.SparseMatrix<_>) = | _ -> None ) - printfn "=== _parent ===" - printVector _parentInner + printfn "=== Data for update parent ===" + printVector data_for_update_parent - let! __parent = - Vector.foldValues _parentInner (fun state (i,v) -> - match state with + // Apply the updates + let! initial_parent_update = + Vector.foldValues data_for_update_parent (fun state (i,v) -> + match state with | Ok state -> let updateResult = Vector.update state i (Some v) (fun old _new -> _new) match updateResult with @@ -147,46 +169,30 @@ let mst (graph:Matrix.SparseMatrix<_>) = (Ok parent) |> Result.mapError mapError'''' - printfn "=== parentResult ===" - printVector __parent - - let rec fixPoint p = - let p2 = Vector.gather p p - if p2 = p then p else fixPoint p2 - let op_min2 x y = - match (x, y) with - | Some v, Some u -> if v < u then Some v else Some u - | Some v, _ -> Some v - | None, Some v -> Some v - | _ -> None - let! parentNew = - Vector.scatter parent __parent parent op_min2 + printfn "=== Initial parent update ===" + printVector initial_parent_update + + let! parent = + Vector.scatter parent initial_parent_update parent op_min |> Result.mapError mapError''' - - printfn "=== parent' ===" - printVector parentNew - let parentFixed = fixPoint parentNew - - printfn "=== Parent for filter ===" - printVector parentFixed - let graphFilter i j = - let i = uint64 i * 1UL - let j = uint64 j * 1UL - let parent_i = Vector.unsafeGet parentFixed i - let parent_j = Vector.unsafeGet parentFixed j - let result = - match (parent_i, parent_j) with - | Some v1, Some v2 when v1 <> v2 -> true - | _ -> false - if iteration < 2 && result then - printfn "GRAPH FILTER iter %d: keep edge (%d,%d)" iteration (i/1UL) (j/1UL) - result - + + printfn "=== Initially updated parent ===" + printVector parent + + // Then ensure that all vertices in a merged component point to the same root. + // This is done by a fixpoint (path compression) that repeatedly gathers parents. + let parent = fixPoint parent + + printfn "=== Parent before data propagation ===" + printVector parent + + // Filter the graph to keep only edges between different components + let graphFilter = graphFilter parent let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) - return! inner graph tree parentFixed (iteration + 1) + return! inner graph tree parent (iteration + 1) } else Ok tree - inner graph (Matrix.empty graph.nrows graph.ncols) parentInit 0 + inner graph (Matrix.empty graph.nrows graph.ncols) parent 0 From d1b059d0b0d20fa2cd553382c2fd560a4f25b1a2 Mon Sep 17 00:00:00 2001 From: gsv Date: Thu, 26 Mar 2026 14:27:20 +0300 Subject: [PATCH 40/52] More tests for Boruvka. --- QuadTree.Tests/Tests.Boruvka.fs | 151 ++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 459f0ec..2b1960a 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -845,5 +845,156 @@ let ``Boruvka MST big.`` () = checkResult (Graph.Boruvka.mst graph) expected +[] +let ``Boruvka MST complex line.`` () = + + let graph = + let clist = + Matrix.CoordinateList(10UL, 10UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + + 3UL, 4UL, 3UL + 4UL, 3UL, 3UL + + 4UL, 5UL, 1UL + 5UL, 4UL, 1UL + + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + + 7UL, 8UL, 1UL + 8UL, 7UL, 1UL + + 8UL, 9UL, 1UL + 9UL, 8UL, 1UL + + + ]) + + Matrix.fromCoordinateList clist + + + let expected = + let clist = + Matrix.CoordinateList(10UL, 10UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + + 3UL, 4UL, 3UL + 4UL, 3UL, 3UL + + 4UL, 5UL, 1UL + 5UL, 4UL, 1UL + + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + + 7UL, 8UL, 1UL + 8UL, 7UL, 1UL + + 8UL, 9UL, 1UL + 9UL, 8UL, 1UL + + + ]) + + Matrix.fromCoordinateList clist + |> Ok + + checkResult (Graph.Boruvka.mst graph) expected +[] +let ``Boruvka MST complex line 2.`` () = + + let graph = + let clist = + Matrix.CoordinateList(10UL, 10UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + + 3UL, 9UL, 3UL + 9UL, 3UL, 3UL + + 9UL, 8UL, 1UL + 8UL, 9UL, 1UL + + 8UL, 7UL, 1UL + 7UL, 8UL, 1UL + + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + + 5UL, 4UL, 1UL + 4UL, 5UL, 1UL + + + ]) + + Matrix.fromCoordinateList clist + + + let expected = + let clist = + Matrix.CoordinateList(10UL, 10UL,[ + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + + 3UL, 9UL, 3UL + 9UL, 3UL, 3UL + + 9UL, 8UL, 1UL + 8UL, 9UL, 1UL + + 8UL, 7UL, 1UL + 7UL, 8UL, 1UL + + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + + 5UL, 4UL, 1UL + 4UL, 5UL, 1UL + + ]) + + Matrix.fromCoordinateList clist + |> Ok + + checkResult (Graph.Boruvka.mst graph) expected From d0e49ca11e3e845f77707f77f63b89933eeb848b Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 4 May 2026 14:03:23 +0300 Subject: [PATCH 41/52] Use Result workflow in new test for TC. --- QuadTree.Tests/Tests.TriangleCount.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QuadTree.Tests/Tests.TriangleCount.fs b/QuadTree.Tests/Tests.TriangleCount.fs index b5df83d..1b95cae 100644 --- a/QuadTree.Tests/Tests.TriangleCount.fs +++ b/QuadTree.Tests/Tests.TriangleCount.fs @@ -88,7 +88,7 @@ let ``5V Triangle count`` () = let actual = match triangle_count g with - | Result.Success(Some x) -> x + | Ok(Some x) -> x | _ -> failwith "Unreachable" Assert.Equal(expected, actual) From 968b11530f53a1a467ac7e3fee40abd920f8d4d2 Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 4 May 2026 14:03:45 +0300 Subject: [PATCH 42/52] Add Boruvka to list of implemented algorithms. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 075e8f5..8084adb 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Infrastructure for benchmarking the implemented algorithms is available in the [ * Single-source level BFS * Single-source shortest path (SSSP) * Triangles counting +* Boruvka MSF ## TODO * [ ] Single-source parent BFS From 35147b3116a62f476e5d4001a5020dc2f729da37 Mon Sep 17 00:00:00 2001 From: gsv Date: Mon, 4 May 2026 14:08:04 +0300 Subject: [PATCH 43/52] Formatted. --- QuadTree.Tests/Tests.Boruvka.fs | 1416 +++++++++++++------------ QuadTree.Tests/Tests.LinearAlgebra.fs | 38 +- QuadTree.Tests/Tests.Matrix.fs | 68 +- QuadTree.Tests/Tests.Vector.fs | 252 +++-- QuadTree/BFS.fs | 22 +- QuadTree/Boruvka.fs | 138 +-- QuadTree/LinearAlgebra.fs | 80 +- QuadTree/Map.fs | 39 +- QuadTree/Matrix.fs | 70 +- QuadTree/Result.fs | 19 +- QuadTree/SSSP.fs | 12 +- QuadTree/TriangleCount.fs | 4 +- QuadTree/Vector.fs | 204 ++-- 13 files changed, 1340 insertions(+), 1022 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index 2b1960a..c55e920 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -8,32 +8,43 @@ open Vector open Common let checkResult name actual expected = - match actual with - | Ok tree -> + match actual with + | Ok tree -> let tree_transposed = Matrix.transpose tree - let actual = Matrix.map2 tree tree_transposed (fun x y -> match (x,y) with | (Some(x),_) | (_, Some x) -> Some x | _ -> None) + + let actual = + Matrix.map2 tree tree_transposed (fun x y -> + match (x, y) with + | (Some(x), _) + | (_, Some x) -> Some x + | _ -> None) + Assert.Equal(expected, actual) - | x -> Assert.Fail (sprintf "Boruvka failed: %A" x) + | x -> Assert.Fail(sprintf "Boruvka failed: %A" x) [] let ``Boruvka MST 2 nodes.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(2UL, 2UL,[ - 0UL, 1UL, 5UL - 1UL, 0UL, 5UL - ]) + Matrix.CoordinateList( + 2UL, + 2UL, + [ 0UL, 1UL, 5UL; 1UL, 0UL, 5UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(2UL, 2UL,[ - 0UL, 1UL, 5UL - 1UL, 0UL, 5UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 2UL, + 2UL, + [ 0UL, 1UL, 5UL; 1UL, 0UL, 5UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -41,26 +52,32 @@ let ``Boruvka MST 2 nodes.`` () = [] let ``Boruvka MST 3 nodes line.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(3UL, 3UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - ]) + Matrix.CoordinateList( + 3UL, + 3UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(3UL, 3UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 3UL, + 3UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -69,30 +86,36 @@ let ``Boruvka MST 3 nodes line.`` () = [] let ``Boruvka MST 4 nodes line.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(4UL, 4UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - 2UL, 3UL, 3UL - 3UL, 2UL, 3UL - ]) + Matrix.CoordinateList( + 4UL, + 4UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(4UL, 4UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - 2UL, 3UL, 3UL - 3UL, 2UL, 3UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 4UL, + 4UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -100,34 +123,40 @@ let ``Boruvka MST 4 nodes line.`` () = [] let ``Boruvka MST 5 nodes line.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(5UL, 5UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - 2UL, 3UL, 3UL - 3UL, 2UL, 3UL - 3UL, 4UL, 4UL - 4UL, 3UL, 4UL - ]) + Matrix.CoordinateList( + 5UL, + 5UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL + 3UL, 4UL, 4UL + 4UL, 3UL, 4UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(5UL, 5UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - 2UL, 3UL, 3UL - 3UL, 2UL, 3UL - 3UL, 4UL, 4UL - 4UL, 3UL, 4UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 5UL, + 5UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL + 3UL, 4UL, 4UL + 4UL, 3UL, 4UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -135,34 +164,40 @@ let ``Boruvka MST 5 nodes line.`` () = [] let ``Boruvka MST 5 nodes star.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(5UL, 5UL,[ - 0UL, 1UL, 5UL - 1UL, 0UL, 5UL - 0UL, 2UL, 4UL - 2UL, 0UL, 4UL - 0UL, 3UL, 3UL - 3UL, 0UL, 3UL - 0UL, 4UL, 2UL - 4UL, 0UL, 2UL - ]) + Matrix.CoordinateList( + 5UL, + 5UL, + [ 0UL, 1UL, 5UL + 1UL, 0UL, 5UL + 0UL, 2UL, 4UL + 2UL, 0UL, 4UL + 0UL, 3UL, 3UL + 3UL, 0UL, 3UL + 0UL, 4UL, 2UL + 4UL, 0UL, 2UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(5UL, 5UL,[ - 0UL, 1UL, 5UL - 1UL, 0UL, 5UL - 0UL, 2UL, 4UL - 2UL, 0UL, 4UL - 0UL, 3UL, 3UL - 3UL, 0UL, 3UL - 0UL, 4UL, 2UL - 4UL, 0UL, 2UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 5UL, + 5UL, + [ 0UL, 1UL, 5UL + 1UL, 0UL, 5UL + 0UL, 2UL, 4UL + 2UL, 0UL, 4UL + 0UL, 3UL, 3UL + 3UL, 0UL, 3UL + 0UL, 4UL, 2UL + 4UL, 0UL, 2UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -170,46 +205,52 @@ let ``Boruvka MST 5 nodes star.`` () = [] let ``Boruvka MST 5 nodes complete.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(5UL, 5UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 0UL, 2UL, 2UL - 2UL, 0UL, 2UL - 0UL, 3UL, 3UL - 3UL, 0UL, 3UL - 0UL, 4UL, 4UL - 4UL, 0UL, 4UL - 1UL, 2UL, 5UL - 2UL, 1UL, 5UL - 1UL, 3UL, 6UL - 3UL, 1UL, 6UL - 1UL, 4UL, 7UL - 4UL, 1UL, 7UL - 2UL, 3UL, 8UL - 3UL, 2UL, 8UL - 2UL, 4UL, 9UL - 4UL, 2UL, 9UL - 3UL, 4UL, 10UL - 4UL, 3UL, 10UL - ]) + Matrix.CoordinateList( + 5UL, + 5UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 0UL, 2UL, 2UL + 2UL, 0UL, 2UL + 0UL, 3UL, 3UL + 3UL, 0UL, 3UL + 0UL, 4UL, 4UL + 4UL, 0UL, 4UL + 1UL, 2UL, 5UL + 2UL, 1UL, 5UL + 1UL, 3UL, 6UL + 3UL, 1UL, 6UL + 1UL, 4UL, 7UL + 4UL, 1UL, 7UL + 2UL, 3UL, 8UL + 3UL, 2UL, 8UL + 2UL, 4UL, 9UL + 4UL, 2UL, 9UL + 3UL, 4UL, 10UL + 4UL, 3UL, 10UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(5UL, 5UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 0UL, 2UL, 2UL - 2UL, 0UL, 2UL - 0UL, 3UL, 3UL - 3UL, 0UL, 3UL - 0UL, 4UL, 4UL - 4UL, 0UL, 4UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 5UL, + 5UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 0UL, 2UL, 2UL + 2UL, 0UL, 2UL + 0UL, 3UL, 3UL + 3UL, 0UL, 3UL + 0UL, 4UL, 4UL + 4UL, 0UL, 4UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -217,40 +258,47 @@ let ``Boruvka MST 5 nodes complete.`` () = [] let ``Boruvka MST two components.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(6UL, 6UL,[ - // Component 1: vertices 0,1,2 - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - 0UL, 2UL, 3UL - 2UL, 0UL, 3UL - // Component 2: vertices 3,4,5 - 3UL, 4UL, 1UL - 4UL, 3UL, 1UL - 4UL, 5UL, 2UL - 5UL, 4UL, 2UL - 3UL, 5UL, 3UL - 5UL, 3UL, 3UL - ]) + Matrix.CoordinateList( + 6UL, + 6UL, + [ + // Component 1: vertices 0,1,2 + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 0UL, 2UL, 3UL + 2UL, 0UL, 3UL + // Component 2: vertices 3,4,5 + 3UL, 4UL, 1UL + 4UL, 3UL, 1UL + 4UL, 5UL, 2UL + 5UL, 4UL, 2UL + 3UL, 5UL, 3UL + 5UL, 3UL, 3UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(6UL, 6UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - 3UL, 4UL, 1UL - 4UL, 3UL, 1UL - 4UL, 5UL, 2UL - 5UL, 4UL, 2UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 6UL, + 6UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 3UL, 4UL, 1UL + 4UL, 3UL, 1UL + 4UL, 5UL, 2UL + 5UL, 4UL, 2UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -258,40 +306,46 @@ let ``Boruvka MST two components.`` () = [] let ``Boruvka MST cycle graph 6 nodes.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(6UL, 6UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - 2UL, 3UL, 3UL - 3UL, 2UL, 3UL - 3UL, 4UL, 4UL - 4UL, 3UL, 4UL - 4UL, 5UL, 5UL - 5UL, 4UL, 5UL - 5UL, 0UL, 6UL - 0UL, 5UL, 6UL - ]) + Matrix.CoordinateList( + 6UL, + 6UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL + 3UL, 4UL, 4UL + 4UL, 3UL, 4UL + 4UL, 5UL, 5UL + 5UL, 4UL, 5UL + 5UL, 0UL, 6UL + 0UL, 5UL, 6UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(6UL, 6UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - 2UL, 3UL, 3UL - 3UL, 2UL, 3UL - 3UL, 4UL, 4UL - 4UL, 3UL, 4UL - 4UL, 5UL, 5UL - 5UL, 4UL, 5UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 6UL, + 6UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 3UL + 3UL, 2UL, 3UL + 3UL, 4UL, 4UL + 4UL, 3UL, 4UL + 4UL, 5UL, 5UL + 5UL, 4UL, 5UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -299,241 +353,267 @@ let ``Boruvka MST cycle graph 6 nodes.`` () = [] let ``Boruvka MST complete bipartite K3,3.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(6UL, 6UL,[ - // K3,3: vertices 0,1,2 connected to 3,4,5 - 0UL, 3UL, 1UL - 3UL, 0UL, 1UL - - 0UL, 4UL, 2UL - 4UL, 0UL, 2UL - - 0UL, 5UL, 3UL - 5UL, 0UL, 3UL - - 1UL, 3UL, 4UL - 3UL, 1UL, 4UL - - 1UL, 4UL, 5UL - 4UL, 1UL, 5UL - - 1UL, 5UL, 6UL - 5UL, 1UL, 6UL - - 2UL, 3UL, 7UL - 3UL, 2UL, 7UL - - 2UL, 4UL, 8UL - 4UL, 2UL, 8UL - - 2UL, 5UL, 9UL - 5UL, 2UL, 9UL - ]) + Matrix.CoordinateList( + 6UL, + 6UL, + [ + // K3,3: vertices 0,1,2 connected to 3,4,5 + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL + + 0UL, 4UL, 2UL + 4UL, 0UL, 2UL + + 0UL, 5UL, 3UL + 5UL, 0UL, 3UL + + 1UL, 3UL, 4UL + 3UL, 1UL, 4UL + + 1UL, 4UL, 5UL + 4UL, 1UL, 5UL + + 1UL, 5UL, 6UL + 5UL, 1UL, 6UL + + 2UL, 3UL, 7UL + 3UL, 2UL, 7UL + + 2UL, 4UL, 8UL + 4UL, 2UL, 8UL + + 2UL, 5UL, 9UL + 5UL, 2UL, 9UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(6UL, 6UL,[ - 0UL, 3UL, 1UL - 3UL, 0UL, 1UL - 1UL, 3UL, 4UL - 3UL, 1UL, 4UL - 2UL, 3UL, 7UL - 3UL, 2UL, 7UL - 0UL, 4UL, 2UL - 4UL, 0UL, 2UL - 0UL, 5UL, 3UL - 5UL, 0UL, 3UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 6UL, + 6UL, + [ 0UL, 3UL, 1UL + 3UL, 0UL, 1UL + 1UL, 3UL, 4UL + 3UL, 1UL, 4UL + 2UL, 3UL, 7UL + 3UL, 2UL, 7UL + 0UL, 4UL, 2UL + 4UL, 0UL, 2UL + 0UL, 5UL, 3UL + 5UL, 0UL, 3UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected [] let ``Boruvka MST random weights.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(8UL, 8UL,[ - 0UL, 1UL, 7UL - 1UL, 0UL, 7UL - 0UL, 2UL, 5UL - 2UL, 0UL, 5UL - 0UL, 3UL, 9UL - 3UL, 0UL, 9UL - 1UL, 2UL, 3UL - 2UL, 1UL, 3UL - 1UL, 3UL, 4UL - 3UL, 1UL, 4UL - 2UL, 3UL, 2UL - 3UL, 2UL, 2UL - 4UL, 5UL, 1UL - 5UL, 4UL, 1UL - 4UL, 6UL, 6UL - 6UL, 4UL, 6UL - 4UL, 7UL, 8UL - 7UL, 4UL, 8UL - 5UL, 6UL, 3UL - 6UL, 5UL, 3UL - 5UL, 7UL, 5UL - 7UL, 5UL, 5UL - 6UL, 7UL, 2UL - 7UL, 6UL, 2UL - // Connect two components - 3UL, 4UL, 10UL - 4UL, 3UL, 10UL - ]) + Matrix.CoordinateList( + 8UL, + 8UL, + [ 0UL, 1UL, 7UL + 1UL, 0UL, 7UL + 0UL, 2UL, 5UL + 2UL, 0UL, 5UL + 0UL, 3UL, 9UL + 3UL, 0UL, 9UL + 1UL, 2UL, 3UL + 2UL, 1UL, 3UL + 1UL, 3UL, 4UL + 3UL, 1UL, 4UL + 2UL, 3UL, 2UL + 3UL, 2UL, 2UL + 4UL, 5UL, 1UL + 5UL, 4UL, 1UL + 4UL, 6UL, 6UL + 6UL, 4UL, 6UL + 4UL, 7UL, 8UL + 7UL, 4UL, 8UL + 5UL, 6UL, 3UL + 6UL, 5UL, 3UL + 5UL, 7UL, 5UL + 7UL, 5UL, 5UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + // Connect two components + 3UL, 4UL, 10UL + 4UL, 3UL, 10UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(8UL, 8UL,[ - 0UL, 2UL, 5UL - 2UL, 0UL, 5UL - 1UL, 2UL, 3UL - 2UL, 1UL, 3UL - 2UL, 3UL, 2UL - 3UL, 2UL, 2UL - 1UL, 3UL, 4UL - 3UL, 1UL, 4UL - 4UL, 5UL, 1UL - 5UL, 4UL, 1UL - 5UL, 6UL, 3UL - 6UL, 5UL, 3UL - 6UL, 7UL, 2UL - 7UL, 6UL, 2UL - 3UL, 4UL, 10UL - 4UL, 3UL, 10UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 8UL, + 8UL, + [ 0UL, 2UL, 5UL + 2UL, 0UL, 5UL + 1UL, 2UL, 3UL + 2UL, 1UL, 3UL + 2UL, 3UL, 2UL + 3UL, 2UL, 2UL + 1UL, 3UL, 4UL + 3UL, 1UL, 4UL + 4UL, 5UL, 1UL + 5UL, 4UL, 1UL + 5UL, 6UL, 3UL + 6UL, 5UL, 3UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + 3UL, 4UL, 10UL + 4UL, 3UL, 10UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected [] let ``Boruvka MST 8 nodes grid.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(8UL, 8UL,[ - // Row 0-1 connections - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL - // Row 2-3 connections - 0UL, 4UL, 3UL - 4UL, 0UL, 3UL - 1UL, 5UL, 4UL - 5UL, 1UL, 4UL - 2UL, 6UL, 5UL - 6UL, 2UL, 5UL - 3UL, 7UL, 6UL - 7UL, 3UL, 6UL - // Cross row connections - 4UL, 5UL, 2UL - 5UL, 4UL, 2UL - 5UL, 6UL, 1UL - 6UL, 5UL, 1UL - 6UL, 7UL, 3UL - 7UL, 6UL, 3UL - ]) + Matrix.CoordinateList( + 8UL, + 8UL, + [ + // Row 0-1 connections + 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + // Row 2-3 connections + 0UL, 4UL, 3UL + 4UL, 0UL, 3UL + 1UL, 5UL, 4UL + 5UL, 1UL, 4UL + 2UL, 6UL, 5UL + 6UL, 2UL, 5UL + 3UL, 7UL, 6UL + 7UL, 3UL, 6UL + // Cross row connections + 4UL, 5UL, 2UL + 5UL, 4UL, 2UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + 6UL, 7UL, 3UL + 7UL, 6UL, 3UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(8UL, 8UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL - 5UL, 6UL, 1UL - 6UL, 5UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - 4UL, 5UL, 2UL - 5UL, 4UL, 2UL - 0UL, 4UL, 3UL - 4UL, 0UL, 3UL - 6UL, 7UL, 3UL - 7UL, 6UL, 3UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 8UL, + 8UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + 4UL, 5UL, 2UL + 5UL, 4UL, 2UL + 0UL, 4UL, 3UL + 4UL, 0UL, 3UL + 6UL, 7UL, 3UL + 7UL, 6UL, 3UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected [] let ``Boruvka MST 10 nodes random.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(10UL, 10UL,[ - 0UL, 1UL, 4UL - 1UL, 0UL, 4UL - 0UL, 5UL, 2UL - 5UL, 0UL, 2UL - 1UL, 2UL, 3UL - 2UL, 1UL, 3UL - 1UL, 6UL, 5UL - 6UL, 1UL, 5UL - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL - 2UL, 7UL, 4UL - 7UL, 2UL, 4UL - 3UL, 4UL, 2UL - 4UL, 3UL, 2UL - 3UL, 8UL, 6UL - 8UL, 3UL, 6UL - 4UL, 9UL, 3UL - 9UL, 4UL, 3UL - 5UL, 6UL, 1UL - 6UL, 5UL, 1UL - 6UL, 7UL, 2UL - 7UL, 6UL, 2UL - 7UL, 8UL, 1UL - 8UL, 7UL, 1UL - 8UL, 9UL, 4UL - 9UL, 8UL, 4UL - ]) + Matrix.CoordinateList( + 10UL, + 10UL, + [ 0UL, 1UL, 4UL + 1UL, 0UL, 4UL + 0UL, 5UL, 2UL + 5UL, 0UL, 2UL + 1UL, 2UL, 3UL + 2UL, 1UL, 3UL + 1UL, 6UL, 5UL + 6UL, 1UL, 5UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + 2UL, 7UL, 4UL + 7UL, 2UL, 4UL + 3UL, 4UL, 2UL + 4UL, 3UL, 2UL + 3UL, 8UL, 6UL + 8UL, 3UL, 6UL + 4UL, 9UL, 3UL + 9UL, 4UL, 3UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + 7UL, 8UL, 1UL + 8UL, 7UL, 1UL + 8UL, 9UL, 4UL + 9UL, 8UL, 4UL ] + ) + Matrix.fromCoordinateList clist let expected = let clist = - Matrix.CoordinateList(10UL, 10UL,[ - 0UL, 1UL, 4UL - 1UL, 0UL, 4UL - 0UL, 5UL, 2UL - 5UL, 0UL, 2UL - 1UL, 2UL, 3UL - 2UL, 1UL, 3UL - 1UL, 6UL, 5UL - 6UL, 1UL, 5UL - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL - 2UL, 7UL, 4UL - 7UL, 2UL, 4UL - 3UL, 4UL, 2UL - 4UL, 3UL, 2UL - 3UL, 8UL, 6UL - 8UL, 3UL, 6UL - 4UL, 9UL, 3UL - 9UL, 4UL, 3UL - 5UL, 6UL, 1UL - 6UL, 5UL, 1UL - 6UL, 7UL, 2UL - 7UL, 6UL, 2UL - 7UL, 8UL, 1UL - 8UL, 7UL, 1UL - 8UL, 9UL, 4UL - 9UL, 8UL, 4UL - ]) - Matrix.fromCoordinateList clist - |> Ok + Matrix.CoordinateList( + 10UL, + 10UL, + [ 0UL, 1UL, 4UL + 1UL, 0UL, 4UL + 0UL, 5UL, 2UL + 5UL, 0UL, 2UL + 1UL, 2UL, 3UL + 2UL, 1UL, 3UL + 1UL, 6UL, 5UL + 6UL, 1UL, 5UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + 2UL, 7UL, 4UL + 7UL, 2UL, 4UL + 3UL, 4UL, 2UL + 4UL, 3UL, 2UL + 3UL, 8UL, 6UL + 8UL, 3UL, 6UL + 4UL, 9UL, 3UL + 9UL, 4UL, 3UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL + 7UL, 8UL, 1UL + 8UL, 7UL, 1UL + 8UL, 9UL, 4UL + 9UL, 8UL, 4UL ] + ) + + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -541,35 +621,40 @@ let ``Boruvka MST 10 nodes random.`` () = [] let ``Boruvka MST simple triangle.`` () = printfn "!!! TEST STARTING !!!" + let graph = let clist = - Matrix.CoordinateList(3UL, 3UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL + Matrix.CoordinateList( + 3UL, + 3UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL - 0UL, 2UL, 1UL - 2UL, 0UL, 1UL + 0UL, 2UL, 1UL + 2UL, 0UL, 1UL - 1UL, 2UL, 1UL - 2UL, 1UL, 1UL + 1UL, 2UL, 1UL + 2UL, 1UL, 1UL - ]) + ] + ) Matrix.fromCoordinateList clist - + let expected = let clist = - Matrix.CoordinateList(3UL, 3UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL + Matrix.CoordinateList( + 3UL, + 3UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL - 0UL, 2UL, 1UL - 2UL, 0UL, 1UL - ]) + 0UL, 2UL, 1UL + 2UL, 0UL, 1UL ] + ) - Matrix.fromCoordinateList clist - |> Ok + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -577,41 +662,46 @@ let ``Boruvka MST simple triangle.`` () = [] let ``Boruvka MST simple square.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(4UL, 4UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL + Matrix.CoordinateList( + 4UL, + 4UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL - 1UL, 2UL, 1UL - 2UL, 1UL, 1UL + 1UL, 2UL, 1UL + 2UL, 1UL, 1UL - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL - 0UL, 3UL, 1UL - 3UL, 0UL, 1UL + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL - ]) + ] + ) Matrix.fromCoordinateList clist - + let expected = let clist = - Matrix.CoordinateList(4UL, 4UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL + Matrix.CoordinateList( + 4UL, + 4UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL - 0UL, 3UL, 1UL - 3UL, 0UL, 1UL + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL - 1UL, 2UL, 1UL - 2UL, 1UL, 1UL - ]) + 1UL, 2UL, 1UL + 2UL, 1UL, 1UL ] + ) - Matrix.fromCoordinateList clist - |> Ok + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -621,41 +711,46 @@ let ``Boruvka MST simple square.`` () = [] let ``Boruvka MST simple square in two steps.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(4UL, 4UL,[ - 0UL, 1UL, 2UL - 1UL, 0UL, 2UL + Matrix.CoordinateList( + 4UL, + 4UL, + [ 0UL, 1UL, 2UL + 1UL, 0UL, 2UL - 1UL, 2UL, 1UL - 2UL, 1UL, 1UL + 1UL, 2UL, 1UL + 2UL, 1UL, 1UL - 2UL, 3UL, 2UL - 3UL, 2UL, 2UL + 2UL, 3UL, 2UL + 3UL, 2UL, 2UL - 0UL, 3UL, 1UL - 3UL, 0UL, 1UL + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL - ]) + ] + ) Matrix.fromCoordinateList clist - + let expected = let clist = - Matrix.CoordinateList(4UL, 4UL,[ - 0UL, 1UL, 2UL - 1UL, 0UL, 2UL + Matrix.CoordinateList( + 4UL, + 4UL, + [ 0UL, 1UL, 2UL + 1UL, 0UL, 2UL - 0UL, 3UL, 1UL - 3UL, 0UL, 1UL + 0UL, 3UL, 1UL + 3UL, 0UL, 1UL - 1UL, 2UL, 1UL - 2UL, 1UL, 1UL - ]) + 1UL, 2UL, 1UL + 2UL, 1UL, 1UL ] + ) - Matrix.fromCoordinateList clist - |> Ok + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected @@ -665,336 +760,357 @@ let ``Boruvka MST simple square in two steps.`` () = [] let ``Boruvka MST.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(7UL, 7UL,[ - 0UL, 1UL, 7UL - 1UL, 0UL, 7UL + Matrix.CoordinateList( + 7UL, + 7UL, + [ 0UL, 1UL, 7UL + 1UL, 0UL, 7UL - 0UL, 4UL, 4UL - 4UL, 0UL, 4UL + 0UL, 4UL, 4UL + 4UL, 0UL, 4UL - 1UL, 2UL, 11UL - 2UL, 1UL, 11UL + 1UL, 2UL, 11UL + 2UL, 1UL, 11UL - 1UL, 3UL, 10UL - 3UL, 1UL, 10UL + 1UL, 3UL, 10UL + 3UL, 1UL, 10UL - 1UL, 4UL, 9UL - 4UL, 1UL, 9UL + 1UL, 4UL, 9UL + 4UL, 1UL, 9UL - 2UL, 3UL, 5UL - 3UL, 2UL, 5UL + 2UL, 3UL, 5UL + 3UL, 2UL, 5UL - 4UL, 3UL, 15UL - 3UL, 4UL, 15UL + 4UL, 3UL, 15UL + 3UL, 4UL, 15UL - 4UL, 5UL, 6UL - 5UL, 4UL, 6UL + 4UL, 5UL, 6UL + 5UL, 4UL, 6UL - 5UL, 3UL, 12UL - 3UL, 5UL, 12UL + 5UL, 3UL, 12UL + 3UL, 5UL, 12UL - 6UL, 3UL, 8UL - 3UL, 6UL, 8UL + 6UL, 3UL, 8UL + 3UL, 6UL, 8UL - 5UL, 6UL, 13UL - 6UL, 5UL, 13UL - ]) + 5UL, 6UL, 13UL + 6UL, 5UL, 13UL ] + ) Matrix.fromCoordinateList clist - + let expected = let clist = - Matrix.CoordinateList(7UL, 7UL,[ - 0UL, 1UL, 7UL - 1UL, 0UL, 7UL + Matrix.CoordinateList( + 7UL, + 7UL, + [ 0UL, 1UL, 7UL + 1UL, 0UL, 7UL - 0UL, 4UL, 4UL - 4UL, 0UL, 4UL + 0UL, 4UL, 4UL + 4UL, 0UL, 4UL - 1UL, 3UL, 10UL - 3UL, 1UL, 10UL + 1UL, 3UL, 10UL + 3UL, 1UL, 10UL - 2UL, 3UL, 5UL - 3UL, 2UL, 5UL + 2UL, 3UL, 5UL + 3UL, 2UL, 5UL - 4UL, 5UL, 6UL - 5UL, 4UL, 6UL + 4UL, 5UL, 6UL + 5UL, 4UL, 6UL - 6UL, 3UL, 8UL - 3UL, 6UL, 8UL + 6UL, 3UL, 8UL + 3UL, 6UL, 8UL - ]) + ] + ) - Matrix.fromCoordinateList clist - |> Ok + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected - + [] let ``Boruvka MST big.`` () = System.Console.Error.WriteLine("TEST STARTING") + let graph = let clist = - Matrix.CoordinateList(12UL, 12UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL - - 1UL, 11UL, 1UL - 11UL, 1UL, 1UL - - 0UL, 11UL, 1UL - 11UL, 0UL, 1UL -//================================================= - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL - - 3UL, 4UL, 1UL - 4UL, 3UL, 1UL - - 2UL, 4UL, 1UL - 4UL, 2UL, 1UL -//================================================= - 5UL, 6UL, 1UL - 6UL, 5UL, 1UL - - 6UL, 7UL, 1UL - 7UL, 6UL, 1UL - - 5UL, 7UL, 1UL - 7UL, 5UL, 1UL -//================================================= - 8UL, 9UL, 1UL - 9UL, 8UL, 1UL - - 9UL, 10UL, 1UL - 10UL, 9UL, 1UL - - 8UL, 10UL, 1UL - 10UL, 8UL, 1UL -//================================================ -//================================================ - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL - - 11UL, 4UL, 2UL - 4UL, 11UL, 2UL - - 10UL, 5UL, 2UL - 5UL, 10UL, 2UL - - 8UL, 7UL, 2UL - 7UL, 8UL, 2UL -//================================================ -//================================================ - 10UL, 11UL, 3UL - 11UL, 10UL, 3UL - - 5UL, 4UL, 3UL - 4UL, 5UL, 3UL - - ]) + Matrix.CoordinateList( + 12UL, + 12UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 1UL, 11UL, 1UL + 11UL, 1UL, 1UL + + 0UL, 11UL, 1UL + 11UL, 0UL, 1UL + //================================================= + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL + + 3UL, 4UL, 1UL + 4UL, 3UL, 1UL + + 2UL, 4UL, 1UL + 4UL, 2UL, 1UL + //================================================= + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL + + 6UL, 7UL, 1UL + 7UL, 6UL, 1UL + + 5UL, 7UL, 1UL + 7UL, 5UL, 1UL + //================================================= + 8UL, 9UL, 1UL + 9UL, 8UL, 1UL + + 9UL, 10UL, 1UL + 10UL, 9UL, 1UL + + 8UL, 10UL, 1UL + 10UL, 8UL, 1UL + //================================================ + //================================================ + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL + + 11UL, 4UL, 2UL + 4UL, 11UL, 2UL + + 10UL, 5UL, 2UL + 5UL, 10UL, 2UL + + 8UL, 7UL, 2UL + 7UL, 8UL, 2UL + //================================================ + //================================================ + 10UL, 11UL, 3UL + 11UL, 10UL, 3UL + + 5UL, 4UL, 3UL + 4UL, 5UL, 3UL + + ] + ) Matrix.fromCoordinateList clist - + let expected = let clist = - Matrix.CoordinateList(12UL, 12UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL + Matrix.CoordinateList( + 12UL, + 12UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL - 0UL, 11UL, 1UL - 11UL, 0UL, 1UL + 0UL, 11UL, 1UL + 11UL, 0UL, 1UL - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL - 2UL, 4UL, 1UL - 4UL, 2UL, 1UL + 2UL, 4UL, 1UL + 4UL, 2UL, 1UL - 5UL, 6UL, 1UL - 6UL, 5UL, 1UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL - 5UL, 7UL, 1UL - 7UL, 5UL, 1UL + 5UL, 7UL, 1UL + 7UL, 5UL, 1UL - 8UL, 9UL, 1UL - 9UL, 8UL, 1UL + 8UL, 9UL, 1UL + 9UL, 8UL, 1UL - 8UL, 10UL, 1UL - 10UL, 8UL, 1UL + 8UL, 10UL, 1UL + 10UL, 8UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL - 5UL, 10UL, 2UL - 10UL, 5UL, 2UL + 5UL, 10UL, 2UL + 10UL, 5UL, 2UL - 4UL, 5UL, 3UL - 5UL, 4UL, 3UL + 4UL, 5UL, 3UL + 5UL, 4UL, 3UL - ]) + ] + ) - Matrix.fromCoordinateList clist - |> Ok + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected - + [] let ``Boruvka MST complex line.`` () = - + let graph = let clist = - Matrix.CoordinateList(10UL, 10UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL + Matrix.CoordinateList( + 10UL, + 10UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL - 3UL, 4UL, 3UL - 4UL, 3UL, 3UL + 3UL, 4UL, 3UL + 4UL, 3UL, 3UL - 4UL, 5UL, 1UL - 5UL, 4UL, 1UL + 4UL, 5UL, 1UL + 5UL, 4UL, 1UL - 5UL, 6UL, 1UL - 6UL, 5UL, 1UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL - 6UL, 7UL, 2UL - 7UL, 6UL, 2UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL - 7UL, 8UL, 1UL - 8UL, 7UL, 1UL + 7UL, 8UL, 1UL + 8UL, 7UL, 1UL - 8UL, 9UL, 1UL - 9UL, 8UL, 1UL + 8UL, 9UL, 1UL + 9UL, 8UL, 1UL - - ]) + + ] + ) Matrix.fromCoordinateList clist - + let expected = let clist = - Matrix.CoordinateList(10UL, 10UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL + Matrix.CoordinateList( + 10UL, + 10UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL - 3UL, 4UL, 3UL - 4UL, 3UL, 3UL + 3UL, 4UL, 3UL + 4UL, 3UL, 3UL - 4UL, 5UL, 1UL - 5UL, 4UL, 1UL + 4UL, 5UL, 1UL + 5UL, 4UL, 1UL - 5UL, 6UL, 1UL - 6UL, 5UL, 1UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL - 6UL, 7UL, 2UL - 7UL, 6UL, 2UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL - 7UL, 8UL, 1UL - 8UL, 7UL, 1UL + 7UL, 8UL, 1UL + 8UL, 7UL, 1UL - 8UL, 9UL, 1UL - 9UL, 8UL, 1UL + 8UL, 9UL, 1UL + 9UL, 8UL, 1UL - ]) + ] + ) - Matrix.fromCoordinateList clist - |> Ok + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected [] let ``Boruvka MST complex line 2.`` () = - + let graph = let clist = - Matrix.CoordinateList(10UL, 10UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL + Matrix.CoordinateList( + 10UL, + 10UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL + + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL + 3UL, 9UL, 3UL + 9UL, 3UL, 3UL - 3UL, 9UL, 3UL - 9UL, 3UL, 3UL + 9UL, 8UL, 1UL + 8UL, 9UL, 1UL - 9UL, 8UL, 1UL - 8UL, 9UL, 1UL + 8UL, 7UL, 1UL + 7UL, 8UL, 1UL - 8UL, 7UL, 1UL - 7UL, 8UL, 1UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL - 6UL, 7UL, 2UL - 7UL, 6UL, 2UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL - 5UL, 6UL, 1UL - 6UL, 5UL, 1UL + 5UL, 4UL, 1UL + 4UL, 5UL, 1UL - 5UL, 4UL, 1UL - 4UL, 5UL, 1UL - - ]) + ] + ) Matrix.fromCoordinateList clist - + let expected = let clist = - Matrix.CoordinateList(10UL, 10UL,[ - 0UL, 1UL, 1UL - 1UL, 0UL, 1UL + Matrix.CoordinateList( + 10UL, + 10UL, + [ 0UL, 1UL, 1UL + 1UL, 0UL, 1UL - 1UL, 2UL, 2UL - 2UL, 1UL, 2UL + 1UL, 2UL, 2UL + 2UL, 1UL, 2UL - 2UL, 3UL, 1UL - 3UL, 2UL, 1UL + 2UL, 3UL, 1UL + 3UL, 2UL, 1UL - 3UL, 9UL, 3UL - 9UL, 3UL, 3UL + 3UL, 9UL, 3UL + 9UL, 3UL, 3UL - 9UL, 8UL, 1UL - 8UL, 9UL, 1UL + 9UL, 8UL, 1UL + 8UL, 9UL, 1UL - 8UL, 7UL, 1UL - 7UL, 8UL, 1UL + 8UL, 7UL, 1UL + 7UL, 8UL, 1UL - 6UL, 7UL, 2UL - 7UL, 6UL, 2UL + 6UL, 7UL, 2UL + 7UL, 6UL, 2UL - 5UL, 6UL, 1UL - 6UL, 5UL, 1UL + 5UL, 6UL, 1UL + 6UL, 5UL, 1UL - 5UL, 4UL, 1UL - 4UL, 5UL, 1UL + 5UL, 4UL, 1UL + 4UL, 5UL, 1UL - ]) + ] + ) - Matrix.fromCoordinateList clist - |> Ok + Matrix.fromCoordinateList clist |> Ok checkResult (Graph.Boruvka.mst graph) expected diff --git a/QuadTree.Tests/Tests.LinearAlgebra.fs b/QuadTree.Tests/Tests.LinearAlgebra.fs index 1cc824b..3bde7b3 100644 --- a/QuadTree.Tests/Tests.LinearAlgebra.fs +++ b/QuadTree.Tests/Tests.LinearAlgebra.fs @@ -38,9 +38,8 @@ let op_add_i x y = | _, Some(a) -> Some(a) | _ -> None -let op_mult_i (i,x) (row,col,y) = - Some(i,row,col) - +let op_mult_i (i, x) (row, col, y) = Some(i, row, col) + let leaf_v v = qtree.Leaf << UserValue <| Some v let leaf_n () = qtree.Leaf << UserValue <| None @@ -271,11 +270,23 @@ let ``Simple vxmi_values. 3 * (3x5)`` () = let expected = let tree = Vector.btree.Node( - Vector.btree.Node(Vector.btree.Node(vleaf_v (1UL,1UL,0UL) - , vleaf_v (0UL,0UL,1UL)) - , Vector.btree.Node(vleaf_v (0UL,0UL,2UL) - , vleaf_v (1UL,1UL,3UL))), - Vector.btree.Node(Vector.btree.Node(vleaf_v (1UL,1UL,4UL), vleaf_d ()), vleaf_d ()) + Vector.btree.Node( + Vector.btree.Node( + vleaf_v (1UL, 1UL, 0UL), + vleaf_v (0UL, 0UL, 1UL) + ), + Vector.btree.Node( + vleaf_v (0UL, 0UL, 2UL), + vleaf_v (1UL, 1UL, 3UL) + ) + ), + Vector.btree.Node( + Vector.btree.Node( + vleaf_v (1UL, 1UL, 4UL), + vleaf_d () + ), + vleaf_d () + ) ) let store = Vector.Storage(8UL, tree) @@ -318,9 +329,14 @@ let ``Simple vxmi_values. 4 * (4x3).`` () = let expected = - let tree = Vector.btree.Node(Vector.btree.Node(vleaf_v (1UL,1UL,0UL) - , vleaf_v (0UL,0UL,1UL)) - , Vector.btree.Node(vleaf_v (0UL,0UL,2UL), vleaf_d ())) + let tree = + Vector.btree.Node( + Vector.btree.Node( + vleaf_v (1UL, 1UL, 0UL), + vleaf_v (0UL, 0UL, 1UL) + ), + Vector.btree.Node(vleaf_v (0UL, 0UL, 2UL), vleaf_d ()) + ) let store = Vector.Storage(4UL, tree) Ok(SparseVector(3UL, 3UL, store)) diff --git a/QuadTree.Tests/Tests.Matrix.fs b/QuadTree.Tests/Tests.Matrix.fs index 8fafdce..347fbfa 100644 --- a/QuadTree.Tests/Tests.Matrix.fs +++ b/QuadTree.Tests/Tests.Matrix.fs @@ -165,16 +165,24 @@ let ``Simple Matrix.map2i. Square where number of cols and rows are power of two let m1 = Matrix.fromCoordinateList ( Matrix.CoordinateList( - 4UL, 4UL, - [ (0UL, 0UL, 1); (0UL, 1UL, 2); (1UL, 0UL, 3); (1UL, 1UL, 4) ] + 4UL, + 4UL, + [ (0UL, 0UL, 1) + (0UL, 1UL, 2) + (1UL, 0UL, 3) + (1UL, 1UL, 4) ] ) ) let m2 = Matrix.fromCoordinateList ( Matrix.CoordinateList( - 4UL, 4UL, - [ (0UL, 0UL, 10); (0UL, 1UL, 20); (1UL, 0UL, 30); (1UL, 1UL, 40) ] + 4UL, + 4UL, + [ (0UL, 0UL, 10) + (0UL, 1UL, 20) + (1UL, 0UL, 30) + (1UL, 1UL, 40) ] ) ) @@ -193,16 +201,28 @@ let ``Simple Matrix.map2i. Square where number of cols and rows are not power of let m1 = Matrix.fromCoordinateList ( Matrix.CoordinateList( - 3UL, 3UL, - [ (0UL, 0UL, 1); (0UL, 1UL, 2); (0UL, 2UL, 3); (1UL, 0UL, 4); (1UL, 1UL, 5); (1UL, 2UL, 6) ] + 3UL, + 3UL, + [ (0UL, 0UL, 1) + (0UL, 1UL, 2) + (0UL, 2UL, 3) + (1UL, 0UL, 4) + (1UL, 1UL, 5) + (1UL, 2UL, 6) ] ) ) let m2 = Matrix.fromCoordinateList ( Matrix.CoordinateList( - 3UL, 3UL, - [ (0UL, 0UL, 10); (0UL, 1UL, 10); (0UL, 2UL, 10); (1UL, 0UL, 10); (1UL, 1UL, 10); (1UL, 2UL, 10) ] + 3UL, + 3UL, + [ (0UL, 0UL, 10) + (0UL, 1UL, 10) + (0UL, 2UL, 10) + (1UL, 0UL, 10) + (1UL, 1UL, 10) + (1UL, 2UL, 10) ] ) ) @@ -221,7 +241,8 @@ let ``Simple Matrix.map2i. Mixed values.`` () = let m1 = Matrix.fromCoordinateList ( Matrix.CoordinateList( - 4UL, 4UL, + 4UL, + 4UL, [ (0UL, 0UL, 1); (2UL, 2UL, 3) ] ) ) @@ -229,7 +250,8 @@ let ``Simple Matrix.map2i. Mixed values.`` () = let m2 = Matrix.fromCoordinateList ( Matrix.CoordinateList( - 4UL, 4UL, + 4UL, + 4UL, [ (1UL, 1UL, 10); (3UL, 3UL, 30) ] ) ) @@ -251,8 +273,12 @@ let ``Simple Matrix.mapi. Square where number of cols and rows are power of two. let m = Matrix.fromCoordinateList ( Matrix.CoordinateList( - 4UL, 4UL, - [ (0UL, 0UL, 1); (0UL, 1UL, 2); (1UL, 0UL, 3); (1UL, 1UL, 4) ] + 4UL, + 4UL, + [ (0UL, 0UL, 1) + (0UL, 1UL, 2) + (1UL, 0UL, 3) + (1UL, 1UL, 4) ] ) ) @@ -271,8 +297,14 @@ let ``Simple Matrix.mapi. Square where number of cols and rows are not power of let m = Matrix.fromCoordinateList ( Matrix.CoordinateList( - 3UL, 3UL, - [ (0UL, 0UL, 1); (0UL, 1UL, 2); (0UL, 2UL, 3); (1UL, 0UL, 4); (1UL, 1UL, 5); (1UL, 2UL, 6) ] + 3UL, + 3UL, + [ (0UL, 0UL, 1) + (0UL, 1UL, 2) + (0UL, 2UL, 3) + (1UL, 0UL, 4) + (1UL, 1UL, 5) + (1UL, 2UL, 6) ] ) ) @@ -291,8 +323,12 @@ let ``Simple Matrix.mapi. Multiply row index by value.`` () = let m = Matrix.fromCoordinateList ( Matrix.CoordinateList( - 4UL, 4UL, - [ (0UL, 0UL, 1); (1UL, 1UL, 2); (2UL, 2UL, 3); (3UL, 3UL, 4) ] + 4UL, + 4UL, + [ (0UL, 0UL, 1) + (1UL, 1UL, 2) + (2UL, 2UL, 3) + (3UL, 3UL, 4) ] ) ) diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index c7d9c5e..bad099d 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -81,7 +81,17 @@ let ``Simple Vector.map. Length is not power of two.`` () = let ``Simple Vector.mapi. Length is power of two, multiply by index.`` () = let v = Vector.fromCoordinateList ( - Vector.CoordinateList(8UL, [ (0UL, 1); (1UL, 1); (2UL, 1); (3UL, 1); (4UL, 2); (5UL, 2); (6UL, 2); (7UL, 2) ]) + Vector.CoordinateList( + 8UL, + [ (0UL, 1) + (1UL, 1) + (2UL, 1) + (3UL, 1) + (4UL, 2) + (5UL, 2) + (6UL, 2) + (7UL, 2) ] + ) ) let f (idx: uint64) x = @@ -91,7 +101,17 @@ let ``Simple Vector.mapi. Length is power of two, multiply by index.`` () = let expected = Vector.fromCoordinateList ( - Vector.CoordinateList(8UL, [ (0UL, 0); (1UL, 1); (2UL, 2); (3UL, 3); (4UL, 8); (5UL, 10); (6UL, 12); (7UL, 14) ]) + Vector.CoordinateList( + 8UL, + [ (0UL, 0) + (1UL, 1) + (2UL, 2) + (3UL, 3) + (4UL, 8) + (5UL, 10) + (6UL, 12) + (7UL, 14) ] + ) ) let actual = Vector.mapi v f @@ -103,7 +123,15 @@ let ``Simple Vector.mapi. Length is not power of two.`` () = // Build vector [1, 1, 1, 1, 1, 1] with dummy at end let v = Vector.fromCoordinateList ( - Vector.CoordinateList(6UL, [ (0UL, 1); (1UL, 1); (2UL, 1); (3UL, 1); (4UL, 1); (5UL, 1) ]) + Vector.CoordinateList( + 6UL, + [ (0UL, 1) + (1UL, 1) + (2UL, 1) + (3UL, 1) + (4UL, 1) + (5UL, 1) ] + ) ) // f idx x = x * idx @@ -115,7 +143,15 @@ let ``Simple Vector.mapi. Length is not power of two.`` () = // Expected: [0, 1, 2, 3, 4, 5] (1*idx for each position) let expected = Vector.fromCoordinateList ( - Vector.CoordinateList(6UL, [ (0UL, 0); (1UL, 1); (2UL, 2); (3UL, 3); (4UL, 4); (5UL, 5) ]) + Vector.CoordinateList( + 6UL, + [ (0UL, 0) + (1UL, 1) + (2UL, 2) + (3UL, 3) + (4UL, 4) + (5UL, 5) ] + ) ) let actual = Vector.mapi v f @@ -149,12 +185,7 @@ let ``Simple Vector.mapi. Uniform leaf expansion.`` () = let ``Simple Vector.mapi. All indices identity.`` () = // Vector with values matching their indices let v = - Vector.fromCoordinateList ( - Vector.CoordinateList( - 4UL, - [ (0UL, 0); (2UL, 2) ] - ) - ) + Vector.fromCoordinateList (Vector.CoordinateList(4UL, [ (0UL, 0); (2UL, 2) ])) let f (idx: uint64) x = match x with @@ -254,12 +285,18 @@ let ``Simple Vector.map2. Length is not power of two.`` () = let ``Simple Vector.map2i. Length is power of two.`` () = let v1 = Vector.fromCoordinateList ( - Vector.CoordinateList(4UL, [ (0UL, 1); (1UL, 2); (2UL, 3); (3UL, 4) ]) + Vector.CoordinateList( + 4UL, + [ (0UL, 1); (1UL, 2); (2UL, 3); (3UL, 4) ] + ) ) let v2 = Vector.fromCoordinateList ( - Vector.CoordinateList(4UL, [ (0UL, 10); (1UL, 20); (2UL, 30); (3UL, 40) ]) + Vector.CoordinateList( + 4UL, + [ (0UL, 10); (1UL, 20); (2UL, 30); (3UL, 40) ] + ) ) let f idx x y = @@ -269,7 +306,10 @@ let ``Simple Vector.map2i. Length is power of two.`` () = let expected = Vector.fromCoordinateList ( - Vector.CoordinateList(4UL, [ (0UL, 11); (1UL, 23); (2UL, 35); (3UL, 47) ]) + Vector.CoordinateList( + 4UL, + [ (0UL, 11); (1UL, 23); (2UL, 35); (3UL, 47) ] + ) ) let actual = Vector.map2i v1 v2 f @@ -280,12 +320,28 @@ let ``Simple Vector.map2i. Length is power of two.`` () = let ``Simple Vector.map2i. Length is not power of two.`` () = let v1 = Vector.fromCoordinateList ( - Vector.CoordinateList(6UL, [ (0UL, 1); (1UL, 2); (2UL, 3); (3UL, 4); (4UL, 5); (5UL, 6) ]) + Vector.CoordinateList( + 6UL, + [ (0UL, 1) + (1UL, 2) + (2UL, 3) + (3UL, 4) + (4UL, 5) + (5UL, 6) ] + ) ) let v2 = Vector.fromCoordinateList ( - Vector.CoordinateList(6UL, [ (0UL, 10); (1UL, 10); (2UL, 10); (3UL, 10); (4UL, 10); (5UL, 10) ]) + Vector.CoordinateList( + 6UL, + [ (0UL, 10) + (1UL, 10) + (2UL, 10) + (3UL, 10) + (4UL, 10) + (5UL, 10) ] + ) ) let f idx x y = @@ -295,7 +351,15 @@ let ``Simple Vector.map2i. Length is not power of two.`` () = let expected = Vector.fromCoordinateList ( - Vector.CoordinateList(6UL, [ (0UL, 10); (1UL, 12); (2UL, 16); (3UL, 22); (4UL, 30); (5UL, 40) ]) + Vector.CoordinateList( + 6UL, + [ (0UL, 10) + (1UL, 12) + (2UL, 16) + (3UL, 22) + (4UL, 30) + (5UL, 40) ] + ) ) let actual = Vector.map2i v1 v2 f @@ -305,14 +369,10 @@ let ``Simple Vector.map2i. Length is not power of two.`` () = [] let ``Simple Vector.map2i. Mixed values.`` () = let v1 = - Vector.fromCoordinateList ( - Vector.CoordinateList(4UL, [ (0UL, 1); (2UL, 3) ]) - ) + Vector.fromCoordinateList (Vector.CoordinateList(4UL, [ (0UL, 1); (2UL, 3) ])) let v2 = - Vector.fromCoordinateList ( - Vector.CoordinateList(4UL, [ (1UL, 10); (3UL, 30) ]) - ) + Vector.fromCoordinateList (Vector.CoordinateList(4UL, [ (1UL, 10); (3UL, 30) ])) let f idx x y = match (x, y) with @@ -395,35 +455,23 @@ let ``Condensation of empty`` () = Assert.Equal(expected, actual) -[] -let ``Gather``() = - let data = - Vector.CoordinateList( - 5UL, - [ (0UL, 0.0) - (1UL, 1.0) - (4UL, 5.0) ] - ) +[] +let ``Gather`` () = + let data = + Vector.CoordinateList(5UL, [ (0UL, 0.0); (1UL, 1.0); (4UL, 5.0) ]) |> Vector.fromCoordinateList - let indices = + let indices = Vector.CoordinateList( - 5UL, - [ (0UL, 1UL) - (1UL, 4UL) - (3UL, 1UL) ] + 5UL, + [ (0UL, 1UL); (1UL, 4UL); (3UL, 1UL) ] ) |> Vector.fromCoordinateList let actual = Vector.gather data indices - let expected = - Vector.CoordinateList( - 5UL, - [ (0UL, 1.0) - (1UL, 5.0) - (3UL, 1.0) ] - ) + let expected = + Vector.CoordinateList(5UL, [ (0UL, 1.0); (1UL, 5.0); (3UL, 1.0) ]) |> Vector.fromCoordinateList Assert.Equal(expected, actual) @@ -469,114 +517,88 @@ let ``Scatter``() = Assert.Equal(expected, actual)*) -let compare x y = - match (x,y) with +let compare x y = + match (x, y) with | Some x, None -> -1 - | Some x, Some y -> if x < y then -1 elif x > y then 1 else 0 + | Some x, Some y -> + if x < y then -1 + elif x > y then 1 + else 0 | None, Some x -> 1 | _ -> 0 -[] -let ``Sort one element vector``() = - let data = - Vector.CoordinateList( - 1UL, - [ (0UL, 0.0) - ] - ) +[] +let ``Sort one element vector`` () = + let data = + Vector.CoordinateList(1UL, [ (0UL, 0.0) ]) |> Vector.fromCoordinateList + let actual = Vector.mergeSort data compare Assert.Equal(data, actual) -[] -let ``Sort vector of two equal elements``() = - let data = - Vector.CoordinateList( - 2UL, - [ (0UL, 0.0);(1UL, 0.0) - ] - ) +[] +let ``Sort vector of two equal elements`` () = + let data = + Vector.CoordinateList(2UL, [ (0UL, 0.0); (1UL, 0.0) ]) |> Vector.fromCoordinateList + let actual = Vector.mergeSort data compare Assert.Equal(data, actual) -[] -let ``Sort vector of three equal elements``() = - let data = - Vector.CoordinateList( - 3UL, - [ (0UL, 2.0);(1UL, 2.0);(2UL, 2.0) - ] - ) +[] +let ``Sort vector of three equal elements`` () = + let data = + Vector.CoordinateList(3UL, [ (0UL, 2.0); (1UL, 2.0); (2UL, 2.0) ]) |> Vector.fromCoordinateList - + let actual = Vector.mergeSort data compare Assert.Equal(data, actual) -[] -let ``Sort vector of three different unordered elements``() = - let data = - Vector.CoordinateList( - 3UL, - [ (0UL, 2.0);(1UL, 1.0);(2UL, 4.0) - ] - ) +[] +let ``Sort vector of three different unordered elements`` () = + let data = + Vector.CoordinateList(3UL, [ (0UL, 2.0); (1UL, 1.0); (2UL, 4.0) ]) |> Vector.fromCoordinateList - let expected = - Vector.CoordinateList( - 3UL, - [ (0UL, 1.0);(1UL, 2.0);(2UL, 4.0) - ] - ) + + let expected = + Vector.CoordinateList(3UL, [ (0UL, 1.0); (1UL, 2.0); (2UL, 4.0) ]) |> Vector.fromCoordinateList + let actual = Vector.mergeSort data compare Assert.Equal(expected, actual) - -[] -let ``Sort long vector with one element``() = - let data = - Vector.CoordinateList( - 5UL, - [ (0UL, 0.0) - ] - ) + +[] +let ``Sort long vector with one element`` () = + let data = + Vector.CoordinateList(5UL, [ (0UL, 0.0) ]) |> Vector.fromCoordinateList + let actual = Vector.mergeSort data compare printVector actual Assert.Equal(data, actual) -[] -let ``Sort sorted vector``() = - let data = - Vector.CoordinateList( - 5UL, - [ (0UL, 0.0); (1UL, 0.0) - ] - ) +[] +let ``Sort sorted vector`` () = + let data = + Vector.CoordinateList(5UL, [ (0UL, 0.0); (1UL, 0.0) ]) |> Vector.fromCoordinateList + let actual = Vector.mergeSort data compare Assert.Equal(data, actual) -[] -let ``Init vector``() = - let expected = - Vector.CoordinateList( - 3UL, - [ (0UL, 0); (1UL, 1); (2UL, 2) - ] - ) +[] +let ``Init vector`` () = + let expected = + Vector.CoordinateList(3UL, [ (0UL, 0); (1UL, 1); (2UL, 2) ]) |> Vector.fromCoordinateList - let actual = Vector.init 3UL (fun i -> Some (int i)) + + let actual = Vector.init 3UL (fun i -> Some(int i)) //printfn "++++ Vector inint ++++" //printVector actual Assert.Equal(expected, actual) - - - - \ No newline at end of file diff --git a/QuadTree/BFS.fs b/QuadTree/BFS.fs index 2f84ec9..56caf37 100644 --- a/QuadTree/BFS.fs +++ b/QuadTree/BFS.fs @@ -16,18 +16,26 @@ let bfs_level graph startVertices = let rec inner level (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) = if frontier.nvals > 0UL then resultM { - let! new_frontier = - LinearAlgebra.vxm - (fun x y -> match (x, y) with | Some(v), _ | _, Some(v) -> Some(v) | _ -> None) - (fun x y -> match (x, y) with | Some(v), Some(_) -> Some(v) | _ -> None) - frontier graph + let! new_frontier = + LinearAlgebra.vxm + (fun x y -> + match (x, y) with + | Some(v), _ + | _, Some(v) -> Some(v) + | _ -> None) + (fun x y -> + match (x, y) with + | Some(v), Some(_) -> Some(v) + | _ -> None) + frontier + graph |> Result.mapError mapError - let! frontier = + let! frontier = Vector.mask new_frontier visited (fun x -> x.IsNone) |> Result.mapError mapError' - let! visited = + let! visited = Vector.map2 visited new_frontier (fun x y -> match (x, y) with | (Some(_), _) -> x diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index febafe9..cdf3afb 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -29,97 +29,106 @@ let printVector (vector: Vector.SparseVector<_>) = printfn " Data: %A" (Vector.toCoordinateList vector).data -let mst (graph:Matrix.SparseMatrix<_>) = +let mst (graph: Matrix.SparseMatrix<_>) = - let op_mult (i,x) (row,col,w) = - Some(w,row) + let op_mult (i, x) (row, col, w) = Some(w, row) - let op_min x y = + let op_min x y = match (x, y) with - | Some v, Some u -> Some (min v u) + | Some v, Some u -> Some(min v u) | Some v, _ -> Some v | None, Some v -> Some v | _ -> None - + let fixPoint p = - let rec inner p iter = + let rec inner p iter = let p2 = Vector.gather p p - if p2 = p then p else inner p2 (iter+1) + if p2 = p then p else inner p2 (iter + 1) + let res = inner p 0 res - let treeFilter edges index = + let treeFilter edges index = fun i j g -> let i = uint64 i * 1UL let j = uint64 j * 1UL let edge = Vector.unsafeGet edges i let idx = Vector.unsafeGet index i - let result = - match edge, idx with - | Some(w, dst), Some idxVal-> - g = w && idxVal = i && uint64 dst = uint64 j + + let result = + match edge, idx with + | Some(w, dst), Some idxVal -> g = w && idxVal = i && uint64 dst = uint64 j | _ -> false - if result then printfn "TREE FILTER: edge (%A,%A) -> tree" i j + + if result then + printfn "TREE FILTER: edge (%A,%A) -> tree" i j + result - - let graphFilter parent = - fun i j -> + + let graphFilter parent = + fun i j -> let i = uint64 i * 1UL let j = uint64 j * 1UL let parent_i = Vector.unsafeGet parent i let parent_j = Vector.unsafeGet parent j + match (parent_i, parent_j) with | Some v1, Some v2 when v1 <> v2 -> true | _ -> false let length = uint64 graph.nrows * 1UL - + let parent = Vector.init length (fun i -> Some i) - + let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent iteration = printfn "=== Iter %d: graph=%A, tree=%A ===" iteration graph.nvals tree.nvals printfn "=== Graph ===" printMatrixCoordinate graph printfn "Parent at start of iter %d:" iteration printVector parent + if graph.nvals > 0UL then - // Cheapest outgoing edge for each vertex + // Cheapest outgoing edge for each vertex // For each vertex j, find the smallest weight edge (i, j, w) // such that i and j are in different components. // Because graph contains only cross‑component edges, // we simply take the min over all neighbors. resultM { - let! edges = + let! edges = LinearAlgebra.vxmi_values op_min op_mult parent graph |> Result.mapError mapError - + printfn "=== Edges ===" - printVector edges + printVector edges // Per‑component cheapest edge // For each component, keep the smallest edges among its vertices. - let! cedges = + let! cedges = Vector.scatter (Vector.empty length) edges parent op_min |> Result.mapError mapError' - + printfn "=== Component Edges ===" printVector cedges // Propagate component's cheapest edge to all its vertices // Each vertex gets its component's edge let t = Vector.gather cedges parent - + // Identify a representative vertex for each component // For each vertex, if its own edge is the component's cheapest, mark it. - let indexInner = Vector.map2i t edges (fun i t e -> match (t,e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) + let indexInner = + Vector.map2i t edges (fun i t e -> + match (t, e) with + | Some v1, Some v2 when v1 = v2 -> Some i + | _ -> None) // Among the marked vertices in a component, keep the smallest index. - let! index = + let! index = Vector.scatter (Vector.empty length) indexInner parent op_min |> Result.mapError mapError'' // now each vertex knows its component's representative let index = Vector.gather index parent - + printfn "=== Index ===" printVector index @@ -127,65 +136,66 @@ let mst (graph:Matrix.SparseMatrix<_>) = // An edge (i, j, w) is added if vertex i is the representative for its component // and (i, j, w) is the cheapest edge of that component. let treeFilter = treeFilter edges index - let tree = - Matrix.map2i tree graph ( - fun i j t g -> - match (t,g) with - | Some t, _ -> Some t - | None, Some g when treeFilter i j g -> Some g - | _ -> None) + + let tree = + Matrix.map2i tree graph (fun i j t g -> + match (t, g) with + | Some t, _ -> Some t + | None, Some g when treeFilter i j g -> Some g + | _ -> None) // Compute new parent assignments (merge components) // For each component representative i with cheapest edge (w, j), we want to merge // the component of i with the component of j. Choose the smaller root. - let data_for_update_parent = - Vector.map2i edges index - (fun i e idx -> - match e,idx with - | Some (v,j), Some (_i) when _i = i -> - let j = uint64 j * 1UL - let parent_i = Vector.unsafeGet parent i - let parent_j = Vector.unsafeGet parent j - match parent_i,parent_j with - | Some p_i, Some p_j -> - if p_i < p_j then Some (j, p_i) else Some (i, p_j) - | x -> failwithf "Unreachable: %A" x - | _ -> None - ) + let data_for_update_parent = + Vector.map2i edges index (fun i e idx -> + match e, idx with + | Some(v, j), Some(_i) when _i = i -> + let j = uint64 j * 1UL + let parent_i = Vector.unsafeGet parent i + let parent_j = Vector.unsafeGet parent j + + match parent_i, parent_j with + | Some p_i, Some p_j -> if p_i < p_j then Some(j, p_i) else Some(i, p_j) + | x -> failwithf "Unreachable: %A" x + | _ -> None) printfn "=== Data for update parent ===" printVector data_for_update_parent // Apply the updates let! initial_parent_update = - Vector.foldValues data_for_update_parent (fun state (i,v) -> - match state with - | Ok state -> - let updateResult = Vector.update state i (Some v) (fun old _new -> _new) - match updateResult with - | Ok u -> Ok u - | Error e -> Error e - | Error e -> Error e) + Vector.foldValues + data_for_update_parent + (fun state (i, v) -> + match state with + | Ok state -> + let updateResult = Vector.update state i (Some v) (fun old _new -> _new) + + match updateResult with + | Ok u -> Ok u + | Error e -> Error e + | Error e -> Error e) (Ok parent) |> Result.mapError mapError'''' printfn "=== Initial parent update ===" printVector initial_parent_update - - let! parent = + + let! parent = Vector.scatter parent initial_parent_update parent op_min |> Result.mapError mapError''' - + printfn "=== Initially updated parent ===" printVector parent - + // Then ensure that all vertices in a merged component point to the same root. // This is done by a fixpoint (path compression) that repeatedly gathers parents. let parent = fixPoint parent - + printfn "=== Parent before data propagation ===" printVector parent - + // Filter the graph to keep only edges between different components let graphFilter = graphFilter parent let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) diff --git a/QuadTree/LinearAlgebra.fs b/QuadTree/LinearAlgebra.fs index f0ae22f..e8e67ed 100644 --- a/QuadTree/LinearAlgebra.fs +++ b/QuadTree/LinearAlgebra.fs @@ -29,10 +29,7 @@ let vxm op_add op_mult (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseM 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 - | Ok((t1, nvals1)), - Ok((t2, nvals2)), - Ok((t3, nvals3)), - Ok((t4, nvals4)) -> + | Ok((t1, nvals1)), Ok((t2, nvals2)), Ok((t3, nvals3)), Ok((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))) @@ -48,8 +45,7 @@ let vxm op_add op_mult (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseM let z2 = vAdd v2 v4 match (z1, z2) with - | Ok(v1), Ok(v2) -> - Ok((Vector.mkNode v1.storage.data v2.storage.data), v1.nvals + v2.nvals) + | Ok(v1), Ok(v2) -> Ok((Vector.mkNode v1.storage.data v2.storage.data), v1.nvals + v2.nvals) | Error(e), _ | _, Error(e) -> Error(VectorAdditionProblem(e)) @@ -106,23 +102,43 @@ let vxm op_add op_mult (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseM else Error Error.InconsistentSizeOfArguments -let vxmi_values +let vxmi_values (op_add: 'c option -> 'c option -> 'c option) (op_mult: uint64 * 'a -> uint64 * uint64 * 'b -> Option<'c>) - (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseMatrix<'b>) = + (vector: Vector.SparseVector<'a>) + (matrix: Matrix.SparseMatrix<'b>) + = - let rec inner (size: uint64) vector (vectorIdx: uint64) matrix (rowIdx: uint64) (colIdx: uint64) = + let rec inner + (size: uint64) + vector + (vectorIdx: uint64) + matrix + (rowIdx: uint64) + (colIdx: uint64) + = let _do x1 x2 y1 y2 y3 y4 = let new_size = size / 2UL - match (inner new_size x1 vectorIdx y1 rowIdx colIdx), - (inner new_size x1 vectorIdx y2 rowIdx (colIdx + (uint64 new_size) * 1UL)), - (inner new_size x2 (vectorIdx + (uint64 new_size) * 1UL) y3 (rowIdx + (uint64 new_size) * 1UL) colIdx), - (inner new_size x2 (vectorIdx + (uint64 new_size) * 1UL) y4 (rowIdx + (uint64 new_size) * 1UL) (colIdx + (uint64 new_size) * 1UL)) with - | Ok((t1, nvals1)), - Ok((t2, nvals2)), - Ok((t3, nvals3)), - Ok((t4, nvals4)) -> + match + (inner new_size x1 vectorIdx y1 rowIdx colIdx), + (inner new_size x1 vectorIdx y2 rowIdx (colIdx + (uint64 new_size) * 1UL)), + (inner + new_size + x2 + (vectorIdx + (uint64 new_size) * 1UL) + y3 + (rowIdx + (uint64 new_size) * 1UL) + colIdx), + (inner + new_size + x2 + (vectorIdx + (uint64 new_size) * 1UL) + y4 + (rowIdx + (uint64 new_size) * 1UL) + (colIdx + (uint64 new_size) * 1UL)) + with + | Ok((t1, nvals1)), Ok((t2, nvals2)), Ok((t3, nvals3)), Ok((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))) @@ -138,8 +154,7 @@ let vxmi_values let z2 = vAdd v2 v4 match (z1, z2) with - | Ok(v1), Ok(v2) -> - Ok((Vector.mkNode v1.storage.data v2.storage.data), v1.nvals + v2.nvals) + | Ok(v1), Ok(v2) -> Ok((Vector.mkNode v1.storage.data v2.storage.data), v1.nvals + v2.nvals) | Error(e), _ | _, Error(e) -> Error(VectorAdditionProblem(e)) @@ -150,8 +165,7 @@ let vxmi_values match (vector, matrix) with | Vector.btree.Leaf(UserValue(Some(v1))), Matrix.qtree.Leaf(UserValue(Some(v2))) -> - if size = 1UL - then + if size = 1UL then let res = op_mult (vectorIdx, v1) (rowIdx, colIdx, v2) let nnz = @@ -160,14 +174,20 @@ let vxmi_values | _ -> 1UL Ok(Vector.btree.Leaf(UserValue(res)), nnz) - else - inner size (Vector.btree.Node(vector,vector)) vectorIdx (Matrix.qtree.Node(matrix, matrix,matrix,matrix)) rowIdx colIdx + else + inner + size + (Vector.btree.Node(vector, vector)) + vectorIdx + (Matrix.qtree.Node(matrix, matrix, matrix, matrix)) + rowIdx + colIdx | Vector.btree.Leaf(UserValue(Some(_))), Matrix.qtree.Node(y1, y2, y3, y4) -> _do vector vector y1 y2 y3 y4 | Vector.btree.Node(x1, x2), Matrix.qtree.Leaf(UserValue(Some(_))) -> _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(UserValue(None)),_ - | _, Matrix.qtree.Leaf(UserValue(None)) -> Ok(Vector.btree.Leaf(UserValue(None)), 0UL) + | Vector.btree.Leaf(UserValue(None)), _ + | _, Matrix.qtree.Leaf(UserValue(None)) -> Ok(Vector.btree.Leaf(UserValue(None)), 0UL) | Vector.btree.Leaf(Dummy), _ | _, Matrix.qtree.Leaf(Dummy) -> Ok(Vector.btree.Leaf(Dummy), 0UL) @@ -190,7 +210,15 @@ let vxmi_values else vector.storage - match inner vector_storage.size vector_storage.data 0UL matrix.storage.data 0UL 0UL with + match + inner + vector_storage.size + vector_storage.data + 0UL + matrix.storage.data + 0UL + 0UL + with | Error x -> Error x | Ok(storage, nvals) -> (Vector.SparseVector( diff --git a/QuadTree/Map.fs b/QuadTree/Map.fs index bcbf636..d0d9d76 100644 --- a/QuadTree/Map.fs +++ b/QuadTree/Map.fs @@ -11,45 +11,40 @@ let private height tree = let private makeNode k v l r = let h = 1 + max (height l) (height r) - Node(k, v, h, l, r) + Node(k, v, h, l, r) -let private rotateRight tree= +let private rotateRight tree = match tree with | Empty -> Empty | Node(x, vx, _, left, right) -> match left with | Empty -> failwith "rotateRight: left child is empty" | Node(y, vy, _, ly, ry) -> - Node(y, vy, - 1 + max (height ly) (height (makeNode x vx ry right)), - ly, makeNode x vx ry right) + Node(y, vy, 1 + max (height ly) (height (makeNode x vx ry right)), ly, makeNode x vx ry right) -let private rotateLeft tree= +let private rotateLeft tree = match tree with | Empty -> Empty | Node(x, vx, _, left, right) -> match right with | Empty -> failwith "rotateLeft: right child is empty" | Node(y, vy, _, ly, ry) -> - Node(y, vy, - 1 + max (height (makeNode x vx left ly)) (height ry), - makeNode x vx left ly, ry) + Node(y, vy, 1 + max (height (makeNode x vx left ly)) (height ry), makeNode x vx left ly, ry) let private balance k v l r = let hl = height l let hr = height r - if hl - hr > 1 then + + if hl - hr > 1 then match l with - | Node(lk, lv, _, ll, lr) when height ll >= height lr -> - rotateRight (Node(k, v, 0, l, r)) + | Node(lk, lv, _, ll, lr) when height ll >= height lr -> rotateRight (Node(k, v, 0, l, r)) | Node(lk, lv, _, ll, lr) -> let newLeft = rotateLeft (Node(lk, lv, 0, ll, lr)) rotateRight (Node(k, v, 0, newLeft, r)) | _ -> failwith "balance: left heavy but left is empty" elif hr - hl > 1 then match r with - | Node(rk, rv, _, rl, rr) when height rr >= height rl -> - rotateLeft (Node(k, v, 0, l, r)) + | Node(rk, rv, _, rl, rr) when height rr >= height rl -> rotateLeft (Node(k, v, 0, l, r)) | Node(rk, rv, _, rl, rr) -> let newRight = rotateRight (Node(rk, rv, 0, rl, rr)) rotateLeft (Node(k, v, 0, l, newRight)) @@ -60,9 +55,11 @@ let private balance k v l r = let empty = Empty let isEmpty map = - match map with Empty -> true | _ -> false + match map with + | Empty -> true + | _ -> false -let rec contains k map = +let rec contains k map = match map with | Empty -> false | Node(k2, _, _, l, r) -> @@ -70,7 +67,7 @@ let rec contains k map = elif k < k2 then contains k l else contains k r -let rec tryFind k map = +let rec tryFind k map = match map with | Empty -> None | Node(k2, v, _, l, r) -> @@ -115,7 +112,7 @@ let rec remove k map = balance k2 v2 (remove k l) r elif k > k2 then balance k2 v2 l (remove k r) - else + else match l, r with | Empty, _ -> r | _, Empty -> l @@ -125,7 +122,8 @@ let rec remove k map = balance minK minV l newR /// Folds over the map in ascending key order. -let rec fold f acc = function +let rec fold f acc = + function | Empty -> acc | Node(k, v, _, l, r) -> let acc' = fold f acc l @@ -137,7 +135,8 @@ let rec fold f acc = function let rec count map = fold (fun acc _ _ -> acc + 1) 0 map /// Returns a list of (key, value) pairs in ascending key order. -let toList map = fold (fun acc k v -> (k, v) :: acc) [] map |> List.rev +let toList map = + fold (fun acc k v -> (k, v) :: acc) [] map |> List.rev /// Creates a map from a sequence of key‑value pairs. let ofList list = diff --git a/QuadTree/Matrix.fs b/QuadTree/Matrix.fs index 4dd3f95..17f09ee 100644 --- a/QuadTree/Matrix.fs +++ b/QuadTree/Matrix.fs @@ -138,7 +138,7 @@ let toCoordinateList (matrix: SparseMatrix<'a>) = CoordinateList(nrows, ncols, coo) let empty nrows ncols = - fromCoordinateList (CoordinateList(nrows,ncols,[])) + fromCoordinateList (CoordinateList(nrows, ncols, [])) let map2 (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = let rec inner (size: uint64) matrix1 matrix2 = @@ -146,12 +146,8 @@ let map2 (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = let new_size = size / 2UL match (inner new_size x1 y1), (inner new_size x2 y2), (inner new_size x3 y3), (inner new_size x4 y4) with - | Ok((new_t1, nvals1)), - Ok((new_t2, nvals2)), - Ok((new_t3, nvals3)), - Ok((new_t4, nvals4)) -> - ((mkNode new_t1 new_t2 new_t3 new_t4), nvals1 + nvals2 + nvals3 + nvals4) - |> Ok + | Ok((new_t1, nvals1)), Ok((new_t2, nvals2)), Ok((new_t3, nvals3)), Ok((new_t4, nvals4)) -> + ((mkNode new_t1 new_t2 new_t3 new_t4), nvals1 + nvals2 + nvals3 + nvals4) |> Ok | Error(e), _, _, _ | _, Error(e), _, _ | _, _, Error(e), _ @@ -188,7 +184,10 @@ let map2i (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = match (matrix1, matrix2) with | Node(x1, x2, x3, x4), Node(y1, y2, y3, y4) -> let halfSize = size / 2UL - let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = getQuadrantCoords (prow, pcol) (uint64 halfSize) + + let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = + getQuadrantCoords (prow, pcol) (uint64 halfSize) + let t1, nvals1 = inner nwR nwC halfSize x1 y1 let t2, nvals2 = inner neR neC halfSize x2 y2 let t3, nvals3 = inner swR swC halfSize x3 y3 @@ -196,7 +195,10 @@ let map2i (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = (mkNode t1 t2 t3 t4), nvals1 + nvals2 + nvals3 + nvals4 | Node(x1, x2, x3, x4), Leaf(v2) -> let halfSize = size / 2UL - let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = getQuadrantCoords (prow, pcol) (uint64 halfSize) + + let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = + getQuadrantCoords (prow, pcol) (uint64 halfSize) + let t1, nvals1 = inner nwR nwC halfSize x1 (Leaf(v2)) let t2, nvals2 = inner neR neC halfSize x2 (Leaf(v2)) let t3, nvals3 = inner swR swC halfSize x3 (Leaf(v2)) @@ -204,7 +206,10 @@ let map2i (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = (mkNode t1 t2 t3 t4), nvals1 + nvals2 + nvals3 + nvals4 | Leaf(v1), Node(y1, y2, y3, y4) -> let halfSize = size / 2UL - let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = getQuadrantCoords (prow, pcol) (uint64 halfSize) + + let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = + getQuadrantCoords (prow, pcol) (uint64 halfSize) + let t1, nvals1 = inner nwR nwC halfSize (Leaf(v1)) y1 let t2, nvals2 = inner neR neC halfSize (Leaf(v1)) y2 let t3, nvals3 = inner swR swC halfSize (Leaf(v1)) y3 @@ -213,20 +218,37 @@ let map2i (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = | Leaf(Dummy), Leaf(Dummy) -> Leaf(Dummy), 0UL | Leaf(UserValue(v1)), Leaf(UserValue(v2)) -> let res = f prow pcol v1 v2 - let nnz = match res with Some _ -> 1UL | None -> 0UL + + let nnz = + match res with + | Some _ -> 1UL + | None -> 0UL + Leaf(UserValue(res)), nnz | Leaf(UserValue(v)), Leaf(Dummy) -> let res = f prow pcol v None - let nnz = match res with Some _ -> 1UL | None -> 0UL + + let nnz = + match res with + | Some _ -> 1UL + | None -> 0UL + Leaf(UserValue(res)), nnz | Leaf(Dummy), Leaf(UserValue(v)) -> let res = f prow pcol None v - let nnz = match res with Some _ -> 1UL | None -> 0UL + + let nnz = + match res with + | Some _ -> 1UL + | None -> 0UL + Leaf(UserValue(res)), nnz | (x, y) -> failwithf "InconsistentStructureOfStorages: %A vs %A" x y if matrix1.nrows = matrix2.nrows && matrix1.ncols = matrix2.ncols then - let storage, nvals = inner 0UL 0UL matrix1.storage.size matrix1.storage.data matrix2.storage.data + let storage, nvals = + inner 0UL 0UL matrix1.storage.size matrix1.storage.data matrix2.storage.data + SparseMatrix(matrix1.nrows, matrix1.ncols, nvals, (Storage(matrix1.storage.size, storage))) else failwithf "InconsistentSizeOfArguments: %A vs %A" matrix1 matrix2 @@ -236,7 +258,10 @@ let mapi (matrix: SparseMatrix<'a>) f = match matrix with | Node(x1, x2, x3, x4) -> let halfSize = size / 2UL - let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = getQuadrantCoords (prow, pcol) (uint64 halfSize) + + let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = + getQuadrantCoords (prow, pcol) (uint64 halfSize) + let t1, nvals1 = inner nwR nwC halfSize x1 let t2, nvals2 = inner neR neC halfSize x2 let t3, nvals3 = inner swR swC halfSize x3 @@ -246,18 +271,27 @@ let mapi (matrix: SparseMatrix<'a>) f = | Leaf(UserValue(v)) -> if size = 1UL then let res = f prow pcol v - let nnz = match res with Some _ -> 1UL | None -> 0UL + + let nnz = + match res with + | Some _ -> 1UL + | None -> 0UL + Leaf(UserValue(res)), nnz else let halfSize = size / 2UL - let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = getQuadrantCoords (prow, pcol) (uint64 halfSize) + + let (nwR, nwC), (neR, neC), (swR, swC), (seR, seC) = + getQuadrantCoords (prow, pcol) (uint64 halfSize) + let t1, nvals1 = inner nwR nwC halfSize (Leaf(UserValue(v))) let t2, nvals2 = inner neR neC halfSize (Leaf(UserValue(v))) let t3, nvals3 = inner swR swC halfSize (Leaf(UserValue(v))) let t4, nvals4 = inner seR seC halfSize (Leaf(UserValue(v))) (mkNode t1 t2 t3 t4), nvals1 + nvals2 + nvals3 + nvals4 - let storage, nvals = inner 0UL 0UL matrix.storage.size matrix.storage.data + let storage, nvals = + inner 0UL 0UL matrix.storage.size matrix.storage.data SparseMatrix(matrix.nrows, matrix.ncols, nvals, (Storage(matrix.storage.size, storage))) diff --git a/QuadTree/Result.fs b/QuadTree/Result.fs index 665dadb..09812d4 100644 --- a/QuadTree/Result.fs +++ b/QuadTree/Result.fs @@ -6,35 +6,40 @@ module Error = let mapError (f: 'e1 -> 'e2) (result: Result<'ok, 'e1>) : Result<'ok, 'e2> = match result with | Ok ok -> Ok ok - | Error err -> Error (f err) + | Error err -> Error(f err) type ResultBuilder() = member _.Return(x: 'ok) : Result<'ok, 'err> = Ok x member _.ReturnFrom(result: Result<'ok, 'err>) : Result<'ok, 'err> = result + member _.Bind(result: Result<'ok, 'err>, f: 'ok -> Result<'ok2, 'err>) : Result<'ok2, 'err> = match result with | Ok ok -> f ok | Error err -> Error err - member _.Zero() : Result = Ok () + + member _.Zero() : Result = Ok() member _.Delay(f: unit -> Result<'ok, 'err>) = f member _.Run(f: unit -> Result<'ok, 'err>) = f () + member this.While(guard: unit -> bool, body: unit -> Result) = - if guard() then - this.Bind(body(), fun () -> this.While(guard, body)) + if guard () then + this.Bind(body (), fun () -> this.While(guard, body)) else this.Zero() + member this.For(sequence: seq<'ok>, f: 'ok -> Result) = use en = sequence.GetEnumerator() this.While(en.MoveNext, fun () -> f en.Current) member _.Combine(result1: Result, result2: Result<'ok, 'err>) : Result<'ok, 'err> = match result1 with - | Ok () -> result2 + | Ok() -> result2 | Error err -> Error err member this.MergeSources(result1: Result<'ok1, 'err>, result2: Result<'ok2, 'err>) : Result<'ok1 * 'ok2, 'err> = match result1, result2 with - | Ok ok1, Ok ok2 -> Ok (ok1, ok2) - | Error err, _ | _, Error err -> Error err + | Ok ok1, Ok ok2 -> Ok(ok1, ok2) + | Error err, _ + | _, Error err -> Error err let resultM = ResultBuilder() diff --git a/QuadTree/SSSP.fs b/QuadTree/SSSP.fs index fc4d084..2ad701d 100644 --- a/QuadTree/SSSP.fs +++ b/QuadTree/SSSP.fs @@ -28,9 +28,7 @@ let sssp graph (startVertex: uint64) = let rec inner (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) iter_num = if frontier.nvals > 0UL && iter_num <= int frontier.length then resultM { - let! new_frontier = - LinearAlgebra.vxm op_add op_mult frontier graph - |> Result.mapError mapError + let! new_frontier = LinearAlgebra.vxm op_add op_mult frontier graph |> Result.mapError mapError let op_min x y = match (x, y) with @@ -38,13 +36,9 @@ let sssp graph (startVertex: uint64) = | Some v, _ -> Some v | _ -> None - let! frontier = - Vector.map2 new_frontier visited op_min - |> Result.mapError mapError' + let! frontier = Vector.map2 new_frontier visited op_min |> Result.mapError mapError' - let! visited = - Vector.map2 visited frontier op_add - |> Result.mapError mapError'' + let! visited = Vector.map2 visited frontier op_add |> Result.mapError mapError'' return! inner frontier visited (iter_num + 1) } diff --git a/QuadTree/TriangleCount.fs b/QuadTree/TriangleCount.fs index 08c355d..1f4314b 100644 --- a/QuadTree/TriangleCount.fs +++ b/QuadTree/TriangleCount.fs @@ -30,9 +30,7 @@ let triangle_count (graph: Matrix.SparseMatrix<_>) = LinearAlgebra.mxm op_add op_mult graph (Matrix.transpose graph) |> Result.mapError mapError - let! CMasked = - Matrix.mask C graph Option.isSome - |> Result.mapError mapError' + let! CMasked = Matrix.mask C graph Option.isSome |> Result.mapError mapError' return Matrix.foldAssociative op_add None CMasked } diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index 0a40ef5..0b04d91 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -47,44 +47,49 @@ type CoordinateList<'value> = new(_length, _data) = { length = _length; data = _data } let update (vector: SparseVector<_>) i v op = - let rec inner vector (i:uint64) size = - match vector with - | Leaf (UserValue x) -> - if size = 1UL - then + let rec inner vector (i: uint64) size = + match vector with + | Leaf(UserValue x) -> + if size = 1UL then let res = op x v - let deltaNNZ = + + let deltaNNZ = match (res, x) with | Some _, None -> 1L - | None , Some _ -> -1L - | _ -> 0 - Leaf (UserValue (op x v)), deltaNNZ - else - let halfSize = size / 2UL - if uint64 i < uint64 halfSize - then - let newVector, deltaNNZ = inner vector i halfSize + | None, Some _ -> -1L + | _ -> 0 + + Leaf(UserValue(op x v)), deltaNNZ + else + let halfSize = size / 2UL + + if uint64 i < uint64 halfSize then + let newVector, deltaNNZ = inner vector i halfSize (mkNode newVector vector), deltaNNZ - else - let newVector, deltaNNZ = inner vector ((uint64 i - uint64 halfSize)*1UL) halfSize + else + let newVector, deltaNNZ = + inner vector ((uint64 i - uint64 halfSize) * 1UL) halfSize + (mkNode vector newVector), deltaNNZ - | Node (x1,x2) -> - let halfSize = size / 2UL - if uint64 i < uint64 halfSize - then + | Node(x1, x2) -> + let halfSize = size / 2UL + + if uint64 i < uint64 halfSize then let newVector, deltaNNZ = inner x1 i halfSize (mkNode newVector x2), deltaNNZ - else - let newVector, deltaNNZ = inner x2 ((uint64 i - uint64 halfSize)*1UL) halfSize + else + let newVector, deltaNNZ = + inner x2 ((uint64 i - uint64 halfSize) * 1UL) halfSize + (mkNode x1 newVector), deltaNNZ | _ -> failwith "Unreachable. But seams that index out of range." - - if uint64 i <= uint64 vector.length - then - let storage, deltaNNZ = inner vector.storage.data i vector.storage.size + + if uint64 i <= uint64 vector.length then + let storage, deltaNNZ = inner vector.storage.data i vector.storage.size let nvals = uint64 (int64 vector.nvals + deltaNNZ) * 1UL - Ok (SparseVector (vector.length, nvals, Storage(vector.storage.size, storage))) - else Error Error.InconsistentSizeOfArguments + Ok(SparseVector(vector.length, nvals, Storage(vector.storage.size, storage))) + else + Error Error.InconsistentSizeOfArguments let fromCoordinateList (lst: CoordinateList<'a>) : SparseVector<'a> = let length = lst.length @@ -127,24 +132,24 @@ let toCoordinateList (vector: SparseVector<'a>) = let lAccum = traverse left accum pointer halfSize let rAccum = traverse right lAccum (pointer + halfSize) halfSize rAccum - + let lst = traverse vector.storage.data [] 0UL ((uint64 vector.storage.size) * 1UL) CoordinateList(length, lst) let empty length = - fromCoordinateList (CoordinateList(length,[])) + fromCoordinateList (CoordinateList(length, [])) -let foldValues (vector: SparseVector<'a>) (f: 'b -> 'a -> 'b) (state:'b) = - let rec inner state (size: uint64) vector= +let foldValues (vector: SparseVector<'a>) (f: 'b -> 'a -> 'b) (state: 'b) = + let rec inner state (size: uint64) vector = match vector with - | Leaf (UserValue (Some v)) -> - let lst = List.replicate (int size) v + | Leaf(UserValue(Some v)) -> + let lst = List.replicate (int size) v List.fold f state lst - | Node (x1, x2) -> + | Node(x1, x2) -> let halfSize = size / 2UL - inner (inner state halfSize x1) halfSize x2 + inner (inner state halfSize x1) halfSize x2 | _ -> state inner state vector.storage.size vector.storage.data @@ -182,14 +187,22 @@ let mapi (vector: SparseVector<'a>) f = (mkNode t1 t2), nvals1 + nvals2 | Leaf(Dummy) -> Leaf(Dummy), 0UL | Leaf(UserValue(v)) -> - if size = 1UL then + if size = 1UL then let res = f pointer v - let nnz = match res with Some _ -> 1UL | None -> 0UL + + let nnz = + match res with + | Some _ -> 1UL + | None -> 0UL + Leaf(UserValue(res)), nnz - else + else let halfSize = size / 2UL let t1, nvals1 = inner pointer halfSize (Leaf(UserValue(v))) - let t2, nvals2 = inner (pointer + (uint64 halfSize) * 1UL) halfSize (Leaf(UserValue(v))) + + let t2, nvals2 = + inner (pointer + (uint64 halfSize) * 1UL) halfSize (Leaf(UserValue(v))) + (mkNode t1 t2), nvals1 + nvals2 let storage, nvals = inner 0UL vector.storage.size vector.storage.data @@ -208,7 +221,11 @@ let init (length: uint64) (f: uint64 -> Option<'a>) : SparseV Leaf Dummy, 0UL else let v = f pointer - Leaf(UserValue v), (match v with Some _ -> 1UL | None -> 0UL) + + Leaf(UserValue v), + (match v with + | Some _ -> 1UL + | None -> 0UL) else let halfSize = size / 2UL let left, nvals1 = build pointer halfSize @@ -228,8 +245,7 @@ let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = let new_size = size / 2UL match (inner new_size x1 y1), (inner new_size x2 y2) with - | Ok((t1, nvals1)), Ok((t2, nvals2)) -> - ((mkNode t1 t2), nvals1 + nvals2) |> Ok + | Ok((t1, nvals1)), Ok((t2, nvals2)) -> ((mkNode t1 t2), nvals1 + nvals2) |> Ok | Error(e), _ | _, Error(e) -> Error(e) @@ -253,8 +269,7 @@ let map2 (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = if len1 = vector2.length then match inner vector1.storage.size vector1.storage.data vector2.storage.data with | Error(e) -> Error(e) - | Ok((storage, nvals)) -> - Ok(SparseVector(len1, nvals, (Storage(vector1.storage.size, storage)))) + | Ok((storage, nvals)) -> Ok(SparseVector(len1, nvals, (Storage(vector1.storage.size, storage)))) else Error Error.InconsistentSizeOfArguments @@ -274,55 +289,81 @@ let map2i (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = | Node(x1, x2), Leaf(v2) -> let halfSize = size / 2UL let t1, nvals1 = inner pointer halfSize x1 (Leaf(v2)) - let t2, nvals2 = inner (pointer + (uint64 halfSize) * 1UL) halfSize x2 (Leaf(v2)) + + let t2, nvals2 = + inner (pointer + (uint64 halfSize) * 1UL) halfSize x2 (Leaf(v2)) + (mkNode t1 t2), nvals1 + nvals2 | Leaf(v1), Node(y1, y2) -> let halfSize = size / 2UL let t1, nvals1 = inner pointer halfSize (Leaf(v1)) y1 - let t2, nvals2 = inner (pointer + (uint64 halfSize) * 1UL) halfSize (Leaf(v1)) y2 + + let t2, nvals2 = + inner (pointer + (uint64 halfSize) * 1UL) halfSize (Leaf(v1)) y2 + (mkNode t1 t2), nvals1 + nvals2 | Leaf(Dummy), Leaf(Dummy) -> Leaf(Dummy), 0UL | Leaf(UserValue(v1)), Leaf(UserValue(v2)) -> let res = f pointer v1 v2 - let nnz = match res with Some _ -> 1UL | None -> 0UL + + let nnz = + match res with + | Some _ -> 1UL + | None -> 0UL + Leaf(UserValue(res)), nnz | Leaf(UserValue(v)), Leaf(Dummy) -> let res = f pointer v None - let nnz = match res with Some _ -> 1UL | None -> 0UL + + let nnz = + match res with + | Some _ -> 1UL + | None -> 0UL + Leaf(UserValue(res)), nnz | Leaf(Dummy), Leaf(UserValue(v)) -> let res = f pointer None v - let nnz = match res with Some _ -> 1UL | None -> 0UL + + let nnz = + match res with + | Some _ -> 1UL + | None -> 0UL + Leaf(UserValue(res)), nnz | (x, y) -> failwithf "InconsistentStructureOfStorages: %A vs %A" x y if len1 = vector2.length then - let storage, nvals = inner 0UL vector1.storage.size vector1.storage.data vector2.storage.data + let storage, nvals = + inner 0UL vector1.storage.size vector1.storage.data vector2.storage.data + SparseVector(len1, nvals, (Storage(vector1.storage.size, storage))) else failwithf "InconsistentSizeOfArguments: %A vs %A" vector1 vector2 /// Returns None if index out of range -let unsafeGet (v : SparseVector<'a>) (index : uint64) = +let unsafeGet (v: SparseVector<'a>) (index: uint64) = let originalIndex = index - let rec getFromTree (tree : btree>) (size : uint64) (index : uint64) = - match tree with + + let rec getFromTree (tree: btree>) (size: uint64) (index: uint64) = + match tree with | Leaf Dummy -> None - | Leaf (UserValue v) -> v + | Leaf(UserValue v) -> v | Node(l: Option<'a> btree, r) -> - let halfSize = size / 2UL - if uint64 index < uint64 halfSize then - getFromTree l halfSize index - else - getFromTree r halfSize ((uint64 index - uint64 halfSize)*1UL) + let halfSize = size / 2UL + + if uint64 index < uint64 halfSize then + getFromTree l halfSize index + else + getFromTree r halfSize ((uint64 index - uint64 halfSize) * 1UL) + getFromTree v.storage.data v.storage.size index /// Gather: w[i] = v[idx[i]] -let gather (v : SparseVector<'value>) (idx : SparseVector>) : SparseVector<'value> = - map idx (fun i -> - match i with - | Some i-> unsafeGet v i +let gather (v: SparseVector<'value>) (idx: SparseVector>) : SparseVector<'value> = + map idx (fun i -> + match i with + | Some i -> unsafeGet v i | None -> None) let mergeSort (v: SparseVector<'a>) (compare: Option<'a> -> Option<'a> -> int) : SparseVector<'a> = @@ -334,7 +375,7 @@ let mergeSort (v: SparseVector<'a>) (compare: Option<'a> -> Option<'a> -> int) : match tree with | Leaf Dummy -> [] | Leaf(UserValue None) -> [] - | Leaf(UserValue v) -> [v] + | Leaf(UserValue v) -> [ v ] | Node(l, r) -> extract l @ extract r // Place sorted values into original tree structure @@ -342,7 +383,7 @@ let mergeSort (v: SparseVector<'a>) (compare: Option<'a> -> Option<'a> -> int) : match tree, sortedVals with | Leaf Dummy, rest -> Leaf Dummy, rest | Leaf(UserValue None), rest -> Leaf(UserValue None), rest - | Leaf(UserValue _), v::rest -> Leaf(UserValue v), rest + | Leaf(UserValue _), v :: rest -> Leaf(UserValue v), rest | Leaf(UserValue _), [] -> Leaf Dummy, [] | Node(l, r), vals -> let l', r1 = place l vals @@ -373,17 +414,28 @@ let mergeSort (v: SparseVector<'a>) (compare: Option<'a> -> Option<'a> -> int) : merge mewLeft newRight *) -//type ScatterError<'a> = +//type ScatterError<'a> = /// Scatter: w[idx[i]] = op(w[idx[i]], v[i]) -let scatter (w: SparseVector<'value>) (v: SparseVector<'value>) (idx: SparseVector>) - (op: Option<'value> -> Option<'value> -> Option<'value>) = - let pairsVec = map2 idx v (fun i v -> match i, v with Some i, Some v -> Some(i, v) | _ -> None) +let scatter + (w: SparseVector<'value>) + (v: SparseVector<'value>) + (idx: SparseVector>) + (op: Option<'value> -> Option<'value> -> Option<'value>) + = + let pairsVec = + map2 idx v (fun i v -> + match i, v with + | Some i, Some v -> Some(i, v) + | _ -> None) + match pairsVec with - | Ok pv -> - foldValues pv (fun state (idx, v) -> - match state with - | Ok state -> update state idx (Some v) op - | Error x -> Error x) - (Ok w) + | Ok pv -> + foldValues + pv + (fun state (idx, v) -> + match state with + | Ok state -> update state idx (Some v) op + | Error x -> Error x) + (Ok w) | Error x -> Error Error.InconsistentStructureOfStorages From 6eaf7e7fd9f39199c84ffc0a1b30516d3445d8af Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 5 May 2026 08:53:52 +0300 Subject: [PATCH 44/52] Fixed 'This rule will never be matched' warning. --- QuadTree/LinearAlgebra.fs | 2 -- QuadTree/Matrix.fs | 1 - QuadTree/Vector.fs | 1 - 3 files changed, 4 deletions(-) diff --git a/QuadTree/LinearAlgebra.fs b/QuadTree/LinearAlgebra.fs index e8e67ed..7405e02 100644 --- a/QuadTree/LinearAlgebra.fs +++ b/QuadTree/LinearAlgebra.fs @@ -71,7 +71,6 @@ let vxm op_add op_mult (vector: Vector.SparseVector<'a>) (matrix: Matrix.SparseM | Vector.btree.Leaf(Dummy), _ | _, Matrix.qtree.Leaf(Dummy) -> Ok(Vector.btree.Leaf(Dummy), 0UL) - | (x, y) -> Error Error.InconsistentStructureOfStorages if uint64 vector.length = uint64 matrix.nrows then let vector_storage = @@ -191,7 +190,6 @@ let vxmi_values | Vector.btree.Leaf(Dummy), _ | _, Matrix.qtree.Leaf(Dummy) -> Ok(Vector.btree.Leaf(Dummy), 0UL) - | (x, y) -> Error Error.InconsistentStructureOfStorages if uint64 vector.length = uint64 matrix.nrows then let vector_storage = diff --git a/QuadTree/Matrix.fs b/QuadTree/Matrix.fs index 17f09ee..b6d69c3 100644 --- a/QuadTree/Matrix.fs +++ b/QuadTree/Matrix.fs @@ -243,7 +243,6 @@ let map2i (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = | None -> 0UL Leaf(UserValue(res)), nnz - | (x, y) -> failwithf "InconsistentStructureOfStorages: %A vs %A" x y if matrix1.nrows = matrix2.nrows && matrix1.ncols = matrix2.ncols then let storage, nvals = diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index 0b04d91..25936c2 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -330,7 +330,6 @@ let map2i (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = | None -> 0UL Leaf(UserValue(res)), nnz - | (x, y) -> failwithf "InconsistentStructureOfStorages: %A vs %A" x y if len1 = vector2.length then let storage, nvals = From 545c19e80e0a5be83f5e749206e364d0fff9a0ab Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 5 May 2026 08:57:50 +0300 Subject: [PATCH 45/52] Turn test on Vector.scatter on. --- QuadTree.Tests/Tests.Vector.fs | 56 +++++++++++++--------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index bad099d..7e3bc17 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -475,47 +475,35 @@ let ``Gather`` () = |> Vector.fromCoordinateList Assert.Equal(expected, actual) -(* -[] -let ``Scatter``() = - let data = - Vector.CoordinateList( - 5UL, - [ (0UL, 4.0) - (2UL, 5.0) - ] - ) + +[] +let ``Scatter`` () = + let data = + Vector.CoordinateList(5UL, [ (0UL, 4.0); (2UL, 5.0) ]) |> Vector.fromCoordinateList - let indices = - Vector.CoordinateList( - 5UL, - [ (0UL, 3UL) - (2UL, 3UL) - ] - ) + let indices = + Vector.CoordinateList(5UL, [ (0UL, 3UL); (2UL, 3UL) ]) |> Vector.fromCoordinateList - let result = - Vector.CoordinateList( - 5UL, - [ (3UL, 1.0) - (4UL, 3.0) - ] - ) + let result = + Vector.CoordinateList(5UL, [ (3UL, 1.0); (4UL, 3.0) ]) |> Vector.fromCoordinateList - let actual = Vector.scatter result data indices (fun x y -> match (x,y) with | (Some x, Some y) -> Some (x + y) | Some x, _ | _, Some x -> Some x | _ -> None) - printVector actual - let expected = - Vector.CoordinateList( - 5UL, - [ (3UL, 10.0) - (4UL, 3.0) - ] - ) + + let actual = + Vector.scatter result data indices (fun x y -> + match (x, y) with + | Some x, Some y -> Some(x + y) + | Some x, _ + | _, Some x -> Some x + | _ -> None) + + let expected = + Vector.CoordinateList(5UL, [ (3UL, 10.0); (4UL, 3.0) ]) |> Vector.fromCoordinateList + |> Result.Ok - Assert.Equal(expected, actual)*) + Assert.Equal(expected, actual) let compare x y = match (x, y) with From da2abcfdf1e66bc98b67bbe2c970053b006a1b8a Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 5 May 2026 09:15:12 +0300 Subject: [PATCH 46/52] Removed trivial error remapping helpers. --- QuadTree/BFS.fs | 14 +++++--------- QuadTree/Boruvka.fs | 18 ++++++------------ QuadTree/SSSP.fs | 10 +++------- QuadTree/TriangleCount.fs | 11 ++++------- 4 files changed, 18 insertions(+), 35 deletions(-) diff --git a/QuadTree/BFS.fs b/QuadTree/BFS.fs index 56caf37..0ba2fc5 100644 --- a/QuadTree/BFS.fs +++ b/QuadTree/BFS.fs @@ -8,10 +8,6 @@ type Error = | FrontierCalculationProblem of Vector.Error | VisitedCalculationProblem of Vector.Error -let mapError (err: LinearAlgebra.Error) = NewFrontierCalculationProblem err -let mapError' (err: Vector.Error) = FrontierCalculationProblem err -let mapError'' (err: Vector.Error) = VisitedCalculationProblem err - let bfs_level graph startVertices = let rec inner level (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) = if frontier.nvals > 0UL then @@ -29,19 +25,19 @@ let bfs_level graph startVertices = | _ -> None) frontier graph - |> Result.mapError mapError + |> Result.mapError NewFrontierCalculationProblem let! frontier = Vector.mask new_frontier visited (fun x -> x.IsNone) - |> Result.mapError mapError' + |> Result.mapError FrontierCalculationProblem let! visited = Vector.map2 visited new_frontier (fun x y -> match (x, y) with - | (Some(_), _) -> x - | (None, Some(_)) -> Some(level) + | Some(_), _ -> x + | None, Some(_) -> Some(level) | _ -> None) - |> Result.mapError mapError'' + |> Result.mapError VisitedCalculationProblem return! inner (level + 1UL) frontier visited } diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index cdf3afb..2338ecb 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -9,13 +9,7 @@ type Error = | CEdgesCalculationProblem of Vector.Error | IndexCalculationProblem of Vector.Error | ScatterProblem of Vector.Error - | FoldValuesError of Vector.Error - -let mapError (err: LinearAlgebra.Error) = EdgesCalculationProblem err -let mapError' (err: Vector.Error) = CEdgesCalculationProblem err -let mapError'' (err: Vector.Error) = IndexCalculationProblem err -let mapError''' (err: Vector.Error) = ScatterProblem err -let mapError'''' (err: Vector.Error) = FoldValuesError err + | FoldValuesProblem of Vector.Error let printMatrixCoordinate (matrix: Matrix.SparseMatrix<_>) = @@ -97,7 +91,7 @@ let mst (graph: Matrix.SparseMatrix<_>) = resultM { let! edges = LinearAlgebra.vxmi_values op_min op_mult parent graph - |> Result.mapError mapError + |> Result.mapError EdgesCalculationProblem printfn "=== Edges ===" printVector edges @@ -106,7 +100,7 @@ let mst (graph: Matrix.SparseMatrix<_>) = // For each component, keep the smallest edges among its vertices. let! cedges = Vector.scatter (Vector.empty length) edges parent op_min - |> Result.mapError mapError' + |> Result.mapError CEdgesCalculationProblem printfn "=== Component Edges ===" printVector cedges @@ -125,7 +119,7 @@ let mst (graph: Matrix.SparseMatrix<_>) = // Among the marked vertices in a component, keep the smallest index. let! index = Vector.scatter (Vector.empty length) indexInner parent op_min - |> Result.mapError mapError'' + |> Result.mapError IndexCalculationProblem // now each vertex knows its component's representative let index = Vector.gather index parent @@ -177,14 +171,14 @@ let mst (graph: Matrix.SparseMatrix<_>) = | Error e -> Error e | Error e -> Error e) (Ok parent) - |> Result.mapError mapError'''' + |> Result.mapError FoldValuesProblem printfn "=== Initial parent update ===" printVector initial_parent_update let! parent = Vector.scatter parent initial_parent_update parent op_min - |> Result.mapError mapError''' + |> Result.mapError ScatterProblem printfn "=== Initially updated parent ===" printVector parent diff --git a/QuadTree/SSSP.fs b/QuadTree/SSSP.fs index 2ad701d..59cc864 100644 --- a/QuadTree/SSSP.fs +++ b/QuadTree/SSSP.fs @@ -8,10 +8,6 @@ type Error = | FrontierCalculationProblem of Vector.Error | VisitedCalculationProblem of Vector.Error -let mapError (err: LinearAlgebra.Error) = NewFrontierCalculationProblem err -let mapError' (err: Vector.Error) = FrontierCalculationProblem err -let mapError'' (err: Vector.Error) = VisitedCalculationProblem err - let sssp graph (startVertex: uint64) = let op_add x y = match (x, y) with @@ -28,7 +24,7 @@ let sssp graph (startVertex: uint64) = let rec inner (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) iter_num = if frontier.nvals > 0UL && iter_num <= int frontier.length then resultM { - let! new_frontier = LinearAlgebra.vxm op_add op_mult frontier graph |> Result.mapError mapError + let! new_frontier = LinearAlgebra.vxm op_add op_mult frontier graph |> Result.mapError NewFrontierCalculationProblem let op_min x y = match (x, y) with @@ -36,9 +32,9 @@ let sssp graph (startVertex: uint64) = | Some v, _ -> Some v | _ -> None - let! frontier = Vector.map2 new_frontier visited op_min |> Result.mapError mapError' + let! frontier = Vector.map2 new_frontier visited op_min |> Result.mapError FrontierCalculationProblem - let! visited = Vector.map2 visited frontier op_add |> Result.mapError mapError'' + let! visited = Vector.map2 visited frontier op_add |> Result.mapError VisitedCalculationProblem return! inner frontier visited (iter_num + 1) } diff --git a/QuadTree/TriangleCount.fs b/QuadTree/TriangleCount.fs index 1f4314b..3260a2d 100644 --- a/QuadTree/TriangleCount.fs +++ b/QuadTree/TriangleCount.fs @@ -4,11 +4,8 @@ open Common open Result type Error = - | MXMError of LinearAlgebra.Error - | MaskingError of Matrix.Error - -let mapError (err: LinearAlgebra.Error) = MXMError err -let mapError' (err: Matrix.Error) = MaskingError err + | MXMProblem of LinearAlgebra.Error + | MaskingProblem of Matrix.Error let triangle_count (graph: Matrix.SparseMatrix<_>) = let graph = Matrix.getLowerTriangle graph @@ -28,9 +25,9 @@ let triangle_count (graph: Matrix.SparseMatrix<_>) = resultM { let! C = LinearAlgebra.mxm op_add op_mult graph (Matrix.transpose graph) - |> Result.mapError mapError + |> Result.mapError MXMProblem - let! CMasked = Matrix.mask C graph Option.isSome |> Result.mapError mapError' + let! CMasked = Matrix.mask C graph Option.isSome |> Result.mapError MaskingProblem return Matrix.foldAssociative op_add None CMasked } From fc218360184345b2bceccceb3afda3ed9766e352 Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 5 May 2026 09:41:56 +0300 Subject: [PATCH 47/52] Partially removed debug printing. --- QuadTree.Tests/Tests.Boruvka.fs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/QuadTree.Tests/Tests.Boruvka.fs b/QuadTree.Tests/Tests.Boruvka.fs index c55e920..6f2e2a0 100644 --- a/QuadTree.Tests/Tests.Boruvka.fs +++ b/QuadTree.Tests/Tests.Boruvka.fs @@ -24,7 +24,6 @@ let checkResult name actual expected = [] let ``Boruvka MST 2 nodes.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -51,7 +50,6 @@ let ``Boruvka MST 2 nodes.`` () = [] let ``Boruvka MST 3 nodes line.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -85,7 +83,6 @@ let ``Boruvka MST 3 nodes line.`` () = [] let ``Boruvka MST 4 nodes line.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -122,7 +119,6 @@ let ``Boruvka MST 4 nodes line.`` () = [] let ``Boruvka MST 5 nodes line.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -163,7 +159,6 @@ let ``Boruvka MST 5 nodes line.`` () = [] let ``Boruvka MST 5 nodes star.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -204,7 +199,6 @@ let ``Boruvka MST 5 nodes star.`` () = [] let ``Boruvka MST 5 nodes complete.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -257,7 +251,6 @@ let ``Boruvka MST 5 nodes complete.`` () = [] let ``Boruvka MST two components.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -305,7 +298,6 @@ let ``Boruvka MST two components.`` () = [] let ``Boruvka MST cycle graph 6 nodes.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -349,10 +341,8 @@ let ``Boruvka MST cycle graph 6 nodes.`` () = checkResult (Graph.Boruvka.mst graph) expected -///!!!!!!!! [] let ``Boruvka MST complete bipartite K3,3.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -414,7 +404,6 @@ let ``Boruvka MST complete bipartite K3,3.`` () = [] let ``Boruvka MST random weights.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -481,7 +470,6 @@ let ``Boruvka MST random weights.`` () = [] let ``Boruvka MST 8 nodes grid.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -543,7 +531,6 @@ let ``Boruvka MST 8 nodes grid.`` () = [] let ``Boruvka MST 10 nodes random.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -620,7 +607,6 @@ let ``Boruvka MST 10 nodes random.`` () = [] let ``Boruvka MST simple triangle.`` () = - printfn "!!! TEST STARTING !!!" let graph = let clist = @@ -661,7 +647,6 @@ let ``Boruvka MST simple triangle.`` () = [] let ``Boruvka MST simple square.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -710,7 +695,6 @@ let ``Boruvka MST simple square.`` () = [] let ``Boruvka MST simple square in two steps.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -759,7 +743,6 @@ let ``Boruvka MST simple square in two steps.`` () = [] let ``Boruvka MST.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -836,7 +819,6 @@ let ``Boruvka MST.`` () = [] let ``Boruvka MST big.`` () = - System.Console.Error.WriteLine("TEST STARTING") let graph = let clist = @@ -879,7 +861,6 @@ let ``Boruvka MST big.`` () = 8UL, 10UL, 1UL 10UL, 8UL, 1UL //================================================ - //================================================ 1UL, 2UL, 2UL 2UL, 1UL, 2UL @@ -892,7 +873,6 @@ let ``Boruvka MST big.`` () = 8UL, 7UL, 2UL 7UL, 8UL, 2UL //================================================ - //================================================ 10UL, 11UL, 3UL 11UL, 10UL, 3UL From ba858e01252ab6472ef150017b89d35ccc1a57de Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 5 May 2026 09:42:33 +0300 Subject: [PATCH 48/52] Result instead of failwith. --- QuadTree.Tests/Tests.Matrix.fs | 51 ++++++++++++++++++++++++++++------ QuadTree.Tests/Tests.Vector.fs | 17 +++++++++--- QuadTree/Boruvka.fs | 20 ++++++++----- QuadTree/Matrix.fs | 3 +- QuadTree/Vector.fs | 4 +-- 5 files changed, 73 insertions(+), 22 deletions(-) diff --git a/QuadTree.Tests/Tests.Matrix.fs b/QuadTree.Tests/Tests.Matrix.fs index 347fbfa..816b4a2 100644 --- a/QuadTree.Tests/Tests.Matrix.fs +++ b/QuadTree.Tests/Tests.Matrix.fs @@ -191,10 +191,21 @@ let ``Simple Matrix.map2i. Square where number of cols and rows are power of two | Some(a), Some(b) -> Some(a + b + int row + int col) | _ -> None + let expected = + Matrix.CoordinateList( + 4UL, + 4UL, + [ (0UL, 0UL, 11) + (0UL, 1UL, 23) + (1UL, 0UL, 34) + (1UL, 1UL, 46) ] + ) + |> Matrix.fromCoordinateList + |> Ok + let actual = Matrix.map2i m1 m2 f - let actualCL = Matrix.toCoordinateList actual - Assert.Equal(4UL, actual.nvals) + Assert.Equal(expected, actual) [] let ``Simple Matrix.map2i. Square where number of cols and rows are not power of two.`` () = @@ -232,9 +243,22 @@ let ``Simple Matrix.map2i. Square where number of cols and rows are not power of | _ -> None let actual = Matrix.map2i m1 m2 f - let actualCL = Matrix.toCoordinateList actual - Assert.Equal(6UL, actual.nvals) + let expected = + Matrix.CoordinateList( + 3UL, + 3UL, + [ (0UL, 0UL, 11) + (0UL, 1UL, 22) + (0UL, 2UL, 33) + (1UL, 0UL, 18) + (1UL, 1UL, 30) + (1UL, 2UL, 42) ] + ) + |> Matrix.fromCoordinateList + |> Ok + + Assert.Equal(expected, actual) [] let ``Simple Matrix.map2i. Mixed values.`` () = @@ -259,14 +283,25 @@ let ``Simple Matrix.map2i. Mixed values.`` () = let f row col x y = match (x, y) with | Some(a), Some(b) -> Some(a + b) - | Some(a), None -> Some(a * 2) - | None, Some(b) -> Some(b * 3) + | Some(a), None -> Some(int col + a * 2) + | None, Some(b) -> Some(int row + b * 3) | _ -> None let actual = Matrix.map2i m1 m2 f - let actualCL = Matrix.toCoordinateList actual - Assert.Equal(4UL, actual.nvals) + let expected = + Matrix.CoordinateList( + 4UL, + 4UL, + [ (0UL, 0UL, 2) + (1UL, 1UL, 31) + (2UL, 2UL, 8) + (3UL, 3UL, 93) ] + ) + |> Matrix.fromCoordinateList + |> Ok + + Assert.Equal(expected, actual) [] let ``Simple Matrix.mapi. Square where number of cols and rows are power of two.`` () = diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index 7e3bc17..5e5c973 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -311,6 +311,7 @@ let ``Simple Vector.map2i. Length is power of two.`` () = [ (0UL, 11); (1UL, 23); (2UL, 35); (3UL, 47) ] ) ) + |> Ok let actual = Vector.map2i v1 v2 f @@ -361,6 +362,7 @@ let ``Simple Vector.map2i. Length is not power of two.`` () = (5UL, 40) ] ) ) + |> Ok let actual = Vector.map2i v1 v2 f @@ -377,14 +379,21 @@ let ``Simple Vector.map2i. Mixed values.`` () = let f idx x y = match (x, y) with | Some(a), Some(b) -> Some(a + b) - | Some(a), None -> Some(a * 2) - | None, Some(b) -> Some(b * 3) + | Some(a), None -> Some(int idx + a * 2) + | None, Some(b) -> Some(int idx * b * 3) | _ -> None let actual = Vector.map2i v1 v2 f - let actualCL = Vector.toCoordinateList actual - Assert.Equal(4UL, actual.nvals) + let expected = + Vector.CoordinateList( + 4UL, + [ (0UL, 2); (1UL, 30); (2UL, 8); (3UL, 270) ] + ) + |> Vector.fromCoordinateList + |> Ok + + Assert.Equal(expected, actual) [] let ``Conversion identity`` () = diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index 2338ecb..f6569eb 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -10,6 +10,9 @@ type Error = | IndexCalculationProblem of Vector.Error | ScatterProblem of Vector.Error | FoldValuesProblem of Vector.Error + | TreeSelectionProblem of Matrix.Error + | IndexInnerCalculationProblem of Vector.Error + | DataForUpgradeParentCalculationProblem of Vector.Error let printMatrixCoordinate (matrix: Matrix.SparseMatrix<_>) = @@ -28,7 +31,7 @@ let mst (graph: Matrix.SparseMatrix<_>) = let op_mult (i, x) (row, col, w) = Some(w, row) let op_min x y = - match (x, y) with + match x, y with | Some v, Some u -> Some(min v u) | Some v, _ -> Some v | None, Some v -> Some v @@ -66,7 +69,7 @@ let mst (graph: Matrix.SparseMatrix<_>) = let parent_i = Vector.unsafeGet parent i let parent_j = Vector.unsafeGet parent j - match (parent_i, parent_j) with + match parent_i, parent_j with | Some v1, Some v2 when v1 <> v2 -> true | _ -> false @@ -111,11 +114,12 @@ let mst (graph: Matrix.SparseMatrix<_>) = // Identify a representative vertex for each component // For each vertex, if its own edge is the component's cheapest, mark it. - let indexInner = + let! indexInner = Vector.map2i t edges (fun i t e -> match (t, e) with | Some v1, Some v2 when v1 = v2 -> Some i | _ -> None) + |> Result.mapError IndexInnerCalculationProblem // Among the marked vertices in a component, keep the smallest index. let! index = Vector.scatter (Vector.empty length) indexInner parent op_min @@ -131,17 +135,18 @@ let mst (graph: Matrix.SparseMatrix<_>) = // and (i, j, w) is the cheapest edge of that component. let treeFilter = treeFilter edges index - let tree = + let! tree = Matrix.map2i tree graph (fun i j t g -> - match (t, g) with + match t, g with | Some t, _ -> Some t | None, Some g when treeFilter i j g -> Some g | _ -> None) + |> Result.mapError TreeSelectionProblem // Compute new parent assignments (merge components) // For each component representative i with cheapest edge (w, j), we want to merge // the component of i with the component of j. Choose the smaller root. - let data_for_update_parent = + let! data_for_update_parent = Vector.map2i edges index (fun i e idx -> match e, idx with | Some(v, j), Some(_i) when _i = i -> @@ -153,6 +158,7 @@ let mst (graph: Matrix.SparseMatrix<_>) = | Some p_i, Some p_j -> if p_i < p_j then Some(j, p_i) else Some(i, p_j) | x -> failwithf "Unreachable: %A" x | _ -> None) + |> Result.mapError DataForUpgradeParentCalculationProblem printfn "=== Data for update parent ===" printVector data_for_update_parent @@ -164,7 +170,7 @@ let mst (graph: Matrix.SparseMatrix<_>) = (fun state (i, v) -> match state with | Ok state -> - let updateResult = Vector.update state i (Some v) (fun old _new -> _new) + let updateResult = Vector.update state i (Some v) (fun _ _new -> _new) match updateResult with | Ok u -> Ok u diff --git a/QuadTree/Matrix.fs b/QuadTree/Matrix.fs index b6d69c3..68ea7d7 100644 --- a/QuadTree/Matrix.fs +++ b/QuadTree/Matrix.fs @@ -249,8 +249,9 @@ let map2i (matrix1: SparseMatrix<_>) (matrix2: SparseMatrix<_>) f = inner 0UL 0UL matrix1.storage.size matrix1.storage.data matrix2.storage.data SparseMatrix(matrix1.nrows, matrix1.ncols, nvals, (Storage(matrix1.storage.size, storage))) + |> Ok else - failwithf "InconsistentSizeOfArguments: %A vs %A" matrix1 matrix2 + Error Error.InconsistentSizeOfArguments let mapi (matrix: SparseMatrix<'a>) f = let rec inner (prow: uint64) (pcol: uint64) (size: uint64) matrix = diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index 25936c2..ad3333b 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -335,9 +335,9 @@ let map2i (vector1: SparseVector<'a>) (vector2: SparseVector<'b>) f = let storage, nvals = inner 0UL vector1.storage.size vector1.storage.data vector2.storage.data - SparseVector(len1, nvals, (Storage(vector1.storage.size, storage))) + SparseVector(len1, nvals, (Storage(vector1.storage.size, storage))) |> Ok else - failwithf "InconsistentSizeOfArguments: %A vs %A" vector1 vector2 + Error InconsistentSizeOfArguments /// Returns None if index out of range From 38afc9153a12fcb88d20316126dcbae096364c71 Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 5 May 2026 11:05:05 +0300 Subject: [PATCH 49/52] Formatted. --- QuadTree/SSSP.fs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/QuadTree/SSSP.fs b/QuadTree/SSSP.fs index 59cc864..9a40fde 100644 --- a/QuadTree/SSSP.fs +++ b/QuadTree/SSSP.fs @@ -24,7 +24,9 @@ let sssp graph (startVertex: uint64) = let rec inner (frontier: Vector.SparseVector<_>) (visited: Vector.SparseVector<_>) iter_num = if frontier.nvals > 0UL && iter_num <= int frontier.length then resultM { - let! new_frontier = LinearAlgebra.vxm op_add op_mult frontier graph |> Result.mapError NewFrontierCalculationProblem + let! new_frontier = + LinearAlgebra.vxm op_add op_mult frontier graph + |> Result.mapError NewFrontierCalculationProblem let op_min x y = match (x, y) with @@ -32,7 +34,9 @@ let sssp graph (startVertex: uint64) = | Some v, _ -> Some v | _ -> None - let! frontier = Vector.map2 new_frontier visited op_min |> Result.mapError FrontierCalculationProblem + let! frontier = + Vector.map2 new_frontier visited op_min + |> Result.mapError FrontierCalculationProblem let! visited = Vector.map2 visited frontier op_add |> Result.mapError VisitedCalculationProblem From 2b12fcffc19947ed026ba376206278032ddc613e Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 5 May 2026 11:17:35 +0300 Subject: [PATCH 50/52] Removed debug printing. --- QuadTree.Tests/Tests.Vector.fs | 3 --- QuadTree/Boruvka.fs | 41 ---------------------------------- 2 files changed, 44 deletions(-) diff --git a/QuadTree.Tests/Tests.Vector.fs b/QuadTree.Tests/Tests.Vector.fs index 5e5c973..c74216a 100644 --- a/QuadTree.Tests/Tests.Vector.fs +++ b/QuadTree.Tests/Tests.Vector.fs @@ -574,7 +574,6 @@ let ``Sort long vector with one element`` () = |> Vector.fromCoordinateList let actual = Vector.mergeSort data compare - printVector actual Assert.Equal(data, actual) @@ -596,6 +595,4 @@ let ``Init vector`` () = |> Vector.fromCoordinateList let actual = Vector.init 3UL (fun i -> Some(int i)) - //printfn "++++ Vector inint ++++" - //printVector actual Assert.Equal(expected, actual) diff --git a/QuadTree/Boruvka.fs b/QuadTree/Boruvka.fs index f6569eb..c0ed119 100644 --- a/QuadTree/Boruvka.fs +++ b/QuadTree/Boruvka.fs @@ -14,18 +14,6 @@ type Error = | IndexInnerCalculationProblem of Vector.Error | DataForUpgradeParentCalculationProblem of Vector.Error - -let printMatrixCoordinate (matrix: Matrix.SparseMatrix<_>) = - printfn "Matrix:" - printfn " Nvals: %A" matrix.nvals - printfn " Data: %A" (Matrix.toCoordinateList matrix).list - -let printVector (vector: Vector.SparseVector<_>) = - printfn "Vector:" - printfn " Nvals: %A" vector.nvals - printfn " Data: %A" (Vector.toCoordinateList vector).data - - let mst (graph: Matrix.SparseMatrix<_>) = let op_mult (i, x) (row, col, w) = Some(w, row) @@ -57,9 +45,6 @@ let mst (graph: Matrix.SparseMatrix<_>) = | Some(w, dst), Some idxVal -> g = w && idxVal = i && uint64 dst = uint64 j | _ -> false - if result then - printfn "TREE FILTER: edge (%A,%A) -> tree" i j - result let graphFilter parent = @@ -78,11 +63,6 @@ let mst (graph: Matrix.SparseMatrix<_>) = let parent = Vector.init length (fun i -> Some i) let rec inner (graph: Matrix.SparseMatrix<_>) (tree: Matrix.SparseMatrix<_>) parent iteration = - printfn "=== Iter %d: graph=%A, tree=%A ===" iteration graph.nvals tree.nvals - printfn "=== Graph ===" - printMatrixCoordinate graph - printfn "Parent at start of iter %d:" iteration - printVector parent if graph.nvals > 0UL then @@ -96,18 +76,12 @@ let mst (graph: Matrix.SparseMatrix<_>) = LinearAlgebra.vxmi_values op_min op_mult parent graph |> Result.mapError EdgesCalculationProblem - printfn "=== Edges ===" - printVector edges - // Per‑component cheapest edge // For each component, keep the smallest edges among its vertices. let! cedges = Vector.scatter (Vector.empty length) edges parent op_min |> Result.mapError CEdgesCalculationProblem - printfn "=== Component Edges ===" - printVector cedges - // Propagate component's cheapest edge to all its vertices // Each vertex gets its component's edge let t = Vector.gather cedges parent @@ -127,9 +101,6 @@ let mst (graph: Matrix.SparseMatrix<_>) = // now each vertex knows its component's representative let index = Vector.gather index parent - printfn "=== Index ===" - printVector index - // Add selected edges to the MST tree // An edge (i, j, w) is added if vertex i is the representative for its component // and (i, j, w) is the cheapest edge of that component. @@ -160,9 +131,6 @@ let mst (graph: Matrix.SparseMatrix<_>) = | _ -> None) |> Result.mapError DataForUpgradeParentCalculationProblem - printfn "=== Data for update parent ===" - printVector data_for_update_parent - // Apply the updates let! initial_parent_update = Vector.foldValues @@ -179,23 +147,14 @@ let mst (graph: Matrix.SparseMatrix<_>) = (Ok parent) |> Result.mapError FoldValuesProblem - printfn "=== Initial parent update ===" - printVector initial_parent_update - let! parent = Vector.scatter parent initial_parent_update parent op_min |> Result.mapError ScatterProblem - printfn "=== Initially updated parent ===" - printVector parent - // Then ensure that all vertices in a merged component point to the same root. // This is done by a fixpoint (path compression) that repeatedly gathers parents. let parent = fixPoint parent - printfn "=== Parent before data propagation ===" - printVector parent - // Filter the graph to keep only edges between different components let graphFilter = graphFilter parent let graph = Matrix.mapi graph (fun i j v -> if graphFilter i j then v else None) From 2f7015a82f8d54d53eb987e1d8a8f979de9b390c Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 5 May 2026 11:22:22 +0300 Subject: [PATCH 51/52] Removed tree-based Map implementation. --- QuadTree/Map.fs | 143 --------------------------------------- QuadTree/QuadTree.fsproj | 1 - 2 files changed, 144 deletions(-) delete mode 100644 QuadTree/Map.fs diff --git a/QuadTree/Map.fs b/QuadTree/Map.fs deleted file mode 100644 index d0d9d76..0000000 --- a/QuadTree/Map.fs +++ /dev/null @@ -1,143 +0,0 @@ -module Map - -type TreeMap<'K, 'V> = - | Empty - | Node of key: 'K * value: 'V * height: int * left: TreeMap<'K, 'V> * right: TreeMap<'K, 'V> - -let private height tree = - match tree with - | Empty -> 0 - | Node(_, _, h, _, _) -> h - -let private makeNode k v l r = - let h = 1 + max (height l) (height r) - Node(k, v, h, l, r) - -let private rotateRight tree = - match tree with - | Empty -> Empty - | Node(x, vx, _, left, right) -> - match left with - | Empty -> failwith "rotateRight: left child is empty" - | Node(y, vy, _, ly, ry) -> - Node(y, vy, 1 + max (height ly) (height (makeNode x vx ry right)), ly, makeNode x vx ry right) - -let private rotateLeft tree = - match tree with - | Empty -> Empty - | Node(x, vx, _, left, right) -> - match right with - | Empty -> failwith "rotateLeft: right child is empty" - | Node(y, vy, _, ly, ry) -> - Node(y, vy, 1 + max (height (makeNode x vx left ly)) (height ry), makeNode x vx left ly, ry) - -let private balance k v l r = - let hl = height l - let hr = height r - - if hl - hr > 1 then - match l with - | Node(lk, lv, _, ll, lr) when height ll >= height lr -> rotateRight (Node(k, v, 0, l, r)) - | Node(lk, lv, _, ll, lr) -> - let newLeft = rotateLeft (Node(lk, lv, 0, ll, lr)) - rotateRight (Node(k, v, 0, newLeft, r)) - | _ -> failwith "balance: left heavy but left is empty" - elif hr - hl > 1 then - match r with - | Node(rk, rv, _, rl, rr) when height rr >= height rl -> rotateLeft (Node(k, v, 0, l, r)) - | Node(rk, rv, _, rl, rr) -> - let newRight = rotateRight (Node(rk, rv, 0, rl, rr)) - rotateLeft (Node(k, v, 0, l, newRight)) - | _ -> failwith "balance: right heavy but right is empty" - else - makeNode k v l r - -let empty = Empty - -let isEmpty map = - match map with - | Empty -> true - | _ -> false - -let rec contains k map = - match map with - | Empty -> false - | Node(k2, _, _, l, r) -> - if k = k2 then true - elif k < k2 then contains k l - else contains k r - -let rec tryFind k map = - match map with - | Empty -> None - | Node(k2, v, _, l, r) -> - if k = k2 then Some v - elif k < k2 then tryFind k l - else tryFind k r - - -let rec add k v map = - match map with - | Empty -> Node(k, v, 1, Empty, Empty) - | Node(k2, v2, _, l, r) -> - if k < k2 then - let newL = add k v l - balance k2 v2 newL r - elif k > k2 then - let newR = add k v r - balance k2 v2 l newR - else - // If key already exists --- update value - Node(k, v, height (Node(k2, v2, 0, l, r)), l, r) - - -/// Removes the entry for the given key. If the key is not exists, the map is unchanged. -let rec remove k map = - let rec minKeyValue map = - match map with - | Empty -> failwith "minKeyValue: empty map" - | Node(k, v, _, Empty, _) -> (k, v) - | Node(_, _, _, l, _) -> minKeyValue l - - let rec removeMin map = - match map with - | Empty -> Empty - | Node(k, v, _, Empty, r) -> r - | Node(k, v, _, l, r) -> balance k v (removeMin l) r - - match map with - | Empty -> Empty - | Node(k2, v2, _, l, r) -> - if k < k2 then - balance k2 v2 (remove k l) r - elif k > k2 then - balance k2 v2 l (remove k r) - else - match l, r with - | Empty, _ -> r - | _, Empty -> l - | _ -> - let (minK, minV) = minKeyValue r - let newR = removeMin r - balance minK minV l newR - -/// Folds over the map in ascending key order. -let rec fold f acc = - function - | Empty -> acc - | Node(k, v, _, l, r) -> - let acc' = fold f acc l - let acc'' = f acc' k v - fold f acc'' r - - -/// Returns the number of entries in the map. -let rec count map = fold (fun acc _ _ -> acc + 1) 0 map - -/// Returns a list of (key, value) pairs in ascending key order. -let toList map = - fold (fun acc k v -> (k, v) :: acc) [] map |> List.rev - -/// Creates a map from a sequence of key‑value pairs. -let ofList list = - List.fold (fun acc (k, v) -> add k v acc) empty list diff --git a/QuadTree/QuadTree.fsproj b/QuadTree/QuadTree.fsproj index b984e0e..438678c 100644 --- a/QuadTree/QuadTree.fsproj +++ b/QuadTree/QuadTree.fsproj @@ -7,7 +7,6 @@ - From 56343e94fd1247deb836b98d041fb5e84cf46c0d Mon Sep 17 00:00:00 2001 From: gsv Date: Tue, 5 May 2026 11:24:11 +0300 Subject: [PATCH 52/52] Code cleanup. --- QuadTree/Vector.fs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/QuadTree/Vector.fs b/QuadTree/Vector.fs index ad3333b..f1ddb16 100644 --- a/QuadTree/Vector.fs +++ b/QuadTree/Vector.fs @@ -395,26 +395,6 @@ let mergeSort (v: SparseVector<'a>) (compare: Option<'a> -> Option<'a> -> int) : SparseVector(v.length, nvals, Storage(storageSize, newTree)) -(*let mergeSort (v: SparseVector<'a>) (compare: Option<'a> -> Option<'a> -> int) : SparseVector<'a> = - let rec merge t1 t2 = - match (t1, t2) with - | Leaf (UserValue v1), Leaf (UserValue v2) -> - if compare v1 v2 <= 0 then mkNode t1 t2 else mkNode (Leaf (UserValue v2)) (Leaf (UserValue v1)) - | Leaf (UserValue v1), Leaf Dummy -> tree - - let rec inner tree = - match tree with - | Node (Leaf (UserValue v1), Leaf (UserValue v2) ) -> - if compare v1 v2 <= 0 then tree else Node (Leaf (UserValue v2), Leaf (UserValue v1)) - | Node (Leaf (UserValue v1), Leaf Dummy) -> tree - | Node (n1, n2) -> - let newLeft = inner n1 - let newRight = inner n2 - merge mewLeft newRight -*) - -//type ScatterError<'a> = - /// Scatter: w[idx[i]] = op(w[idx[i]], v[i]) let scatter (w: SparseVector<'value>)