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/Benchmarks.fsproj b/Benchmarks/Benchmarks.fsproj index f08f2399..5d5d8caf 100644 --- a/Benchmarks/Benchmarks.fsproj +++ b/Benchmarks/Benchmarks.fsproj @@ -9,12 +9,12 @@ - - + + - - + + 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..47714e54 100644 --- a/HomeWork.sln +++ b/HomeWork.sln @@ -5,12 +5,34 @@ 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}") = "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}") = "Benchmarks", "Benchmarks\Benchmarks.fsproj", "{66023F5A-8456-4F66-9318-A0BFB68ED14A}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ImageProcessing", "src\ImageProcessing\ImageProcessing.fsproj", "{7B9D1692-F56C-43C7-92BA-2CDDE21A7D57}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ImageProcessingT", "Tests\ImageProcessingT\ImageProcessingT.fsproj", "{EB2F699B-DE06-42EC-974A-A2C39E5C8D2A}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "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("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Graphs", "src\Graphs\Graphs.fsproj", "{CF32EADA-1A26-456B-AA5D-075444540057}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "GraphsT", "Tests\GraphsT\GraphsT.fsproj", "{E39D15F4-AE96-42ED-957D-D335208D8BF9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -20,20 +42,71 @@ 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 + {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 {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 + {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 + {CF32EADA-1A26-456B-AA5D-075444540057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF32EADA-1A26-456B-AA5D-075444540057}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF32EADA-1A26-456B-AA5D-075444540057}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF32EADA-1A26-456B-AA5D-075444540057}.Release|Any CPU.Build.0 = Release|Any CPU + {E39D15F4-AE96-42ED-957D-D335208D8BF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E39D15F4-AE96-42ED-957D-D335208D8BF9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E39D15F4-AE96-42ED-957D-D335208D8BF9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E39D15F4-AE96-42ED-957D-D335208D8BF9}.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} + {CF32EADA-1A26-456B-AA5D-075444540057} = {00DFC406-0A95-4C11-8BF2-4FD28C28061D} + {E39D15F4-AE96-42ED-957D-D335208D8BF9} = {B4AC50D2-34AD-46DF-B39E-FBCC5D0653C6} 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/GraphsT/DataAndFuncs.fs b/Tests/GraphsT/DataAndFuncs.fs new file mode 100644 index 00000000..c3d644ef --- /dev/null +++ b/Tests/GraphsT/DataAndFuncs.fs @@ -0,0 +1,132 @@ +namespace DataAndFuncs + +open System +open System.Collections.Generic +open Xunit +open FsCheck +open FsCheck.Xunit +open FsCheck.FSharp +open LineralAlgebra + +open Graphs + + +module Data = + let leaf = Leaf (Some [|1|]) + let gLeaf1 = { n = 1; qtree = leaf } + let gLeaf4 = { n = 4; qtree = leaf } + + let leafArr = Leaf (Some [|1; 2; 3|]) + let gLeafArr1 = { n = 1; qtree = leafArr } + let gLeafArr4 = { n = 4; qtree = leafArr } + + let node = Node ( + Node ( Leaf None, Leaf (Some [|1|]), Leaf (Some [|1; 2|]), Leaf (Some [|3|])), + Node ( Leaf (Some [|4; 5|]), Leaf (Some [|6|]), Leaf (Some [|7; 8|]), Leaf (Some [|9|])), + Leaf (Some [|10|]), + Node ( Leaf (Some [|11|]), Leaf (Some [|12|]), Leaf (Some [|13|]), Leaf (Some [|14|])) + ) + let gNode = { n = 4; qtree = node } + + let zeroGraph = { n = 4; qtree = Leaf None } + let fullGraph = { n = 4; qtree = Leaf (Some [|1|])} + + let node1 = Node ( + Leaf None, + Leaf (Some [|'a'|]), + Leaf None, + Leaf None + ) + let graph1 = { n = 2; qtree = node1 } + let node2 = Node ( + Node ( Leaf None, Leaf (Some [|true|]), Leaf None, Leaf None), + Node ( Leaf None, Leaf None, Leaf (Some [|true|]), Leaf None), + Leaf None, + Node ( Leaf None, Leaf (Some [|true|]), Leaf None, Leaf None) + ) + let graph2 = { n = 4; qtree = node2 } + + +module Generator = + let GraphGen size typeOfMatr = + let LeafGen = + let someOrNone = Random().Next(0, 1) + if someOrNone = 0 then Leaf None + else + let size = Random().Next(1, 10) + let array = Array.zeroCreate size + for i in 0 .. size - 1 do + array.[i] <- Random().Next(-100, 10) + + Leaf (Some array) + + let rec QTreeGen size typeOfMatr = + if size = 1 then + match typeOfMatr with + | "Leaf" -> LeafGen + | "Node" -> LeafGen + | _ -> 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 + + +module Funcs = + let toAdjacencyMatrix (graph: Matrix>) = + let func (value: Edjes<'t>) = + match value with + | Some _ -> 1 + | None -> 0 + let res = Matrix.map func graph + res + + let rec getElOfQTree (qtree: QTree>) = + let handleLeaf edjes = + match edjes with + | None -> + Unchecked.defaultof<'t> + | Some array -> + Array.min array + + match qtree with + | Leaf edjes -> handleLeaf edjes + | Node(_, _, _, _) -> failwith "Not Implemented" + + let rec findValue (qtree: QTree<'t>) (size: int) i j : 't = + match qtree with + | Leaf value -> value + | Node(nw, ne, sw, se) -> + if i < size / 2 && j < size / 2 then + findValue nw (size / 2) i j + elif i < size / 2 && j >= size / 2 then + findValue ne (size / 2) i (j - size / 2) + elif i >= size / 2 && j < size / 2 then + findValue sw (size / 2) (i - size / 2) j + else + findValue se (size / 2) (i - size / 2) (j - size / 2) + + let transitiveClosureMatrices (matrix: int array2d) = + if matrix = null then + Array2D.create 0 0 0 + else + let rows = Array2D.length1 matrix + let res = Array2D.copy matrix + + for k in 0 .. rows - 1 do + for i in 0 .. rows - 1 do + for j in 0 .. rows - 1 do + if res.[i,k] = 1 && res.[k,j] = 1 then + res.[i,j] <- 1 + else + res.[i,j] <- max res.[i,j] res.[i,k] * res.[k,j] + res \ No newline at end of file diff --git a/Tests/GraphsT/GraphsT.fsproj b/Tests/GraphsT/GraphsT.fsproj new file mode 100644 index 00000000..7969a62f --- /dev/null +++ b/Tests/GraphsT/GraphsT.fsproj @@ -0,0 +1,32 @@ + + + + net8.0 + + false + false + true + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/GraphsT/Program.fs b/Tests/GraphsT/Program.fs new file mode 100644 index 00000000..0695f84c --- /dev/null +++ b/Tests/GraphsT/Program.fs @@ -0,0 +1 @@ +module Program = let [] main _ = 0 diff --git a/Tests/GraphsT/PropertyGraphs.fs b/Tests/GraphsT/PropertyGraphs.fs new file mode 100644 index 00000000..c3a0078b --- /dev/null +++ b/Tests/GraphsT/PropertyGraphs.fs @@ -0,0 +1,70 @@ +namespace PropertyGraphs + +open System +open Xunit +open FsCheck +open FsCheck.Xunit +open FsCheck.FSharp +open LineralAlgebra + +open Graphs +open Graphs.Graphs +open DataAndFuncs.Generator +open DataAndFuncs.Funcs + + +[] +type ShortestWay() = + + let power = Random().Next(1, 3) + let size = pown 2 power + + [] + member _.leaf1 () = + let graph = GraphGen 1 "Leaf" + let res = shortestWay graph 0 0 Array.min + let ex = getElOfQTree graph.qtree + Assert.Equal(ex, res) + + [] + member _.leafSize () = + let graph = GraphGen size "Leaf" + let res = shortestWay graph 0 1 Array.min + let ex = getElOfQTree graph.qtree + Assert.Equal(ex, res) + + [] + member _.node () = + let graph = GraphGen size "Node" + let res = Array2D.zeroCreate size size + for i in 0 .. size - 1 do + for j in 0 .. size - 1 do + res.[i, j] <- shortestWay graph i j Array.min + + let graphArray2D = QTrees.qtreeToArray2D graph.qtree graph.n + + let ex = Array2D.zeroCreate size size + for i in 0 .. size - 1 do + for j in 0 .. size - 1 do + match graphArray2D.[i, j] with + | Some array -> ex.[i, j] <- Array.min array + | None -> ex.[i, j] <- 0 + Assert.Equal(ex, res) + + +[] +type TransitiveClosure() = + let power = Random().Next(1, 3) + let size = pown 2 power + + [] + member _.trClosure () = + let generatedGraph = GraphGen size "Node" + let generatedGraphTrCl = transitiveClosure generatedGraph + let resArray = QTrees.qtreeToArray2D generatedGraphTrCl.qtree generatedGraph.n + + let generatedGraphToAdjM = toAdjacencyMatrix generatedGraph + let adjMto2Darray = QTrees.qtreeToArray2D generatedGraphToAdjM.qtree generatedGraphToAdjM.n + + let arrayTrCl = transitiveClosureMatrices adjMto2Darray + Assert.Equal(arrayTrCl, resArray) \ No newline at end of file diff --git a/Tests/GraphsT/UnitGraphs.fs b/Tests/GraphsT/UnitGraphs.fs new file mode 100644 index 00000000..82fa466d --- /dev/null +++ b/Tests/GraphsT/UnitGraphs.fs @@ -0,0 +1,101 @@ +namespace UnitGraphs + +open System +open Xunit +open FsCheck +open FsCheck.Xunit +open FsCheck.FSharp +open LineralAlgebra + +open Graphs.Graphs +open DataAndFuncs.Data + + +module ShortestWay = + + [] + let leaf () = + let res = shortestWay gLeaf1 0 0 Array.min + let ex = 1 + Assert.Equal(ex, res) + + [] + let leaf4 () = + let res = shortestWay gLeaf4 0 1 Array.min + let ex = 1 + Assert.Equal(ex, res) + + [] + let leafArr () = + let res = shortestWay gLeafArr1 0 0 Array.min + let ex = 1 + Assert.Equal(ex, res) + + [] + let leafArr4 () = + let res = shortestWay gLeafArr4 1 0 Array.min + let ex = 1 + Assert.Equal(ex, res) + + [] + let node () = + let res = Array2D.zeroCreate 4 4 + for i in 0 .. 3 do + for j in 0 .. 3 do + res.[i, j] <- shortestWay gNode i j Array.min + + let arrayArray = + [| + [|0; 1; 4; 6|]; + [|1; 3; 7; 9|]; + [|10; 10; 11; 12|]; + [|10; 10; 13; 14|] + |] + + let ex = Array2D.init 4 4 (fun i j -> + if j < arrayArray.[i].Length then + arrayArray.[i].[j] + else + 0 + ) + + Assert.Equal(ex, res) + + +module TransitiveClosure = + + [] + let zeroGraph () = + let res = transitiveClosure zeroGraph + let ex = { n = 4; qtree = Leaf 0 } + Assert.Equal(ex, res) + + [] + let fullGraph () = + let res = transitiveClosure fullGraph + let ex = { n = 4; qtree = Leaf 1 } + Assert.Equal(ex, res) + + [] + let graph2x2 () = + let res = transitiveClosure graph1 + let node = Node ( + Leaf 0, + Leaf 1, + Leaf 0, + Leaf 0 + ) + let ex = { n = 2; qtree = node } + Assert.Equal(ex, res) + + [] + let graph4x4 () = + let res = transitiveClosure graph2 + let node = Node ( + Node ( Leaf 0, Leaf 1, Leaf 0, Leaf 0), + Leaf 1, + Leaf 0, + Node ( Leaf 0, Leaf 1, Leaf 0, Leaf 0) + ) + let ex = { n = 4; qtree = node } + Assert.Equal(ex, res) \ No newline at end of file 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..32d65918 --- /dev/null +++ b/Tests/ImageProcessingT/PropertyImageProcessing.fs @@ -0,0 +1,76 @@ +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 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: Rgba32[,]) = + let imageAfterFilter = applyFilter gaussianBlur image + Assert.Equal(100, imageAfterFilter.GetLength(0)) + Assert.Equal(100, imageAfterFilter.GetLength(1)) + + [ |])>] + member _.idDoesntChangeData (image: Rgba32[,]) = + let imageAfterFilter = applyFilter id image + Assert.Equal(image, imageAfterFilter) + + [ |])>] + member _.imageSmallerThanFilter (image: Rgba32[,]) = + let imageAfterFilter = applyFilter black image + Assert.Equal(true, imageIsBlack imageAfterFilter) + + [ |])>] + member _.blackFilter (image: Rgba32[,]) = + let imageBlack = applyFilter black image + Assert.Equal(true, imageIsBlack imageBlack) + + [ |])>] + member _.shiftComposition (image: Rgba32[,]) = + let trivial1and2 = applyFilter shiftRight image |> applyFilter shiftDown + let trivial12 = applyFilter shiftDiagonal image + Assert.Equal(trivial1and2, trivial12) + + [ |])>] + member _.extendedComposition (image: Rgba32[,]) = + let imageAfterFilter = applyFilter kernel image + let imageAfterExtendedFilter = applyFilter kernelExtended image + Assert.Equal(imageAfterFilter, imageAfterExtendedFilter) + + [ |])>] + member _.someAreCommutative (image: Rgba32[,]) = + let image12 = applyFilter shiftRight image |> applyFilter shiftDown + let image21 = applyFilter shiftDown image |> applyFilter shiftRight + Assert.Equal(image12, image21) \ No newline at end of file diff --git a/Tests/ImageProcessingT/UnitImageProcessing.fs b/Tests/ImageProcessingT/UnitImageProcessing.fs new file mode 100644 index 00000000..73880dc0 --- /dev/null +++ b/Tests/ImageProcessingT/UnitImageProcessing.fs @@ -0,0 +1,134 @@ +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 = loadAsRgba2D im1 + let imageSmall = loadAsRgba2D 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= loadAsRgba2D imId + let imageShiftRightDown= loadAsRgba2D imShiftRightDown + let imageShiftDownRight= loadAsRgba2D imShiftDownRight + let imageShiftDiagonal= loadAsRgba2D imShiftDiagonal + let imageKernel= loadAsRgba2D imKernel + let imageKernelExtended= loadAsRgba2D imKernelExtended + + + 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 (image: Rgba32[,]) = + 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 + + isBlack + + +module Filter = + open Data + + [] + let idDoesntChangeData () = + let imageAfterFilter = applyFilter id image1 + Assert.Equal(imageId, imageAfterFilter) + + [] + let shiftComposition () = + let shiftRightDown = applyFilter shiftRight image1 |> applyFilter shiftDown + let shiftDiagonal = applyFilter shiftDiagonal image1 + Assert.Equal(imageShiftRightDown, imageShiftDiagonal) + Assert.Equal(imageShiftRightDown, shiftRightDown) + Assert.Equal(imageShiftRightDown, shiftDiagonal) + + [] + let extendedComposition () = + let kernel = applyFilter kernel image1 + let kernelExtended = applyFilter kernelExtended image1 + Assert.Equal(imageKernel, imageKernelExtended) + Assert.Equal(imageKernel, kernel) + Assert.Equal(imageKernel, kernelExtended) + + [] + let someAreCommutative () = + let imageRD = applyFilter shiftRight image1 |> applyFilter shiftDown + let imageDR = applyFilter shiftDown image1 |> applyFilter shiftRight + Assert.Equal(imageShiftDownRight, imageShiftRightDown) + Assert.Equal(imageShiftDownRight, imageDR) + Assert.Equal(imageShiftDownRight, imageRD) \ 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/Graphs/Graphs.fs b/src/Graphs/Graphs.fs new file mode 100644 index 00000000..0986c9f3 --- /dev/null +++ b/src/Graphs/Graphs.fs @@ -0,0 +1,95 @@ +namespace Graphs + +open LineralAlgebra +open System + + +type Edjes<'t> = + | Some of array<'t> + | None + member this.Min (func: array<'t> -> 't) = + match this with + | None -> failwith "Edges data type is None" + | Some array -> func array + + +module Graphs = + let rec private findValue (qtree: QTree<'t>) (size: int) i j = + match qtree with + | Leaf value -> value + | Node(nw, ne, sw, se) -> + if i < size / 2 && j < size / 2 then + findValue nw (size / 2) i j + elif i < size / 2 && j >= size / 2 then + findValue ne (size / 2) i (j - size / 2) + elif i >= size / 2 && j < size / 2 then + findValue sw (size / 2) (i - size / 2) j + else + findValue se (size / 2) (i - size / 2) (j - size / 2) + + let private toAdjacencyMatrix (graph: Matrix>) = + let func (value: Edjes<'t>) = + match value with + | Some _ -> 1 + | None -> 0 + let res = Matrix.map func graph + res + + let private opMult x y = + if x = 1 && y = 1 then 1 + else 0 + + let private opAdd x y = + if x = 0 && y = 0 then 0 + else 1 + + + /// Finds the shortest path between vertices i and j of the graph. + /// A graph in which the shortest path must be found. + /// Row coordinate of the adjacency matrix of the graph. + /// Column coordinate of the adjacency matrix of a graph. + /// Finds mim 't in 't array. + /// Shortest path length. + let shortestWay (graph: Matrix>) (i: int) (j: int) (func: array<'t> -> 't) = + if i < 0 then failwithf "\n\nThe row coordinate i must be > 0\nYour i: %d\n" i + elif j < 0 then failwithf "\n\nThe column coordinate j must be > 0\nYour j: %d\n" j + elif i >= graph.n then failwithf "\n\nThis row coordinate does not exist\nMaximum column coordinate: %d\nYour coordinate: %d\n" graph.n i + elif j >= graph.n then failwithf "\n\nThis column coordinate does not exist\nMaximum row coordinate: %d\nYour coordinate: %d\n" graph.n j + + let handleLeaf edjes = + match edjes with + | None -> + printfn "There is no path from %d to %d" i j + Unchecked.defaultof<'t> + | Some _ -> + edjes.Min func + + let rec findValue (qtree: QTree>) (size: int) i j : 't = + match qtree with + | Leaf value -> handleLeaf value + | Node(nw, ne, sw, se) -> + if i < size / 2 && j < size / 2 then + findValue nw (size / 2) i j + elif i < size / 2 && j >= size / 2 then + findValue ne (size / 2) i (j - size / 2) + elif i >= size / 2 && j < size / 2 then + findValue sw (size / 2) (i - size / 2) j + else + findValue se (size / 2) (i - size / 2) (j - size / 2) + + let value = findValue graph.qtree graph.n i j + value + + + /// Creates a new graph that is the transitive closure of the underected graph given as argument. + /// The graph whose transitive closure is to be constructed. + /// Transitive closure graph. + let transitiveClosure (graph: Matrix>) = + let adjM = toAdjacencyMatrix graph + let mutable result = adjM + + for i in 2 .. graph.n do + let power = Matrix.multiply result adjM opAdd opMult 0 + result <- Matrix.map2 opAdd result power + + result \ No newline at end of file diff --git a/src/Graphs/Graphs.fsproj b/src/Graphs/Graphs.fsproj new file mode 100644 index 00000000..5adb60d9 --- /dev/null +++ b/src/Graphs/Graphs.fsproj @@ -0,0 +1,16 @@ + + + + net8.0 + true + + + + + + + + + + + diff --git a/src/ImageProcessing/ImageProcessing.fs b/src/ImageProcessing/ImageProcessing.fs new file mode 100644 index 00000000..653a8620 --- /dev/null +++ b/src/ImageProcessing/ImageProcessing.fs @@ -0,0 +1,241 @@ +namespace ImageProcessing + +open SixLabors.ImageSharp +open SixLabors.ImageSharp.PixelFormats + +[] +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 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 applyFilter (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 processPixel px py = + let dataToHandle = [| + for i in px - filterD .. px + filterD do + for j in py - filterD .. py + filterD do + if i < 0 || i >= imgH || j < 0 || j >= imgW then + (0.0f, 0.0f, 0.0f) + else + let pixel = img.[i, j] + (float32 pixel.R, float32 pixel.G, float32 pixel.B) + |] + + let mutable rSum = 0.0f + let mutable gSum = 0.0f + let mutable bSum = 0.0f + + Array.iteri (fun index (r, g, b) -> + rSum <- rSum + r * filter.[index] + gSum <- gSum + g * filter.[index] + bSum <- bSum + b * filter.[index] + ) dataToHandle + + (byte rSum, byte gSum, byte bSum) + + Array2D.mapi (fun x y _ -> + let (r, g, b) = processPixel x y + Rgba32(r, g, b, img.[x, y].A) + ) img \ 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..f78667ad --- /dev/null +++ b/src/ImageProcessing/Program.fs @@ -0,0 +1,72 @@ +open ImageProcessing.ImProcessing +open Argu + + +type Filters = + | gaussianBlur = 1 + | motionDiagonal135deg = 2 + | motionDiagonal315deg = 3 + | motionVertical = 4 + | motionHorizontal = 5 + | edgesHorizontal = 6 + | edgesVertical = 7 + | edgesDioganal135deg = 8 + | edgesDioganal315deg = 9 + | edgesAllDirections = 10 + | sharpen = 11 + | sharpenSoft = 12 + | sharpenWithEdges = 13 + | emboss = 14 + | embossHard = 15 + +type Arguments = + | [] Input_File of string + | [] Out_File of string + | [] Filters of list + interface IArgParserTemplate with + member this.Usage = + match this with + | Input_File _ -> "File to process." + | Out_File _ -> "Where to save result." + | Filters _ -> "Which filters to apply (comma-separated)." + + +[] +let main argv = + + let parser = ArgumentParser.Create(programName = "ImageProcessing") + let results = parser.Parse argv + + let inFile = results.GetResult Input_File + let outFile = results.GetResult Out_File + let filters = results.GetResult Filters + + let inImage = loadAsRgba2D inFile + + let resultImage = + filters |> List.fold (fun img filter -> + match filter with + | Filters.gaussianBlur -> applyFilter gaussianBlur img + | Filters.motionDiagonal135deg -> applyFilter motionDiagonal135deg img + | Filters.motionDiagonal315deg -> applyFilter motionDiagonal315deg img + | Filters.motionVertical -> applyFilter motionVertical img + | Filters.motionHorizontal -> applyFilter motionHorizontal img + | Filters.edgesHorizontal -> applyFilter edgesHorizontal img + | Filters.edgesVertical -> applyFilter edgesVertical img + | Filters.edgesDioganal135deg -> applyFilter edgesDioganal135deg img + | Filters.edgesDioganal315deg -> applyFilter edgesDioganal315deg img + | Filters.edgesAllDirections -> applyFilter edgesAllDirections img + | Filters.sharpen -> applyFilter sharpen img + | Filters.sharpenSoft -> applyFilter sharpenSoft img + | Filters.sharpenWithEdges -> applyFilter sharpenWithEdges img + | Filters.emboss -> applyFilter emboss img + | Filters.embossHard -> applyFilter embossHard img + | _ -> + printfn "Unknown filter" + img + + ) inImage + + saveRgbaImage resultImage outFile + + 0 \ No newline at end of file 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 + + + + + + +