diff --git a/App/App.fsproj b/App/App.fsproj new file mode 100644 index 00000000..5a3c6972 --- /dev/null +++ b/App/App.fsproj @@ -0,0 +1,12 @@ + + + + Exe + net8.0 + + + + + + + diff --git a/App/Program.fs b/App/Program.fs new file mode 100644 index 00000000..87a889fa --- /dev/null +++ b/App/Program.fs @@ -0,0 +1,25 @@ +open System.Threading.Tasks + +let height = 10 +let width = 20 + +// Parallel.For(0, height * width, fun index -> +// let i = index / width +// let j = index % width + +// printfn "i: %d, j: %d, Thread: %d" i j System.Threading.Thread.CurrentThread.ManagedThreadId +// ) |> ignore + +(* +0 .. 10 +.. +20 +*) + +// for k in 0 .. 10 * 20 - 1 do +// let i = k / 10 +// let j = k % 10 +// printfn "%d %d %d" k i j +let a = 5 / 2 + +printfn "%d" a \ No newline at end of file diff --git a/Benchmarks/ImageProcessingB/ImageProcessingB.fsproj b/Benchmarks/ImageProcessingB/ImageProcessingB.fsproj new file mode 100644 index 00000000..956482e1 --- /dev/null +++ b/Benchmarks/ImageProcessingB/ImageProcessingB.fsproj @@ -0,0 +1,21 @@ + + + + Exe + net8.0 + + + + + + + + + + + + + + + + diff --git a/Benchmarks/ImageProcessingB/Program.fs b/Benchmarks/ImageProcessingB/Program.fs new file mode 100644 index 00000000..2fdaa4db --- /dev/null +++ b/Benchmarks/ImageProcessingB/Program.fs @@ -0,0 +1,55 @@ +namespace ImageProcessingB + +open System +open BenchmarkDotNet.Attributes +open BenchmarkDotNet.Running +open BenchmarkDotNet.Configs +open BenchmarkDotNet.Reports +open Perfolizer.Horology + +open ImageProcessing.ImProcessing +open SixLabors.ImageSharp.PixelFormats + +type ipBenchmark() = + + static member Sizes = [|2; 4|] + member this.Random = System.Random() + + [] + member val MatrixSize = 0 with get, set + member val MatrixToSort = Array2D.zeroCreate 1 1 with get, set + + [] + member this.GetArrayToSort () = + this.MatrixToSort <- Array2D.init this.MatrixSize this.MatrixSize (fun _ _ -> + let r = byte (this.Random.Next 256) + let g = byte (this.Random.Next 256) + let b = byte (this.Random.Next 256) + let a = byte (this.Random.Next 256) + Rgba32 (r, g, b, a) + ) + + [] + member this.NoParallelism () = applyFilterNoParallelism gaussianBlur this.MatrixToSort + + [] + member this.PixelParallelism () = applyFilterPixelParallelism gaussianBlur this.MatrixToSort + + [] + member this.ParallelismInParts () = applyFilterParallelismInParts gaussianBlur this.MatrixToSort + + [] + member this.RowParallelism () = applyFilterRowParallelism gaussianBlur this.MatrixToSort + + [] + member this.ColParallelism () = applyFilterColParallelism gaussianBlur this.MatrixToSort + + +module Main = + [] + let main argv = + let benchmarks = + BenchmarkSwitcher [| typeof |] + + benchmarks.Run argv |> ignore + 0 \ No newline at end of file diff --git a/Benchmarks/Benchmarks.fsproj b/Benchmarks/SortingsB/Benchmarks.fsproj similarity index 80% rename from Benchmarks/Benchmarks.fsproj rename to Benchmarks/SortingsB/Benchmarks.fsproj index 5d5d8caf..eb948afd 100644 --- a/Benchmarks/Benchmarks.fsproj +++ b/Benchmarks/SortingsB/Benchmarks.fsproj @@ -1,20 +1,20 @@ - - - - Exe - net8.0 - - - - - - - - - - - - - - - + + + + Exe + net8.0 + + + + + + + + + + + + + + + diff --git a/Benchmarks/Program.fs b/Benchmarks/SortingsB/Program.fs similarity index 95% rename from Benchmarks/Program.fs rename to Benchmarks/SortingsB/Program.fs index 34a08ad2..ecb872e3 100644 --- a/Benchmarks/Program.fs +++ b/Benchmarks/SortingsB/Program.fs @@ -1,76 +1,76 @@ -namespace Benchmarks - -open System -open BenchmarkDotNet.Attributes -open BenchmarkDotNet.Running -open BenchmarkDotNet.Configs -open BenchmarkDotNet.Reports -open Perfolizer.Horology - -open ArraySorts -open MyListSorts - -type ArraysBenchmark() = - - static member Lengths = [|10000..10000..100000|] - member this.Random = System.Random() - - [] - member val ArrayLength = 0 with get, set - member val ArrayToSort = [|0.0|] with get, set - - [] - member this.GetArrayToSort () = - this.ArrayToSort <- Array.init this.ArrayLength (fun _ -> this.Random.NextDouble()) - - [] - member this.ArrayQuickSort () = Arrays.quickSort this.ArrayToSort - - [] - member this.ArrayBubbleSort () = Arrays.bubbleSort this.ArrayToSort - - [] - member this.ArrayMergeSort () = Arrays.mergeSort this.ArrayToSort - - [] - member this.ArraySystem () = Array.Sort this.ArrayToSort - - -type ListBenchmark() = - - static member Lengths = [|10000..10000..100000|] - member this.Random = System.Random() - - [] - member val ListLength = 0 with get, set - member val ListToSort = [0.0] with get, set - - [] - member this.GetListToSort () = - this.ListToSort <- List.init this.ListLength (fun _ -> this.Random.NextDouble()) - - [] - member this.MyListBubbleSort () = MyList.fromSystemList this.ListToSort |> MyList.quickSort - - [] - member this.MyListQuickSort () = MyList.fromSystemList this.ListToSort |> MyList.bubbleSort - - [] - member this.MyListMergeSort () = MyList.fromSystemList this.ListToSort |> MyList.mergeSort - - [] - member this.MyListSystem () = List.sort this.ListToSort - - -module Main = - [] - let main argv = - - let config = ManualConfig.Create(DefaultConfig.Instance) - .WithSummaryStyle(SummaryStyle.Default.WithTimeUnit(TimeUnit.Millisecond)) - .WithOptions(ConfigOptions.DisableOptimizationsValidator) - let benchmarks = - BenchmarkSwitcher [| typeof; typeof|] - - benchmarks.Run argv |> ignore - 0 +namespace SortingsB + +open System +open BenchmarkDotNet.Attributes +open BenchmarkDotNet.Running +open BenchmarkDotNet.Configs +open BenchmarkDotNet.Reports +open Perfolizer.Horology + +open ArraySorts +open MyListSorts + +type ArraysBenchmark() = + + static member Lengths = [|10000..10000..100000|] + member this.Random = System.Random() + + [] + member val ArrayLength = 0 with get, set + member val ArrayToSort = [|0.0|] with get, set + + [] + member this.GetArrayToSort () = + this.ArrayToSort <- Array.init this.ArrayLength (fun _ -> this.Random.NextDouble()) + + [] + member this.ArrayQuickSort () = Arrays.quickSort this.ArrayToSort + + [] + member this.ArrayBubbleSort () = Arrays.bubbleSort this.ArrayToSort + + [] + member this.ArrayMergeSort () = Arrays.mergeSort this.ArrayToSort + + [] + member this.ArraySystem () = Array.Sort this.ArrayToSort + + +type ListBenchmark() = + + static member Lengths = [|10000..10000..100000|] + member this.Random = System.Random() + + [] + member val ListLength = 0 with get, set + member val ListToSort = [0.0] with get, set + + [] + member this.GetListToSort () = + this.ListToSort <- List.init this.ListLength (fun _ -> this.Random.NextDouble()) + + [] + member this.MyListBubbleSort () = MyList.fromSystemList this.ListToSort |> MyList.quickSort + + [] + member this.MyListQuickSort () = MyList.fromSystemList this.ListToSort |> MyList.bubbleSort + + [] + member this.MyListMergeSort () = MyList.fromSystemList this.ListToSort |> MyList.mergeSort + + [] + member this.MyListSystem () = List.sort this.ListToSort + + +module Main = + [] + let main argv = + + let config = ManualConfig.Create(DefaultConfig.Instance) + .WithSummaryStyle(SummaryStyle.Default.WithTimeUnit(TimeUnit.Millisecond)) + .WithOptions(ConfigOptions.DisableOptimizationsValidator) + let benchmarks = + BenchmarkSwitcher [| typeof; typeof|] + + benchmarks.Run argv |> ignore + 0 diff --git a/HomeWork.sln b/HomeWork.sln index afb549e7..eb7e6948 100644 --- a/HomeWork.sln +++ b/HomeWork.sln @@ -15,12 +15,14 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Sortings", "src\Sortings\So EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "SortingsT", "Tests\SortingsT\SortingsT.fsproj", "{1D6CFA13-FD9D-4586-A463-1C023123E2CA}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Benchmarks", "Benchmarks\Benchmarks.fsproj", "{66023F5A-8456-4F66-9318-A0BFB68ED14A}" +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "SortingsB", "Benchmarks\SortingsB\Benchmarks.fsproj", "{66023F5A-8456-4F66-9318-A0BFB68ED14A}" EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ImageProcessing", "src\ImageProcessing\ImageProcessing.fsproj", "{7B9D1692-F56C-43C7-92BA-2CDDE21A7D57}" EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ImageProcessingT", "Tests\ImageProcessingT\ImageProcessingT.fsproj", "{EB2F699B-DE06-42EC-974A-A2C39E5C8D2A}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ImageProcessingB", "Benchmarks\ImageProcessingB\ImageProcessingB.fsproj", "{538E3C6C-8ADC-44EE-919C-EAD4C67C3AF0}" +EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Trees", "src\Trees\Trees.fsproj", "{CAC5303C-D4CF-493E-94B4-4409BE7F2865}" EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TreesT", "Tests\TreesT\TreesT.fsproj", "{7E4032B2-27F7-4691-8474-5C57A97F5721}" @@ -29,6 +31,12 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "LineralAlgebra", "src\Liner EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "LineralAlgebraT", "Tests\LineralAlgebraT\LineralAlgebraT.fsproj", "{C42A6017-8A61-4469-8FCD-EEBF49198D80}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "App", "App\App.fsproj", "{9C6529F4-1014-4655-A47E-D807D8604BD0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks\SortingsB", "Benchmarks\SortingsB", "{2DE1F8AE-2C09-422E-84AD-AC77FA4BFDED}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{BD15DB9C-BF1B-4219-AF93-796337C6399A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -58,6 +66,10 @@ Global {66023F5A-8456-4F66-9318-A0BFB68ED14A}.Debug|Any CPU.Build.0 = Debug|Any CPU {66023F5A-8456-4F66-9318-A0BFB68ED14A}.Release|Any CPU.ActiveCfg = Release|Any CPU {66023F5A-8456-4F66-9318-A0BFB68ED14A}.Release|Any CPU.Build.0 = Release|Any CPU + {538E3C6C-8ADC-44EE-919C-EAD4C67C3AF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {538E3C6C-8ADC-44EE-919C-EAD4C67C3AF0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {538E3C6C-8ADC-44EE-919C-EAD4C67C3AF0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {538E3C6C-8ADC-44EE-919C-EAD4C67C3AF0}.Release|Any CPU.Build.0 = Release|Any CPU {7B9D1692-F56C-43C7-92BA-2CDDE21A7D57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B9D1692-F56C-43C7-92BA-2CDDE21A7D57}.Debug|Any CPU.Build.0 = Debug|Any CPU {7B9D1692-F56C-43C7-92BA-2CDDE21A7D57}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -82,6 +94,10 @@ Global {C42A6017-8A61-4469-8FCD-EEBF49198D80}.Debug|Any CPU.Build.0 = Debug|Any CPU {C42A6017-8A61-4469-8FCD-EEBF49198D80}.Release|Any CPU.ActiveCfg = Release|Any CPU {C42A6017-8A61-4469-8FCD-EEBF49198D80}.Release|Any CPU.Build.0 = Release|Any CPU + {9C6529F4-1014-4655-A47E-D807D8604BD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C6529F4-1014-4655-A47E-D807D8604BD0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C6529F4-1014-4655-A47E-D807D8604BD0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C6529F4-1014-4655-A47E-D807D8604BD0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {F793D6BB-E68A-473E-B11F-1D7888DF4D4A} = {00DFC406-0A95-4C11-8BF2-4FD28C28061D} @@ -94,5 +110,7 @@ Global {7E4032B2-27F7-4691-8474-5C57A97F5721} = {B4AC50D2-34AD-46DF-B39E-FBCC5D0653C6} {C05FDC93-8EE3-442C-868A-031CE2A5F4E4} = {00DFC406-0A95-4C11-8BF2-4FD28C28061D} {C42A6017-8A61-4469-8FCD-EEBF49198D80} = {B4AC50D2-34AD-46DF-B39E-FBCC5D0653C6} + {66023F5A-8456-4F66-9318-A0BFB68ED14A} = {2DE1F8AE-2C09-422E-84AD-AC77FA4BFDED} + {538E3C6C-8ADC-44EE-919C-EAD4C67C3AF0} = {BD15DB9C-BF1B-4219-AF93-796337C6399A} EndGlobalSection EndGlobal diff --git a/Tests/ImageProcessingT/PropertyImageProcessing.fs b/Tests/ImageProcessingT/PropertyImageProcessing.fs index 32d65918..70a6c24b 100644 --- a/Tests/ImageProcessingT/PropertyImageProcessing.fs +++ b/Tests/ImageProcessingT/PropertyImageProcessing.fs @@ -18,12 +18,13 @@ module ImageGen = let a = byte 255 return Rgba32(r, g, b, a) } - let array2DGen (size: int) : Gen = + let array2DGen (size: int) : Gen> = gen { let! pixels = Gen.array2DOfDim (size, size) pixelGen - return pixels + return async { return pixels } } - + + type Image100() = static member Rgba32() = Arb.fromGen (ImageGen.array2DGen 100) @@ -37,40 +38,149 @@ type Image2() = type Filter() = [ |])>] - member _.filterDoesntChangeSize (image: Rgba32[,]) = - let imageAfterFilter = applyFilter gaussianBlur image - Assert.Equal(100, imageAfterFilter.GetLength(0)) - Assert.Equal(100, imageAfterFilter.GetLength(1)) + member _.filterDoesntChangeSize (image: Async) = + let resNoParallelism = + applyFilterNoParallelismA gaussianBlur image + |> Async.RunSynchronously + + let resPixelParallelism = + applyFilterPixelParallelismA gaussianBlur image + |> Async.RunSynchronously + + let resPartsParallelism = + applyFilterParallelismInPartsA gaussianBlur image + |> Async.RunSynchronously + + let resRowParallelism = + applyFilterRowParallelismA gaussianBlur image + |> Async.RunSynchronously + + let resColParallelism = + applyFilterColParallelismA gaussianBlur image + |> Async.RunSynchronously + + Assert.Equal(100, resNoParallelism.GetLength 0) + Assert.Equal(100, resNoParallelism.GetLength 1) + + Assert.Equal(100, resPixelParallelism.GetLength 0) + Assert.Equal(100, resPixelParallelism.GetLength 1) + + Assert.Equal(100, resPartsParallelism.GetLength 0) + Assert.Equal(100, resPartsParallelism.GetLength 1) + + Assert.Equal(100, resRowParallelism.GetLength 0) + Assert.Equal(100, resRowParallelism.GetLength 1) + + Assert.Equal(100, resColParallelism.GetLength 0) + Assert.Equal(100, resColParallelism.GetLength 1) [ |])>] - member _.idDoesntChangeData (image: Rgba32[,]) = - let imageAfterFilter = applyFilter id image - Assert.Equal(image, imageAfterFilter) + member _.idDoesntChangeData (image: Async) = + let resNoParallelism = applyFilterNoParallelismA id image + let resPixelParallelism = applyFilterPixelParallelismA id image + let resPartsParallelism = applyFilterParallelismInPartsA id image + let resRowParallelism = applyFilterRowParallelismA id image + let resColParallelism = applyFilterColParallelismA id image + + Assert.Equal(image |> Async.RunSynchronously, resNoParallelism |> Async.RunSynchronously) + Assert.Equal(image |> Async.RunSynchronously, resPixelParallelism |> Async.RunSynchronously) + Assert.Equal(image |> Async.RunSynchronously, resPartsParallelism |> Async.RunSynchronously) + Assert.Equal(image |> Async.RunSynchronously, resRowParallelism |> Async.RunSynchronously) + Assert.Equal(image |> Async.RunSynchronously, resColParallelism |> Async.RunSynchronously) [ |])>] - member _.imageSmallerThanFilter (image: Rgba32[,]) = - let imageAfterFilter = applyFilter black image - Assert.Equal(true, imageIsBlack imageAfterFilter) + member _.imageSmallerThanFilter (image: Async) = + let resNoParallelism = applyFilterNoParallelismA black image + let resPixelParallelism = applyFilterPixelParallelismA black image + let resPartsParallelism = applyFilterParallelismInPartsA black image + let resRowParallelism = applyFilterRowParallelismA black image + let resColParallelism = applyFilterColParallelismA black image + + Assert.Equal(true, imageIsBlack resNoParallelism) + Assert.Equal(true, imageIsBlack resPixelParallelism) + Assert.Equal(true, imageIsBlack resPartsParallelism) + Assert.Equal(true, imageIsBlack resRowParallelism) + Assert.Equal(true, imageIsBlack resColParallelism) [ |])>] - member _.blackFilter (image: Rgba32[,]) = - let imageBlack = applyFilter black image - Assert.Equal(true, imageIsBlack imageBlack) + member _.blackFilter (image: Async) = + let imageBlack_NoParallelism = applyFilterNoParallelismA black image + let imageBlack_PixelParallelism = applyFilterPixelParallelismA black image + let imageBlack_PartsParallelism = applyFilterParallelismInPartsA black image + let imageBlac_RowParallelism = applyFilterRowParallelismA black image + let imageBlack_ColParallelism = applyFilterColParallelismA black image + + Assert.Equal(true, imageIsBlack imageBlack_NoParallelism) + Assert.Equal(true, imageIsBlack imageBlack_PixelParallelism) + Assert.Equal(true, imageIsBlack imageBlack_PartsParallelism) + Assert.Equal(true, imageIsBlack imageBlac_RowParallelism) + Assert.Equal(true, imageIsBlack imageBlack_ColParallelism) [ |])>] - member _.shiftComposition (image: Rgba32[,]) = - let trivial1and2 = applyFilter shiftRight image |> applyFilter shiftDown - let trivial12 = applyFilter shiftDiagonal image - Assert.Equal(trivial1and2, trivial12) + member _.shiftComposition (image: Async) = + let trivial1and2_NoParallelism = applyFilterNoParallelismA shiftRight image |> applyFilterNoParallelismA shiftDown + let trivial12_NoParallelism = applyFilterNoParallelismA shiftDiagonal image + + let trivial1and2_PixelParallelism = applyFilterPixelParallelismA shiftRight image |> applyFilterPixelParallelismA shiftDown + let trivial12_PixelParallelism = applyFilterPixelParallelismA shiftDiagonal image + + let trivial1and2_PartsParallelism = applyFilterParallelismInPartsA shiftRight image |> applyFilterParallelismInPartsA shiftDown + let trivial12_PartsParallelism = applyFilterParallelismInPartsA shiftDiagonal image + + let trivial1and2_RowParallelism = applyFilterRowParallelismA shiftRight image |> applyFilterRowParallelismA shiftDown + let trivial12_RowParallelism = applyFilterRowParallelismA shiftDiagonal image + + let trivial1and2_ColParallelism = applyFilterColParallelismA shiftRight image |> applyFilterColParallelismA shiftDown + let trivial12_ColParallelism = applyFilterColParallelismA shiftDiagonal image + + Assert.Equal(trivial1and2_NoParallelism |> Async.RunSynchronously, trivial12_NoParallelism |> Async.RunSynchronously) + Assert.Equal(trivial1and2_PixelParallelism |> Async.RunSynchronously, trivial12_PixelParallelism |> Async.RunSynchronously) + Assert.Equal(trivial1and2_PartsParallelism |> Async.RunSynchronously, trivial12_PartsParallelism |> Async.RunSynchronously) + Assert.Equal(trivial1and2_RowParallelism |> Async.RunSynchronously, trivial12_RowParallelism |> Async.RunSynchronously) + Assert.Equal(trivial1and2_ColParallelism |> Async.RunSynchronously, trivial12_ColParallelism |> Async.RunSynchronously) [ |])>] - member _.extendedComposition (image: Rgba32[,]) = - let imageAfterFilter = applyFilter kernel image - let imageAfterExtendedFilter = applyFilter kernelExtended image - Assert.Equal(imageAfterFilter, imageAfterExtendedFilter) + member _.extendedComposition (image: Async) = + let imageAfterFilter_NoParallelism = applyFilterNoParallelismA kernel image + let imageAfterExtendedFilter_NoParallelism = applyFilterNoParallelismA kernelExtended image + + let imageAfterFilter_PixelParallelism = applyFilterPixelParallelismA kernel image + let imageAfterExtendedFilter_PixelParallelism = applyFilterPixelParallelismA kernelExtended image + + let imageAfterFilter_PartsParallelism = applyFilterParallelismInPartsA kernel image + let imageAfterExtendedFilter_PartsParallelism = applyFilterParallelismInPartsA kernelExtended image + + let imageAfterFilter_RowParallelism = applyFilterRowParallelismA kernel image + let imageAfterExtendedFilter_RowParallelism = applyFilterRowParallelismA kernelExtended image + + let imageAfterFilter_ColParallelism = applyFilterColParallelismA kernel image + let imageAfterExtendedFilter_ColParallelism = applyFilterColParallelismA kernelExtended image + + Assert.Equal(imageAfterFilter_NoParallelism |> Async.RunSynchronously, imageAfterExtendedFilter_NoParallelism |> Async.RunSynchronously) + Assert.Equal(imageAfterFilter_PixelParallelism |> Async.RunSynchronously, imageAfterExtendedFilter_PixelParallelism |> Async.RunSynchronously) + Assert.Equal(imageAfterFilter_PartsParallelism |> Async.RunSynchronously, imageAfterExtendedFilter_PartsParallelism |> Async.RunSynchronously) + Assert.Equal(imageAfterFilter_RowParallelism |> Async.RunSynchronously, imageAfterExtendedFilter_RowParallelism |> Async.RunSynchronously) + Assert.Equal(imageAfterFilter_ColParallelism |> Async.RunSynchronously, imageAfterExtendedFilter_ColParallelism |> Async.RunSynchronously) [ |])>] - member _.someAreCommutative (image: Rgba32[,]) = - let image12 = applyFilter shiftRight image |> applyFilter shiftDown - let image21 = applyFilter shiftDown image |> applyFilter shiftRight - Assert.Equal(image12, image21) \ No newline at end of file + member _.someAreCommutative (image: Async) = + let image12_NoParallelism = applyFilterNoParallelismA shiftRight image |> applyFilterNoParallelismA shiftDown + let image21_NoParallelism = applyFilterNoParallelismA shiftDown image |> applyFilterNoParallelismA shiftRight + + let image12_PixelParallelism = applyFilterPixelParallelismA shiftRight image |> applyFilterPixelParallelismA shiftDown + let image21_PixelParallelism = applyFilterPixelParallelismA shiftDown image |> applyFilterPixelParallelismA shiftRight + + let image12_PartsParallelism = applyFilterParallelismInPartsA shiftRight image |> applyFilterParallelismInPartsA shiftDown + let image21_PartsParallelism = applyFilterParallelismInPartsA shiftDown image |> applyFilterParallelismInPartsA shiftRight + + let image12_RowParallelism = applyFilterRowParallelismA shiftRight image |> applyFilterRowParallelismA shiftDown + let image21_RowParallelism = applyFilterRowParallelismA shiftDown image |> applyFilterRowParallelismA shiftRight + + let image12_ColParallelism = applyFilterColParallelismA shiftRight image |> applyFilterColParallelismA shiftDown + let image21_ColParallelism = applyFilterColParallelismA shiftDown image |> applyFilterColParallelismA shiftRight + + Assert.Equal(image12_NoParallelism |> Async.RunSynchronously, image21_NoParallelism |> Async.RunSynchronously) + Assert.Equal(image12_PixelParallelism |> Async.RunSynchronously, image21_PixelParallelism |> Async.RunSynchronously) + Assert.Equal(image12_PartsParallelism |> Async.RunSynchronously, image21_PartsParallelism |> Async.RunSynchronously) + Assert.Equal(image12_RowParallelism |> Async.RunSynchronously, image21_RowParallelism |> Async.RunSynchronously) + Assert.Equal(image12_ColParallelism |> Async.RunSynchronously, image21_ColParallelism |> Async.RunSynchronously) \ No newline at end of file diff --git a/Tests/ImageProcessingT/UnitImageProcessing.fs b/Tests/ImageProcessingT/UnitImageProcessing.fs index 73880dc0..3ac54427 100644 --- a/Tests/ImageProcessingT/UnitImageProcessing.fs +++ b/Tests/ImageProcessingT/UnitImageProcessing.fs @@ -10,8 +10,8 @@ module Data = let im1 = "../../../Images/image1.png" let imSmall = "../../../Images/image2x2px.png" - let image1 = loadAsRgba2D im1 - let imageSmall = loadAsRgba2D imSmall + let image1 = loadAsRgba2DA im1 + let imageSmall = loadAsRgba2DA imSmall let imId = "../../../Images/id.png" let imShiftRightDown = "../../../Images/shiftRightDown.png" @@ -19,12 +19,12 @@ module Data = let imShiftDiagonal = "../../../Images/shiftDiagonal.png" let imKernel = "../../../Images/kernel.png" let imKernelExtended = "../../../Images/kernelExtended.png" - let imageId= loadAsRgba2D imId - let imageShiftRightDown= loadAsRgba2D imShiftRightDown - let imageShiftDownRight= loadAsRgba2D imShiftDownRight - let imageShiftDiagonal= loadAsRgba2D imShiftDiagonal - let imageKernel= loadAsRgba2D imKernel - let imageKernelExtended= loadAsRgba2D imKernelExtended + let imageId= loadAsRgba2DA imId |> Async.RunSynchronously + let imageShiftRightDown= loadAsRgba2DA imShiftRightDown |> Async.RunSynchronously + let imageShiftDownRight= loadAsRgba2DA imShiftDownRight |> Async.RunSynchronously + let imageShiftDiagonal= loadAsRgba2DA imShiftDiagonal |> Async.RunSynchronously + let imageKernel= loadAsRgba2DA imKernel |> Async.RunSynchronously + let imageKernelExtended= loadAsRgba2DA imKernelExtended |> Async.RunSynchronously let id = @@ -86,19 +86,23 @@ module Data = |> Array.map (Array.map float32) - let imageIsBlack (image: Rgba32[,]) = - let h = image.GetLength 0 - let w = image.GetLength 1 + let imageIsBlack (imageAsync: Async) = + async { + let! image = imageAsync + let h = image.GetLength 0 + let w = image.GetLength 1 - let mutable isBlack = true + let mutable isBlack = true - for i in 0 .. h - 1 do - for j in 0 .. w - 1 do - let pixel = image.[i, j] - if pixel <> Rgba32(byte 0, byte 0, byte 0, byte 255) then - isBlack <- false + for i in 0 .. h - 1 do + for j in 0 .. w - 1 do + let pixel = image.[i, j] + if pixel <> Rgba32(byte 0, byte 0, byte 0, byte 255) then + isBlack <- false + + return isBlack + } |> Async.RunSynchronously - isBlack module Filter = @@ -106,29 +110,113 @@ module Filter = [] let idDoesntChangeData () = - let imageAfterFilter = applyFilter id image1 - Assert.Equal(imageId, imageAfterFilter) + let resNoParallelism = applyFilterNoParallelismA id image1 + let resPixelParallelism = applyFilterPixelParallelismA id image1 + let resPartsParallelism = applyFilterParallelismInPartsA id image1 + let resRowParallelism = applyFilterRowParallelismA id image1 + let resColParallelism = applyFilterColParallelismA id image1 + + Assert.Equal(imageId, resNoParallelism |> Async.RunSynchronously) + Assert.Equal(imageId, resPixelParallelism |> Async.RunSynchronously) + Assert.Equal(imageId, resPartsParallelism |> Async.RunSynchronously) + Assert.Equal(imageId, resRowParallelism |> Async.RunSynchronously) + Assert.Equal(imageId, resColParallelism |> Async.RunSynchronously) [] let shiftComposition () = - let shiftRightDown = applyFilter shiftRight image1 |> applyFilter shiftDown - let shiftDiagonal = applyFilter shiftDiagonal image1 + let shiftRightDown_NoParallelism = applyFilterNoParallelismA shiftRight image1 |> applyFilterNoParallelismA shiftDown + let shiftDiagonal_NoParallelism = applyFilterNoParallelismA shiftDiagonal image1 + + let shiftRightDown_PixelParallelism = applyFilterPixelParallelismA shiftRight image1 |> applyFilterPixelParallelismA shiftDown + let shiftDiagonal_PixelParallelism = applyFilterPixelParallelismA shiftDiagonal image1 + + let shiftRightDown_PartsParallelism = applyFilterParallelismInPartsA shiftRight image1 |> applyFilterParallelismInPartsA shiftDown + let shiftDiagonal_PartsParallelism = applyFilterParallelismInPartsA shiftDiagonal image1 + + let shiftRightDown_RowParallelism = applyFilterRowParallelismA shiftRight image1 |> applyFilterRowParallelismA shiftDown + let shiftDiagonal_RowParallelism = applyFilterRowParallelismA shiftDiagonal image1 + + let shiftRightDown_ColParallelism = applyFilterColParallelismA shiftRight image1 |> applyFilterColParallelismA shiftDown + let shiftDiagonal_ColParallelism = applyFilterColParallelismA shiftDiagonal image1 + Assert.Equal(imageShiftRightDown, imageShiftDiagonal) - Assert.Equal(imageShiftRightDown, shiftRightDown) - Assert.Equal(imageShiftRightDown, shiftDiagonal) + Assert.Equal(imageShiftRightDown, shiftRightDown_NoParallelism |> Async.RunSynchronously) + Assert.Equal(imageShiftRightDown, shiftDiagonal_NoParallelism |> Async.RunSynchronously) + + Assert.Equal(imageShiftRightDown, shiftRightDown_PixelParallelism |> Async.RunSynchronously) + Assert.Equal(imageShiftRightDown, shiftDiagonal_PixelParallelism |> Async.RunSynchronously) + + Assert.Equal(imageShiftRightDown, shiftRightDown_PartsParallelism |> Async.RunSynchronously) + Assert.Equal(imageShiftRightDown, shiftDiagonal_PartsParallelism |> Async.RunSynchronously) + + Assert.Equal(imageShiftRightDown, shiftRightDown_RowParallelism |> Async.RunSynchronously) + Assert.Equal(imageShiftRightDown, shiftDiagonal_RowParallelism |> Async.RunSynchronously) + + Assert.Equal(imageShiftRightDown, shiftRightDown_ColParallelism |> Async.RunSynchronously) + Assert.Equal(imageShiftRightDown, shiftDiagonal_ColParallelism |> Async.RunSynchronously) [] let extendedComposition () = - let kernel = applyFilter kernel image1 - let kernelExtended = applyFilter kernelExtended image1 + let kernel_NoParallelism = applyFilterNoParallelismA kernel image1 + let kernelExtended_NoParallelism = applyFilterNoParallelismA kernelExtended image1 + + let kernel_PixelParallelism = applyFilterPixelParallelismA kernel image1 + let kernelExtended_PixelParallelism = applyFilterPixelParallelismA kernelExtended image1 + + let kernel_PartsParallelism = applyFilterParallelismInPartsA kernel image1 + let kernelExtended_PartsParallelism = applyFilterParallelismInPartsA kernelExtended image1 + + let kernel_RowParallelism = applyFilterRowParallelismA kernel image1 + let kernelExtended_RowParallelism = applyFilterRowParallelismA kernelExtended image1 + + let kernel_ColParallelism = applyFilterColParallelismA kernel image1 + let kernelExtended_ColParallelism = applyFilterColParallelismA kernelExtended image1 + Assert.Equal(imageKernel, imageKernelExtended) - Assert.Equal(imageKernel, kernel) - Assert.Equal(imageKernel, kernelExtended) + Assert.Equal(imageKernel, kernel_NoParallelism |> Async.RunSynchronously) + Assert.Equal(imageKernel, kernelExtended_NoParallelism |> Async.RunSynchronously) + + Assert.Equal(imageKernel, kernel_PixelParallelism |> Async.RunSynchronously) + Assert.Equal(imageKernel, kernelExtended_PixelParallelism |> Async.RunSynchronously) + + Assert.Equal(imageKernel, kernel_PartsParallelism |> Async.RunSynchronously) + Assert.Equal(imageKernel, kernelExtended_PartsParallelism |> Async.RunSynchronously) + + Assert.Equal(imageKernel, kernel_RowParallelism |> Async.RunSynchronously) + Assert.Equal(imageKernel, kernelExtended_RowParallelism |> Async.RunSynchronously) + + Assert.Equal(imageKernel, kernel_ColParallelism |> Async.RunSynchronously) + Assert.Equal(imageKernel, kernelExtended_ColParallelism |> Async.RunSynchronously) [] let someAreCommutative () = - let imageRD = applyFilter shiftRight image1 |> applyFilter shiftDown - let imageDR = applyFilter shiftDown image1 |> applyFilter shiftRight + let imageRD_NoParallelism = applyFilterNoParallelismA shiftRight image1 |> applyFilterNoParallelismA shiftDown + let imageDR_NoParallelism = applyFilterNoParallelismA shiftDown image1 |> applyFilterNoParallelismA shiftRight + + let imageRD_PixelParallelism = applyFilterPixelParallelismA shiftRight image1 |> applyFilterPixelParallelismA shiftDown + let imageDR_PixelParallelism = applyFilterPixelParallelismA shiftDown image1 |> applyFilterPixelParallelismA shiftRight + + let imageRD_PartsParallelism = applyFilterParallelismInPartsA shiftRight image1 |> applyFilterParallelismInPartsA shiftDown + let imageDR_PartsParallelism = applyFilterParallelismInPartsA shiftDown image1 |> applyFilterParallelismInPartsA shiftRight + + let imageRD_RowParallelism = applyFilterRowParallelismA shiftRight image1 |> applyFilterRowParallelismA shiftDown + let imageDR_RowParallelism = applyFilterRowParallelismA shiftDown image1 |> applyFilterRowParallelismA shiftRight + + let imageRD_ColParallelism = applyFilterColParallelismA shiftRight image1 |> applyFilterColParallelismA shiftDown + let imageDR_ColParallelism = applyFilterColParallelismA shiftDown image1 |> applyFilterColParallelismA shiftRight + Assert.Equal(imageShiftDownRight, imageShiftRightDown) - Assert.Equal(imageShiftDownRight, imageDR) - Assert.Equal(imageShiftDownRight, imageRD) \ No newline at end of file + Assert.Equal(imageShiftDownRight, imageDR_NoParallelism |> Async.RunSynchronously) + Assert.Equal(imageShiftDownRight, imageRD_NoParallelism |> Async.RunSynchronously) + + Assert.Equal(imageShiftDownRight, imageDR_PixelParallelism |> Async.RunSynchronously) + Assert.Equal(imageShiftDownRight, imageRD_PixelParallelism |> Async.RunSynchronously) + + Assert.Equal(imageShiftDownRight, imageDR_PartsParallelism |> Async.RunSynchronously) + Assert.Equal(imageShiftDownRight, imageRD_PartsParallelism |> Async.RunSynchronously) + + Assert.Equal(imageShiftDownRight, imageDR_RowParallelism |> Async.RunSynchronously) + Assert.Equal(imageShiftDownRight, imageRD_RowParallelism |> Async.RunSynchronously) + + Assert.Equal(imageShiftDownRight, imageDR_ColParallelism |> Async.RunSynchronously) + Assert.Equal(imageShiftDownRight, imageRD_ColParallelism |> Async.RunSynchronously) \ No newline at end of file diff --git a/Tests/LineralAlgebraT/PropertyLA.fs b/Tests/LineralAlgebraT/PropertyLA.fs index c5a64777..fe7569e0 100644 --- a/Tests/LineralAlgebraT/PropertyLA.fs +++ b/Tests/LineralAlgebraT/PropertyLA.fs @@ -8,9 +8,7 @@ open FsCheck open FsCheck.Xunit open FsCheck.FSharp -open LineralAlgebra -open LineralAlgebra.QTrees -open LineralAlgebra.Matrix +open LineralAlgebra open UnitTrees.dataAndFuncs @@ -27,27 +25,6 @@ module DataAndFuncs = areAlmostEqual value1 value2 1e-5f | _ -> false - let rec toCorrectQTree qtree = - match qtree with - | Leaf value -> Leaf value - - | Node (nw, ne, se, sw) -> - let NW = toCorrectQTree nw - let NE = toCorrectQTree ne - let SE = toCorrectQTree se - let SW = toCorrectQTree sw - - match NW, NE, SE, SW with - | Leaf value1, - Leaf value2, - Leaf value3, - Leaf value4 - when value1 = value2 && value2 = value3 && value3 = value4 -> - - Leaf value1 - - | _ -> Node (NW, NE, SE, SW) - let multiplyArray2D (arr1: 't[,]) (arr2: 't[,]) : 't[,] = let rows1 = Array2D.length1 arr1 let cols1 = Array2D.length2 arr1 @@ -90,7 +67,7 @@ module DataAndFuncs = let MatrGen (size: int) = let qtree = QTreeGen size typeOfMatr - { n = size; qtree = toCorrectQTree qtree } + { n = size; qtree = QTrees.toCorrectQTree qtree } let res = MatrGen size res @@ -103,31 +80,31 @@ type Map() = [] member _.intId (qtree: QTree) = - qtree |> toCorrectQTree = map id qtree + qtree |> QTrees.toCorrectQTree = QTrees.map id qtree [] member _.floatId (qtree: QTree) = - let res = map id qtree - Assert.True(floatQTreesAreEqual (qtree |> toCorrectQTree) res) + let res = QTrees.map id qtree + Assert.True(floatQTreesAreEqual (qtree |> QTrees.toCorrectQTree) res) [] member _.intComposition (qtree: QTree) = - let qtree1 = map ((+) 1)((map ((+) 2)) qtree) - let qtree2 = map ((+) 3) qtree + let qtree1 = QTrees.map ((+) 1)((QTrees.map ((+) 2)) qtree) + let qtree2 = QTrees.map ((+) 3) qtree qtree1 = qtree2 [] member _.floatComposition (qtree: QTree) = - let qtree1 = map ((+) 1.0f) (map ((+) 2.0f) qtree) - let qtree2 = map ((+) 3.0f) qtree + let qtree1 = QTrees.map ((+) 1.0f) (QTrees.map ((+) 2.0f) qtree) + let qtree2 = QTrees.map ((+) 3.0f) qtree Assert.True(floatQTreesAreEqual qtree1 qtree2) [] member _.intHighIsConst (qtree: QTree) = - let h1 = height (qtree |> toCorrectQTree) - let h2 = height (map ((+) 1) qtree) + let h1 = QTrees.height (qtree |> QTrees.toCorrectQTree) + let h2 = QTrees.height (QTrees.map ((+) 1) qtree) h1 = h2 @@ -141,47 +118,47 @@ type Multiply() = member _.leafLeaf () = let matr1 = MatrixGen 1 "Leaf" let matr2 = MatrixGen 1 "Leaf" - let res = multiply matr1 matr2 (+) ( * ) - let arrayRess = qtreeToArray2D res.qtree res.n - let arrayEx = multiplyArray2D (qtreeToArray2D matr1.qtree matr1.n) (qtreeToArray2D matr2.qtree matr2.n) + let res = Matrix.multiply matr1 matr2 (+) ( * ) + let arrayRess = QTrees.qtreeToArray2D res.qtree res.n + let arrayEx = multiplyArray2D (QTrees.qtreeToArray2D matr1.qtree matr1.n) (QTrees.qtreeToArray2D matr2.qtree matr2.n) Assert.Equal(arrayEx, arrayRess) [] member _.nodeLeaf () = let matr1 = MatrixGen size "Node" let matr2 = MatrixGen size "Leaf" - let res = multiply matr1 matr2 (+) ( * ) - let arrayRess = qtreeToArray2D res.qtree res.n - let arrayEx = multiplyArray2D (qtreeToArray2D matr1.qtree matr1.n) (qtreeToArray2D matr2.qtree matr2.n) + let res = Matrix.multiply matr1 matr2 (+) ( * ) + let arrayRess = QTrees.qtreeToArray2D res.qtree res.n + let arrayEx = multiplyArray2D (QTrees.qtreeToArray2D matr1.qtree matr1.n) (QTrees.qtreeToArray2D matr2.qtree matr2.n) Assert.Equal(arrayEx, arrayRess) [] member _.leafNode () = let matr1 = MatrixGen size "Leaf" let matr2 = MatrixGen size "Node" - let res = multiply matr1 matr2 (+) ( * ) - let arrayRess = qtreeToArray2D res.qtree res.n - let arrayEx = multiplyArray2D (qtreeToArray2D matr1.qtree matr1.n) (qtreeToArray2D matr2.qtree matr2.n) + let res = Matrix.multiply matr1 matr2 (+) ( * ) + let arrayRess = QTrees.qtreeToArray2D res.qtree res.n + let arrayEx = multiplyArray2D (QTrees.qtreeToArray2D matr1.qtree matr1.n) (QTrees.qtreeToArray2D matr2.qtree matr2.n) Assert.Equal(arrayEx, arrayRess) [] member _.nodeNode () = let matr1 = MatrixGen size "Node" let matr2 = MatrixGen size "Node" - let res = multiply matr1 matr2 (+) ( * ) - let arrayRess = qtreeToArray2D res.qtree res.n - let arrayEx = multiplyArray2D (qtreeToArray2D matr1.qtree matr1.n) (qtreeToArray2D matr2.qtree matr2.n) + let res = Matrix.multiply matr1 matr2 (+) ( * ) + let arrayRess = QTrees.qtreeToArray2D res.qtree res.n + let arrayEx = multiplyArray2D (QTrees.qtreeToArray2D matr1.qtree matr1.n) (QTrees.qtreeToArray2D matr2.qtree matr2.n) Assert.Equal(arrayEx, arrayRess) [] member _.zero () = let matr1 = MatrixGen size "Zero" let matr2 = MatrixGen size "Node" - let res = multiply matr1 matr2 (+) ( * ) - let arrayRess = qtreeToArray2D res.qtree res.n - let res1 = multiply matr2 matr1 (+) ( * ) - let arrayRess1 = qtreeToArray2D res1.qtree res1.n + let res = Matrix.multiply matr1 matr2 (+) ( * ) + let arrayRess = QTrees.qtreeToArray2D res.qtree res.n + let res1 = Matrix.multiply matr2 matr1 (+) ( * ) + let arrayRess1 = QTrees.qtreeToArray2D res1.qtree res1.n - let arrayEx = multiplyArray2D (qtreeToArray2D matr1.qtree matr1.n) (qtreeToArray2D matr2.qtree matr2.n) + let arrayEx = multiplyArray2D (QTrees.qtreeToArray2D matr1.qtree matr1.n) (QTrees.qtreeToArray2D matr2.qtree matr2.n) Assert.Equal(arrayEx, arrayRess) Assert.Equal(arrayEx, arrayRess1) \ No newline at end of file diff --git a/Tests/LineralAlgebraT/UnitLA.fs b/Tests/LineralAlgebraT/UnitLA.fs index 3ecb263a..90523cda 100644 --- a/Tests/LineralAlgebraT/UnitLA.fs +++ b/Tests/LineralAlgebraT/UnitLA.fs @@ -4,8 +4,6 @@ open System open Xunit open LineralAlgebra -open LineralAlgebra.QTrees -open LineralAlgebra.Matrix module DataAndFuncs = @@ -68,18 +66,18 @@ module Map = [] let intId () = - let res = map id intQTree1 + let res = QTrees.map id intQTree1 Assert.Equal(intQTree1, res) [] let floatId () = - let res = map id floatQTree1 + let res = QTrees.map id floatQTree1 Assert.Equal(floatQTree1, res) [] let intAdd () = - let res = map ((+) 1) intQTree1 + let res = QTrees.map ((+) 1) intQTree1 let ex = Node ( Node ( Leaf 2, Leaf 3, Leaf 4, Leaf 5), Node ( Leaf -4, Leaf -5, Leaf -6, Leaf -7), @@ -90,7 +88,7 @@ module Map = [] let floatAdd () = - let res = map ((+) 1.0) floatQTree1 + let res = QTrees.map ((+) 1.0) floatQTree1 let ex = Node ( Node ( Leaf 2.0, Leaf 3.0, Leaf 4.0, Leaf 5.0), Node ( Leaf -4.0, Leaf -5.0, Leaf -6.0, Leaf -7.0), @@ -102,7 +100,7 @@ module Map = [] let intMult () = - let res = map (fun x -> 2 * x) intQTree1 + let res = QTrees.map (fun x -> 2 * x) intQTree1 let ex = Node ( Node ( Leaf 2, Leaf 4, Leaf 6, Leaf 8), Node ( Leaf -10, Leaf -12, Leaf -14, Leaf -16), @@ -113,7 +111,7 @@ module Map = [] let floatMult () = - let res = map (fun x -> 2.0 * x) floatQTree1 + let res = QTrees.map (fun x -> 2.0 * x) floatQTree1 let ex = Node ( Node ( Leaf 2.0, Leaf 4.0, Leaf 6.0, Leaf 8.0), Node ( Leaf -10.0, Leaf -12.0, Leaf -14.0, Leaf -16.0), @@ -127,7 +125,7 @@ module Map = [] let intSign () = - let res = map (fun (x: int) -> Math.Sign x) intQTree1 + let res = QTrees.map (fun (x: int) -> Math.Sign x) intQTree1 let ex = Node ( Leaf 1, Leaf -1, @@ -138,7 +136,7 @@ module Map = [] let floatSign () = - let res = map (fun (x: float) -> Math.Sign x) floatQTree1 + let res = QTrees.map (fun (x: float) -> Math.Sign x) floatQTree1 let ex = Node ( Leaf 1, Leaf -1, @@ -150,8 +148,8 @@ module Map = [] let intComposition () = - let tree1 = map ((+) 1)((map ((+) 2)) intQTree1) - let tree2 = map ((+) 3) intQTree1 + let tree1 = QTrees.map ((+) 1)((QTrees.map ((+) 2)) intQTree1) + let tree2 = QTrees.map ((+) 3) intQTree1 let ex = Node ( Node ( Leaf 4, Leaf 5, Leaf 6, Leaf 7), Node ( Leaf -2, Leaf -3, Leaf -4, Leaf -5), @@ -163,8 +161,8 @@ module Map = [] let floatComposition () = - let tree1 = map ((+) 1.0) (map ((+) 2.0) floatQTree1) - let tree2 = map ((+) 3.0) floatQTree1 + let tree1 = QTrees.map ((+) 1.0) (QTrees.map ((+) 2.0) floatQTree1) + let tree2 = QTrees.map ((+) 3.0) floatQTree1 let ex = Node ( Node ( Leaf 4.0, Leaf 5.0, Leaf 6.0, Leaf 7.0), Node ( Leaf -2.0, Leaf -3.0, Leaf -4.0, Leaf -5.0), @@ -177,15 +175,15 @@ module Map = [] let intHighIsConst () = - let h1 = height intQTree1 - let h2 = height (map ((+) 1) intQTree1) + let h1 = QTrees.height intQTree1 + let h2 = QTrees.height (QTrees.map ((+) 1) intQTree1) Assert.Equal(3, h1) Assert.Equal(3, h2) [] let floatHighIsConst () = - let h1 = height floatQTree1 - let h2 = height (map ((+) 1.0) floatQTree1) + let h1 = QTrees.height floatQTree1 + let h2 = QTrees.height (QTrees.map ((+) 1.0) floatQTree1) Assert.Equal(3, h1) Assert.Equal(3, h2) @@ -197,12 +195,12 @@ module Map = [] let intHighIsExpected () = - let h = height (map (fun (x: int) -> Math.Sign x) intQTree1) + let h = QTrees.height (QTrees.map (fun (x: int) -> Math.Sign x) intQTree1) Assert.Equal(2, h) [] let floatHighIsExpected () = - let h = height (map (fun (x: float) -> Math.Sign x) floatQTree1) + let h = QTrees.height (QTrees.map (fun (x: float) -> Math.Sign x) floatQTree1) Assert.Equal(2, h) @@ -211,7 +209,7 @@ module Map2 = [] let intAdd () = - let res = map2 (+) intQTree1 intQTree2 + let res = QTrees.map2 (+) intQTree1 intQTree2 let ex = Node ( Node ( Leaf 2, Leaf 4, Leaf 6, Leaf 8), Node ( Leaf 0, Leaf -1, Leaf -2, Leaf -3), @@ -222,7 +220,7 @@ module Map2 = [] let floatAdd () = - let res = map2 (+) floatQTree1 floatQTree2 + let res = QTrees.map2 (+) floatQTree1 floatQTree2 let ex = Node ( Node ( Leaf 2.0, Leaf 4.0, Leaf 6.0, Leaf 8.0), Node ( Leaf 0.0, Leaf -1.0, Leaf -2.0, Leaf -3.0), @@ -234,7 +232,7 @@ module Map2 = [] let intMult () = - let res = map2 (fun x y -> x * y) intQTree1 intQTree2 + let res = QTrees.map2 (fun x y -> x * y) intQTree1 intQTree2 let ex = Node ( Node ( Leaf 1, Leaf 4, Leaf 9, Leaf 16), Node ( Leaf -25, Leaf -30, Leaf -35, Leaf -40), @@ -245,7 +243,7 @@ module Map2 = [] let floatMult () = - let res = map2 (fun x y -> x * y) floatQTree1 floatQTree2 + let res = QTrees.map2 (fun x y -> x * y) floatQTree1 floatQTree2 let ex = Node ( Node ( Leaf 1.0, Leaf 4.0, Leaf 9.0, Leaf 16.0), Node ( Leaf -25.0, Leaf -30.0, Leaf -35.0, Leaf -40.0), @@ -257,19 +255,19 @@ module Map2 = [] let intHighIsExpected () = - let h1 = height intQTree1 - let h2 = height intOneLeaf1 + let h1 = QTrees.height intQTree1 + let h2 = QTrees.height intOneLeaf1 let h3 = max h1 h2 - let h4 = height (map2 (+) intQTree1 intOneLeaf1) + let h4 = QTrees.height (QTrees.map2 (+) intQTree1 intOneLeaf1) Assert.Equal(3, h3) Assert.Equal(3, h4) [] let floatHighIsExpected () = - let h1 = height floatQTree1 - let h2 = height floatOneLeaf + let h1 = QTrees.height floatQTree1 + let h2 = QTrees.height floatOneLeaf let h3 = max h1 h2 - let h4 = height (map2 (+) floatQTree1 floatOneLeaf) + let h4 = QTrees.height (QTrees.map2 (+) floatQTree1 floatOneLeaf) Assert.Equal(3, h3) Assert.Equal(3, h4) @@ -279,22 +277,22 @@ module Mult = [] let sizeIsImportant () = - let res1 = multiply MintOneLeaf3 MintOneLeaf4 (+) ( * ) + let res1 = Matrix.multiply MintOneLeaf3 MintOneLeaf4 (+) ( * ) let ex1 = { n = 1; qtree = Leaf 6 } - let res2 = multiply MintNode1 MintNode2 (+) ( * ) + let res2 = Matrix.multiply MintNode1 MintNode2 (+) ( * ) let ex2 = { n = 2; qtree = Leaf 12 } Assert.Equal(ex1, res1) Assert.Equal(ex2, res2) [] let leafLeaf () = - let res = multiply MintOneLeaf3 MintOneLeaf4 (+) ( * ) + let res = Matrix.multiply MintOneLeaf3 MintOneLeaf4 (+) ( * ) let ex = { n = 1; qtree = Leaf 6 } Assert.Equal(ex, res) [] let nodeLeaf () = - let res = multiply MintQTree1 MintOneLeaf1 (+) ( * ) + let res = Matrix.multiply MintQTree1 MintOneLeaf1 (+) ( * ) let ex = { n = 4; qtree = Node ( @@ -308,7 +306,7 @@ module Mult = [] let leafNode () = - let res = multiply MintOneLeaf1 MintQTree1 (+) ( * ) + let res = Matrix.multiply MintOneLeaf1 MintQTree1 (+) ( * ) let ex = { n = 4; qtree = Node ( @@ -322,7 +320,7 @@ module Mult = [] let nodeNode () = - let res = multiply MintQTree1 MintQTree2 (+) ( * ) + let res = Matrix.multiply MintQTree1 MintQTree2 (+) ( * ) let ex = { n = 4; qtree = Node ( @@ -336,8 +334,8 @@ module Mult = [] let zero () = - let res1 = multiply MintQTree1 MintZero (+) ( * ) - let res2 = multiply MintZero MintQTree1 (+) ( * ) + let res1 = Matrix.multiply MintQTree1 MintZero (+) ( * ) + let res2 = Matrix.multiply MintZero MintQTree1 (+) ( * ) let ex = { n = 4; qtree = Leaf 0 } Assert.Equal(ex, res1) Assert.Equal(ex, res2) \ No newline at end of file diff --git a/src/ImageProcessing/ImageProcessing.fs b/src/ImageProcessing/ImageProcessing.fs index 653a8620..04f686ab 100644 --- a/src/ImageProcessing/ImageProcessing.fs +++ b/src/ImageProcessing/ImageProcessing.fs @@ -2,6 +2,9 @@ namespace ImageProcessing open SixLabors.ImageSharp open SixLabors.ImageSharp.PixelFormats +open System.Threading.Tasks +open Microsoft.FSharp.Control +open System.IO [] type Image = @@ -183,6 +186,193 @@ module ImProcessing = |> Array.map (Array.map (fun x -> (float32 x) / + 128.0f)) + let loadAsRgba2DA (file: string) = + async { + use fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize = 4096, useAsync = true) + + let! img = Image.LoadAsync fileStream |> Async.AwaitTask + let res = Array2D.zeroCreate img.Height img.Width + + for i in 0 .. img.Width - 1 do + for j in 0 .. img.Height - 1 do + res.[j, i] <- img.[i, j] + + return res + } + + let saveRgbaImageA (rgbaDataAsync: Async) file = + async { + let! rgbaData = rgbaDataAsync + + let h = rgbaData.GetLength 0 + let w = rgbaData.GetLength 1 + + use img = new Image(w, h) + + for x in 0 .. h - 1 do + for y in 0 .. w - 1 do + img.[y, x] <- rgbaData.[x, y] + + let! _ = img.SaveAsync file |> Async.AwaitTask + return () + } + + let processPixel px py (filter: float32 array) filterD (img: Rgba32[,]) imgH imgW = + let dataToHandle = [| + for i in px - filterD .. px + filterD do + for j in py - filterD .. py + filterD do + if i < 0 || i >= imgH || j < 0 || j >= imgW then + 0.0f, 0.0f, 0.0f + else + let pixel = img.[i, j] + float32 pixel.R, float32 pixel.G, float32 pixel.B + |] + + let mutable rSum = 0.0f + let mutable gSum = 0.0f + let mutable bSum = 0.0f + + Array.iteri (fun index (r, g, b) -> + rSum <- rSum + r * filter.[index] + gSum <- gSum + g * filter.[index] + bSum <- bSum + b * filter.[index] + ) dataToHandle + + byte rSum, byte gSum, byte bSum // Async<[,]> + + let applyFilterNoParallelismA (filter: float32[][]) (imgAsync: Async) = + async { + let! img = imgAsync + + let imgH = img.GetLength 0 + let imgW = img.GetLength 1 + + let filterD = Array.length filter / 2 + let filter = Array.concat filter + + let res = + Array2D.mapi (fun x y _ -> + let r, g, b = processPixel x y filter filterD img imgH imgW + Rgba32(r, g, b, img.[x, y].A) + ) img + return res + } + + let applyFilterPixelParallelismA (filter: float32[][]) (imgAsync: Async) = + async { + let! img = imgAsync + + let imgH = img.GetLength 0 + let imgW = img.GetLength 1 + + let filterD = Array.length filter / 2 + let filter = Array.concat filter + + let res = Array2D.create imgH imgW (Rgba32(0.0f, 0.0f, 0.0f, 0.0f)) + + Parallel.For(0, imgH * imgW, fun k -> + let i = k / imgW + let j = k % imgW + + let r, g, b = processPixel i j filter filterD img imgH imgW + res.[i, j] <- Rgba32(r, g, b, img.[i, j].A) + + ) |> ignore + + return res + } + + let applyFilterParallelismInPartsA (filter: float32[][]) (imgAsync: Async) = + async { + let! img = imgAsync + + let imgH = img.GetLength 0 + let imgW = img.GetLength 1 + + let filterD = Array.length filter / 2 + let filter = Array.concat filter + + let halfImgH = imgH / 2 + let halfImgW = imgW / 2 + + let res = Array2D.create imgH imgW (Rgba32(0.0f, 0.0f, 0.0f, 0.0f)) + + Parallel.For (0, 4, fun k -> + if k = 0 then + for i in 0 .. halfImgH - 1 do + for j in 0 .. halfImgW - 1 do + let r, g, b = processPixel i j filter filterD img imgH imgW + res.[i, j] <- Rgba32(r, g, b, img.[i, j].A) + + elif k = 1 then + for i in halfImgH .. imgH - 1 do + for j in 0 .. halfImgW - 1 do + let r, g, b = processPixel i j filter filterD img imgH imgW + res.[i, j] <- Rgba32(r, g, b, img.[i, j].A) + + elif k = 2 then + for i in 0 .. halfImgH - 1 do + for j in halfImgW .. imgW - 1 do + let r, g, b = processPixel i j filter filterD img imgH imgW + res.[i, j] <- Rgba32(r, g, b, img.[i, j].A) + + else + for i in halfImgH .. imgH - 1 do + for j in halfImgW .. imgW - 1 do + let r, g, b = processPixel i j filter filterD img imgH imgW + res.[i, j] <- Rgba32(r, g, b, img.[i, j].A) + ) |> ignore + + return res + } + + let applyFilterRowParallelismA (filter: float32[][]) (imgAsync: Async) = + async { + let! img = imgAsync + + let imgH = img.GetLength 0 + let imgW = img.GetLength 1 + + let filterD = Array.length filter / 2 + let filter = Array.concat filter + + let res = Array2D.create imgH imgW (Rgba32(0.0f, 0.0f, 0.0f, 0.0f)) + + Parallel.For (0, imgH, fun k -> + for i in 0 .. imgW - 1 do + let r, g, b = processPixel k i filter filterD img imgH imgW + res.[k, i] <- Rgba32(r, g, b, img.[k, i].A) + ) |> ignore + + return res + } + + let applyFilterColParallelismA (filter: float32[][]) (imgAsync: Async) = + async { + let! img = imgAsync + + let imgH = img.GetLength 0 + let imgW = img.GetLength 1 + + let filterD = Array.length filter / 2 + let filter = Array.concat filter + + let res = Array2D.create imgH imgW (Rgba32(0.0f, 0.0f, 0.0f, 0.0f)) + + Parallel.For (0, imgW, fun k -> + for i in 0 .. imgH - 1 do + let r, g, b = processPixel i k filter filterD img imgH imgW + res.[i, k] <- Rgba32(r, g, b, img.[i, k].A) + ) |> ignore + + return res + } + + + +// СИНХРОННАЯ ВЕРСИЯ ФУНКЦИЙ ВЫШЕ + + let loadAsRgba2D (file: string) = let img = Image.Load file let res = Array2D.zeroCreate img.Height img.Width @@ -190,12 +380,11 @@ module ImProcessing = for i in 0 .. img.Width - 1 do for j in 0 .. img.Height - 1 do res.[j, i] <- img.[i, j] - res let saveRgbaImage (rgbaData: Rgba32[,]) file = - let h = rgbaData.GetLength(0) - let w = rgbaData.GetLength(1) + let h = rgbaData.GetLength 0 + let w = rgbaData.GetLength 1 use img = new Image(w, h) @@ -203,39 +392,106 @@ module ImProcessing = for y in 0 .. w - 1 do img.[y, x] <- rgbaData.[x, y] - img.Save(file) + img.Save file - let applyFilter (filter: float32[][]) (img: Rgba32[,]) = + let applyFilterNoParallelism (filter: float32[][]) (img: Rgba32[,]) = let imgH = img.GetLength 0 let imgW = img.GetLength 1 - let filterD = (Array.length filter) / 2 + let filterD = Array.length filter / 2 let filter = Array.concat filter - let processPixel px py = - let dataToHandle = [| - for i in px - filterD .. px + filterD do - for j in py - filterD .. py + filterD do - if i < 0 || i >= imgH || j < 0 || j >= imgW then - (0.0f, 0.0f, 0.0f) - else - let pixel = img.[i, j] - (float32 pixel.R, float32 pixel.G, float32 pixel.B) - |] - - let mutable rSum = 0.0f - let mutable gSum = 0.0f - let mutable bSum = 0.0f - - Array.iteri (fun index (r, g, b) -> - rSum <- rSum + r * filter.[index] - gSum <- gSum + g * filter.[index] - bSum <- bSum + b * filter.[index] - ) dataToHandle - - (byte rSum, byte gSum, byte bSum) - Array2D.mapi (fun x y _ -> - let (r, g, b) = processPixel x y + let r, g, b = processPixel x y filter filterD img imgH imgW Rgba32(r, g, b, img.[x, y].A) - ) img \ No newline at end of file + ) img + + let applyFilterPixelParallelism (filter: float32[][]) (img: Rgba32[,]) = + let imgH = img.GetLength 0 + let imgW = img.GetLength 1 + + let filterD = Array.length filter / 2 + let filter = Array.concat filter + + let res = Array2D.create imgH imgW (Rgba32(0.0f, 0.0f, 0.0f, 0.0f)) + + Parallel.For(0, imgH * imgW, fun k -> + let i = k / imgW + let j = k % imgW + + let r, g, b = processPixel i j filter filterD img imgH imgW + res.[i, j] <- Rgba32(r, g, b, img.[i, j].A) + + ) |> ignore + res + + let applyFilterParallelismInParts (filter: float32[][]) (img: Rgba32[,]) = + let imgH = img.GetLength 0 + let imgW = img.GetLength 1 + + let filterD = Array.length filter / 2 + let filter = Array.concat filter + + let halfImgH = imgH / 2 + let halfImgW = imgW / 2 + + let res = Array2D.create imgH imgW (Rgba32(0.0f, 0.0f, 0.0f, 0.0f)) + + Parallel.For (0, 4, fun k -> + if k = 0 then + for i in 0 .. halfImgH - 1 do + for j in 0 .. halfImgW - 1 do + let r, g, b = processPixel i j filter filterD img imgH imgW + res.[i, j] <- Rgba32(r, g, b, img.[i, j].A) + + elif k = 1 then + for i in halfImgH .. imgH - 1 do + for j in 0 .. halfImgW - 1 do + let r, g, b = processPixel i j filter filterD img imgH imgW + res.[i, j] <- Rgba32(r, g, b, img.[i, j].A) + + elif k = 2 then + for i in 0 .. halfImgH - 1 do + for j in halfImgW .. imgW - 1 do + let r, g, b = processPixel i j filter filterD img imgH imgW + res.[i, j] <- Rgba32(r, g, b, img.[i, j].A) + + else + for i in halfImgH .. imgH - 1 do + for j in halfImgW .. imgW - 1 do + let r, g, b = processPixel i j filter filterD img imgH imgW + res.[i, j] <- Rgba32(r, g, b, img.[i, j].A) + ) |> ignore + res + + let applyFilterRowParallelism (filter: float32[][]) (img: Rgba32[,]) = + let imgH = img.GetLength 0 + let imgW = img.GetLength 1 + + let filterD = Array.length filter / 2 + let filter = Array.concat filter + + let res = Array2D.create imgH imgW (Rgba32(0.0f, 0.0f, 0.0f, 0.0f)) + + Parallel.For (0, imgH, fun k -> + for i in 0 .. imgW - 1 do + let r, g, b = processPixel k i filter filterD img imgH imgW + res.[k, i] <- Rgba32(r, g, b, img.[k, i].A) + ) |> ignore + res + + let applyFilterColParallelism (filter: float32[][]) (img: Rgba32[,]) = + let imgH = img.GetLength 0 + let imgW = img.GetLength 1 + + let filterD = Array.length filter / 2 + let filter = Array.concat filter + + let res = Array2D.create imgH imgW (Rgba32(0.0f, 0.0f, 0.0f, 0.0f)) + + Parallel.For (0, imgW, fun k -> + for i in 0 .. imgH - 1 do + let r, g, b = processPixel i k filter filterD img imgH imgW + res.[i, k] <- Rgba32(r, g, b, img.[i, k].A) + ) |> ignore + res \ No newline at end of file diff --git a/src/ImageProcessing/Program.fs b/src/ImageProcessing/Program.fs index f78667ad..e191ff74 100644 --- a/src/ImageProcessing/Program.fs +++ b/src/ImageProcessing/Program.fs @@ -1,72 +1,163 @@ -open ImageProcessing.ImProcessing +open System +open System.Threading.Tasks +open System.IO +open ImageProcessing.ImProcessing open Argu - +open SixLabors.ImageSharp.PixelFormats type Filters = - | gaussianBlur = 1 - | motionDiagonal135deg = 2 - | motionDiagonal315deg = 3 - | motionVertical = 4 - | motionHorizontal = 5 - | edgesHorizontal = 6 - | edgesVertical = 7 - | edgesDioganal135deg = 8 - | edgesDioganal315deg = 9 - | edgesAllDirections = 10 - | sharpen = 11 - | sharpenSoft = 12 - | sharpenWithEdges = 13 - | emboss = 14 - | embossHard = 15 + | GaussianBlur + | MotionDiagonal135deg + | MotionDiagonal315deg + | MotionVertical + | MotionHorizontal + | EdgesHorizontal + | EdgesVertical + | EdgesDioganal135deg + | EdgesDioganal315deg + | EdgesAllDirections + | Sharpen + | SharpenSoft + | SharpenWithEdges + | Emboss + | EmbossHard + + +type ParallelismTypes = + | NoParallelism + | PixelParallelism + | ParallelismInParts + | RowParallelism + | ColParallelism + type Arguments = - | [] Input_File of string - | [] Out_File of string + | [] Input_Folder of string + | [] Out_Folder of string | [] Filters of list + | [] Parallelism of list interface IArgParserTemplate with member this.Usage = match this with - | Input_File _ -> "File to process." - | Out_File _ -> "Where to save result." + | Input_Folder _ -> "Folder with images for processing." + | Out_Folder _ -> "Folder for processed images." | Filters _ -> "Which filters to apply (comma-separated)." + | Parallelism _ -> "Type of parallelism." + + +type FileProcessorMessage = + | ProcessImage of string * string * list * list * AsyncReplyChannel> + | Stop + + +let createFileProcessor () = + let getParallelismType (parallelism: list) (filter: float32[][]) (img: Async) = + match parallelism.[0] with + | NoParallelism -> applyFilterColParallelismA filter img + | PixelParallelism -> applyFilterPixelParallelismA filter img + | ParallelismInParts -> applyFilterParallelismInPartsA filter img + | RowParallelism -> applyFilterRowParallelismA filter img + | ColParallelism -> applyFilterColParallelismA filter img + + MailboxProcessor.Start(fun inbox -> + + let rec loop () = + async { + let! msg = inbox.Receive() + + match msg with + | ProcessImage (sourcePath, destinationPath, filters, parallelism, replyChannel) -> + try + let imageData = loadAsRgba2DA sourcePath + let! filteredImage = + filters |> List.fold (fun img filter -> + match filter with + | GaussianBlur -> getParallelismType parallelism gaussianBlur img + | MotionDiagonal135deg -> getParallelismType parallelism motionDiagonal135deg img + | MotionDiagonal315deg -> getParallelismType parallelism motionDiagonal315deg img + | MotionVertical -> getParallelismType parallelism motionVertical img + | MotionHorizontal -> getParallelismType parallelism motionHorizontal img + | EdgesHorizontal -> getParallelismType parallelism edgesHorizontal img + | EdgesVertical -> getParallelismType parallelism edgesVertical img + | EdgesDioganal135deg -> getParallelismType parallelism edgesDioganal135deg img + | EdgesDioganal315deg -> getParallelismType parallelism edgesDioganal315deg img + | EdgesAllDirections -> getParallelismType parallelism edgesAllDirections img + | Sharpen -> getParallelismType parallelism sharpen img + | SharpenSoft -> getParallelismType parallelism sharpenSoft img + | SharpenWithEdges -> getParallelismType parallelism sharpenWithEdges img + | Emboss -> getParallelismType parallelism emboss img + | EmbossHard -> getParallelismType parallelism embossHard img + + ) imageData + + do! saveRgbaImageA (async.Return filteredImage) destinationPath + replyChannel.Reply(Ok ()) + return! loop () + with + | ex -> + replyChannel.Reply(Error ex.Message) + return! loop () + + | Stop -> + return () + } + loop () + ) [] let main argv = - + + let fileProcessor = createFileProcessor () + + let processImageAsync (sourcePath: string) (destinationPath: string) (filters: list) (parallelism: list) = + async { + let! reply = fileProcessor.PostAndAsyncReply (fun replyChannel -> ProcessImage(sourcePath, destinationPath, filters, parallelism, replyChannel)) + return reply + } + let parser = ArgumentParser.Create(programName = "ImageProcessing") let results = parser.Parse argv - let inFile = results.GetResult Input_File - let outFile = results.GetResult Out_File + let inFolder = results.GetResult Input_Folder + let outFolder = results.GetResult Out_Folder let filters = results.GetResult Filters + let parallelisms = results.GetResult Parallelism + + + if not (Directory.Exists inFolder) then + printfn $"Error: Input folder '{inFolder}' does not exist." + 1 + else + let imageFiles = + try + Directory.GetFiles(inFolder, "*.*") + |> Array.filter (fun file -> + let extension = Path.GetExtension file + extension.ToLower() = ".jpg" || extension.ToLower() = ".jpeg" || extension.ToLower() = ".png" || extension.ToLower() = ".bmp") + |> Array.toList + with ex -> + printfn $"Error getting image files from '{inFolder}': {ex.Message}" + [] + + if imageFiles.IsEmpty then + printfn $"Error: No images found in input folder '{inFolder}'." + 1 + else + Directory.CreateDirectory outFolder |> ignore + + let processingTasks = + imageFiles + |> List.map (fun sourcePath -> + let filename = Path.GetFileName sourcePath + let destinationPath = Path.Combine(outFolder, filename) + processImageAsync sourcePath destinationPath filters parallelisms + ) + + Async.AwaitTask (Task.WhenAll(processingTasks |> List.map Async.StartAsTask |> List.toArray)) |> Async.RunSynchronously |> ignore + + fileProcessor.Post Stop + + printfn "Processing complete." - let inImage = loadAsRgba2D inFile - - let resultImage = - filters |> List.fold (fun img filter -> - match filter with - | Filters.gaussianBlur -> applyFilter gaussianBlur img - | Filters.motionDiagonal135deg -> applyFilter motionDiagonal135deg img - | Filters.motionDiagonal315deg -> applyFilter motionDiagonal315deg img - | Filters.motionVertical -> applyFilter motionVertical img - | Filters.motionHorizontal -> applyFilter motionHorizontal img - | Filters.edgesHorizontal -> applyFilter edgesHorizontal img - | Filters.edgesVertical -> applyFilter edgesVertical img - | Filters.edgesDioganal135deg -> applyFilter edgesDioganal135deg img - | Filters.edgesDioganal315deg -> applyFilter edgesDioganal315deg img - | Filters.edgesAllDirections -> applyFilter edgesAllDirections img - | Filters.sharpen -> applyFilter sharpen img - | Filters.sharpenSoft -> applyFilter sharpenSoft img - | Filters.sharpenWithEdges -> applyFilter sharpenWithEdges img - | Filters.emboss -> applyFilter emboss img - | Filters.embossHard -> applyFilter embossHard img - | _ -> - printfn "Unknown filter" - img - - ) inImage - - saveRgbaImage resultImage outFile - - 0 \ No newline at end of file + 0 \ No newline at end of file diff --git a/src/LineralAlgebra/LineralAlgebra.fs b/src/LineralAlgebra/LineralAlgebra.fs index 46b101cd..422f9120 100644 --- a/src/LineralAlgebra/LineralAlgebra.fs +++ b/src/LineralAlgebra/LineralAlgebra.fs @@ -15,15 +15,15 @@ type Matrix<'t> = module private Private = - let rec private toCorrectQTreePrivate qtree = + let rec toCorrectQTree qtree = match qtree with | Leaf value -> Leaf value | Node (nw, ne, se, sw) -> - let NW = toCorrectQTreePrivate nw - let NE = toCorrectQTreePrivate ne - let SE = toCorrectQTreePrivate se - let SW = toCorrectQTreePrivate sw + let NW = toCorrectQTree nw + let NE = toCorrectQTree ne + let SE = toCorrectQTree se + let SW = toCorrectQTree sw match NW, NE, SE, SW with | Leaf value1, @@ -36,14 +36,13 @@ module private Private = | _ -> Node (NW, NE, SE, SW) - let toCorrectQTree qtree = - qtree |> toCorrectQTreePrivate - open Private module QTrees = + let toCorrectQTree qtree = + qtree |> toCorrectQTree let rec map func qtree = match qtree with @@ -129,7 +128,15 @@ module QTrees = Array.max heights + 1 -module Matrix = +module Matrix = + + let map func (matr: Matrix<'t>) = + let res = QTrees.map func matr.qtree + { n = matr.n; qtree = res } + + let map2 func (matr1: Matrix<'t>) (matr2: Matrix<'t>) = + let res = QTrees.map2 func matr1.qtree matr2.qtree + { n = max matr1.n matr2.n; qtree = res } let rec private add qtree1 qtree2 size (opAdd: 't -> 't -> 't) (opMult: 't -> 't -> 't) = match qtree1, qtree2 with diff --git a/src/LineralAlgebra/LineralAlgebra.fsproj b/src/LineralAlgebra/LineralAlgebra.fsproj index 37391835..f5bc22e4 100644 --- a/src/LineralAlgebra/LineralAlgebra.fsproj +++ b/src/LineralAlgebra/LineralAlgebra.fsproj @@ -4,7 +4,7 @@ net8.0 true LineralAlgebra - 1.0.4 + 1.1.0 Me Also me This package is part of my homework that will be used in my other homework. But if you somehow stumbled upon it, here's its readme diff --git a/src/Res/res.png b/src/Res/res.png new file mode 100644 index 00000000..98e59e00 Binary files /dev/null and b/src/Res/res.png differ diff --git a/src/img/NewCanvas2.png b/src/img/NewCanvas2.png new file mode 100644 index 00000000..68717c20 Binary files /dev/null and b/src/img/NewCanvas2.png differ diff --git a/src/img/id.png b/src/img/id.png new file mode 100644 index 00000000..d270290e Binary files /dev/null and b/src/img/id.png differ