diff --git a/.gitignore b/.gitignore
index 15a14fd0..60b2ea06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,400 @@
-src/Library/bin/
-src/Library/obj/
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
-Tests/bin/
-Tests/obj/
-Tests/TestResults/
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
-Benchmarks/bin/
-Benchmarks/obj/
-Benchmarks/BenchmarkDotNet.Artifacts/
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
-GraphsAndStatistics/venv/
\ No newline at end of file
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+# but not Directory.Build.rsp, as it configures directory-level build defaults
+!Directory.Build.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.tlog
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio 6 auto-generated project file (contains which files were open etc.)
+*.vbp
+
+# Visual Studio 6 workspace and project file (working project files containing files to include in project)
+*.dsw
+*.dsp
+
+# Visual Studio 6 technical files
+*.ncb
+*.aps
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# Visual Studio History (VSHistory) files
+.vshistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+# VS Code files for those working on multiple tools
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# JetBrains Rider
+*.sln.iml
\ No newline at end of file
diff --git a/Benchmarks/ImProcessingB/ImProcessingB.fsproj b/Benchmarks/ImProcessingB/ImProcessingB.fsproj
new file mode 100644
index 00000000..e9b982df
--- /dev/null
+++ b/Benchmarks/ImProcessingB/ImProcessingB.fsproj
@@ -0,0 +1,21 @@
+
+
+
+ Exe
+ net8.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Benchmarks/ImProcessingB/Program.fs b/Benchmarks/ImProcessingB/Program.fs
new file mode 100644
index 00000000..2fdaa4db
--- /dev/null
+++ b/Benchmarks/ImProcessingB/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/Program.fs b/Benchmarks/SortingsB/Program.fs
similarity index 96%
rename from Benchmarks/Program.fs
rename to Benchmarks/SortingsB/Program.fs
index 34a08ad2..8e9a7502 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 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
diff --git a/Benchmarks/Benchmarks.fsproj b/Benchmarks/SortingsB/SortingsB.fsproj
similarity index 81%
rename from Benchmarks/Benchmarks.fsproj
rename to Benchmarks/SortingsB/SortingsB.fsproj
index f08f2399..eb948afd 100644
--- a/Benchmarks/Benchmarks.fsproj
+++ b/Benchmarks/SortingsB/SortingsB.fsproj
@@ -1,20 +1,20 @@
-
-
-
- Exe
- net8.0
-
-
-
-
-
-
+
+
+
+ Exe
+ net8.0
+
+
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
diff --git a/GraphsAndStatistics/Array Performance.png b/GraphicsAndStatistics/Array Performance.png
similarity index 100%
rename from GraphsAndStatistics/Array Performance.png
rename to GraphicsAndStatistics/Array Performance.png
diff --git a/GraphsAndStatistics/BubbleCompare.png b/GraphicsAndStatistics/BubbleCompare.png
similarity index 100%
rename from GraphsAndStatistics/BubbleCompare.png
rename to GraphicsAndStatistics/BubbleCompare.png
diff --git a/GraphsAndStatistics/MergeCompare.png b/GraphicsAndStatistics/MergeCompare.png
similarity index 100%
rename from GraphsAndStatistics/MergeCompare.png
rename to GraphicsAndStatistics/MergeCompare.png
diff --git a/GraphsAndStatistics/MyList Performance.png b/GraphicsAndStatistics/MyList Performance.png
similarity index 100%
rename from GraphsAndStatistics/MyList Performance.png
rename to GraphicsAndStatistics/MyList Performance.png
diff --git a/GraphsAndStatistics/QuickCompare.png b/GraphicsAndStatistics/QuickCompare.png
similarity index 100%
rename from GraphsAndStatistics/QuickCompare.png
rename to GraphicsAndStatistics/QuickCompare.png
diff --git a/GraphsAndStatistics/main.py b/GraphicsAndStatistics/main.py
similarity index 100%
rename from GraphsAndStatistics/main.py
rename to GraphicsAndStatistics/main.py
diff --git a/GraphicsAndStatistics/presentation.pdf b/GraphicsAndStatistics/presentation.pdf
new file mode 100644
index 00000000..58d7034d
Binary files /dev/null and b/GraphicsAndStatistics/presentation.pdf differ
diff --git a/HomeWork.sln b/HomeWork.sln
index 36ce6c22..0139a377 100644
--- a/HomeWork.sln
+++ b/HomeWork.sln
@@ -5,11 +5,33 @@ VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{00DFC406-0A95-4C11-8BF2-4FD28C28061D}"
EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Library", "src\Library\Library.fsproj", "{B853FD9B-45DA-4524-8E5D-9BDC24C29F63}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B4AC50D2-34AD-46DF-B39E-FBCC5D0653C6}"
EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tests", "Tests\Tests.fsproj", "{8FFAF33E-03C8-4A55-84E1-C42E0C602625}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Functions", "src\Functions\Functions.fsproj", "{F793D6BB-E68A-473E-B11F-1D7888DF4D4A}"
EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Benchmarks", "Benchmarks\Benchmarks.fsproj", "{66023F5A-8456-4F66-9318-A0BFB68ED14A}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FunctionsT", "Tests\FunctionsT\FunctionsT.fsproj", "{66214A3F-2D3A-4A98-8A9E-25412278BABD}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Sortings", "src\Sortings\Sortings.fsproj", "{55D388AF-E9D9-4EC0-923A-0735BFD93CB8}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "SortingsT", "Tests\SortingsT\SortingsT.fsproj", "{1D6CFA13-FD9D-4586-A463-1C023123E2CA}"
+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}") = "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}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "LineralAlgebra", "src\LineralAlgebra\LineralAlgebra.fsproj", "{C05FDC93-8EE3-442C-868A-031CE2A5F4E4}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "LineralAlgebraT", "Tests\LineralAlgebraT\LineralAlgebraT.fsproj", "{C42A6017-8A61-4469-8FCD-EEBF49198D80}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{6069DD77-A270-4D88-97FF-61D1AB48754C}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "SortingsB", "Benchmarks\SortingsB\SortingsB.fsproj", "{FA459D58-7CC6-491C-82AE-12618F55CBEF}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ImProcessingB", "Benchmarks\ImProcessingB\ImProcessingB.fsproj", "{F44DA1CA-F101-4C9A-97EB-AECD77885CC6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -20,20 +42,67 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {B853FD9B-45DA-4524-8E5D-9BDC24C29F63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B853FD9B-45DA-4524-8E5D-9BDC24C29F63}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B853FD9B-45DA-4524-8E5D-9BDC24C29F63}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B853FD9B-45DA-4524-8E5D-9BDC24C29F63}.Release|Any CPU.Build.0 = Release|Any CPU
- {8FFAF33E-03C8-4A55-84E1-C42E0C602625}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8FFAF33E-03C8-4A55-84E1-C42E0C602625}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8FFAF33E-03C8-4A55-84E1-C42E0C602625}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8FFAF33E-03C8-4A55-84E1-C42E0C602625}.Release|Any CPU.Build.0 = Release|Any CPU
- {66023F5A-8456-4F66-9318-A0BFB68ED14A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {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
+ {F793D6BB-E68A-473E-B11F-1D7888DF4D4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F793D6BB-E68A-473E-B11F-1D7888DF4D4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F793D6BB-E68A-473E-B11F-1D7888DF4D4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F793D6BB-E68A-473E-B11F-1D7888DF4D4A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66214A3F-2D3A-4A98-8A9E-25412278BABD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {66214A3F-2D3A-4A98-8A9E-25412278BABD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66214A3F-2D3A-4A98-8A9E-25412278BABD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {66214A3F-2D3A-4A98-8A9E-25412278BABD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {55D388AF-E9D9-4EC0-923A-0735BFD93CB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {55D388AF-E9D9-4EC0-923A-0735BFD93CB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {55D388AF-E9D9-4EC0-923A-0735BFD93CB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {55D388AF-E9D9-4EC0-923A-0735BFD93CB8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1D6CFA13-FD9D-4586-A463-1C023123E2CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1D6CFA13-FD9D-4586-A463-1C023123E2CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1D6CFA13-FD9D-4586-A463-1C023123E2CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1D6CFA13-FD9D-4586-A463-1C023123E2CA}.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
+ {7B9D1692-F56C-43C7-92BA-2CDDE21A7D57}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EB2F699B-DE06-42EC-974A-A2C39E5C8D2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EB2F699B-DE06-42EC-974A-A2C39E5C8D2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EB2F699B-DE06-42EC-974A-A2C39E5C8D2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EB2F699B-DE06-42EC-974A-A2C39E5C8D2A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CAC5303C-D4CF-493E-94B4-4409BE7F2865}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CAC5303C-D4CF-493E-94B4-4409BE7F2865}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CAC5303C-D4CF-493E-94B4-4409BE7F2865}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CAC5303C-D4CF-493E-94B4-4409BE7F2865}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7E4032B2-27F7-4691-8474-5C57A97F5721}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7E4032B2-27F7-4691-8474-5C57A97F5721}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7E4032B2-27F7-4691-8474-5C57A97F5721}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7E4032B2-27F7-4691-8474-5C57A97F5721}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C05FDC93-8EE3-442C-868A-031CE2A5F4E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C05FDC93-8EE3-442C-868A-031CE2A5F4E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C05FDC93-8EE3-442C-868A-031CE2A5F4E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C05FDC93-8EE3-442C-868A-031CE2A5F4E4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C42A6017-8A61-4469-8FCD-EEBF49198D80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {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
+ {FA459D58-7CC6-491C-82AE-12618F55CBEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FA459D58-7CC6-491C-82AE-12618F55CBEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FA459D58-7CC6-491C-82AE-12618F55CBEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FA459D58-7CC6-491C-82AE-12618F55CBEF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F44DA1CA-F101-4C9A-97EB-AECD77885CC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F44DA1CA-F101-4C9A-97EB-AECD77885CC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F44DA1CA-F101-4C9A-97EB-AECD77885CC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F44DA1CA-F101-4C9A-97EB-AECD77885CC6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
- {B853FD9B-45DA-4524-8E5D-9BDC24C29F63} = {00DFC406-0A95-4C11-8BF2-4FD28C28061D}
+ {F793D6BB-E68A-473E-B11F-1D7888DF4D4A} = {00DFC406-0A95-4C11-8BF2-4FD28C28061D}
+ {66214A3F-2D3A-4A98-8A9E-25412278BABD} = {B4AC50D2-34AD-46DF-B39E-FBCC5D0653C6}
+ {55D388AF-E9D9-4EC0-923A-0735BFD93CB8} = {00DFC406-0A95-4C11-8BF2-4FD28C28061D}
+ {1D6CFA13-FD9D-4586-A463-1C023123E2CA} = {B4AC50D2-34AD-46DF-B39E-FBCC5D0653C6}
+ {7B9D1692-F56C-43C7-92BA-2CDDE21A7D57} = {00DFC406-0A95-4C11-8BF2-4FD28C28061D}
+ {EB2F699B-DE06-42EC-974A-A2C39E5C8D2A} = {B4AC50D2-34AD-46DF-B39E-FBCC5D0653C6}
+ {CAC5303C-D4CF-493E-94B4-4409BE7F2865} = {00DFC406-0A95-4C11-8BF2-4FD28C28061D}
+ {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}
+ {FA459D58-7CC6-491C-82AE-12618F55CBEF} = {6069DD77-A270-4D88-97FF-61D1AB48754C}
+ {F44DA1CA-F101-4C9A-97EB-AECD77885CC6} = {6069DD77-A270-4D88-97FF-61D1AB48754C}
EndGlobalSection
EndGlobal
diff --git a/LICENSE b/LICENSE
index 28063e6a..490e1882 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2024 Kate Titova
+Copyright (c) 2025 Kate Titova
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Tests/FunctionsT/FunctionsT.fsproj b/Tests/FunctionsT/FunctionsT.fsproj
new file mode 100644
index 00000000..b448ceba
--- /dev/null
+++ b/Tests/FunctionsT/FunctionsT.fsproj
@@ -0,0 +1,27 @@
+
+
+
+ net8.0
+
+ false
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/FunctionsT/Program.fs b/Tests/FunctionsT/Program.fs
new file mode 100644
index 00000000..fdc31cde
--- /dev/null
+++ b/Tests/FunctionsT/Program.fs
@@ -0,0 +1 @@
+module Program = let [] main _ = 0
diff --git a/Tests/UnitTestsFunctions.fs b/Tests/FunctionsT/UnitFunctions.fs
similarity index 82%
rename from Tests/UnitTestsFunctions.fs
rename to Tests/FunctionsT/UnitFunctions.fs
index 5278c26b..009d3ada 100644
--- a/Tests/UnitTestsFunctions.fs
+++ b/Tests/FunctionsT/UnitFunctions.fs
@@ -1,52 +1,52 @@
-namespace UnitTestsFunctions
-
-open System
-open Microsoft.VisualStudio.TestTools.UnitTesting
-
-open Functions.Factorial
-open Functions.Fibinacci
-
-
-[]
-
-type FactorialTests() =
-
- [] // 0!
- member this.testFactorialZero() = Assert.AreEqual(1, factorial (0))
-
- [] // 1!
- member this.testFactorialOne() = Assert.AreEqual(1, factorial (1))
-
- [] // 5!
- member this.testFactorialFive() = Assert.AreEqual(120, factorial (5))
-
- [] // (-1)!
- member this.testFactorialNegative() =
- let ex = Assert.ThrowsException(fun () -> factorial -1 :> obj)
- Assert.AreEqual("The factorial of negative numbers is not calculated by this program\n", ex.Message)
-
-
-[]
-
-type FibinacciMatrixTests() =
-
- [] // F0
- member this.fibZero() = Assert.AreEqual(0L, fibonacci (0))
-
- [] // F1
- member this.fibOne() = Assert.AreEqual(1L, fibonacci (1))
-
- [] // F2
- member this.fibTwo() = Assert.AreEqual(1L, fibonacci (2))
-
- [] // F3
- member this.fibThree() = Assert.AreEqual(2L, fibonacci (3))
-
- [] // F30
- member this.fibThreety() =
- Assert.AreEqual(832040L, fibonacci (30))
-
- [] // F(-1)
- member this.fibNegative() =
- let ex = Assert.ThrowsException(fun () -> fibonacci -1 :> obj)
- Assert.AreEqual("Fibonacci numbers for negative n are not defined\n", ex.Message)
+namespace UnitTestsFunctions
+
+open System
+open Microsoft.VisualStudio.TestTools.UnitTesting
+
+open Functions.Factorial
+open Functions.Fibinacci
+
+
+[]
+
+type FactorialTests() =
+
+ []
+ member this.testFactorialZero() = Assert.AreEqual(1, factorial (0))
+
+ []
+ member this.testFactorialOne() = Assert.AreEqual(1, factorial (1))
+
+ []
+ member this.testFactorialFive() = Assert.AreEqual(120, factorial (5))
+
+ []
+ member this.testFactorialNegative() =
+ let ex = Assert.ThrowsException(fun () -> factorial -1 :> obj)
+ Assert.AreEqual("The factorial of negative numbers is not calculated by this program\n", ex.Message)
+
+
+[]
+
+type FibinacciMatrixTests() =
+
+ []
+ member this.fibZero() = Assert.AreEqual(0L, fibonacci (0))
+
+ []
+ member this.fibOne() = Assert.AreEqual(1L, fibonacci (1))
+
+ []
+ member this.fibTwo() = Assert.AreEqual(1L, fibonacci (2))
+
+ []
+ member this.fibThree() = Assert.AreEqual(2L, fibonacci (3))
+
+ []
+ member this.fibThreety() =
+ Assert.AreEqual(832040L, fibonacci (30))
+
+ []
+ member this.fibNegative() =
+ let ex = Assert.ThrowsException(fun () -> fibonacci -1 :> obj)
+ Assert.AreEqual("Fibonacci numbers for negative n are not defined\n", ex.Message)
diff --git a/Tests/ImageProcessingT/ImageProcessingT.fsproj b/Tests/ImageProcessingT/ImageProcessingT.fsproj
new file mode 100644
index 00000000..54626247
--- /dev/null
+++ b/Tests/ImageProcessingT/ImageProcessingT.fsproj
@@ -0,0 +1,30 @@
+
+
+
+ net8.0
+
+ false
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/ImageProcessingT/Images/id.png b/Tests/ImageProcessingT/Images/id.png
new file mode 100644
index 00000000..d270290e
Binary files /dev/null and b/Tests/ImageProcessingT/Images/id.png differ
diff --git a/Tests/ImageProcessingT/Images/image1.png b/Tests/ImageProcessingT/Images/image1.png
new file mode 100644
index 00000000..8828a550
Binary files /dev/null and b/Tests/ImageProcessingT/Images/image1.png differ
diff --git a/Tests/ImageProcessingT/Images/image2x2px.png b/Tests/ImageProcessingT/Images/image2x2px.png
new file mode 100644
index 00000000..5d286d9d
Binary files /dev/null and b/Tests/ImageProcessingT/Images/image2x2px.png differ
diff --git a/Tests/ImageProcessingT/Images/kernel.png b/Tests/ImageProcessingT/Images/kernel.png
new file mode 100644
index 00000000..ecca06c3
Binary files /dev/null and b/Tests/ImageProcessingT/Images/kernel.png differ
diff --git a/Tests/ImageProcessingT/Images/kernelExtended.png b/Tests/ImageProcessingT/Images/kernelExtended.png
new file mode 100644
index 00000000..ecca06c3
Binary files /dev/null and b/Tests/ImageProcessingT/Images/kernelExtended.png differ
diff --git a/Tests/ImageProcessingT/Images/shiftDiagonal.png b/Tests/ImageProcessingT/Images/shiftDiagonal.png
new file mode 100644
index 00000000..beab1f2f
Binary files /dev/null and b/Tests/ImageProcessingT/Images/shiftDiagonal.png differ
diff --git a/Tests/ImageProcessingT/Images/shiftDownRight.png b/Tests/ImageProcessingT/Images/shiftDownRight.png
new file mode 100644
index 00000000..beab1f2f
Binary files /dev/null and b/Tests/ImageProcessingT/Images/shiftDownRight.png differ
diff --git a/Tests/ImageProcessingT/Images/shiftRightDown.png b/Tests/ImageProcessingT/Images/shiftRightDown.png
new file mode 100644
index 00000000..beab1f2f
Binary files /dev/null and b/Tests/ImageProcessingT/Images/shiftRightDown.png differ
diff --git a/Tests/ImageProcessingT/Program.fs b/Tests/ImageProcessingT/Program.fs
new file mode 100644
index 00000000..fdc31cde
--- /dev/null
+++ b/Tests/ImageProcessingT/Program.fs
@@ -0,0 +1 @@
+module Program = let [] main _ = 0
diff --git a/Tests/ImageProcessingT/PropertyImageProcessing.fs b/Tests/ImageProcessingT/PropertyImageProcessing.fs
new file mode 100644
index 00000000..70a6c24b
--- /dev/null
+++ b/Tests/ImageProcessingT/PropertyImageProcessing.fs
@@ -0,0 +1,186 @@
+namespace PropertyImageProcessing
+
+open Xunit
+open FsCheck
+open FsCheck.Xunit
+open SixLabors.ImageSharp.PixelFormats
+
+open ImageProcessing.ImProcessing
+open UnitImageProcessing.Data
+
+
+module ImageGen =
+ let private pixelGen : Gen =
+ gen {
+ let! r = Gen.choose(0, 255) |> Gen.map byte
+ let! g = Gen.choose(0, 255) |> Gen.map byte
+ let! b = Gen.choose(0, 255) |> Gen.map byte
+ let a = byte 255
+ return Rgba32(r, g, b, a)
+ }
+ let array2DGen (size: int) : Gen> =
+ gen {
+ let! pixels = Gen.array2DOfDim (size, size) pixelGen
+ return async { return pixels }
+ }
+
+
+type Image100() =
+ static member Rgba32() =
+ Arb.fromGen (ImageGen.array2DGen 100)
+
+type Image2() =
+ static member Rgba32() =
+ Arb.fromGen (ImageGen.array2DGen 2)
+
+
+[]
+type Filter() =
+
+ [ |])>]
+ 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: 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: 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: 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: 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: 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: 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
new file mode 100644
index 00000000..3ac54427
--- /dev/null
+++ b/Tests/ImageProcessingT/UnitImageProcessing.fs
@@ -0,0 +1,222 @@
+namespace UnitImageProcessing
+
+open Xunit
+open SixLabors.ImageSharp.PixelFormats
+
+open ImageProcessing.ImProcessing
+
+
+module Data =
+
+ let im1 = "../../../Images/image1.png"
+ let imSmall = "../../../Images/image2x2px.png"
+ let image1 = loadAsRgba2DA im1
+ let imageSmall = loadAsRgba2DA imSmall
+
+ let imId = "../../../Images/id.png"
+ let imShiftRightDown = "../../../Images/shiftRightDown.png"
+ let imShiftDownRight = "../../../Images/shiftDownRight.png"
+ let imShiftDiagonal = "../../../Images/shiftDiagonal.png"
+ let imKernel = "../../../Images/kernel.png"
+ let imKernelExtended = "../../../Images/kernelExtended.png"
+ 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 =
+ [|
+ [| 0; 0; 0 |]
+ [| 0; 1; 0 |]
+ [| 0; 0; 0 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let black =
+ [|
+ [| 0; 0; 0 |]
+ [| 0; 0; 0 |]
+ [| 0; 0; 0 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let shiftRight =
+ [|
+ [| 0; 0; 0 |]
+ [| 0; 0; 1 |]
+ [| 0; 0; 0 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let shiftDown =
+ [|
+ [| 0; 0; 0 |]
+ [| 0; 0; 0 |]
+ [| 0; 1; 0 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let shiftDiagonal =
+ [|
+ [| 0; 0; 0 |]
+ [| 0; 0; 0 |]
+ [| 0; 0; 1 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let kernel =
+ [|
+ [| 1; 1; 1 |]
+ [| 1; -7; 1 |]
+ [| 1; 1; 1 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let kernelExtended =
+ [|
+ [| 0; 0; 0; 0; 0 |]
+ [| 0; 1; 1; 1; 0 |]
+ [| 0; 1; -7; 1; 0 |]
+ [| 0; 1; 1; 1; 0 |]
+ [| 0; 0; 0; 0; 0 |]
+ |]
+ |> Array.map (Array.map float32)
+
+
+ let imageIsBlack (imageAsync: Async) =
+ async {
+ let! image = imageAsync
+ let h = image.GetLength 0
+ let w = image.GetLength 1
+
+ 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
+
+ return isBlack
+ } |> Async.RunSynchronously
+
+
+
+module Filter =
+ open Data
+
+ []
+ let idDoesntChangeData () =
+ 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_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_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_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_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_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_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/LineralAlgebraT.fsproj b/Tests/LineralAlgebraT/LineralAlgebraT.fsproj
new file mode 100644
index 00000000..d2724295
--- /dev/null
+++ b/Tests/LineralAlgebraT/LineralAlgebraT.fsproj
@@ -0,0 +1,34 @@
+
+
+
+ net8.0
+
+ false
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
diff --git a/Tests/LineralAlgebraT/Program.fs b/Tests/LineralAlgebraT/Program.fs
new file mode 100644
index 00000000..fdc31cde
--- /dev/null
+++ b/Tests/LineralAlgebraT/Program.fs
@@ -0,0 +1 @@
+module Program = let [] main _ = 0
diff --git a/Tests/LineralAlgebraT/PropertyLA.fs b/Tests/LineralAlgebraT/PropertyLA.fs
new file mode 100644
index 00000000..ec5c0052
--- /dev/null
+++ b/Tests/LineralAlgebraT/PropertyLA.fs
@@ -0,0 +1,164 @@
+#nowarn "64"
+
+namespace PropertyLA
+
+open System
+open Xunit
+open FsCheck
+open FsCheck.Xunit
+open FsCheck.FSharp
+
+open LineralAlgebra
+open UnitTrees.dataAndFuncs
+
+
+module DataAndFuncs =
+
+ let rec floatQTreesAreEqual (qtree1: QTree) (qtree2: QTree) : bool =
+ match qtree1, qtree2 with
+ | Node (nw, ne, se, sw), Node (NW, NE, SE, SW) ->
+ floatQTreesAreEqual nw NW &&
+ floatQTreesAreEqual ne NE &&
+ floatQTreesAreEqual se SE &&
+ floatQTreesAreEqual sw SW
+ | Leaf value1, Leaf value2 ->
+ areAlmostEqual value1 value2 1e-5f
+ | _ -> false
+
+ let multiplyArray2D (arr1: 't[,]) (arr2: 't[,]) : 't[,] =
+ let rows1 = Array2D.length1 arr1
+ let cols1 = Array2D.length2 arr1
+ let rows2 = Array2D.length1 arr2
+ let cols2 = Array2D.length2 arr2
+
+ if cols1 <> rows2 then
+ failwith "Number of columns in the first array must match the number of rows in the second array."
+
+ let result = Array2D.create rows1 cols2 Unchecked.defaultof<'t>
+
+ for i in 0 .. rows1 - 1 do
+ for j in 0 .. cols2 - 1 do
+ for k in 0 .. cols1 - 1 do
+ result.[i, j] <- result.[i, j] + arr1.[i, k] * arr2.[k, j]
+
+ result
+
+
+ let MatrixGen size typeOfMatr =
+ let rec QTreeGen size typeOfMatr : QTree =
+ if size = 1 then
+ match typeOfMatr with
+ | "Leaf" ->
+ let value = Random().Next(-100, 101)
+ Leaf value
+ | "Node" ->
+ let value = Random().Next(-100, 101)
+ Leaf value
+ | "Zero" ->
+ let value = 0
+ Leaf value
+ | _ -> failwith "Not Implemented"
+ else
+ let nw = QTreeGen (size / 2) typeOfMatr
+ let ne = QTreeGen (size / 2) typeOfMatr
+ let sw = QTreeGen (size / 2) typeOfMatr
+ let se = QTreeGen (size / 2) typeOfMatr
+ Node (nw, ne, sw, se)
+
+ let MatrGen (size: int) =
+ let qtree = QTreeGen size typeOfMatr
+ { n = size; qtree = QTrees.toCorrectQTree qtree }
+
+ let res = MatrGen size
+ res
+
+
+open DataAndFuncs
+
+[]
+type Map() =
+
+ []
+ member _.intId (qtree: QTree) =
+ qtree |> QTrees.toCorrectQTree = QTrees.map id qtree
+
+ []
+ member _.floatId (qtree: QTree) =
+ let res = QTrees.map id qtree
+ Assert.True(floatQTreesAreEqual (qtree |> QTrees.toCorrectQTree) res)
+
+
+ []
+ member _.intComposition (qtree: QTree) =
+ let qtree1 = QTrees.map ((+) 1)((QTrees.map ((+) 2)) qtree)
+ let qtree2 = QTrees.map ((+) 3) qtree
+ qtree1 = qtree2
+
+ []
+ member _.floatComposition (qtree: 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 = QTrees.height (qtree |> QTrees.toCorrectQTree)
+ let h2 = QTrees.height (QTrees.map ((+) 1) qtree)
+ h1 = h2
+
+
+[]
+type Multiply() =
+
+ let power = Random().Next(1, 6)
+ let size = pown 2 power
+
+ []
+ member _.leafLeaf () =
+ let matr1 = MatrixGen 1 "Leaf"
+ let matr2 = MatrixGen 1 "Leaf"
+ let res = Matrix.multiply matr1 matr2 (+) ( * ) 0
+ 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 = Matrix.multiply matr1 matr2 (+) ( * ) 0
+ 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 = Matrix.multiply matr1 matr2 (+) ( * ) 0
+ 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 = Matrix.multiply matr1 matr2 (+) ( * ) 0
+ 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 = Matrix.multiply matr1 matr2 (+) ( * ) 0
+ let arrayRess = QTrees.qtreeToArray2D res.qtree res.n
+ let res1 = Matrix.multiply matr2 matr1 (+) ( * ) 0
+ let arrayRess1 = QTrees.qtreeToArray2D res1.qtree res1.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
new file mode 100644
index 00000000..a0f77d81
--- /dev/null
+++ b/Tests/LineralAlgebraT/UnitLA.fs
@@ -0,0 +1,341 @@
+namespace UnitLA
+
+open System
+open Xunit
+
+open LineralAlgebra
+
+
+module DataAndFuncs =
+
+ let intOneLeaf1 = Leaf 1
+ let MintOneLeaf1 = { n = 4; qtree = intOneLeaf1 }
+
+ let intOneLeaf2 = Leaf 2
+
+ let intOneLeaf3 = Leaf 2
+ let MintOneLeaf3 = { n = 1; qtree = intOneLeaf3 }
+
+ let intOneLeaf4 = Leaf 3
+ let MintOneLeaf4 = { n = 1; qtree = intOneLeaf4 }
+
+ let intNode1 = Leaf 2
+ let MintNode1 = { n = 2; qtree = intNode1 }
+
+ let intNode2 = Leaf 3
+ let MintNode2 = { n = 2; qtree = intNode2 }
+
+ let intZero = Leaf 0
+ let MintZero = { n = 4; qtree = intZero }
+
+ let floatOneLeaf = Leaf 1.0
+
+ let intQTree1 = Node (
+ Node ( Leaf 1, Leaf 2, Leaf 3, Leaf 4),
+ Node ( Leaf -5, Leaf -6, Leaf -7, Leaf -8),
+ Leaf 9,
+ Node ( Leaf -10, Leaf -11, Leaf -12, Leaf -13)
+ )
+ let MintQTree1 = { n = 4; qtree = intQTree1 }
+
+ let intQTree2 = Node (
+ Node ( Leaf 1, Leaf 2, Leaf 3, Leaf 4),
+ Leaf 5,
+ Leaf 6,
+ Node ( Leaf 7, Leaf 8, Leaf 9, Leaf 10)
+ )
+ let MintQTree2 = { n = 4; qtree = intQTree2 }
+
+ let floatQTree1 = Node (
+ Node ( Leaf 1.0, Leaf 2.0, Leaf 3.0, Leaf 4.0),
+ Node ( Leaf -5.0, Leaf -6.0, Leaf -7.0, Leaf -8.0),
+ Leaf 9.0,
+ Node ( Leaf -10.0, Leaf -11.0, Leaf -12.0, Leaf -13.0)
+ )
+
+ let floatQTree2 = Node (
+ Node ( Leaf 1.0, Leaf 2.0, Leaf 3.0, Leaf 4.0),
+ Leaf 5.0,
+ Leaf 6.0,
+ Node ( Leaf 7.0, Leaf 8.0, Leaf 9.0, Leaf 10.0)
+ )
+
+
+module Map =
+ open DataAndFuncs
+
+ []
+ let intId () =
+ let res = QTrees.map id intQTree1
+ Assert.Equal(intQTree1, res)
+
+ []
+ let floatId () =
+ let res = QTrees.map id floatQTree1
+ Assert.Equal(floatQTree1, res)
+
+
+ []
+ let intAdd () =
+ 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),
+ Leaf 10,
+ Node ( Leaf -9, Leaf -10, Leaf -11, Leaf -12)
+ )
+ Assert.Equal(ex, res)
+
+ []
+ let floatAdd () =
+ 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),
+ Leaf 10.0,
+ Node ( Leaf -9.0, Leaf -10.0, Leaf -11.0, Leaf -12.0)
+ )
+ Assert.Equal(ex, res)
+
+
+ []
+ let intMult () =
+ 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),
+ Leaf 18,
+ Node ( Leaf -20, Leaf -22, Leaf -24, Leaf -26)
+ )
+ Assert.Equal(ex, res)
+
+ []
+ let floatMult () =
+ 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),
+ Leaf 18.0,
+ Node ( Leaf -20.0, Leaf -22.0, Leaf -24.0, Leaf -26.0)
+ )
+ Assert.Equal(ex, res)
+
+
+ // functions intSign and floatSign are written to check that nodes with the same leaves are merged into 1 leaf
+
+ []
+ let intSign () =
+ let res = QTrees.map (fun (x: int) -> Math.Sign x) intQTree1
+ let ex = Node (
+ Leaf 1,
+ Leaf -1,
+ Leaf 1,
+ Leaf -1
+ )
+ Assert.Equal(ex, res)
+
+ []
+ let floatSign () =
+ let res = QTrees.map (fun (x: float) -> Math.Sign x) floatQTree1
+ let ex = Node (
+ Leaf 1,
+ Leaf -1,
+ Leaf 1,
+ Leaf -1
+ )
+ Assert.Equal(ex, res)
+
+
+ []
+ let intComposition () =
+ 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),
+ Leaf 12,
+ Node ( Leaf -7, Leaf -8, Leaf -9, Leaf -10)
+ )
+ Assert.Equal(ex, tree1)
+ Assert.Equal(ex, tree2)
+
+ []
+ let floatComposition () =
+ 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),
+ Leaf 12.0,
+ Node ( Leaf -7, Leaf -8.0, Leaf -9.0, Leaf -10.0)
+ )
+ Assert.Equal(ex, tree1)
+ Assert.Equal(ex, tree2)
+
+
+ []
+ let intHighIsConst () =
+ 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 = QTrees.height floatQTree1
+ let h2 = QTrees.height (QTrees.map ((+) 1.0) floatQTree1)
+ Assert.Equal(3, h1)
+ Assert.Equal(3, h2)
+
+
+ (*
+ functions intHighIsExpected and floatHighIsExpected are written to check that
+ when merging nodes into a leaf, the height decreases correctly
+ *)
+
+ []
+ let intHighIsExpected () =
+ let h = QTrees.height (QTrees.map (fun (x: int) -> Math.Sign x) intQTree1)
+ Assert.Equal(2, h)
+
+ []
+ let floatHighIsExpected () =
+ let h = QTrees.height (QTrees.map (fun (x: float) -> Math.Sign x) floatQTree1)
+ Assert.Equal(2, h)
+
+
+module Map2 =
+ open DataAndFuncs
+
+ []
+ let intAdd () =
+ 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),
+ Leaf 15,
+ Leaf -3
+ )
+ Assert.Equal(ex, res)
+
+ []
+ let floatAdd () =
+ 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),
+ Leaf 15.0,
+ Leaf -3.0
+ )
+ Assert.Equal(ex, res)
+
+
+ []
+ let intMult () =
+ 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),
+ Leaf 54,
+ Node ( Leaf -70, Leaf -88, Leaf -108, Leaf -130)
+ )
+ Assert.Equal(ex, res)
+
+ []
+ let floatMult () =
+ 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),
+ Leaf 54.0,
+ Node ( Leaf -70.0, Leaf -88.0, Leaf -108.0, Leaf -130.0)
+ )
+ Assert.Equal(ex, res)
+
+
+ []
+ let intHighIsExpected () =
+ let h1 = QTrees.height intQTree1
+ let h2 = QTrees.height intOneLeaf1
+ let h3 = max h1 h2
+ let h4 = QTrees.height (QTrees.map2 (+) intQTree1 intOneLeaf1)
+ Assert.Equal(3, h3)
+ Assert.Equal(3, h4)
+
+ []
+ let floatHighIsExpected () =
+ let h1 = QTrees.height floatQTree1
+ let h2 = QTrees.height floatOneLeaf
+ let h3 = max h1 h2
+ let h4 = QTrees.height (QTrees.map2 (+) floatQTree1 floatOneLeaf)
+ Assert.Equal(3, h3)
+ Assert.Equal(3, h4)
+
+
+module Multiply =
+ open DataAndFuncs
+
+ []
+ let sizeIsImportant () =
+ let res1 = Matrix.multiply MintOneLeaf3 MintOneLeaf4 (+) ( * ) 0
+ let ex1 = { n = 1; qtree = Leaf 6 }
+ let res2 = Matrix.multiply MintNode1 MintNode2 (+) ( * ) 0
+ let ex2 = { n = 2; qtree = Leaf 12 }
+ Assert.Equal(ex1, res1)
+ Assert.Equal(ex2, res2)
+
+ []
+ let leafLeaf () =
+ let res = Matrix.multiply MintOneLeaf3 MintOneLeaf4 (+) ( * ) 0
+ let ex = { n = 1; qtree = Leaf 6 }
+ Assert.Equal(ex, res)
+
+ []
+ let nodeLeaf () =
+ let res = Matrix.multiply MintQTree1 MintOneLeaf1 (+) ( * ) 0
+ let ex = {
+ n = 4;
+ qtree = Node (
+ Leaf -8,
+ Leaf -8,
+ Node ( Leaf -3, Leaf -3, Leaf -7, Leaf -7),
+ Node ( Leaf -3, Leaf -3, Leaf -7, Leaf -7)
+ )
+ }
+ Assert.Equal(ex, res)
+
+ []
+ let leafNode () =
+ let res = Matrix.multiply MintOneLeaf1 MintQTree1 (+) ( * ) 0
+ let ex = {
+ n = 4;
+ qtree = Node (
+ Node ( Leaf 22, Leaf 24, Leaf 22, Leaf 24),
+ Node ( Leaf -34, Leaf -38, Leaf -34, Leaf -38),
+ Node ( Leaf 22, Leaf 24, Leaf 22, Leaf 24),
+ Node ( Leaf -34, Leaf -38, Leaf -34, Leaf -38)
+ )
+ }
+ Assert.Equal(ex, res)
+
+ []
+ let nodeNode () =
+ let res = Matrix.multiply MintQTree1 MintQTree2 (+) ( * ) 0
+ let ex = {
+ n = 4;
+ qtree = Node (
+ Node (Leaf -59, Leaf -56, Leaf -75, Leaf -68),
+ Node (Leaf -74, Leaf -85, Leaf -86, Leaf -101),
+ Node (Leaf -90, Leaf -72, Leaf -114, Leaf -96),
+ Node (Leaf -79, Leaf -100, Leaf -111, Leaf -136)
+ )
+ }
+ Assert.Equal(ex, res)
+
+ []
+ let zero () =
+ let res1 = Matrix.multiply MintQTree1 MintZero (+) ( * ) 0
+ let res2 = Matrix.multiply MintZero MintQTree1 (+) ( * ) 0
+ let ex = { n = 4; qtree = Leaf 0 }
+ Assert.Equal(ex, res1)
+ Assert.Equal(ex, res2)
\ No newline at end of file
diff --git a/Tests/Program.fs b/Tests/Program.fs
deleted file mode 100644
index f1bb4ba9..00000000
--- a/Tests/Program.fs
+++ /dev/null
@@ -1,3 +0,0 @@
-module Program =
- []
- let main _ = 0
\ No newline at end of file
diff --git a/Tests/SortingsT/Program.fs b/Tests/SortingsT/Program.fs
new file mode 100644
index 00000000..fdc31cde
--- /dev/null
+++ b/Tests/SortingsT/Program.fs
@@ -0,0 +1 @@
+module Program = let [] main _ = 0
diff --git a/Tests/PropertyTestsMyListSorts.fs b/Tests/SortingsT/PropertyMyListSorts.fs
similarity index 99%
rename from Tests/PropertyTestsMyListSorts.fs
rename to Tests/SortingsT/PropertyMyListSorts.fs
index f7ca8fd7..c0d8e8f6 100644
--- a/Tests/PropertyTestsMyListSorts.fs
+++ b/Tests/SortingsT/PropertyMyListSorts.fs
@@ -142,4 +142,4 @@ type MergeEqualsQuick() =
member _.charTest(testCases: char list) =
let merge = bubbleSort (MyList.fromSystemList testCases) |> MyList.toSystemList
let quick = quickSort (MyList.fromSystemList testCases) |> MyList.toSystemList
- Assert.Equal(merge, quick)
+ Assert.Equal(merge, quick)
\ No newline at end of file
diff --git a/Tests/Tests.fsproj b/Tests/SortingsT/SortingsT.fsproj
similarity index 73%
rename from Tests/Tests.fsproj
rename to Tests/SortingsT/SortingsT.fsproj
index a26f074d..ded21517 100644
--- a/Tests/Tests.fsproj
+++ b/Tests/SortingsT/SortingsT.fsproj
@@ -9,29 +9,28 @@
-
-
-
-
+
+
+
-
+
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
+
+
diff --git a/Tests/UnitTestsArraySorts.fs b/Tests/SortingsT/UnitArraySorts.fs
similarity index 100%
rename from Tests/UnitTestsArraySorts.fs
rename to Tests/SortingsT/UnitArraySorts.fs
diff --git a/Tests/UnitTestsMyListSorts.fs b/Tests/SortingsT/UnitMyListSorts.fs
similarity index 100%
rename from Tests/UnitTestsMyListSorts.fs
rename to Tests/SortingsT/UnitMyListSorts.fs
diff --git a/Tests/TreesT/Program.fs b/Tests/TreesT/Program.fs
new file mode 100644
index 00000000..fdc31cde
--- /dev/null
+++ b/Tests/TreesT/Program.fs
@@ -0,0 +1 @@
+module Program = let [] main _ = 0
diff --git a/Tests/TreesT/PropertyTrees.fs b/Tests/TreesT/PropertyTrees.fs
new file mode 100644
index 00000000..8d27e790
--- /dev/null
+++ b/Tests/TreesT/PropertyTrees.fs
@@ -0,0 +1,157 @@
+namespace PropertyTrees
+
+open System
+open Xunit
+open FsCheck
+open FsCheck.Xunit
+
+open Trees
+open Trees.Tree
+open UnitTrees.dataAndFuncs
+
+
+[]
+type mapProp() =
+
+ []
+ member _.intId (tree: Tree) =
+ tree = map id tree
+
+ []
+ member _.floatId (tree: Tree) =
+ let list = leafToList tree
+ let idList = leafToList (map id tree)
+ Assert.True(List.forall2 (fun a b -> areAlmostEqual a b 1e-10f)list idList)
+
+ []
+ member _.charId (tree: Tree) =
+ tree = map id tree
+
+ []
+ member _.arrayId (tree: Tree>) =
+ tree = map id tree
+
+
+ []
+ member _.intListEqTree (tree: Tree) =
+ let list = List.map ((+) 1) (leafToList tree)
+ let treeList = leafToList (map ((+) 1) tree)
+ list = treeList
+
+ []
+ member _.floatListEqTree (tree: Tree) =
+ let list = List.map ((+) 1.0f) (leafToList tree)
+ let treeList = leafToList (map (fun x -> x + 1.0f) tree)
+ Assert.True(List.forall2 (fun a b -> areAlmostEqual a b 1e-10f)list treeList)
+
+ []
+ member _.charListEqTree (tree: Tree) =
+ let list = List.map (char << ((+) 1 << int)) (leafToList tree)
+ let treeList = leafToList (map (fun c -> char (int c + 1)) tree)
+ list = treeList
+
+ []
+ member _.arrayListEqTree (tree: Tree>) =
+ let func list = Array.map (fun x -> x * x) list
+ let list = List.map func (leafToList tree)
+ let treeList = leafToList (map func tree)
+ list = treeList
+
+
+ []
+ member _.intComposition (tree: Tree) =
+ let tree1 = map ((+) 2) (map ((+) 1) tree)
+ let tree2 = map ((+) 3) tree
+ tree1 = tree2
+
+ []
+ member _.floatComposition (tree: Tree) =
+ let tree1 = leafToList (map ((+) 2.0f) (map ((+) 1.0f) tree))
+ let tree2 = leafToList (map ((+) 3.0f) tree )
+ Assert.True(List.forall2 (fun a b -> areAlmostEqual a b 1e-5f) tree1 tree2)
+
+ []
+ member _.charComposition (tree: Tree) =
+ let tree1 = map (char << ((+) 1 << int)) (map (char << ((+) 1 << int)) tree)
+ let tree2 = map (char << ((+) 2 << int)) tree
+ tree1 = tree2
+
+ []
+ member _.arrayComposition (tree: Tree>) =
+ let f array a = Array.map (fun x -> a * x) array
+ let tree1 = map (fun a -> f a 3) (map (fun a -> f a 2) tree)
+ let tree2 = map (fun a -> f a 6) tree
+ tree1 = tree2
+
+
+ []
+ member _.intHighIsConst (tree: Tree) =
+ let h1 = high (map ((+) 3) tree)
+ let h2 = high (map ((+) 5) tree)
+ h1 = h2
+
+ []
+ member _.floatHighIsConst (tree: Tree) =
+ let h1 = high (map ((+) 3.0f) tree)
+ let h2 = high (map ((+) 5.6f) tree)
+ h1 = h2
+
+ []
+ member _.charHighIsConst (tree: Tree) =
+ let h1 = high (map (char << ((+) 1 << int)) tree)
+ let h2 = high (map (char << ((+) 1 << int)) tree)
+ h1 = h2
+
+ []
+ member _.arrayHighIsConst (tree: Tree>) =
+ let f a array = Array.map (fun x -> a * x) array
+ let h1 = high (map (fun a -> f 2 a) tree)
+ let h2 = high (map (fun a -> f 3 a) tree)
+ h1 = h2
+
+
+[]
+type leftRightFold() =
+
+ []
+ member _.intAdd (tree: Tree) =
+ let sumFunc acc value = acc + value
+ let sum1 = foldLeft sumFunc 0 tree
+ let sum2 = foldRight sumFunc 0 tree
+ sum1 = sum2
+
+ []
+ member _.floatAdd (tree: Tree) =
+ let sumFunc acc value = acc + value
+ let sum1 = foldLeft sumFunc 0.0f tree
+ let sum2 = foldRight sumFunc 0.0f tree
+ Assert.Equal(sum1, sum2, 1)
+
+ []
+ member _.charAdd (tree: Tree) =
+ let sumFunc acc value = acc + (int value + 1)
+ let sum1 = foldLeft sumFunc 0 tree
+ let sum2 = foldRight sumFunc 0 tree
+ sum1 = sum2
+
+
+ []
+ member _.intMult (tree: Tree) =
+ let sumFunc acc value = acc * value
+ let sum1 = foldLeft sumFunc 1 tree
+ let sum2 = foldRight sumFunc 1 tree
+ sum1 = sum2
+
+ []
+ member _.floatMult (tree: Tree) =
+ let sumFunc acc value = acc * value
+ let sum1 = foldLeft sumFunc 0.0f tree
+ let sum2 = foldRight sumFunc 0.0f tree
+ Assert.Equal(sum1, sum2, 1)
+
+ []
+ member _.charMult (tree: Tree) =
+ let sumFunc acc value = acc * (int value + 1)
+ let sum1 = foldLeft sumFunc 0 tree
+ let sum2 = foldRight sumFunc 0 tree
+ sum1 = sum2
\ No newline at end of file
diff --git a/Tests/TreesT/TreesT.fsproj b/Tests/TreesT/TreesT.fsproj
new file mode 100644
index 00000000..9da1a97d
--- /dev/null
+++ b/Tests/TreesT/TreesT.fsproj
@@ -0,0 +1,30 @@
+
+
+
+ net8.0
+
+ false
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/TreesT/UnitTrees.fs b/Tests/TreesT/UnitTrees.fs
new file mode 100644
index 00000000..0af09ab4
--- /dev/null
+++ b/Tests/TreesT/UnitTrees.fs
@@ -0,0 +1,245 @@
+namespace UnitTrees
+
+open System
+open Xunit
+
+open Trees
+open Trees.Tree
+
+module dataAndFuncs =
+
+ let oneLeaf = Leaf 1
+
+ let intTree =
+ Node(Cons(
+ Node(Cons(
+ Leaf(1),
+ Single (Leaf(2)))
+ ),
+ Single (Node(Single (Leaf(3))))
+ )
+ )
+
+ let floatTree =
+ Node(Cons(
+ Node(Cons(
+ Leaf(1.00f),
+ Single (Leaf(2.00f)))
+ ),
+ Single (Node(Single (Leaf(3.00f))))
+ )
+ )
+
+ let charTree =
+ Node(Cons(
+ Node(Cons(
+ Leaf('a'),
+ Single (Leaf('b')))
+ ),
+ Single (Node(Single (Leaf('c'))))
+ )
+ )
+
+ let arrayTree =
+ Node(Cons(
+ Node(Cons(
+ Leaf([|1; 2; 3|]),
+ Single (Leaf([|5; 0; 0|])))
+ ),
+ Single (Node(Single (Leaf([|2; 3|]))))
+ )
+ )
+
+ let rec leafToList tree =
+ match tree with
+ | Leaf value -> [value]
+ | Node children ->
+ match children with
+ | Single child -> leafToList child
+ | Cons (head, tail) ->
+ leafToList head @ leafToList (Node tail)
+
+ let areAlmostEqual (a: float32) (b: float32) (epsilon: float32) =
+ if Single.IsFinite(a) && Single.IsFinite(b) then abs (a - b) < epsilon
+ elif Single.IsNaN(a) && Single.IsNaN(b) then true
+ elif Single.IsInfinity(a) && Single.IsInfinity(b) then true
+ elif Single.IsNegativeInfinity(a) && Single.IsNegativeInfinity(b) then true
+ elif Single.IsPositiveInfinity(a) && Single.IsPositiveInfinity(b) then true
+ else false
+
+
+module map =
+ open dataAndFuncs
+
+ []
+ let intId () = intTree = map id intTree
+
+ []
+ let floatId () = floatTree = map id floatTree
+
+ []
+ let charId () = charTree = map id charTree
+
+ []
+ let arrayId () = arrayTree = map id arrayTree
+
+
+ []
+ let intListEqTree () =
+ let list = List.map ((+) 1) (leafToList intTree)
+ let treeList = leafToList (map ((+) 1) intTree)
+ let ex = [ 2; 3; 4 ]
+ Assert.Equal(ex, list)
+ Assert.Equal(ex, treeList)
+
+ []
+ let floatListEqTree () =
+ let list = List.map ((+) 1.0f) (leafToList floatTree)
+ let treeList = leafToList (map (fun x -> x + 1.0f) floatTree)
+ let ex = [ 2.00f; 3.00f; 4.00f ]
+ Assert.Equal(ex, list)
+ Assert.Equal(ex, treeList)
+
+ []
+ let charListEqTree () =
+ let list = List.map (char << ((+) 1 << int)) (leafToList charTree)
+ let treeList = leafToList (map (fun c -> char (int c + 1)) charTree)
+ let ex = [ 'b'; 'c'; 'd' ]
+ Assert.Equal(ex, list)
+ Assert.Equal(ex, treeList)
+
+ []
+ let arrayListEqTree () =
+ let func list = Array.map (fun x -> x * x) list
+ let list = List.map func (leafToList arrayTree)
+ let treeList = leafToList (map func arrayTree)
+ let ex = [ [|1; 4; 9|]; [|25; 0; 0|]; [|4; 9|] ]
+ Assert.Equal>(ex, list)
+ Assert.Equal>(ex, treeList)
+
+
+ []
+ let intComposition () =
+ let tree1 = map ((+) 2) (map ((+) 1) intTree)
+ let tree2 = map ((+) 3) intTree
+ let ex = Node(Cons(Node(Cons(Leaf(4), Single (Leaf(5)))), Single (Node(Single (Leaf(6))))))
+ Assert.Equal>(ex, tree1)
+ Assert.Equal>(ex, tree2)
+
+ []
+ let floatComposition () =
+ let tree1 = leafToList (map ((+) 1.00f) (map ((+) 2.00f) floatTree))
+ let tree2 = leafToList (map ((+) 3.00f) floatTree)
+ let ex = leafToList (Node(Cons(Node(Cons(Leaf(4.00f), Single (Leaf(5.00f)))), Single (Node(Single (Leaf(6.00f)))))))
+ Assert.True(List.forall2 (fun e a -> areAlmostEqual e a 1e-10f) ex tree1)
+ Assert.True(List.forall2 (fun e a -> areAlmostEqual e a 1e-10f) ex tree2)
+
+ []
+ let charComposition () =
+ let tree1 = map (char << ((+) 1 << int)) (map (char << ((+) 1 << int)) charTree)
+ let tree2 = map (char << ((+) 2 << int)) charTree
+ let ex = Node(Cons(Node(Cons(Leaf('c'), Single (Leaf('d')))), Single (Node(Single (Leaf('e'))))))
+ Assert.Equal>(ex, tree1)
+ Assert.Equal>(ex, tree2)
+
+ []
+ let arrayComposition () =
+ let f list a = Array.map (fun x -> a * x) list
+ let tree1 = map (fun a -> f a 3) (map (fun a -> f a 2) arrayTree)
+ let tree2 = map (fun a -> f a 6) arrayTree
+ let ex = Node(Cons(Node(Cons(Leaf([|6; 12; 18|]), Single (Leaf([|30; 0; 0|])))), Single (Node(Single (Leaf([|12; 18|]))))))
+ Assert.Equal>>(ex, tree1)
+ Assert.Equal>>(ex, tree2)
+
+
+ []
+ let intHighIsConst () =
+ let h = high (map ((+) 3) intTree)
+ Assert.Equal(3, h)
+
+ []
+ let floatHighIsConst () =
+ let h = high (map ((+) 3.0f) floatTree)
+ Assert.Equal(3, h)
+
+ []
+ let charHighIsConst () =
+ let h = high (map (char << ((+) 1 << int)) charTree)
+ Assert.Equal(3, h)
+
+ []
+ let arrayHighIsConst () =
+ let f a list = Array.map (fun x -> a * x) list
+ let h = high (map (fun a -> f 2 ) arrayTree)
+ Assert.Equal(3, h)
+
+
+module AssociativeFolds =
+ open dataAndFuncs
+
+ []
+ let intAdd () =
+ let sumFunc value acc = acc + value
+ let sum1 = foldLeft sumFunc 0 intTree
+ let sum2 = foldRight sumFunc 0 intTree
+ Assert.Equal(6, sum1)
+ Assert.Equal(6, sum2)
+
+ []
+ let floatAdd () =
+ let sumFunc acc value = acc + value
+ let sum1 = foldLeft sumFunc 0.0f floatTree
+ let sum2 = foldRight sumFunc 0.0f floatTree
+ Assert.Equal(6.00f, sum1, 1)
+ Assert.Equal(6.00f, sum2, 1)
+
+ []
+ let charAdd () =
+ let sumFunc acc value = acc + (int value)
+ let sum1 = foldLeft sumFunc 0 charTree
+ let sum2 = foldRight sumFunc 0 charTree
+ Assert.Equal(294, sum1)
+ Assert.Equal(294, sum2)
+
+
+ []
+ let intMult () =
+ let sumFunc acc value = acc * value
+ let sum1 = foldLeft sumFunc 1 intTree
+ let sum2 = foldRight sumFunc 1 intTree
+ Assert.Equal(6, sum1)
+ Assert.Equal(6, sum2)
+
+ []
+ let floatMult () =
+ let sumFunc acc value = acc * value
+ let sum1 = foldLeft sumFunc 1.0f floatTree
+ let sum2 = foldRight sumFunc 1.0f floatTree
+ Assert.Equal(6.00f, sum1, 1)
+ Assert.Equal(6.00f, sum2, 1)
+
+ []
+ let charMult () =
+ let sumFunc acc value = acc * (int value)
+ let sum1 = foldLeft sumFunc 1 charTree
+ let sum2 = foldRight sumFunc 1 charTree
+ Assert.Equal(941094, sum1)
+ Assert.Equal(941094, sum2)
+
+
+module tHighOfTree =
+ open dataAndFuncs
+
+ []
+ let high () =
+ let oneHigh = high oneLeaf
+ let intHigh = high intTree
+ let floatHigh = high floatTree
+ let charHigh = high charTree
+ let arrayHigh = high arrayTree
+
+ Assert.Equal(1, oneHigh)
+ Assert.Equal(3, intHigh)
+ Assert.Equal(3, floatHigh)
+ Assert.Equal(3, charHigh)
+ Assert.Equal(3, arrayHigh)
diff --git a/src/Library/Functions.fs b/src/Functions/Functions.fs
similarity index 96%
rename from src/Library/Functions.fs
rename to src/Functions/Functions.fs
index 44984563..cde2f069 100644
--- a/src/Library/Functions.fs
+++ b/src/Functions/Functions.fs
@@ -1,43 +1,44 @@
-namespace Functions
-
-
-module Factorial =
- let rec factorial n =
- if n < 0 then
- failwith "The factorial of negative numbers is not calculated by this program\n"
- elif n = 0 || n = 1 then
- 1
- else
- n * factorial (n - 1)
-
-
-module Fibinacci =
-
- type Matrix = int64 array array
-
- let private multiply (m1: Matrix) (m2: Matrix) : Matrix =
- [| [| m1.[0].[0] * m2.[0].[0] + m1.[0].[1] * m2.[1].[0]
- m1.[0].[0] * m2.[0].[1] + m1.[0].[1] * m2.[1].[1] |]
- [| m1.[1].[0] * m2.[0].[0] + m1.[1].[1] * m2.[1].[0]
- m1.[1].[0] * m2.[0].[1] + m1.[1].[1] * m2.[1].[1] |] |]
-
- let rec private power (matrix: Matrix) (n: int) : Matrix =
- if n = 1 then
- matrix
- else
- let halfPower = power matrix (n / 2)
- let result = multiply halfPower halfPower
- if n % 2 = 0 then result else multiply result matrix
-
- let fibonacci (n: int) : int64 =
- if n < 0 then
- failwith "Fibonacci numbers for negative n are not defined\n"
-
- if n = 0 then
- 0L
- elif n = 1 then
- 1L
- else
- let mainMatrix = [| [| 1L; 1L |]; [| 1L; 0L |] |]
- let resultMatrix = power mainMatrix (n - 1)
- resultMatrix.[0].[0]
+namespace Functions
+
+
+module Factorial =
+
+ let rec factorial n =
+ if n < 0 then
+ failwith "The factorial of negative numbers is not calculated by this program\n"
+ elif n = 0 || n = 1 then
+ 1
+ else
+ n * factorial (n - 1)
+
+
+module Fibinacci =
+
+ type Matrix = int64 array array
+
+ let private multiply (m1: Matrix) (m2: Matrix) : Matrix =
+ [| [| m1.[0].[0] * m2.[0].[0] + m1.[0].[1] * m2.[1].[0]
+ m1.[0].[0] * m2.[0].[1] + m1.[0].[1] * m2.[1].[1] |]
+ [| m1.[1].[0] * m2.[0].[0] + m1.[1].[1] * m2.[1].[0]
+ m1.[1].[0] * m2.[0].[1] + m1.[1].[1] * m2.[1].[1] |] |]
+
+ let rec private power (matrix: Matrix) (n: int) : Matrix =
+ if n = 1 then
+ matrix
+ else
+ let halfPower = power matrix (n / 2)
+ let result = multiply halfPower halfPower
+ if n % 2 = 0 then result else multiply result matrix
+
+ let fibonacci (n: int) : int64 =
+ if n < 0 then
+ failwith "Fibonacci numbers for negative n are not defined\n"
+
+ if n = 0 then
+ 0L
+ elif n = 1 then
+ 1L
+ else
+ let mainMatrix = [| [| 1L; 1L |]; [| 1L; 0L |] |]
+ let resultMatrix = power mainMatrix (n - 1)
+ resultMatrix.[0].[0]
diff --git a/src/Functions/Functions.fsproj b/src/Functions/Functions.fsproj
new file mode 100644
index 00000000..56277329
--- /dev/null
+++ b/src/Functions/Functions.fsproj
@@ -0,0 +1,12 @@
+
+
+
+ net8.0
+ true
+
+
+
+
+
+
+
diff --git a/src/ImageProcessing/ImageProcessing.fs b/src/ImageProcessing/ImageProcessing.fs
new file mode 100644
index 00000000..04f686ab
--- /dev/null
+++ b/src/ImageProcessing/ImageProcessing.fs
@@ -0,0 +1,497 @@
+namespace ImageProcessing
+
+open SixLabors.ImageSharp
+open SixLabors.ImageSharp.PixelFormats
+open System.Threading.Tasks
+open Microsoft.FSharp.Control
+open System.IO
+
+[]
+type Image =
+ val Data: array
+ val Width: int
+ val Height: int
+ val Name: string
+
+ new(data, width, height, name) =
+ {
+ Data = data
+ Width = width
+ Height = height
+ Name = name
+ }
+ static member Create(width: int, height: int) =
+ let data = Array.init (height * width) (fun _ -> Rgba32(0uy, 0uy, 0uy, 255uy))
+ Image(data, width, height, "New Image")
+
+
+module ImProcessing =
+
+ let gaussianBlur =
+ [|
+ [| 1; 4; 6; 4; 1 |]
+ [| 4; 16; 24; 16; 4 |]
+ [| 6; 24; 36; 24; 6 |]
+ [| 4; 16; 24; 16; 4 |]
+ [| 1; 4; 6; 4; 1 |]
+ |]
+ |> Array.map (Array.map (fun x -> (float32 x) / 256.0f))
+
+ let motionDiagonal135deg =
+ [|
+ [| 1; 0; 0; 0; 0; 0; 0; 0; 0 |]
+ [| 0; 1; 0; 0; 0; 0; 0; 0; 0 |]
+ [| 0; 0; 1; 0; 0; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 1; 0; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 0; 1; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 0; 0; 1; 0; 0 |]
+ [| 0; 0; 0; 0; 0; 0; 0; 1; 0 |]
+ [| 0; 0; 0; 0; 0; 0; 0; 0; 1 |]
+ |]
+ |> Array.map (Array.map (fun x -> (float32 x) / 9.0f))
+
+ let motionDiagonal315deg =
+ [|
+ [| 0; 0; 0; 0; 0; 0; 0; 0; 1 |]
+ [| 0; 0; 0; 0; 0; 0; 0; 1; 0 |]
+ [| 0; 0; 0; 0; 0; 0; 1; 0; 0 |]
+ [| 0; 0; 0; 0; 0; 1; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 1; 0; 0; 0; 0; 0 |]
+ [| 0; 0; 1; 0; 0; 0; 0; 0; 0 |]
+ [| 0; 1; 0; 0; 0; 0; 0; 0; 0 |]
+ [| 1; 0; 0; 0; 0; 0; 0; 0; 0 |]
+ |]
+ |> Array.map (Array.map (fun x -> (float32 x) / 9.0f))
+
+ let motionVertical =
+ [|
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 1; 0; 0; 0; 0 |]
+ |]
+ |> Array.map (Array.map (fun x -> (float32 x) / 9.0f))
+
+ let motionHorizontal =
+ [|
+ [| 0; 0; 0; 0; 0; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 0; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 0; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 0; 0; 0; 0; 0 |]
+ [| 1; 1; 1; 1; 1; 1; 1; 1; 1 |]
+ [| 0; 0; 0; 0; 0; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 0; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 0; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 0; 0; 0; 0; 0 |]
+ |]
+ |> Array.map (Array.map (fun x -> (float32 x) / 9.0f))
+
+ let edgesHorizontal =
+ [|
+ [| 0; 0; -1; 0; 0 |]
+ [| 0; 0; -1; 0; 0 |]
+ [| 0; 0; 2; 0; 0 |]
+ [| 0; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 0 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let edgesVertical =
+ [|
+ [| 0; 0; -1; 0; 0 |]
+ [| 0; 0; -1; 0; 0 |]
+ [| 0; 0; 4; 0; 0 |]
+ [| 0; 0; -1; 0; 0 |]
+ [| 0; 0; -1; 0; 0 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let edgesDioganal135deg =
+ [|
+ [| -1; 0; 0; 0; 0 |]
+ [| 0; -2; 0; 0; 0 |]
+ [| 0; 0; 6; 0; 0 |]
+ [| 0; 0; 0; -2; 0 |]
+ [| 0; 0; 0; 0; -1 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let edgesDioganal315deg =
+ [|
+ [| 0; 0; 0; 0; -1 |]
+ [| 0; 0; 0; -2; 0 |]
+ [| 0; 0; 6; 0; 0 |]
+ [| 0; -2; 0; -0; 0 |]
+ [| -1; 0; 0; 0; 0 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let edgesAllDirections =
+ [|
+ [| -1; -1; -1 |]
+ [| -1; 8; -1 |]
+ [| -1; -1; -1 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let sharpen =
+ [|
+ [| -1; -1; -1 |]
+ [| -1; 9; -1 |]
+ [| -1; -1; -1 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let sharpenSoft =
+ [|
+ [| -1; -1; -1; -1; -1 |]
+ [| -1; 2; 2; 2; -1 |]
+ [| -1; 2; 8; 2; -1 |]
+ [| -1; 2; 2; 2; -1 |]
+ [| -1; -1; -1; -1; -1 |]
+ |]
+ |> Array.map (Array.map (fun x -> (float32 x) / 8.0f))
+
+ let sharpenWithEdges =
+ [|
+ [| 1; 1; 1 |]
+ [| 1; -7; 1 |]
+ [| 1; 1; 1 |]
+ |]
+ |> Array.map (Array.map float32)
+
+ let emboss =
+ [|
+ [| -1; -1; 0 |]
+ [| -1; 0; 1 |]
+ [| 0; 1; 1 |]
+ |]
+ |> Array.map (Array.map (fun x -> (float32 x) / + 128.0f))
+
+ let embossHard =
+ [|
+ [|-1; -1; -1; -1; 0 |]
+ [|-1; -1; -1; 0; 1 |]
+ [|-1; -1; 0; 1; 1 |]
+ [|-1; 0; 1; 1; 1 |]
+ [| 0; 1; 1; 1; 1 |]
+ |]
+ |> 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
+
+ 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
+
+ use img = new Image