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(w, h) + + for x in 0 .. h - 1 do + for y in 0 .. w - 1 do + img.[y, x] <- rgbaData.[x, y] + + img.Save file + + let applyFilterNoParallelism (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 + + 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 + + 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/ImageProcessing.fsproj b/src/ImageProcessing/ImageProcessing.fsproj new file mode 100644 index 00000000..b2e0d7d1 --- /dev/null +++ b/src/ImageProcessing/ImageProcessing.fsproj @@ -0,0 +1,18 @@ + + + + Exe + net8.0 + + + + + + + + + + + + + diff --git a/src/ImageProcessing/Program.fs b/src/ImageProcessing/Program.fs new file mode 100644 index 00000000..3eb992d9 --- /dev/null +++ b/src/ImageProcessing/Program.fs @@ -0,0 +1,163 @@ +open System +open System.Threading.Tasks +open System.IO +open ImageProcessing.ImProcessing +open Argu +open SixLabors.ImageSharp.PixelFormats + +type Filters = + | 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_Folder of string + | [] Out_Folder of string + | [] Filters of list + | [] Parallelism of list + interface IArgParserTemplate with + member this.Usage = + match this with + | 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 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." + + 0 \ No newline at end of file diff --git a/src/LineralAlgebra/LineralAlgebra.fs b/src/LineralAlgebra/LineralAlgebra.fs new file mode 100644 index 00000000..0bc901a1 --- /dev/null +++ b/src/LineralAlgebra/LineralAlgebra.fs @@ -0,0 +1,265 @@ +namespace LineralAlgebra + + +type QTree<'t> = + | Leaf of 't + | Node of QTree<'t> * QTree<'t> * QTree<'t> * QTree<'t> + + +type Matrix<'t> = + { + n: int; + qtree: QTree<'t> + } + + +module private Private = + + 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) + + +open Private + + +module QTrees = + /// The function goes through the whole tree and merges (if any) 4 leaves with the same values, coming from one node into one leaf of the original node with the original value. + /// The input qtree. + /// Correctly built qtree. + let toCorrectQTree qtree = + qtree |> toCorrectQTree + + /// Builds a new qtree whose elements are the results of applying the given function to each of the elements of the qtree. + /// The function to transform elements of the qtree. + /// The input qtree. + /// The qtree of transformed elements. + let rec map mapping qtree = + match qtree with + | Leaf value -> Leaf (mapping value) + | Node (nw,ne, se, sw) -> + Node (map mapping nw, map mapping ne, map mapping se, map mapping sw) + |> toCorrectQTree + + /// Builds a new qtree whose elements are the results of applying the given function to the corresponding elements of the two collections pairwise. + /// The function to transform the pairs of the input elements. + /// The first input qtree. + /// The second input qtree. + /// The qtree of transformed elements. + let rec map2 mapping qtree1 qtree2 = + match qtree1, qtree2 with + | Leaf value1, Leaf value2 -> + Leaf (mapping value1 value2) + + | Leaf value, Node (nw, ne, se, sw) -> + Node ( + map2 mapping (Leaf value) nw, + map2 mapping (Leaf value) ne, + map2 mapping (Leaf value) se, + map2 mapping (Leaf value) sw + ) + + | Node (nw, ne, se, sw), Leaf value -> + Node ( + map2 mapping nw (Leaf value), + map2 mapping ne (Leaf value), + map2 mapping se (Leaf value), + map2 mapping sw (Leaf value) + ) + + | Node (nw, ne, se, sw), Node (NW, NE, SE, SW) -> + Node ( + map2 mapping nw NW, + map2 mapping ne NE, + map2 mapping se SE, + map2 mapping sw SW + ) + |> toCorrectQTree + + /// Creates a square array2D with elements from a qtree. + /// The qtree from which the elements are taken. + /// The output array size can only be a power of two due to the structure of qtrees. + /// The created array2D. + let qtreeToArray2D (qtree: QTree<'t>) (size: int) : 't[,] = + if size <= 0 || size &&& (size - 1) <> 0 then + failwithf "\n\n The size is not a power of two or <= 0\n\n size: %d\n" size + + let rec qtrToArray2D (qtree: QTree<'t>) (size: int) : 't[,] = + match qtree with + | Leaf value when size = 1 -> + Array2D.create 1 1 value + + | Leaf value when size > 1 -> + Array2D.create size size value + + | Node (nw, ne, sw, se) -> + let NW = qtrToArray2D nw (size / 2) + let NE = qtrToArray2D ne (size / 2) + let SW = qtrToArray2D sw (size / 2) + let SE = qtrToArray2D se (size / 2) + + let mainSize = Array2D.length1 NW + + let matrix = Array2D.create (mainSize * 2) (mainSize * 2) Unchecked.defaultof<'t> + + for i in 0 .. mainSize - 1 do + for j in 0 .. mainSize - 1 do + matrix[i, j] <- NW[i, j] + matrix[i, j + mainSize] <- NE[i, j] + matrix[i + mainSize, j] <- SW[i, j] + matrix[i + mainSize, j + mainSize] <- SE[i, j] + + matrix + + | Leaf _ -> failwith "Not Implemented" + + qtrToArray2D qtree size + + /// Calculates the number of levels at which tree nodes are located, from the root to any leaf. + /// The input qtree. + /// The number of levels in the qtree. + let rec height qtree = + match qtree with + | Leaf _-> 1 + | Node (nw, ne, se, sw) -> + let heights = [| height nw; height ne; height se; height sw |] + Array.max heights + 1 + + +module Matrix = + + /// Builds a new matrix whose elements are the results of applying the given function to each of the elements of the matrix. + /// The function to transform elements of the matrix. + /// The input matrix. + /// The matrix of transformed elements. + let map mapping (matr: Matrix<'t>) = + let res = QTrees.map mapping matr.qtree + { n = matr.n; qtree = res } + + /// Builds a new matrix whose elements are the results of applying the given function to the corresponding elements of the two collections pairwise. + /// The function to transform the pairs of the input elements. + /// The first input matrix. + /// The second input matrix. + /// The matrix of transformed elements. + let map2 mapping (matr1: Matrix<'t>) (matr2: Matrix<'t>) = + let res = QTrees.map2 mapping 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 + | Leaf value1, Leaf value2 -> + Leaf(opAdd value1 value2) + + | Leaf _ , Node(nw, ne, sw, se) -> + Node( + add qtree1 nw (size / 2) opAdd opMult, + add qtree1 ne (size / 2) opAdd opMult, + add qtree1 sw (size / 2) opAdd opMult, + add qtree1 se (size / 2) opAdd opMult + ) + + | Node(nw, ne, sw, se), Leaf _ -> + Node( + add nw qtree2 (size / 2) opAdd opMult, + add ne qtree2 (size / 2) opAdd opMult, + add sw qtree2 (size / 2) opAdd opMult, + add se qtree2 (size / 2) opAdd opMult + ) + + | Node(nw, ne, sw, se), Node(NW, NE, SW, SE) -> + Node( + add nw NW (size / 2) opAdd opMult, + add ne NE (size / 2) opAdd opMult, + add sw SW (size / 2) opAdd opMult, + add se SE (size / 2) opAdd opMult + ) + + let rec private mult qtree1 qtree2 size (opAdd: 't -> 't -> 't) (opMult: 't -> 't -> 't) (neutral: 't) = + match qtree1, qtree2 with + | Leaf value1, Leaf value2 -> + let add = opMult value1 value2 + let mutable value = neutral + + for i in 0 .. size - 1 do + value <- opAdd value add + + Leaf value + + | Leaf _ , Node(nw, ne, sw, se) -> + let Vnw = mult qtree1 nw (size / 2) opAdd opMult neutral + let Vsw = mult qtree1 sw (size / 2) opAdd opMult neutral + let Vne = mult qtree1 ne (size / 2) opAdd opMult neutral + let Vse = mult qtree1 se (size / 2) opAdd opMult neutral + + Node( + add Vnw Vsw (size / 2) opAdd opMult, + add Vne Vse (size / 2) opAdd opMult, + add Vnw Vsw (size / 2) opAdd opMult, + add Vne Vse (size / 2) opAdd opMult + ) + + | Node(nw, ne, sw, se), Leaf _ -> + let nwV = mult nw qtree2 (size / 2) opAdd opMult neutral + let neV = mult ne qtree2 (size / 2) opAdd opMult neutral + let swV = mult sw qtree2 (size / 2) opAdd opMult neutral + let seV = mult se qtree2 (size / 2) opAdd opMult neutral + + Node( + add nwV neV (size / 2) opAdd opMult, + add nwV neV (size / 2) opAdd opMult, + add swV seV (size / 2) opAdd opMult, + add swV seV (size / 2) opAdd opMult + ) + + | Node(nw, ne, sw, se), Node(NW, NE, SW, SE) -> + let nwNW = mult nw NW (size / 2) opAdd opMult neutral + let neSW = mult ne SW (size / 2) opAdd opMult neutral + let nwNE = mult nw NE (size / 2) opAdd opMult neutral + let neSE = mult ne SE (size / 2) opAdd opMult neutral + let swNW = mult sw NW (size / 2) opAdd opMult neutral + let seSW = mult se SW (size / 2) opAdd opMult neutral + let swNE = mult sw NE (size / 2) opAdd opMult neutral + let seSE = mult se SE (size / 2) opAdd opMult neutral + + Node( + add nwNW neSW (size / 2) opAdd opMult, + add nwNE neSE (size / 2) opAdd opMult, + add swNW seSW (size / 2) opAdd opMult, + add swNE seSE (size / 2) opAdd opMult + ) + + /// The function assumes that the matrices have already been converted to the same correct size: nxn where n = 2^N. + /// First matrix in matrix product. + /// Second matrix in matrix product. + /// Operation of addition of elements 't. + /// Operation of multiplication of elements 't. + /// Neutral element by addition. + /// Product of matr1 * matr2. + let multiply (matr1: Matrix<'t>) (matr2: Matrix<'t>) (opAdd: 't -> 't -> 't) (opMult: 't -> 't -> 't) (neutral: 't) = + if matr1.n <> matr2.n then + failwithf "\n\n Matr1 and matr2 have different sizes:\n\n Matr1: %d\n Matr2: %d\n" matr1.n matr2.n + elif matr1.n <= 0 || matr1.n &&& (matr1.n - 1) <> 0 then + failwithf "\n\n The size of matr1 is not a power of two or <= 0\n\n Matr1: %d\n" matr1.n + elif matr2.n <= 0 || matr2.n &&& (matr2.n - 1) <> 0 then + failwithf "\n\n The size of matr2 is not a power of two or <= 0\n\n Matr1: %d\n" matr2.n + + let result = mult matr1.qtree matr2.qtree matr1.n opAdd opMult neutral + let matrix = result |> toCorrectQTree + { n = max matr1.n matr2.n; qtree = matrix } \ No newline at end of file diff --git a/src/LineralAlgebra/LineralAlgebra.fsproj b/src/LineralAlgebra/LineralAlgebra.fsproj new file mode 100644 index 00000000..df23649b --- /dev/null +++ b/src/LineralAlgebra/LineralAlgebra.fsproj @@ -0,0 +1,20 @@ + + + + net8.0 + true + LineralAlgebra + 1.2.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 + + MIT + I'm fixing all sorts of little things regarding documentation + + + + + + + diff --git a/src/Library/ArraySorts.fs b/src/Sortings/ArraySorts.fs similarity index 100% rename from src/Library/ArraySorts.fs rename to src/Sortings/ArraySorts.fs diff --git a/src/Library/MyListSorts.fs b/src/Sortings/MyListSorts.fs similarity index 100% rename from src/Library/MyListSorts.fs rename to src/Sortings/MyListSorts.fs diff --git a/src/Library/Library.fsproj b/src/Sortings/Sortings.fsproj similarity index 85% rename from src/Library/Library.fsproj rename to src/Sortings/Sortings.fsproj index 240b2e4a..da92f555 100644 --- a/src/Library/Library.fsproj +++ b/src/Sortings/Sortings.fsproj @@ -6,7 +6,6 @@ - diff --git a/src/Trees/Trees.fs b/src/Trees/Trees.fs new file mode 100644 index 00000000..43914c1b --- /dev/null +++ b/src/Trees/Trees.fs @@ -0,0 +1,66 @@ +namespace Trees + +type NonEmptyList<'t> = + | Single of 't + | Cons of 't * NonEmptyList<'t> + +type Tree<'t> = + | Node of Tree<'t> NonEmptyList + | Leaf of 't + + +module NonEmptyList = + + let rec map func list = + match list with + | Single value -> Single (func value) + | Cons(head, tail) -> Cons(func head, map func tail) + + let rec fold func acc list = + match list with + | Single value -> func value acc + | Cons(head, tail) -> + let newAcc = func head acc + fold func newAcc tail + + let rec foldBack func list acc = + match list with + | Single value -> func value acc + | Cons(head, tail) -> foldBack func tail (func head acc) + + let rec max list = + match list with + | Single x -> x + | Cons (head, tail) -> + let tailMax = max tail + if head > tailMax then head else tailMax + + +module Tree = + + let rec map func tree = + match tree with + | Leaf value -> Leaf (func value) + | Node children -> + Node (NonEmptyList.map (map func) children) + + let rec foldLeft func acc tree = + match tree with + | Leaf value -> func acc value + | Node children -> + NonEmptyList.fold (fun child acc -> foldLeft func acc child) acc children + + let rec foldRight func acc tree = + match tree with + | Leaf value -> func acc value + | Node children -> + NonEmptyList.foldBack (fun child acc -> foldRight func acc child) children acc + + let rec high tree= + match tree with + | Leaf _ -> 1 + | Node children -> + let heights = NonEmptyList.map high children + 1 + NonEmptyList.max heights + + \ No newline at end of file diff --git a/src/Trees/Trees.fsproj b/src/Trees/Trees.fsproj new file mode 100644 index 00000000..241cc98c --- /dev/null +++ b/src/Trees/Trees.fsproj @@ -0,0 +1,12 @@ + + + + net8.0 + true + + + + + + +