From 484959f30f44bd31824f61be8c92c380469b5fd8 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 6 Sep 2023 22:10:13 -0500 Subject: [PATCH 001/293] Initial commit --- .editorconfig | 160 +++++++++ .gitattributes | 2 + .gitignore | 398 +++++++++++++++++++++ LICENSE | 21 ++ Mathematics.NET.sln | 25 ++ src/Mathematics.NET/Mathematics.NET.csproj | 9 + 6 files changed, 615 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Mathematics.NET.sln create mode 100644 src/Mathematics.NET/Mathematics.NET.csproj diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..0aeaf666 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,160 @@ +### General ### +[*] + +file_header_template = \nMathematics.NET\nhttps://github.com/HamletTanyavong/Mathematics.NET\n\nMIT License\n\nCopyright (c) 2023 Hamlet Tanyavong\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n + +indent_style = space +trim_trailing_whitespace = true +insert_final_newline = true + +### Json files ### +[*.json] + +indent_size = 2 + +### Xml files ### +[*.xml] + +indent_size = 2 + +### Http files ### +[*.http] + +indent_size = 2 + +### C# ### +[*.cs] + +# Naming rules + +dotnet_naming_rule.private_or_internal_static_field_should_be_s_with_underscore.severity = suggestion +dotnet_naming_rule.private_or_internal_static_field_should_be_s_with_underscore.symbols = private_or_internal_static_field +dotnet_naming_rule.private_or_internal_static_field_should_be_s_with_underscore.style = s_with_underscore + +dotnet_naming_rule.private_or_internal_field_should_be_underscore.severity = suggestion +dotnet_naming_rule.private_or_internal_field_should_be_underscore.symbols = private_or_internal_field +dotnet_naming_rule.private_or_internal_field_should_be_underscore.style = underscore + +# Symbol specifications + +dotnet_naming_symbols.private_or_internal_static_field.applicable_kinds = field +dotnet_naming_symbols.private_or_internal_static_field.applicable_accessibilities = internal, private, private_protected +dotnet_naming_symbols.private_or_internal_static_field.required_modifiers = static + +dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field +dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private, private_protected +dotnet_naming_symbols.private_or_internal_field.required_modifiers = + +# Naming styles + +dotnet_naming_style.s_with_underscore.required_prefix = s_ +dotnet_naming_style.s_with_underscore.required_suffix = +dotnet_naming_style.s_with_underscore.word_separator = +dotnet_naming_style.s_with_underscore.capitalization = camel_case + +dotnet_naming_style.underscore.required_prefix = _ +dotnet_naming_style.underscore.required_suffix = +dotnet_naming_style.underscore.word_separator = +dotnet_naming_style.underscore.capitalization = camel_case +csharp_indent_labels = one_less_than_current +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = file_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_methods = when_on_single_line:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = when_on_single_line:silent +csharp_style_expression_bodied_properties = when_on_single_line:silent +csharp_style_expression_bodied_indexers = when_on_single_line:silent +csharp_style_expression_bodied_accessors = when_on_single_line:silent +csharp_style_expression_bodied_lambdas = when_on_single_line:silent +csharp_style_expression_bodied_local_functions = when_on_single_line:silent +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion +csharp_space_around_binary_operators = before_and_after + +# C# and Visual Basic +[*.{cs,vb}] + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion + +# Diagnostics + +# Default severity for analyzer diagnostics with category 'Style' +dotnet_analyzer_diagnostic.category-Style.severity = suggestion + +# IDE0073: The file header does not match the required text +dotnet_diagnostic.IDE0073.severity = warning + +# IDE0008: Use explicit type +dotnet_diagnostic.IDE0008.severity = none diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..dfe07704 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..426d76dd --- /dev/null +++ b/.gitignore @@ -0,0 +1,398 @@ +## 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 + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# 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 +*.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 diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..0c64253e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Hamlet Tanyavong + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln new file mode 100644 index 00000000..6a24988d --- /dev/null +++ b/Mathematics.NET.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34024.191 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET", "Mathematics.NET\Mathematics.NET.csproj", "{86370FDB-532F-4C3C-813B-3D1BBFE0B063}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {86370FDB-532F-4C3C-813B-3D1BBFE0B063}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86370FDB-532F-4C3C-813B-3D1BBFE0B063}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86370FDB-532F-4C3C-813B-3D1BBFE0B063}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86370FDB-532F-4C3C-813B-3D1BBFE0B063}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {179D9282-B1D9-42EC-A6A0-C1970012ED73} + EndGlobalSection +EndGlobal diff --git a/src/Mathematics.NET/Mathematics.NET.csproj b/src/Mathematics.NET/Mathematics.NET.csproj new file mode 100644 index 00000000..cfadb03d --- /dev/null +++ b/src/Mathematics.NET/Mathematics.NET.csproj @@ -0,0 +1,9 @@ + + + + net7.0 + enable + enable + + + From 9c8ad90017e9d2248d9b87e8350905033939073e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 6 Sep 2023 23:05:23 -0500 Subject: [PATCH 002/293] Add src folder - Add src folder to solution and move Mathematics.NET project inside --- Mathematics.NET.sln | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index 6a24988d..fe040a5b 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.7.34024.191 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET", "Mathematics.NET\Mathematics.NET.csproj", "{86370FDB-532F-4C3C-813B-3D1BBFE0B063}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET", "src\Mathematics.NET\Mathematics.NET.csproj", "{558EB964-1CE7-4786-9656-6EEC36A7072E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DAD16084-D255-4DF4-A20D-077E92B88EC5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -11,14 +13,18 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {86370FDB-532F-4C3C-813B-3D1BBFE0B063}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {86370FDB-532F-4C3C-813B-3D1BBFE0B063}.Debug|Any CPU.Build.0 = Debug|Any CPU - {86370FDB-532F-4C3C-813B-3D1BBFE0B063}.Release|Any CPU.ActiveCfg = Release|Any CPU - {86370FDB-532F-4C3C-813B-3D1BBFE0B063}.Release|Any CPU.Build.0 = Release|Any CPU + {558EB964-1CE7-4786-9656-6EEC36A7072E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {558EB964-1CE7-4786-9656-6EEC36A7072E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {558EB964-1CE7-4786-9656-6EEC36A7072E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {558EB964-1CE7-4786-9656-6EEC36A7072E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {558EB964-1CE7-4786-9656-6EEC36A7072E} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} + {557642D0-685A-4846-AD31-DC764692E853} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {179D9282-B1D9-42EC-A6A0-C1970012ED73} EndGlobalSection From 3ebfe6b9820c8b824a20436a0665cd228129231d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 6 Sep 2023 23:05:56 -0500 Subject: [PATCH 003/293] Add files to Solution Items folder - Add .editorconfig, .gitattributes, .gitignore, and LICENSE files to Solution Items folder --- Mathematics.NET.sln | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index fe040a5b..cd95f8b4 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -7,6 +7,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET", "src\Math EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DAD16084-D255-4DF4-A20D-077E92B88EC5}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ADB18351-2BD5-4FA8-921A-09726E7AA6FC}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitattributes = .gitattributes + .gitignore = .gitignore + LICENSE = LICENSE + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU From 55218a3468dcc55ff95148e89d95ae67da395d5f Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 6 Sep 2023 23:06:11 -0500 Subject: [PATCH 004/293] Add tests folder --- Mathematics.NET.sln | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index cd95f8b4..84c1abcd 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -15,6 +15,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution LICENSE = LICENSE EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{91DB0FE7-BAA4-4D16-8A39-65332DD53662}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU From 8ff41bf7a6b54a344912c8202d164eacddd73762 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 6 Sep 2023 23:10:33 -0500 Subject: [PATCH 005/293] Add source generator project - Fix spacing in Mathematics.NET.csproj --- Mathematics.NET.sln | 6 ++++++ .../Mathematics.NET.SourceGenerators.csproj | 18 ++++++++++++++++++ src/Mathematics.NET/Mathematics.NET.csproj | 6 +++++- 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index 84c1abcd..ffb2d5cc 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -17,6 +17,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{91DB0FE7-BAA4-4D16-8A39-65332DD53662}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET.SourceGenerators", "src\Mathematics.NET.SourceGenerators\Mathematics.NET.SourceGenerators.csproj", "{557642D0-685A-4846-AD31-DC764692E853}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {558EB964-1CE7-4786-9656-6EEC36A7072E}.Debug|Any CPU.Build.0 = Debug|Any CPU {558EB964-1CE7-4786-9656-6EEC36A7072E}.Release|Any CPU.ActiveCfg = Release|Any CPU {558EB964-1CE7-4786-9656-6EEC36A7072E}.Release|Any CPU.Build.0 = Release|Any CPU + {557642D0-685A-4846-AD31-DC764692E853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {557642D0-685A-4846-AD31-DC764692E853}.Debug|Any CPU.Build.0 = Debug|Any CPU + {557642D0-685A-4846-AD31-DC764692E853}.Release|Any CPU.ActiveCfg = Release|Any CPU + {557642D0-685A-4846-AD31-DC764692E853}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj b/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj new file mode 100644 index 00000000..d70db3ce --- /dev/null +++ b/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj @@ -0,0 +1,18 @@ + + + + true + false + latest + netstandard2.0 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/src/Mathematics.NET/Mathematics.NET.csproj b/src/Mathematics.NET/Mathematics.NET.csproj index cfadb03d..0ad1fa6f 100644 --- a/src/Mathematics.NET/Mathematics.NET.csproj +++ b/src/Mathematics.NET/Mathematics.NET.csproj @@ -1,4 +1,4 @@ - + net7.0 @@ -6,4 +6,8 @@ enable + + + + From 340b3a823649f33940102911fdc2ce0c6b280a96 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:35:41 -0500 Subject: [PATCH 006/293] Update Mathematics.NET.sln --- Mathematics.NET.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index ffb2d5cc..01d116a1 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -17,7 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{91DB0FE7-BAA4-4D16-8A39-65332DD53662}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET.SourceGenerators", "src\Mathematics.NET.SourceGenerators\Mathematics.NET.SourceGenerators.csproj", "{557642D0-685A-4846-AD31-DC764692E853}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.SourceGenerators", "src\Mathematics.NET.SourceGenerators\Mathematics.NET.SourceGenerators.csproj", "{557642D0-685A-4846-AD31-DC764692E853}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 026e66ef112bafddf8d9bf057aa995ff2ad441e8 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:53:31 -0500 Subject: [PATCH 007/293] Target x64 --- Mathematics.NET.sln | 20 +++++++++---------- .../Mathematics.NET.SourceGenerators.csproj | 1 + src/Mathematics.NET/Mathematics.NET.csproj | 1 + 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index 01d116a1..b1578b72 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -21,18 +21,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.SourceGener EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {558EB964-1CE7-4786-9656-6EEC36A7072E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {558EB964-1CE7-4786-9656-6EEC36A7072E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {558EB964-1CE7-4786-9656-6EEC36A7072E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {558EB964-1CE7-4786-9656-6EEC36A7072E}.Release|Any CPU.Build.0 = Release|Any CPU - {557642D0-685A-4846-AD31-DC764692E853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {557642D0-685A-4846-AD31-DC764692E853}.Debug|Any CPU.Build.0 = Debug|Any CPU - {557642D0-685A-4846-AD31-DC764692E853}.Release|Any CPU.ActiveCfg = Release|Any CPU - {557642D0-685A-4846-AD31-DC764692E853}.Release|Any CPU.Build.0 = Release|Any CPU + {558EB964-1CE7-4786-9656-6EEC36A7072E}.Debug|x64.ActiveCfg = Debug|x64 + {558EB964-1CE7-4786-9656-6EEC36A7072E}.Debug|x64.Build.0 = Debug|x64 + {558EB964-1CE7-4786-9656-6EEC36A7072E}.Release|x64.ActiveCfg = Release|x64 + {558EB964-1CE7-4786-9656-6EEC36A7072E}.Release|x64.Build.0 = Release|x64 + {557642D0-685A-4846-AD31-DC764692E853}.Debug|x64.ActiveCfg = Debug|x64 + {557642D0-685A-4846-AD31-DC764692E853}.Debug|x64.Build.0 = Debug|x64 + {557642D0-685A-4846-AD31-DC764692E853}.Release|x64.ActiveCfg = Release|x64 + {557642D0-685A-4846-AD31-DC764692E853}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj b/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj index d70db3ce..6a6637e7 100644 --- a/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj +++ b/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj @@ -5,6 +5,7 @@ false latest netstandard2.0 + x64 diff --git a/src/Mathematics.NET/Mathematics.NET.csproj b/src/Mathematics.NET/Mathematics.NET.csproj index 0ad1fa6f..e8022477 100644 --- a/src/Mathematics.NET/Mathematics.NET.csproj +++ b/src/Mathematics.NET/Mathematics.NET.csproj @@ -4,6 +4,7 @@ net7.0 enable enable + x64 From 56470014448f16f25cc7942ece68d346bb4590a5 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 8 Sep 2023 16:00:16 -0500 Subject: [PATCH 008/293] Add console application - Add console application for help with development - Add the project folder to .gitignore since the project is only for testing --- .gitignore | 3 +++ Mathematics.NET.sln | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/.gitignore b/.gitignore index 426d76dd..b23fb46a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ ## ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore +# Manually-added items +/src/Application/ + # User-specific files *.rsuser *.suo diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index b1578b72..f0289ad3 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -19,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{91DB0FE7 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.SourceGenerators", "src\Mathematics.NET.SourceGenerators\Mathematics.NET.SourceGenerators.csproj", "{557642D0-685A-4846-AD31-DC764692E853}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application", "src\Application\Application.csproj", "{173526DA-4560-4D64-81EF-5D757A44FBFA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -33,6 +35,10 @@ Global {557642D0-685A-4846-AD31-DC764692E853}.Debug|x64.Build.0 = Debug|x64 {557642D0-685A-4846-AD31-DC764692E853}.Release|x64.ActiveCfg = Release|x64 {557642D0-685A-4846-AD31-DC764692E853}.Release|x64.Build.0 = Release|x64 + {173526DA-4560-4D64-81EF-5D757A44FBFA}.Debug|x64.ActiveCfg = Debug|x64 + {173526DA-4560-4D64-81EF-5D757A44FBFA}.Debug|x64.Build.0 = Debug|x64 + {173526DA-4560-4D64-81EF-5D757A44FBFA}.Release|x64.ActiveCfg = Release|x64 + {173526DA-4560-4D64-81EF-5D757A44FBFA}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -40,6 +46,7 @@ Global GlobalSection(NestedProjects) = preSolution {558EB964-1CE7-4786-9656-6EEC36A7072E} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} {557642D0-685A-4846-AD31-DC764692E853} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} + {173526DA-4560-4D64-81EF-5D757A44FBFA} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {179D9282-B1D9-42EC-A6A0-C1970012ED73} From 199592ea6bc12dcdade276b3cd39eadb7497db36 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 8 Sep 2023 16:47:27 -0500 Subject: [PATCH 009/293] Add test project --- Mathematics.NET.sln | 7 +++++ .../Mathematics.NET.Tests.csproj | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index f0289ad3..a5b4eeff 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.SourceGener EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application", "src\Application\Application.csproj", "{173526DA-4560-4D64-81EF-5D757A44FBFA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET.Tests", "tests\Mathematics.NET.Tests\Mathematics.NET.Tests.csproj", "{A608C0E2-D431-45E9-AD05-A49115BE59AB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -39,6 +41,10 @@ Global {173526DA-4560-4D64-81EF-5D757A44FBFA}.Debug|x64.Build.0 = Debug|x64 {173526DA-4560-4D64-81EF-5D757A44FBFA}.Release|x64.ActiveCfg = Release|x64 {173526DA-4560-4D64-81EF-5D757A44FBFA}.Release|x64.Build.0 = Release|x64 + {A608C0E2-D431-45E9-AD05-A49115BE59AB}.Debug|x64.ActiveCfg = Debug|x64 + {A608C0E2-D431-45E9-AD05-A49115BE59AB}.Debug|x64.Build.0 = Debug|x64 + {A608C0E2-D431-45E9-AD05-A49115BE59AB}.Release|x64.ActiveCfg = Release|x64 + {A608C0E2-D431-45E9-AD05-A49115BE59AB}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -47,6 +53,7 @@ Global {558EB964-1CE7-4786-9656-6EEC36A7072E} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} {557642D0-685A-4846-AD31-DC764692E853} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} {173526DA-4560-4D64-81EF-5D757A44FBFA} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} + {A608C0E2-D431-45E9-AD05-A49115BE59AB} = {91DB0FE7-BAA4-4D16-8A39-65332DD53662} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {179D9282-B1D9-42EC-A6A0-C1970012ED73} diff --git a/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj b/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj new file mode 100644 index 00000000..85c84edf --- /dev/null +++ b/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj @@ -0,0 +1,27 @@ + + + + net7.0 + enable + enable + + false + true + AnyCPU;x64 + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + From 5702a3e34b4b203ee4402a9d115faf523de0fd45 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 8 Sep 2023 16:47:53 -0500 Subject: [PATCH 010/293] Ignore .runsettings file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b23fb46a..7fed5599 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ # Manually-added items /src/Application/ +*.runsettings # User-specific files *.rsuser From 666994ccac4b093c92968ebbe06404a6e64a61a0 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 8 Sep 2023 22:36:49 -0500 Subject: [PATCH 011/293] Create IAdditionOperation.cs - Add an interface that defines the addition operation --- .../Core/Operations/IAdditionOperation.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/Mathematics.NET/Core/Operations/IAdditionOperation.cs diff --git a/src/Mathematics.NET/Core/Operations/IAdditionOperation.cs b/src/Mathematics.NET/Core/Operations/IAdditionOperation.cs new file mode 100644 index 00000000..6493c0bb --- /dev/null +++ b/src/Mathematics.NET/Core/Operations/IAdditionOperation.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Operations; + +/// Defines a mechanism for adding two values +/// The input type +/// The output type +public interface IAdditionOperation + where TInput : IAdditionOperation +{ + static abstract TOutput operator +(TInput left, TInput right); + static virtual TOutput operator checked +(TInput left, TInput right) => left + right; +} From fa5e203bc050800e167ae968b238c34dc0a8c0fa Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 8 Sep 2023 22:37:04 -0500 Subject: [PATCH 012/293] Create IMultiplicationOperation.cs - Add an interface that defines the multiplication operation --- .../Operations/IMultiplicationOperation.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/Mathematics.NET/Core/Operations/IMultiplicationOperation.cs diff --git a/src/Mathematics.NET/Core/Operations/IMultiplicationOperation.cs b/src/Mathematics.NET/Core/Operations/IMultiplicationOperation.cs new file mode 100644 index 00000000..1aaab338 --- /dev/null +++ b/src/Mathematics.NET/Core/Operations/IMultiplicationOperation.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Operations; + +/// Defines a mechanism for multiplying two values +/// The input type +/// The output type +public interface IMultiplicationOperation + where TInput : IMultiplicationOperation +{ + static abstract TOutput operator *(TInput left, TInput right); + static virtual TOutput operator checked *(TInput left, TInput right) => left * right; +} From f723f2bb9467b852e80cd946d38d167d9ad722da Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 8 Sep 2023 22:42:43 -0500 Subject: [PATCH 013/293] Create ISubtractionOperation.cs - Add an interface that defines the subtraction operation --- .../Core/Operations/ISubtractionOperation.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/Mathematics.NET/Core/Operations/ISubtractionOperation.cs diff --git a/src/Mathematics.NET/Core/Operations/ISubtractionOperation.cs b/src/Mathematics.NET/Core/Operations/ISubtractionOperation.cs new file mode 100644 index 00000000..a76e4c61 --- /dev/null +++ b/src/Mathematics.NET/Core/Operations/ISubtractionOperation.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Operations; + +/// Defines a mechanism for subtracting two values +/// The input type +/// The output type +public interface ISubtractionOperation + where TInput : ISubtractionOperation +{ + static abstract TOutput operator -(TInput left, TInput right); + static virtual TOutput operator checked -(TInput left, TInput right) => left - right; +} From 17d0bef546d19040f7e210750728f0a3edabd15e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 8 Sep 2023 22:42:56 -0500 Subject: [PATCH 014/293] Create IDivisionOperation.cs - Add an interface that defines the division operation --- .../Core/Operations/IDivisionOperation.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/Mathematics.NET/Core/Operations/IDivisionOperation.cs diff --git a/src/Mathematics.NET/Core/Operations/IDivisionOperation.cs b/src/Mathematics.NET/Core/Operations/IDivisionOperation.cs new file mode 100644 index 00000000..2388458f --- /dev/null +++ b/src/Mathematics.NET/Core/Operations/IDivisionOperation.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Operations; + +/// Defines a mechanism for dividing two values +/// The input type +/// The output type +public interface IDivisionOperation + where TInput : IDivisionOperation +{ + static abstract TOutput operator /(TInput left, TInput right); + static virtual TOutput operator checked /(TInput left, TInput right) => left / right; +} From 2b6d6299b290bc9c4638b792e811603194fdaa4d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 9 Sep 2023 12:01:39 -0500 Subject: [PATCH 015/293] Add project reference --- tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj b/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj index 85c84edf..88d91375 100644 --- a/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj +++ b/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj @@ -20,6 +20,10 @@ + + + + From 0efd1067ccf1c3dce419fe11636fc5a6fb0ee2bf Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 9 Sep 2023 12:01:51 -0500 Subject: [PATCH 016/293] Add global using --- tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj b/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj index 88d91375..320c6e6e 100644 --- a/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj +++ b/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj @@ -25,6 +25,7 @@ + From beb8fe7a6e100ee0fc1d80496be3d7bd352fb53b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 9 Sep 2023 12:02:42 -0500 Subject: [PATCH 017/293] Add class for testing complex numbers - Add tests for complex conjugation --- .../Core/ComplexNumberTests.cs | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/Mathematics.NET.Tests/Core/ComplexNumberTests.cs diff --git a/tests/Mathematics.NET.Tests/Core/ComplexNumberTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexNumberTests.cs new file mode 100644 index 00000000..dc736bdd --- /dev/null +++ b/tests/Mathematics.NET.Tests/Core/ComplexNumberTests.cs @@ -0,0 +1,57 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Tests.Core; + +[TestClass] +[TestCategory("Core"), TestCategory("Complex Number")] +public sealed class ComplexNumberTests +{ + [TestMethod] + [DataRow(1, 2, 1, -2)] + public void Conjugate_ComplexNumberOfInt32_ReturnsConjugate(int inReal, int inImaginary, int outReal, int outImaginary) + { + ComplexNumber input = new(inReal, inImaginary); + ComplexNumber expected = new(outReal, outImaginary); + + var actual = ComplexNumber.Conjugate(input); + + Assert.AreEqual(expected, actual); + } + + [TestMethod] + [DataRow(1.2, 2.3, 1.2, -2.3)] + public void Conjugate_ComplexNumberOfDouble_ReturnsConjugate(double inReal, double inImaginary, double outReal, double outImaginary) + { + ComplexNumber input = new(inReal, inImaginary); + ComplexNumber expected = new(outReal, outImaginary); + + var actual = ComplexNumber.Conjugate(input); + + Assert.AreEqual(expected, actual); + } +} From b9b8706ce1ebf75caa981a99c9ec77beaa01c222 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 10 Sep 2023 13:09:25 -0500 Subject: [PATCH 018/293] Create Precision.cs - Add machine epsilons for float and double --- src/Mathematics.NET/Core/Precision.cs | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/Mathematics.NET/Core/Precision.cs diff --git a/src/Mathematics.NET/Core/Precision.cs b/src/Mathematics.NET/Core/Precision.cs new file mode 100644 index 00000000..294bfa83 --- /dev/null +++ b/src/Mathematics.NET/Core/Precision.cs @@ -0,0 +1,46 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Numerics; + +namespace Mathematics.NET.Core; + +/// A class for working with floating-point numbers +public static class Precision +{ + /// Machine epsilon for single-precision floating-point numbers according to the formal definition + public const double FltEpsilonFormal = 5.96046447753906250e-8; + + /// Machine epsilon for double-precision floating-point numbers according to the formal definition + public const double DblEpsilonFormal = 1.11022302462515654e-16; + + /// Machine epsilon for single-precision floating-point numbers according to the variant definition + public const double FltEpsilonVariant = 1.19209289550781250e-7; + + /// Machine epsilon for double-precision floating-point numbers according to the variant definition + public const double DblEpsilonVariant = 2.22044604925031308e-16; +} From 76142417eb9302111b06c048af0a052c992bbe90 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 11:55:25 -0500 Subject: [PATCH 019/293] Create IComplex.cs - Add interface defining support for complex numbers --- src/Mathematics.NET/Core/IComplex.cs | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/Mathematics.NET/Core/IComplex.cs diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs new file mode 100644 index 00000000..0797d998 --- /dev/null +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -0,0 +1,42 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Numerics; +using Mathematics.NET.Core.Operations; + +namespace Mathematics.NET.Core; + +/// Defines support for complex numbers +/// The type that implements the interface +/// A type that implements +public interface IComplex + where T : IComplex + where U : INumber +{ + public U Real { get; } + public virtual U Imaginary => U.Zero; +} From 929b832309cf23ea650b5324f1cc707bc521fb82 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 11:57:52 -0500 Subject: [PATCH 020/293] Create ComplexNumber.cs - Implement IComplex interface --- src/Mathematics.NET/Core/ComplexNumber.cs | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/Mathematics.NET/Core/ComplexNumber.cs diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/ComplexNumber.cs new file mode 100644 index 00000000..9962d378 --- /dev/null +++ b/src/Mathematics.NET/Core/ComplexNumber.cs @@ -0,0 +1,46 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Numerics; + +namespace Mathematics.NET.Core; + +public readonly struct ComplexNumber : IComplex, T> + where T : INumber +{ + private readonly T _real; + private readonly T _imaginary; + + public ComplexNumber(T real, T imaginary) + { + _real = real; + _imaginary = imaginary; + } + + public T Real => _real; + public T Imaginary => _imaginary; +} From 57c3fe834efb39d79862eb9eadf764f68eb17fd7 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:00:39 -0500 Subject: [PATCH 021/293] Rename ComplexNumber to Complex - Update test class to match change --- .../Core/{ComplexNumber.cs => Complex.cs} | 6 +++--- ...{ComplexNumberTests.cs => ComplexTests.cs} | 20 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) rename src/Mathematics.NET/Core/{ComplexNumber.cs => Complex.cs} (89%) rename tests/Mathematics.NET.Tests/Core/{ComplexNumberTests.cs => ComplexTests.cs} (67%) diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/Complex.cs similarity index 89% rename from src/Mathematics.NET/Core/ComplexNumber.cs rename to src/Mathematics.NET/Core/Complex.cs index 9962d378..8eea3147 100644 --- a/src/Mathematics.NET/Core/ComplexNumber.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -1,4 +1,4 @@ -// +// // Mathematics.NET // https://github.com/HamletTanyavong/Mathematics.NET // @@ -29,13 +29,13 @@ namespace Mathematics.NET.Core; -public readonly struct ComplexNumber : IComplex, T> +public readonly struct Complex : IComplex, T> where T : INumber { private readonly T _real; private readonly T _imaginary; - public ComplexNumber(T real, T imaginary) + public Complex(T real, T imaginary) { _real = real; _imaginary = imaginary; diff --git a/tests/Mathematics.NET.Tests/Core/ComplexNumberTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs similarity index 67% rename from tests/Mathematics.NET.Tests/Core/ComplexNumberTests.cs rename to tests/Mathematics.NET.Tests/Core/ComplexTests.cs index dc736bdd..a78c592f 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexNumberTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -1,4 +1,4 @@ -// +// // Mathematics.NET // https://github.com/HamletTanyavong/Mathematics.NET // @@ -29,28 +29,28 @@ namespace Mathematics.NET.Tests.Core; [TestClass] [TestCategory("Core"), TestCategory("Complex Number")] -public sealed class ComplexNumberTests +public sealed class ComplexTests { [TestMethod] [DataRow(1, 2, 1, -2)] - public void Conjugate_ComplexNumberOfInt32_ReturnsConjugate(int inReal, int inImaginary, int outReal, int outImaginary) + public void Conjugate_ComplexOfInt32_ReturnsConjugate(int inReal, int inImaginary, int outReal, int outImaginary) { - ComplexNumber input = new(inReal, inImaginary); - ComplexNumber expected = new(outReal, outImaginary); + Complex input = new(inReal, inImaginary); + Complex expected = new(outReal, outImaginary); - var actual = ComplexNumber.Conjugate(input); + var actual = Complex.Conjugate(input); Assert.AreEqual(expected, actual); } [TestMethod] [DataRow(1.2, 2.3, 1.2, -2.3)] - public void Conjugate_ComplexNumberOfDouble_ReturnsConjugate(double inReal, double inImaginary, double outReal, double outImaginary) + public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inImaginary, double outReal, double outImaginary) { - ComplexNumber input = new(inReal, inImaginary); - ComplexNumber expected = new(outReal, outImaginary); + Complex input = new(inReal, inImaginary); + Complex expected = new(outReal, outImaginary); - var actual = ComplexNumber.Conjugate(input); + var actual = Complex.Conjugate(input); Assert.AreEqual(expected, actual); } From 67ed222f45026dc3f2cf3d5be93a69df28ded947 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:02:16 -0500 Subject: [PATCH 022/293] Add conjugation --- src/Mathematics.NET/Core/Complex.cs | 2 ++ src/Mathematics.NET/Core/IComplex.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 8eea3147..354bc2cb 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -43,4 +43,6 @@ public Complex(T real, T imaginary) public T Real => _real; public T Imaginary => _imaginary; + + public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); } diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 0797d998..d66a410f 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -39,4 +39,5 @@ public interface IComplex { public U Real { get; } public virtual U Imaginary => U.Zero; + static abstract T Conjugate(T z); } From 3a958dc1d8e0d928074ae3dae92c15e3886d111d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:05:46 -0500 Subject: [PATCH 023/293] Update IComplex.cs - Inherit basic arithmetical operations which have already been defined --- src/Mathematics.NET/Core/IComplex.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index d66a410f..17590f89 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -34,6 +34,10 @@ namespace Mathematics.NET.Core; /// The type that implements the interface /// A type that implements public interface IComplex + : IAdditionOperation, + IDivisionOperation, + IMultiplicationOperation, + ISubtractionOperation where T : IComplex where U : INumber { From e9859c1513168166f9bf8628db5144ad9cc98b06 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:12:23 -0500 Subject: [PATCH 024/293] Update Complex.cs - Implement addition, subtraction, and multiplication as required by interface. Division requires care and will be added later. --- src/Mathematics.NET/Core/Complex.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 354bc2cb..af9d330a 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -44,5 +44,15 @@ public Complex(T real, T imaginary) public T Real => _real; public T Imaginary => _imaginary; + public static Complex operator +(Complex z, Complex w) => new(z._real + w._real, z._imaginary + w._imaginary); + + public static Complex operator -(Complex z, Complex w) => new(z._real - w._real, z._imaginary - w._imaginary); + + public static Complex operator *(Complex z, Complex w) + => new(z._real * w._real - z._imaginary * w._imaginary, z._real * w._imaginary + w._real * z._imaginary); + + public static Complex operator /(Complex z, Complex w) + => throw new NotImplementedException(); + public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); } From aaf6a481edc9d3e5d63d109b806a359ec03281b7 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:20:25 -0500 Subject: [PATCH 025/293] Add documentation comments --- src/Mathematics.NET/Core/Complex.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index af9d330a..a9adf67f 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -29,6 +29,8 @@ namespace Mathematics.NET.Core; +/// Represents a complex number +/// A type that implements public readonly struct Complex : IComplex, T> where T : INumber { From 55bde4497da06eb4fedcf79d6e0a1a463f6b01d1 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:20:34 -0500 Subject: [PATCH 026/293] Add documentation comments --- src/Mathematics.NET/Core/IComplex.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 17590f89..f168d66c 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -41,7 +41,9 @@ public interface IComplex where T : IComplex where U : INumber { + /// The real part of the complex number public U Real { get; } + /// The imaginary part of the complex number public virtual U Imaginary => U.Zero; static abstract T Conjugate(T z); } From 571911fbc68d127e96b3ef3cadaab2b1f3cd782b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:22:27 -0500 Subject: [PATCH 027/293] Create INegationOperation.cs - Add an interface that defines the negation operation --- .../Core/Operations/INegationOperation.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/Mathematics.NET/Core/Operations/INegationOperation.cs diff --git a/src/Mathematics.NET/Core/Operations/INegationOperation.cs b/src/Mathematics.NET/Core/Operations/INegationOperation.cs new file mode 100644 index 00000000..7153054b --- /dev/null +++ b/src/Mathematics.NET/Core/Operations/INegationOperation.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Operations; + +/// Defines a mechanism for negating values +/// The input type +/// The output type +public interface INegationOperation + where TInput : INegationOperation +{ + static abstract TResult operator -(TInput value); + static virtual TResult operator checked -(TInput value) => -value; +} From 2eb94982a7d3dddfd31cabf04b0a56b3f0bbd59e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 19:39:44 -0500 Subject: [PATCH 028/293] Use IFloatingPointIeee754 instead of INumber - Remove test to reflect this change. Complex is no longer allowed. --- src/Mathematics.NET/Core/Complex.cs | 4 ++-- src/Mathematics.NET/Core/IComplex.cs | 4 ++-- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 12 ------------ 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index a9adf67f..1c7720fc 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -30,9 +30,9 @@ namespace Mathematics.NET.Core; /// Represents a complex number -/// A type that implements +/// A type that implements public readonly struct Complex : IComplex, T> - where T : INumber + where T : IFloatingPointIeee754 { private readonly T _real; private readonly T _imaginary; diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index f168d66c..b219914e 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -32,14 +32,14 @@ namespace Mathematics.NET.Core; /// Defines support for complex numbers /// The type that implements the interface -/// A type that implements +/// A type that implements public interface IComplex : IAdditionOperation, IDivisionOperation, IMultiplicationOperation, ISubtractionOperation where T : IComplex - where U : INumber + where U : IFloatingPointIeee754 { /// The real part of the complex number public U Real { get; } diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index a78c592f..8a65c36e 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -31,18 +31,6 @@ namespace Mathematics.NET.Tests.Core; [TestCategory("Core"), TestCategory("Complex Number")] public sealed class ComplexTests { - [TestMethod] - [DataRow(1, 2, 1, -2)] - public void Conjugate_ComplexOfInt32_ReturnsConjugate(int inReal, int inImaginary, int outReal, int outImaginary) - { - Complex input = new(inReal, inImaginary); - Complex expected = new(outReal, outImaginary); - - var actual = Complex.Conjugate(input); - - Assert.AreEqual(expected, actual); - } - [TestMethod] [DataRow(1.2, 2.3, 1.2, -2.3)] public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inImaginary, double outReal, double outImaginary) From 1a68b9388e7b7c20cfe58607831f04d2774f4c94 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 19:40:00 -0500 Subject: [PATCH 029/293] Update IComplex.cs - Inherit negation operation --- src/Mathematics.NET/Core/IComplex.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index b219914e..2b372d9b 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -34,7 +34,8 @@ namespace Mathematics.NET.Core; /// The type that implements the interface /// A type that implements public interface IComplex - : IAdditionOperation, + : INegationOperation, + IAdditionOperation, IDivisionOperation, IMultiplicationOperation, ISubtractionOperation From 3b30259d5668236535bebc2593cd3221b762f71f Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 19:45:58 -0500 Subject: [PATCH 030/293] Create IReal.cs --- src/Mathematics.NET/Core/IReal.cs | 39 +++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/Mathematics.NET/Core/IReal.cs diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs new file mode 100644 index 00000000..597af61b --- /dev/null +++ b/src/Mathematics.NET/Core/IReal.cs @@ -0,0 +1,39 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Numerics; + +namespace Mathematics.NET.Core; + +/// Defines support for real numbers +/// A type that implements the interface +/// A type that implements +public interface IReal : IComplex + where T : IReal + where U : IFloatingPointIeee754 +{ +} From 2a327d335f93268655a0b8b7fb00a2a4f4557880 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 20:15:14 -0500 Subject: [PATCH 031/293] Implement negation operator --- src/Mathematics.NET/Core/Complex.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 1c7720fc..6afa19a3 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -46,6 +46,8 @@ public Complex(T real, T imaginary) public T Real => _real; public T Imaginary => _imaginary; + public static Complex operator -(Complex z) => new(-z._real, -z._imaginary); + public static Complex operator +(Complex z, Complex w) => new(z._real + w._real, z._imaginary + w._imaginary); public static Complex operator -(Complex z, Complex w) => new(z._real - w._real, z._imaginary - w._imaginary); From 7119764485e39316d23c71dc16c04be50f6df732 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 20:33:46 -0500 Subject: [PATCH 032/293] Create Real number class and implement interface --- src/Mathematics.NET/Core/Real.cs | 59 ++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/Mathematics.NET/Core/Real.cs diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs new file mode 100644 index 00000000..56cdbc7f --- /dev/null +++ b/src/Mathematics.NET/Core/Real.cs @@ -0,0 +1,59 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Numerics; + +namespace Mathematics.NET.Core; + +/// Represents a real number +/// A type that implements +public readonly struct Real : IReal, T> + where T : IFloatingPointIeee754 +{ + private readonly T _real; + + public Real(T real) + { + _real = real; + } + + // Real number properties + + public Real Re => _real; + + // Operators + + public static Real operator -(Real value) => -value._real; + public static Real operator +(Real left, Real right) => left._real + right._real; + public static Real operator -(Real left, Real right) => left._real - right._real; + public static Real operator *(Real left, Real right) => left._real * right._real; + public static Real operator /(Real left, Real right) => left._real / right._real; + + // Methods + + public static Real Conjugate(Real z) => throw new NotImplementedException(); +} From 4fce819ca091b1a3fe2d69f847776bd41237bf70 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 20:42:53 -0500 Subject: [PATCH 033/293] Use Real instead of T - Update interface - Add comments --- src/Mathematics.NET/Core/Complex.cs | 14 ++++++++++---- src/Mathematics.NET/Core/IComplex.cs | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 6afa19a3..fbb362fa 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -34,8 +34,8 @@ namespace Mathematics.NET.Core; public readonly struct Complex : IComplex, T> where T : IFloatingPointIeee754 { - private readonly T _real; - private readonly T _imaginary; + private readonly Real _real; + private readonly Real _imaginary; public Complex(T real, T imaginary) { @@ -43,8 +43,12 @@ public Complex(T real, T imaginary) _imaginary = imaginary; } - public T Real => _real; - public T Imaginary => _imaginary; + // Complex number properties + + public Real Re => _real; + public Real Im => _imaginary; + + // Operators public static Complex operator -(Complex z) => new(-z._real, -z._imaginary); @@ -58,5 +62,7 @@ public Complex(T real, T imaginary) public static Complex operator /(Complex z, Complex w) => throw new NotImplementedException(); + // Methods + public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); } diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 2b372d9b..441520f0 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -43,8 +43,8 @@ public interface IComplex where U : IFloatingPointIeee754 { /// The real part of the complex number - public U Real { get; } + public Real Re { get; } /// The imaginary part of the complex number - public virtual U Imaginary => U.Zero; + public virtual Real Im => Real.Zero; static abstract T Conjugate(T z); } From 73c7e64713a78aa370238b84da38c488e9d11df0 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 20:43:16 -0500 Subject: [PATCH 034/293] Add constructor --- src/Mathematics.NET/Core/Complex.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index fbb362fa..82f61bb1 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -37,7 +37,13 @@ namespace Mathematics.NET.Core; private readonly Real _real; private readonly Real _imaginary; - public Complex(T real, T imaginary) + public Complex(Real real) + { + _real = real; + _imaginary = T.Zero; + } + + public Complex(Real real, Real imaginary) { _real = real; _imaginary = imaginary; From 66ba75d89b815711cc1f2b6ec813f0b63fe13a40 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 20:44:23 -0500 Subject: [PATCH 035/293] Add constants Zero and One --- src/Mathematics.NET/Core/Complex.cs | 5 +++++ src/Mathematics.NET/Core/IComplex.cs | 4 ++++ src/Mathematics.NET/Core/Real.cs | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 82f61bb1..0117faa3 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -54,6 +54,11 @@ public Complex(Real real, Real imaginary) public Real Re => _real; public Real Im => _imaginary; + // Constants + + public static Complex Zero => new(Real.Zero, Real.Zero); + public static Complex One => new(Real.One, Real.Zero); + // Operators public static Complex operator -(Complex z) => new(-z._real, -z._imaginary); diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 441520f0..ef9e5a23 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -46,5 +46,9 @@ public interface IComplex public Real Re { get; } /// The imaginary part of the complex number public virtual Real Im => Real.Zero; + /// Reprsents zero for the type + static abstract T Zero { get; } + /// Represents one for the type + static abstract T One { get; } static abstract T Conjugate(T z); } diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 56cdbc7f..61541768 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -45,6 +45,11 @@ public Real(T real) public Real Re => _real; + // Constants + + public static Real Zero => T.Zero; + public static Real One => T.One; + // Operators public static Real operator -(Real value) => -value._real; From d329fc7db0c91dec136ab4f17ec25be7c8f3a6df Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 20:45:11 -0500 Subject: [PATCH 036/293] Add and implement implicit operator --- src/Mathematics.NET/Core/Complex.cs | 4 ++++ src/Mathematics.NET/Core/IComplex.cs | 1 + src/Mathematics.NET/Core/Real.cs | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 0117faa3..b5f15844 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -76,4 +76,8 @@ public Complex(Real real, Real imaginary) // Methods public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); + + // Implicit Operators + + public static implicit operator Complex(T x) => new(x); } diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index ef9e5a23..0b31b97f 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -51,4 +51,5 @@ public interface IComplex /// Represents one for the type static abstract T One { get; } static abstract T Conjugate(T z); + static abstract implicit operator T(U x); } diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 61541768..f5460767 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -61,4 +61,8 @@ public Real(T real) // Methods public static Real Conjugate(Real z) => throw new NotImplementedException(); + + // Implicit operators + + public static implicit operator Real(T x) => new(x); } From 3ec77c331c6ab250014e658efc18923897325cae Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 20:48:08 -0500 Subject: [PATCH 037/293] Disable code style warning --- src/Mathematics.NET/Core/Complex.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index b5f15844..d5399e4a 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -25,6 +25,8 @@ // SOFTWARE. // +#pragma warning disable IDE0032 + using System.Numerics; namespace Mathematics.NET.Core; From fb1a8cb727357412100e49af23e08df219d6d087 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 21:36:41 -0500 Subject: [PATCH 038/293] Disable code style warning --- src/Mathematics.NET/Core/Real.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index f5460767..76618f87 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -25,6 +25,8 @@ // SOFTWARE. // +#pragma warning disable IDE0032 + using System.Numerics; namespace Mathematics.NET.Core; From f4f6ab42727fea38a7c49c615bad1b225243a889 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 22:05:37 -0500 Subject: [PATCH 039/293] Update IReal interface and implementation - Define and implement way to get the backing value of a real number --- src/Mathematics.NET/Core/IReal.cs | 2 ++ src/Mathematics.NET/Core/Real.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 597af61b..a0ece939 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -36,4 +36,6 @@ public interface IReal : IComplex where T : IReal where U : IFloatingPointIeee754 { + /// The backing value of the type + U Value { get; } } diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 76618f87..8e76a273 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -46,6 +46,7 @@ public Real(T real) // Real number properties public Real Re => _real; + public T Value => _real; // Constants From 90355def069b4a81685b10b25fbe7e8f70e877f9 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 11 Sep 2023 23:08:50 -0500 Subject: [PATCH 040/293] Update ComplexTests.cs - Add test for verifying the phase of a complex number --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 8a65c36e..664bb4ab 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -42,4 +42,18 @@ public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inI Assert.AreEqual(expected, actual); } + + [TestMethod] + [DataRow(1, 1, 0, Math.PI / 2)] + [DataRow(1, -1, -Math.PI / 2, 0)] + [DataRow(-1, 1, Math.PI / 2, Math.PI)] + [DataRow(-1, -1, -Math.PI, -Math.PI / 2)] + public void Phase_ComplexOfDouble_ReturnsAngleInCorrectQuadrant(double inReal, double inImaginary, double min, double max) + { + Complex z = new(inReal, inImaginary); + + var actual = z.Phase.Value; + + Assert.IsTrue(min <= actual && actual <= max); + } } From fe1cc305a01d1f9cb6734027d913369c4b0a794b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 00:01:22 -0500 Subject: [PATCH 041/293] Add Magnitude and Phase properties --- src/Mathematics.NET/Core/Complex.cs | 2 ++ src/Mathematics.NET/Core/IComplex.cs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index d5399e4a..698a9606 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -55,6 +55,8 @@ public Complex(Real real, Real imaginary) public Real Re => _real; public Real Im => _imaginary; + public Real Magnitude => T.Hypot(_real.Value, _imaginary.Value); + public Real Phase => T.Atan2(_imaginary.Value, _real.Value); // Constants diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 0b31b97f..9e119419 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -46,6 +46,10 @@ public interface IComplex public Real Re { get; } /// The imaginary part of the complex number public virtual Real Im => Real.Zero; + /// The magnitude of the complex number in polar coordinates + public virtual Real Magnitude => U.Hypot(Re.Value, Im.Value); + /// The phase of the complex number in polar coordinates + public virtual Real Phase => U.Atan2(Im.Value, Re.Value); /// Reprsents zero for the type static abstract T Zero { get; } /// Represents one for the type From 015ed698826c138f2cb8501bc337e7cf0465d62a Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 00:37:48 -0500 Subject: [PATCH 042/293] Add constants as fields - Add ImUnit to represent the imaginary unit --- src/Mathematics.NET/Core/Complex.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 698a9606..05fcbdbb 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -36,6 +36,10 @@ namespace Mathematics.NET.Core; public readonly struct Complex : IComplex, T> where T : IFloatingPointIeee754 { + public static readonly Complex Zero = new(Real.Zero, Real.Zero); + public static readonly Complex One = new(Real.One, Real.Zero); + public static readonly Complex ImUnit = new(Real.Zero, Real.One); + private readonly Real _real; private readonly Real _imaginary; @@ -60,8 +64,8 @@ public Complex(Real real, Real imaginary) // Constants - public static Complex Zero => new(Real.Zero, Real.Zero); - public static Complex One => new(Real.One, Real.Zero); + static Complex IComplex, T>.Zero => Zero; + static Complex IComplex, T>.One => One; // Operators From f1e444536057dcf5fac799f133f17c60e3975fd2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 09:00:19 -0500 Subject: [PATCH 043/293] Add constants as fields --- src/Mathematics.NET/Core/Real.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 8e76a273..c44070fc 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -36,6 +36,9 @@ namespace Mathematics.NET.Core; public readonly struct Real : IReal, T> where T : IFloatingPointIeee754 { + public static readonly Real Zero = T.Zero; + public static readonly Real One = T.One; + private readonly T _real; public Real(T real) @@ -50,8 +53,8 @@ public Real(T real) // Constants - public static Real Zero => T.Zero; - public static Real One => T.One; + static Real IComplex, T>.Zero => Zero; + static Real IComplex, T>.One => One; // Operators From aa06f12241e6bc2ad28af9ae5151761897c02c34 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 09:01:00 -0500 Subject: [PATCH 044/293] Add NaN for complex and real numbers --- src/Mathematics.NET/Core/Complex.cs | 2 ++ src/Mathematics.NET/Core/IComplex.cs | 1 + src/Mathematics.NET/Core/Real.cs | 2 ++ 3 files changed, 5 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 05fcbdbb..0c51f121 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -39,6 +39,7 @@ namespace Mathematics.NET.Core; public static readonly Complex Zero = new(Real.Zero, Real.Zero); public static readonly Complex One = new(Real.One, Real.Zero); public static readonly Complex ImUnit = new(Real.Zero, Real.One); + public static readonly Complex NaN = new(Real.NaN, Real.NaN); private readonly Real _real; private readonly Real _imaginary; @@ -66,6 +67,7 @@ public Complex(Real real, Real imaginary) static Complex IComplex, T>.Zero => Zero; static Complex IComplex, T>.One => One; + static Complex IComplex, T>.NaN => NaN; // Operators diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 9e119419..528e5611 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -54,6 +54,7 @@ public interface IComplex static abstract T Zero { get; } /// Represents one for the type static abstract T One { get; } + static abstract T NaN { get; } static abstract T Conjugate(T z); static abstract implicit operator T(U x); } diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index c44070fc..5be625dc 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -38,6 +38,7 @@ namespace Mathematics.NET.Core; { public static readonly Real Zero = T.Zero; public static readonly Real One = T.One; + public static readonly Real NaN = T.NaN; private readonly T _real; @@ -55,6 +56,7 @@ public Real(T real) static Real IComplex, T>.Zero => Zero; static Real IComplex, T>.One => One; + static Real IComplex, T>.NaN => NaN; // Operators From e60c2e771b28b6cded7b90755fac8e1ac380ce94 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 09:32:47 -0500 Subject: [PATCH 045/293] Rename parameters for clarity --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 664bb4ab..4d7e6eef 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -48,12 +48,12 @@ public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inI [DataRow(1, -1, -Math.PI / 2, 0)] [DataRow(-1, 1, Math.PI / 2, Math.PI)] [DataRow(-1, -1, -Math.PI, -Math.PI / 2)] - public void Phase_ComplexOfDouble_ReturnsAngleInCorrectQuadrant(double inReal, double inImaginary, double min, double max) + public void Phase_ComplexOfDouble_ReturnsAngleInCorrectQuadrant(double inReal, double inImaginary, double expectedMin, double expectedMax) { Complex z = new(inReal, inImaginary); var actual = z.Phase.Value; - Assert.IsTrue(min <= actual && actual <= max); + Assert.IsTrue(expectedMin <= actual && actual <= expectedMax); } } From fc154e97735e147e01a4336e37456636ae109c5c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 10:03:42 -0500 Subject: [PATCH 046/293] Rename field --- src/Mathematics.NET/Core/Complex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 0c51f121..e8d61efe 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -38,7 +38,7 @@ namespace Mathematics.NET.Core; { public static readonly Complex Zero = new(Real.Zero, Real.Zero); public static readonly Complex One = new(Real.One, Real.Zero); - public static readonly Complex ImUnit = new(Real.Zero, Real.One); + public static readonly Complex ImaginaryUnit = new(Real.Zero, Real.One); public static readonly Complex NaN = new(Real.NaN, Real.NaN); private readonly Real _real; From 83306dacda7c0f5652b1d72a78bb43017493be4d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 10:11:41 -0500 Subject: [PATCH 047/293] Rename field --- src/Mathematics.NET/Core/Real.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 5be625dc..608d5fa6 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -40,17 +40,17 @@ namespace Mathematics.NET.Core; public static readonly Real One = T.One; public static readonly Real NaN = T.NaN; - private readonly T _real; + private readonly T _value; public Real(T real) { - _real = real; + _value = real; } // Real number properties - public Real Re => _real; - public T Value => _real; + public Real Re => _value; + public T Value => _value; // Constants @@ -60,11 +60,11 @@ public Real(T real) // Operators - public static Real operator -(Real value) => -value._real; - public static Real operator +(Real left, Real right) => left._real + right._real; - public static Real operator -(Real left, Real right) => left._real - right._real; - public static Real operator *(Real left, Real right) => left._real * right._real; - public static Real operator /(Real left, Real right) => left._real / right._real; + public static Real operator -(Real value) => -value._value; + public static Real operator +(Real left, Real right) => left._value + right._value; + public static Real operator -(Real left, Real right) => left._value - right._value; + public static Real operator *(Real left, Real right) => left._value * right._value; + public static Real operator /(Real left, Real right) => left._value / right._value; // Methods From f7a6e68d49b01bc80ee743c4ba60e0657376b961 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 10:30:37 -0500 Subject: [PATCH 048/293] Add documentation comment --- src/Mathematics.NET/Core/IComplex.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 528e5611..a15fff27 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -54,6 +54,7 @@ public interface IComplex static abstract T Zero { get; } /// Represents one for the type static abstract T One { get; } + /// Represents NaN for the type static abstract T NaN { get; } static abstract T Conjugate(T z); static abstract implicit operator T(U x); From 232eb41a08d3402a58a95e971798c5cb051244e4 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 10:35:23 -0500 Subject: [PATCH 049/293] Update ComplexTests.cs - Add test for verifying the magnitude of a complex number --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 4d7e6eef..61973068 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -43,6 +43,17 @@ public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inI Assert.AreEqual(expected, actual); } + [TestMethod] + [DataRow(3, 4, 5)] + public void Magnitude_ComplexOfDouble_ReturnsMagnitude(double inReal, double inImaginary, double expected) + { + Complex z = new(inReal, inImaginary); + + var actual = z.Magnitude.Value; + + Assert.AreEqual(expected, actual); + } + [TestMethod] [DataRow(1, 1, 0, Math.PI / 2)] [DataRow(1, -1, -Math.PI / 2, 0)] From 23740dc5919ae3d164ea0dcf221bdee9a2dd7d7a Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 10:51:20 -0500 Subject: [PATCH 050/293] Add positive and negative infinities --- src/Mathematics.NET/Core/IReal.cs | 4 ++++ src/Mathematics.NET/Core/Real.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index a0ece939..8e737647 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -38,4 +38,8 @@ public interface IReal : IComplex { /// The backing value of the type U Value { get; } + /// Represents negative infinty for the type + static abstract T NegativeInfinity { get; } + /// Represents positive infinity for the type + static abstract T PositiveInfinity { get; } } diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 608d5fa6..89540255 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -39,6 +39,8 @@ namespace Mathematics.NET.Core; public static readonly Real Zero = T.Zero; public static readonly Real One = T.One; public static readonly Real NaN = T.NaN; + public static readonly Real NegativeInfinity = T.NegativeInfinity; + public static readonly Real PositiveInfinity = T.PositiveInfinity; private readonly T _value; @@ -57,6 +59,8 @@ public Real(T real) static Real IComplex, T>.Zero => Zero; static Real IComplex, T>.One => One; static Real IComplex, T>.NaN => NaN; + static Real IReal, T>.NegativeInfinity => NegativeInfinity; + static Real IReal, T>.PositiveInfinity => PositiveInfinity; // Operators From 8a8f382ee25d1c76a1e14061b7069affd10361b2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 11:13:37 -0500 Subject: [PATCH 051/293] Implement conjugate --- src/Mathematics.NET/Core/Real.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 89540255..68a76726 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -72,7 +72,7 @@ public Real(T real) // Methods - public static Real Conjugate(Real z) => throw new NotImplementedException(); + public static Real Conjugate(Real x) => x; // Implicit operators From ec1fdfef171f27f1a9051cba0fce3b44cf2e5871 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 12:17:20 -0500 Subject: [PATCH 052/293] Update ComplexTests.cs - Add test for verifying the TryFormat method --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 61973068..6ca910d6 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -67,4 +67,19 @@ public void Phase_ComplexOfDouble_ReturnsAngleInCorrectQuadrant(double inReal, d Assert.IsTrue(expectedMin <= actual && actual <= expectedMax); } + + [TestMethod] + [DataRow(1.2, 2.3, 10, null, "(1.2, 2.3)")] + [DataRow(1.23, 3.4567, 14, "ALL", "(1.23, 3.4567)")] + [DataRow(4.537, 2.3, 5, "RE", "4.537")] + [DataRow(1.2, 7, 1, "IM", "7")] + public void TryFormat_ComplexOfDouble_ReturnsSpanOfCharacters(double inReal, double inImaginary, int length, string? format, string expected) + { + Complex z = new(inReal, inImaginary); + + Span actual = new char[length]; + _ = z.TryFormat(actual, out int _, format, null); + + CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray()); + } } From 0d633fcd5f51bc9fc73245756ab8d820c982cdf2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 12:26:07 -0500 Subject: [PATCH 053/293] Use ISpanFormattable - Implement TryFormat in real and complex number classes --- src/Mathematics.NET/Core/Complex.cs | 60 ++++++++++++++++++++++++++++ src/Mathematics.NET/Core/IComplex.cs | 3 +- src/Mathematics.NET/Core/Real.cs | 7 ++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index e8d61efe..5ff8f14c 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -27,6 +27,7 @@ #pragma warning disable IDE0032 +using System.Globalization; using System.Numerics; namespace Mathematics.NET.Core; @@ -87,6 +88,65 @@ public Complex(Real real, Real imaginary) public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); + // Formatting + + public string ToString(string? format, IFormatProvider? formatProvider) => throw new NotImplementedException(); + + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + format = format.IsEmpty ? "ALL" : format.ToString().ToUpperInvariant(); + provider ??= NumberFormatInfo.InvariantInfo; + + if (format is "ALL") + { + // There are a minimum of 6 characters for "(0, 0)". + int charsCurrentlyWritten = 0; + if (destination.Length < 6) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + destination[charsCurrentlyWritten++] = '('; + + bool tryFormatSucceeded = _real.TryFormat(destination[charsCurrentlyWritten..], out int tryFormatCharsWritten, null, provider); + if (!tryFormatSucceeded) + { + charsWritten = charsCurrentlyWritten; + return false; + } + charsCurrentlyWritten += tryFormatCharsWritten; + + destination[charsCurrentlyWritten++] = ','; + destination[charsCurrentlyWritten++] = ' '; + + tryFormatSucceeded = _imaginary.TryFormat(destination[charsCurrentlyWritten..], out tryFormatCharsWritten, null, provider); + if (!tryFormatSucceeded) + { + charsWritten = charsCurrentlyWritten; + return false; + } + charsCurrentlyWritten += tryFormatCharsWritten; + + destination[charsCurrentlyWritten++] = ')'; + + charsWritten = charsCurrentlyWritten; + return true; + } + else if (format is "RE") + { + return _real.TryFormat(destination, out charsWritten, null, provider); + } + else if (format is "IM") + { + return _imaginary.TryFormat(destination, out charsWritten, null, provider); + } + else + { + throw new FormatException($"The \"{format}\" format is not supported."); + } + } + // Implicit Operators public static implicit operator Complex(T x) => new(x); diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index a15fff27..9ce46fcd 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -38,7 +38,8 @@ public interface IComplex IAdditionOperation, IDivisionOperation, IMultiplicationOperation, - ISubtractionOperation + ISubtractionOperation, + ISpanFormattable where T : IComplex where U : IFloatingPointIeee754 { diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 68a76726..40ae03e4 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -74,6 +74,13 @@ public Real(T real) public static Real Conjugate(Real x) => x; + // Formatting + + public string ToString(string? format, IFormatProvider? formatProvider) => throw new NotImplementedException(); + + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + => _value.TryFormat(destination, out charsWritten, null, provider); + // Implicit operators public static implicit operator Real(T x) => new(x); From cdae1f5e347cd4f6891705b3cb21091c5998857d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 12:52:46 -0500 Subject: [PATCH 054/293] Implement ToString --- src/Mathematics.NET/Core/Complex.cs | 25 ++++++++++++++++++++++++- src/Mathematics.NET/Core/Real.cs | 4 +++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 5ff8f14c..3d4ab8ce 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -90,7 +90,30 @@ public Complex(Real real, Real imaginary) // Formatting - public string ToString(string? format, IFormatProvider? formatProvider) => throw new NotImplementedException(); + public override string ToString() => ToString(null, null); + + public string ToString(string? format, IFormatProvider? formatProvider) + { + format = string.IsNullOrEmpty(format) ? "ALL" : format.ToUpperInvariant(); + formatProvider ??= NumberFormatInfo.InvariantInfo; + + if (format is "ALL") + { + return string.Format(formatProvider, "({0}, {1})", _real, _imaginary); + } + else if (format is "RE") + { + return string.Format(formatProvider, "{0}", _real); + } + else if (format is "IM") + { + return string.Format(formatProvider, "{0}", _imaginary); + } + else + { + throw new FormatException($"The \"{format}\" format is not supported."); + } + } public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) { diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 40ae03e4..140d9374 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -76,7 +76,9 @@ public Real(T real) // Formatting - public string ToString(string? format, IFormatProvider? formatProvider) => throw new NotImplementedException(); + public override string ToString() => ToString(null, null); + + public string ToString(string? format, IFormatProvider? formatProvider) => string.Format(formatProvider, "{0}", _value); public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => _value.TryFormat(destination, out charsWritten, null, provider); From 1b7ce4f8d0038e1b151b62e73da5b67b1313584d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 12:59:30 -0500 Subject: [PATCH 055/293] Update ComplexTests.cs - Add test for ToString method --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 6ca910d6..da30b833 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -68,6 +68,20 @@ public void Phase_ComplexOfDouble_ReturnsAngleInCorrectQuadrant(double inReal, d Assert.IsTrue(expectedMin <= actual && actual <= expectedMax); } + [TestMethod] + [DataRow(1.23, 4.567, null, "(1.23, 4.567)")] + [DataRow(24.56, 9.23, "ALL", "(24.56, 9.23)")] + [DataRow(62.151, 27, "RE", "62.151")] + [DataRow(7.345, 124.841, "IM", "124.841")] + public void ToString_ComplexOfDouble_ReturnsString(double inReal, double inImaginary, string? format, string expected) + { + Complex z = new(inReal, inImaginary); + + var actual = z.ToString(format, null); + + Assert.AreEqual(expected, actual); + } + [TestMethod] [DataRow(1.2, 2.3, 10, null, "(1.2, 2.3)")] [DataRow(1.23, 3.4567, 14, "ALL", "(1.23, 3.4567)")] From 51f1511ce162d79f982806e76dc7d69f51352faa Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:39:27 -0500 Subject: [PATCH 056/293] Update Complex.cs - Fix error that occurs when destination span is too short --- src/Mathematics.NET/Core/Complex.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 3d4ab8ce..4038cc91 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -133,23 +133,33 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan destination[charsCurrentlyWritten++] = '('; bool tryFormatSucceeded = _real.TryFormat(destination[charsCurrentlyWritten..], out int tryFormatCharsWritten, null, provider); - if (!tryFormatSucceeded) + charsCurrentlyWritten += tryFormatCharsWritten; + if (!tryFormatSucceeded || destination.Length < charsCurrentlyWritten + 1) { charsWritten = charsCurrentlyWritten; return false; } - charsCurrentlyWritten += tryFormatCharsWritten; destination[charsCurrentlyWritten++] = ','; + if (destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } destination[charsCurrentlyWritten++] = ' '; + if (destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } tryFormatSucceeded = _imaginary.TryFormat(destination[charsCurrentlyWritten..], out tryFormatCharsWritten, null, provider); - if (!tryFormatSucceeded) + charsCurrentlyWritten += tryFormatCharsWritten; + if (!tryFormatSucceeded || destination.Length < charsCurrentlyWritten + 1) { charsWritten = charsCurrentlyWritten; return false; } - charsCurrentlyWritten += tryFormatCharsWritten; destination[charsCurrentlyWritten++] = ')'; From e9b86f38d46cdb2298683fc012c2e8f7ffe33fd2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:51:29 -0500 Subject: [PATCH 057/293] Update ComplexTests.cs - Add a test to check if TryFormat gives the correct amount of characters written even if it returns false --- .../Core/ComplexTests.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index da30b833..f3bf35c4 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -82,6 +82,28 @@ public void ToString_ComplexOfDouble_ReturnsString(double inReal, double inImagi Assert.AreEqual(expected, actual); } + [TestMethod] + [DataRow(0, 0, 6, 6)] + [DataRow(1.23, 45.678, 14, 14)] + [DataRow(1.23, 45.678, 13, 13)] + [DataRow(1.23, 45.678, 9, 7)] + [DataRow(1.23, 45.678, 6, 6)] + [DataRow(1.23, 45.678, 1, 0)] + [DataRow(0, 1.2345, 6, 4)] + [DataRow(1.2345, 0, 6, 1)] + [DataRow(1.2345, 0, 6, 1)] + [DataRow(1.2345, 0, 7, 7)] + [DataRow(1.2345, 0, 8, 8)] + public void TryFormat_ComplexOfDoubleWithShortDestinationSpan_ReturnsCorrectNumberOfCharsWritten(double inReal, double inImaginary, int length, int expected) + { + Complex z = new(inReal, inImaginary); + + Span span = new char[length]; + _ = z.TryFormat(span, out int actual, null, null); + + Assert.AreEqual(expected, actual); + } + [TestMethod] [DataRow(1.2, 2.3, 10, null, "(1.2, 2.3)")] [DataRow(1.23, 3.4567, 14, "ALL", "(1.23, 3.4567)")] From bd6c0206a7efdbbaa6de520cc07e3e1939e94528 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:51:39 -0500 Subject: [PATCH 058/293] Update ComplexTests.cs - Add tests to verify that TryFormat returns the correct Boolean --- .../Core/ComplexTests.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index f3bf35c4..2a75ad91 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -82,6 +82,32 @@ public void ToString_ComplexOfDouble_ReturnsString(double inReal, double inImagi Assert.AreEqual(expected, actual); } + [TestMethod] + [DataRow(0, 0, 6)] + [DataRow(1.23, 2.34, 12)] + public void TryFormat_ComplexOfDoubleWithAdequateDestinationLength_ReturnsTrue(double inReal, double inImaginary, int length) + { + Complex z = new(inReal, inImaginary); + + Span span = new char[length]; + var actual = z.TryFormat(span, out int _, null, null); + + Assert.IsTrue(actual); + } + + [TestMethod] + [DataRow(0, 0, 5)] + [DataRow(1.23, 2.34, 11)] + public void TryFormat_ComplexOfDoubleWithInadequateDestinationLength_ReturnsFalse(double inReal, double inImaginary, int length) + { + Complex z = new(inReal, inImaginary); + + Span span = new char[length]; + var actual = z.TryFormat(span, out int _, null, null); + + Assert.IsFalse(actual); + } + [TestMethod] [DataRow(0, 0, 6, 6)] [DataRow(1.23, 45.678, 14, 14)] From ff736fb22817d812986ca40a039ee9fbe21f26d1 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 22:01:57 -0500 Subject: [PATCH 059/293] Update Precision.cs - Add methods for comparing floating-point numbers --- src/Mathematics.NET/Core/Precision.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Mathematics.NET/Core/Precision.cs b/src/Mathematics.NET/Core/Precision.cs index 294bfa83..7089d3b7 100644 --- a/src/Mathematics.NET/Core/Precision.cs +++ b/src/Mathematics.NET/Core/Precision.cs @@ -43,4 +43,20 @@ public static class Precision /// Machine epsilon for double-precision floating-point numbers according to the variant definition public const double DblEpsilonVariant = 2.22044604925031308e-16; + + public static bool AreApproximatelyEqual(T left, T right, T epsilon) + where T : IBinaryFloatingPointIeee754 + => T.Abs(left - right) <= epsilon * T.Max(T.Abs(left), T.Abs(right)); + + public static bool AreEssentiallyEqual(T left, T right, T epsilon) + where T : IBinaryFloatingPointIeee754 + => T.Abs(left - right) <= epsilon * T.Min(T.Abs(left), T.Abs(right)); + + public static bool IsDefinitelyGreaterThan(this T number, T value, T epsilon) + where T : IBinaryFloatingPointIeee754 + => number - value > epsilon * T.Max(T.Abs(number), T.Abs(value)); + + public static bool IsDefinitelyLessThan(this T number, T value, T epsilon) + where T : IBinaryFloatingPointIeee754 + => value - number > epsilon * T.Max(T.Abs(number), T.Abs(value)); } From fc27f1e1f1211556531455fa3b0d7a6cb03ad14c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 12 Sep 2023 22:43:07 -0500 Subject: [PATCH 060/293] Create PrecisionTests.cs - Add tests for verifying floating-point equality methods --- .../Core/PrecisionTests.cs | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tests/Mathematics.NET.Tests/Core/PrecisionTests.cs diff --git a/tests/Mathematics.NET.Tests/Core/PrecisionTests.cs b/tests/Mathematics.NET.Tests/Core/PrecisionTests.cs new file mode 100644 index 00000000..6395e45d --- /dev/null +++ b/tests/Mathematics.NET.Tests/Core/PrecisionTests.cs @@ -0,0 +1,61 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Tests.Core; + +[TestClass] +[TestCategory("Core"), TestCategory("Precision")] +public sealed class PrecisionTests +{ + [TestMethod] + [DataRow(1e-13, 1.0000000000000002e-13, Precision.DblEpsilonVariant, true)] + [DataRow(1e-13, 1.0000000000000004e-13, Precision.DblEpsilonVariant, false)] + [DataRow(1.0, 1.0000000000000002, Precision.DblEpsilonVariant, true)] + [DataRow(1.0, 1.0000000000000004, Precision.DblEpsilonVariant, false)] + [DataRow(1.23e27, 1.2300000000000002e27, Precision.DblEpsilonVariant, true)] + [DataRow(1.23e27, 1.2300000000000004e27, Precision.DblEpsilonVariant, false)] + public void AreApproximatelyEqual_TwoDoublePrecisionFloatingPointNumbers_ReturnsBool(double left, double right, double epsilon, bool expected) + { + var actual = Precision.AreApproximatelyEqual(left, right, epsilon); + + Assert.AreEqual(expected, actual); + } + + [TestMethod] + [DataRow(1e-13, 1.0000000000000002e-13, Precision.DblEpsilonVariant, true)] + [DataRow(1e-13, 1.0000000000000004e-13, Precision.DblEpsilonVariant, false)] + [DataRow(1.0, 1.0000000000000002, Precision.DblEpsilonVariant, true)] + [DataRow(1.0, 1.0000000000000004, Precision.DblEpsilonVariant, false)] + [DataRow(1.23e27, 1.2300000000000002e27, Precision.DblEpsilonVariant, true)] + [DataRow(1.23e27, 1.2300000000000004e27, Precision.DblEpsilonVariant, false)] + public void AreEssentiallyEqual_TwoDoublePrecisionFloatingPointNumbers_ReturnsBool(double left, double right, double epsilon, bool expected) + { + var actual = Precision.AreEssentiallyEqual(left, right, epsilon); + + Assert.AreEqual(expected, actual); + } +} From 977f3ff5c0e0c89674d7f7b9cbc1cd126eac522d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 01:46:36 -0500 Subject: [PATCH 061/293] Create Constants.cs --- src/Mathematics.NET/Core/Constants.cs | 63 +++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/Mathematics.NET/Core/Constants.cs diff --git a/src/Mathematics.NET/Core/Constants.cs b/src/Mathematics.NET/Core/Constants.cs new file mode 100644 index 00000000..a650eda8 --- /dev/null +++ b/src/Mathematics.NET/Core/Constants.cs @@ -0,0 +1,63 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core; + +/// Common mathematical constants +public static class Constants +{ + /// Represents the natural logarithmic base, e + public const double E = 2.71828182845904523; + /// Represents the ratio of the circumference of a circle to its diameter, π + public const double Pi = 3.14159265358979323; + /// Represents π/2 + public const double PiHalf = 1.57079632679489661; + /// Represents π squared + public const double PiSquared = 9.86960440108935861; + /// Represents 2π + public const double Tau = 6.28318530717958647; + /// Represents the Euler-Mascheroni constant, γ + public const double EulerMascheroni = 5.77215664901532860e-1; + /// Represents the golden ratio, φ + public const double GoldenRatio = 1.61803398874989484; + /// Represents the natural logarithm of 2 + public const double Ln2 = 6.93147180559945309e-1; + /// Represents the natural logarithm of 3 + public const double Ln3 = 1.09861228866810969; + /// Represents the natural logarithm of 4 + public const double Ln4 = 1.38629436111989061; + /// Represents the natural logarithm of 5 + public const double Ln5 = 1.60943791243410037; + /// Represents the natural logarithm of 10 + public const double Ln10 = 2.30258509299404568; + /// Represents the square root of 2 + public const double Sqrt2 = 1.41421356237309504; + /// Represents the square root of 3 + public const double Sqrt3 = 1.73205080756887729; + /// Represents the square root of 5 + public const double Sqrt5 = 2.23606797749978969; +} From 15694e49051de2de9b4fb00b3c678654787d643b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:12:02 -0500 Subject: [PATCH 062/293] Implement IEquatable interface - Update IComplex interface --- src/Mathematics.NET/Core/Complex.cs | 4 ++++ src/Mathematics.NET/Core/IComplex.cs | 1 + src/Mathematics.NET/Core/Real.cs | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 4038cc91..73de6e38 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -88,6 +88,10 @@ public Complex(Real real, Real imaginary) public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); + // Equality + + public bool Equals(Complex value) => _real.Equals(value.Re) && _imaginary.Equals(value.Im); + // Formatting public override string ToString() => ToString(null, null); diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 9ce46fcd..6886b944 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -39,6 +39,7 @@ public interface IComplex IDivisionOperation, IMultiplicationOperation, ISubtractionOperation, + IEquatable, ISpanFormattable where T : IComplex where U : IFloatingPointIeee754 diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 140d9374..38a40348 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -74,6 +74,10 @@ public Real(T real) public static Real Conjugate(Real x) => x; + // Equality + + public bool Equals(Real value) => _value.Equals(value); + // Formatting public override string ToString() => ToString(null, null); From 4f4968354cbdf9a8ce463f27415107cfb2bb7061 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:19:53 -0500 Subject: [PATCH 063/293] Override Equals and GetHashCode - Implement == and != operators --- src/Mathematics.NET/Core/Complex.cs | 9 +++++++++ src/Mathematics.NET/Core/Real.cs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 73de6e38..3cd04d8a 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -27,6 +27,7 @@ #pragma warning disable IDE0032 +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Numerics; @@ -90,8 +91,16 @@ public Complex(Real real, Real imaginary) // Equality + public static bool operator ==(Complex left, Complex right) => left.Re == right.Re && left.Im == right.Im; + + public static bool operator !=(Complex left, Complex right) => left.Re != right.Re || left.Im != right.Im; + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Complex other && Equals(other); + public bool Equals(Complex value) => _real.Equals(value.Re) && _imaginary.Equals(value.Im); + public override int GetHashCode() => HashCode.Combine(_real, _imaginary); + // Formatting public override string ToString() => ToString(null, null); diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 38a40348..dadd970f 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -27,6 +27,7 @@ #pragma warning disable IDE0032 +using System.Diagnostics.CodeAnalysis; using System.Numerics; namespace Mathematics.NET.Core; @@ -76,8 +77,16 @@ public Real(T real) // Equality + public static bool operator ==(Real left, Real right) => left._value == right._value; + + public static bool operator !=(Real left, Real right) => left._value != right._value; + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Real other && Equals(other); + public bool Equals(Real value) => _value.Equals(value); + public override int GetHashCode() => HashCode.Combine(_value); + // Formatting public override string ToString() => ToString(null, null); From c972bd692237469ca37a9b65109bda58a83fa913 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:36:25 -0500 Subject: [PATCH 064/293] Use ToString - Rename parameter --- src/Mathematics.NET/Core/Complex.cs | 10 +++++----- src/Mathematics.NET/Core/Real.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 3cd04d8a..6f2e0ab4 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -105,22 +105,22 @@ public Complex(Real real, Real imaginary) public override string ToString() => ToString(null, null); - public string ToString(string? format, IFormatProvider? formatProvider) + public string ToString(string? format, IFormatProvider? provider) { format = string.IsNullOrEmpty(format) ? "ALL" : format.ToUpperInvariant(); - formatProvider ??= NumberFormatInfo.InvariantInfo; + provider ??= NumberFormatInfo.InvariantInfo; if (format is "ALL") { - return string.Format(formatProvider, "({0}, {1})", _real, _imaginary); + return string.Format(provider, "({0}, {1})", _real.ToString(null, provider), _imaginary.ToString(null, provider)); } else if (format is "RE") { - return string.Format(formatProvider, "{0}", _real); + return string.Format(provider, "{0}", _real.ToString(null, provider)); } else if (format is "IM") { - return string.Format(formatProvider, "{0}", _imaginary); + return string.Format(provider, "{0}", _imaginary.ToString(null, provider)); } else { diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index dadd970f..5221234a 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -91,7 +91,7 @@ public Real(T real) public override string ToString() => ToString(null, null); - public string ToString(string? format, IFormatProvider? formatProvider) => string.Format(formatProvider, "{0}", _value); + public string ToString(string? format, IFormatProvider? provider) => string.Format(provider, "{0}", _value.ToString(format, provider)); public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => _value.TryFormat(destination, out charsWritten, null, provider); From 26bb7a63388fed50461430081542db7b8ce30b5c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:40:55 -0500 Subject: [PATCH 065/293] Move method --- src/Mathematics.NET/Core/Complex.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 6f2e0ab4..1f4ac9b3 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -85,10 +85,6 @@ public Complex(Real real, Real imaginary) public static Complex operator /(Complex z, Complex w) => throw new NotImplementedException(); - // Methods - - public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); - // Equality public static bool operator ==(Complex left, Complex right) => left.Re == right.Re && left.Im == right.Im; @@ -193,6 +189,10 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan } } + // Methods + + public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); + // Implicit Operators public static implicit operator Complex(T x) => new(x); From 7663845dce78317afa4d9e20950008d80593854d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:41:13 -0500 Subject: [PATCH 066/293] Move method --- src/Mathematics.NET/Core/Real.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 5221234a..d53c4896 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -71,10 +71,6 @@ public Real(T real) public static Real operator *(Real left, Real right) => left._value * right._value; public static Real operator /(Real left, Real right) => left._value / right._value; - // Methods - - public static Real Conjugate(Real x) => x; - // Equality public static bool operator ==(Real left, Real right) => left._value == right._value; @@ -96,6 +92,10 @@ public Real(T real) public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => _value.TryFormat(destination, out charsWritten, null, provider); + // Methods + + public static Real Conjugate(Real x) => x; + // Implicit operators public static implicit operator Real(T x) => new(x); From 16462acfd9676c8fc10898c412be6594b4a6713c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:43:04 -0500 Subject: [PATCH 067/293] Update ComplexTests.cs - Add tests for verifying complex division --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 2a75ad91..06dc163c 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -43,6 +43,20 @@ public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inI Assert.AreEqual(expected, actual); } + [TestMethod] + [DataRow(1, 2, 2, 1, 0.8, 0.6)] + [DataRow(1, 2, 3, 4, 0.44, 0.08)] + public void Division_ComplexOfDoubles_ReturnsComplexOfDouble(double dividendRe, double dividendIm, double divisorRe, double divisorIm, double expectedRe, double expectedIm) + { + Complex dividend = new(dividendRe, dividendIm); + Complex divisor = new(divisorRe, divisorIm); + Complex expected = new(expectedRe, expectedIm); + + var actual = dividend / divisor; + + Assert.AreEqual(expected, actual); + } + [TestMethod] [DataRow(3, 4, 5)] public void Magnitude_ComplexOfDouble_ReturnsMagnitude(double inReal, double inImaginary, double expected) From 706efde2ae5487ddbff0b24e51d11894dbb795b6 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 12:17:57 -0500 Subject: [PATCH 068/293] Create IEqualityRelation.cs --- .../Core/Relations/IEqualityRelation.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/Mathematics.NET/Core/Relations/IEqualityRelation.cs diff --git a/src/Mathematics.NET/Core/Relations/IEqualityRelation.cs b/src/Mathematics.NET/Core/Relations/IEqualityRelation.cs new file mode 100644 index 00000000..62b104e2 --- /dev/null +++ b/src/Mathematics.NET/Core/Relations/IEqualityRelation.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Relations; + +/// Defines a mechanism for determining equality of two values +/// The type that implements the interface +/// The result type +public interface IEqualityRelation + where TSelf : IEqualityRelation +{ + static abstract TResult operator ==(TSelf left, TSelf right); + static abstract TResult operator !=(TSelf left, TSelf right); +} From d133841e1d379d808e6792c585f06743a29e8aef Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 12:19:17 -0500 Subject: [PATCH 069/293] Update IComplex.cs - Implement IEqualityRelation interface --- src/Mathematics.NET/Core/IComplex.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 6886b944..2ebbbbfc 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -27,6 +27,7 @@ using System.Numerics; using Mathematics.NET.Core.Operations; +using Mathematics.NET.Core.Relations; namespace Mathematics.NET.Core; @@ -39,6 +40,7 @@ public interface IComplex IDivisionOperation, IMultiplicationOperation, ISubtractionOperation, + IEqualityRelation, IEquatable, ISpanFormattable where T : IComplex From 9b611335e2a09e85233408e3b71502a3173aee10 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 12:57:52 -0500 Subject: [PATCH 070/293] Fix equality --- src/Mathematics.NET/Core/Real.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index d53c4896..a0afc77e 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -79,7 +79,7 @@ public Real(T real) public override bool Equals([NotNullWhen(true)] object? obj) => obj is Real other && Equals(other); - public bool Equals(Real value) => _value.Equals(value); + public bool Equals(Real value) => _value.Equals(value._value); public override int GetHashCode() => HashCode.Combine(_value); From eac5c874e44318402b07fc94b15252e4acb37e19 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:57:04 -0500 Subject: [PATCH 071/293] Implement IComparable and IComparable - Update interface --- src/Mathematics.NET/Core/IReal.cs | 5 ++++- src/Mathematics.NET/Core/Real.cs | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 8e737647..48fceaf4 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -32,7 +32,10 @@ namespace Mathematics.NET.Core; /// Defines support for real numbers /// A type that implements the interface /// A type that implements -public interface IReal : IComplex +public interface IReal + : IComplex, + IComparable, + IComparable where T : IReal where U : IFloatingPointIeee754 { diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index a0afc77e..fcf26c80 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -83,6 +83,25 @@ public Real(T real) public override int GetHashCode() => HashCode.Combine(_value); + // Comparison + + public int CompareTo(object? obj) + { + if (obj is null) + { + return 1; + } + + if (obj is Real value) + { + return _value.CompareTo(value._value); + } + + throw new ArgumentException("Argument is not a real number"); + } + + public int CompareTo(Real value) => _value.CompareTo(value._value); + // Formatting public override string ToString() => ToString(null, null); From 8413643be12fbd852defc5b4f821aa04b56927d4 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 14:32:07 -0500 Subject: [PATCH 072/293] Create IInequalityRelations.cs --- .../Core/Relations/IInequalityRelations.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/Mathematics.NET/Core/Relations/IInequalityRelations.cs diff --git a/src/Mathematics.NET/Core/Relations/IInequalityRelations.cs b/src/Mathematics.NET/Core/Relations/IInequalityRelations.cs new file mode 100644 index 00000000..9b37c2ae --- /dev/null +++ b/src/Mathematics.NET/Core/Relations/IInequalityRelations.cs @@ -0,0 +1,40 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Relations; + +/// Defines a mechanism for ordering values +/// The type that implements the interface +/// The result type +public interface IInequalityRelations + where TSelf : IInequalityRelations +{ + static abstract TResult operator <(TSelf left, TSelf right); + static abstract TResult operator >(TSelf left, TSelf right); + static abstract TResult operator <=(TSelf left, TSelf right); + static abstract TResult operator >=(TSelf left, TSelf right); +} From ca3872f2d159635c6fd4b6d3dd5cd92f3c8f6141 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 14:39:48 -0500 Subject: [PATCH 073/293] Implement IInequalityRelations - Update interface --- src/Mathematics.NET/Core/IReal.cs | 2 ++ src/Mathematics.NET/Core/Real.cs | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 48fceaf4..5b30f5c0 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -26,6 +26,7 @@ // using System.Numerics; +using Mathematics.NET.Core.Relations; namespace Mathematics.NET.Core; @@ -34,6 +35,7 @@ namespace Mathematics.NET.Core; /// A type that implements public interface IReal : IComplex, + IInequalityRelations, IComparable, IComparable where T : IReal diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index fcf26c80..109b9a16 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -85,6 +85,11 @@ public Real(T real) // Comparison + public static bool operator <(Real left, Real right) => left._value < right._value; + public static bool operator >(Real left, Real right) => left._value > right._value; + public static bool operator <=(Real left, Real right) => left._value <= right._value; + public static bool operator >=(Real left, Real right) => left._value >= right._value; + public int CompareTo(object? obj) { if (obj is null) From c5c82a626b998e645970c7950c8b99cb52e1d7f3 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 14:42:34 -0500 Subject: [PATCH 074/293] Update Complex.cs - Add new line for clarity --- src/Mathematics.NET/Core/Complex.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 1f4ac9b3..f5d45b7d 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -62,6 +62,7 @@ public Complex(Real real, Real imaginary) public Real Re => _real; public Real Im => _imaginary; + public Real Magnitude => T.Hypot(_real.Value, _imaginary.Value); public Real Phase => T.Atan2(_imaginary.Value, _real.Value); From 2d0e28cf023e9e7f90c0759e9b090932cb739d39 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 15:41:16 -0500 Subject: [PATCH 075/293] Create IIncrementOperation.cs --- .../Core/Operations/IIncrementOperation.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/Mathematics.NET/Core/Operations/IIncrementOperation.cs diff --git a/src/Mathematics.NET/Core/Operations/IIncrementOperation.cs b/src/Mathematics.NET/Core/Operations/IIncrementOperation.cs new file mode 100644 index 00000000..7185632c --- /dev/null +++ b/src/Mathematics.NET/Core/Operations/IIncrementOperation.cs @@ -0,0 +1,37 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Operations; + +/// Defines a mechanism for incrementing values +/// The type that implements the interface +public interface IIncrementOperation + where T : IIncrementOperation +{ + static abstract T operator ++(T value); + static virtual T operator checked ++(T value) => ++value; +} From a8231272a07ac39ebc90b73dbbba87c75eac74fb Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:09:35 -0500 Subject: [PATCH 076/293] Create IDecrementOperation.cs --- .../Core/Operations/IDecrementOperation.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/Mathematics.NET/Core/Operations/IDecrementOperation.cs diff --git a/src/Mathematics.NET/Core/Operations/IDecrementOperation.cs b/src/Mathematics.NET/Core/Operations/IDecrementOperation.cs new file mode 100644 index 00000000..0ad57f83 --- /dev/null +++ b/src/Mathematics.NET/Core/Operations/IDecrementOperation.cs @@ -0,0 +1,37 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Operations; + +/// Defines a mechanism for decrementing values +/// The type that implements the interface +public interface IDecrementOperation + where T : IDecrementOperation +{ + static abstract T operator --(T value); + static virtual T operator checked --(T value) => --value; +} From ea46162b9f09f96fbf13722fdd74a57f0fc4b6e3 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 13 Sep 2023 18:08:20 -0500 Subject: [PATCH 077/293] Add documentation comments --- src/Mathematics.NET/Core/IComplex.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 2ebbbbfc..33496b37 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -60,6 +60,11 @@ public interface IComplex static abstract T One { get; } /// Represents NaN for the type static abstract T NaN { get; } + /// Compute the complex conjugate of the number + /// A complex number + /// The complex conjugate static abstract T Conjugate(T z); + /// Convert a value of type to one of type + /// The value to convert static abstract implicit operator T(U x); } From c5a112a5521822d64ca930b62915f4cd1b573eaa Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 01:11:14 -0500 Subject: [PATCH 078/293] Update ComplexTests.cs --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 06dc163c..b3270bfb 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -50,11 +50,13 @@ public void Division_ComplexOfDoubles_ReturnsComplexOfDouble(double dividendRe, { Complex dividend = new(dividendRe, dividendIm); Complex divisor = new(divisorRe, divisorIm); - Complex expected = new(expectedRe, expectedIm); - var actual = dividend / divisor; + var actualResult = dividend / divisor; + var actualRe = actualResult.Re.Value; + var actualIm = actualResult.Im.Value; - Assert.AreEqual(expected, actual); + Assert.AreEqual(expectedRe, actualRe, 1e-15); + Assert.AreEqual(expectedIm, actualIm, 1e-15); } [TestMethod] From 2e6488c43cf49dc3fc69e678cc4e8e5657863c5b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 01:20:39 -0500 Subject: [PATCH 079/293] Implement complex division --- src/Mathematics.NET/Core/Complex.cs | 38 ++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index f5d45b7d..501743ec 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -83,8 +83,44 @@ public Complex(Real real, Real imaginary) public static Complex operator *(Complex z, Complex w) => new(z._real * w._real - z._imaginary * w._imaginary, z._real * w._imaginary + w._real * z._imaginary); + // From Michael Baudin and Robert L. Smith public static Complex operator /(Complex z, Complex w) - => throw new NotImplementedException(); + { + var zRe = z._real.Value; + var zIm = z._imaginary.Value; + var wRe = w._real.Value; + var wIm = w._imaginary.Value; + + T reResult; + T imResult; + if (T.Abs(wIm) <= T.Abs(wRe)) + { + DivisionHelper(zRe, zIm, wRe, wIm, out reResult, out imResult); + } + else + { + DivisionHelper(zIm, zRe, wIm, wRe, out reResult, out imResult); + imResult = -imResult; + } + + return new(reResult, imResult); + } + + private static void DivisionHelper(T x, T y, T maxW, T minW, out T real, out T imaginary) + { + var ratio = minW / maxW; + var scale = T.One / (maxW + minW * ratio); + if (ratio != T.Zero) + { + real = (x + y * ratio) * scale; + imaginary = (y - x * ratio) * scale; + } + else + { + real = (x + minW * (y / maxW)) * scale; + imaginary = (y - minW * (x / maxW)) * scale; + } + } // Equality From 4db11dfce292c659c4bb4c12c929df7b3d3e88e5 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 01:55:32 -0500 Subject: [PATCH 080/293] Update ComplexTests.cs - Add test cases --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index b3270bfb..245a58ca 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -46,6 +46,8 @@ public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inI [TestMethod] [DataRow(1, 2, 2, 1, 0.8, 0.6)] [DataRow(1, 2, 3, 4, 0.44, 0.08)] + [DataRow(2, 1.5, 5, 3, 0.4264705882352942, 0.04411764705882351)] + [DataRow(5, 3.5, 7, 0, 0.7142857142857142, 0.5)] public void Division_ComplexOfDoubles_ReturnsComplexOfDouble(double dividendRe, double dividendIm, double divisorRe, double divisorIm, double expectedRe, double expectedIm) { Complex dividend = new(dividendRe, dividendIm); From d83471f44ba7c2a847accf536140f0a4cd3822d2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:28:13 -0500 Subject: [PATCH 081/293] Remove AnyCPU option --- tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj b/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj index 320c6e6e..5829ef8a 100644 --- a/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj +++ b/tests/Mathematics.NET.Tests/Mathematics.NET.Tests.csproj @@ -7,7 +7,7 @@ false true - AnyCPU;x64 + x64 From 9a04185e946bf034881f86bc5e581ed4fb5b5614 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:28:23 -0500 Subject: [PATCH 082/293] Add benchmarks project --- Mathematics.NET.sln | 9 +++++- .../Mathematics.NET.Benchmarks.csproj | 11 ++++++++ tests/Mathematics.NET.Benchmarks/Program.cs | 28 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj create mode 100644 tests/Mathematics.NET.Benchmarks/Program.cs diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index a5b4eeff..0ac10aed 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -21,7 +21,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.SourceGener EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application", "src\Application\Application.csproj", "{173526DA-4560-4D64-81EF-5D757A44FBFA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET.Tests", "tests\Mathematics.NET.Tests\Mathematics.NET.Tests.csproj", "{A608C0E2-D431-45E9-AD05-A49115BE59AB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.Tests", "tests\Mathematics.NET.Tests\Mathematics.NET.Tests.csproj", "{A608C0E2-D431-45E9-AD05-A49115BE59AB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET.Benchmarks", "tests\Mathematics.NET.Benchmarks\Mathematics.NET.Benchmarks.csproj", "{DD2741ED-C10C-4D76-8CEB-C378F3626D0D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -45,6 +47,10 @@ Global {A608C0E2-D431-45E9-AD05-A49115BE59AB}.Debug|x64.Build.0 = Debug|x64 {A608C0E2-D431-45E9-AD05-A49115BE59AB}.Release|x64.ActiveCfg = Release|x64 {A608C0E2-D431-45E9-AD05-A49115BE59AB}.Release|x64.Build.0 = Release|x64 + {DD2741ED-C10C-4D76-8CEB-C378F3626D0D}.Debug|x64.ActiveCfg = Debug|x64 + {DD2741ED-C10C-4D76-8CEB-C378F3626D0D}.Debug|x64.Build.0 = Debug|x64 + {DD2741ED-C10C-4D76-8CEB-C378F3626D0D}.Release|x64.ActiveCfg = Release|x64 + {DD2741ED-C10C-4D76-8CEB-C378F3626D0D}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -54,6 +60,7 @@ Global {557642D0-685A-4846-AD31-DC764692E853} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} {173526DA-4560-4D64-81EF-5D757A44FBFA} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} {A608C0E2-D431-45E9-AD05-A49115BE59AB} = {91DB0FE7-BAA4-4D16-8A39-65332DD53662} + {DD2741ED-C10C-4D76-8CEB-C378F3626D0D} = {91DB0FE7-BAA4-4D16-8A39-65332DD53662} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {179D9282-B1D9-42EC-A6A0-C1970012ED73} diff --git a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj new file mode 100644 index 00000000..4733d1ff --- /dev/null +++ b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj @@ -0,0 +1,11 @@ + + + + Exe + net7.0 + enable + enable + x64 + + + diff --git a/tests/Mathematics.NET.Benchmarks/Program.cs b/tests/Mathematics.NET.Benchmarks/Program.cs new file mode 100644 index 00000000..c796ec43 --- /dev/null +++ b/tests/Mathematics.NET.Benchmarks/Program.cs @@ -0,0 +1,28 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +Console.WriteLine("Hello, World!"); From 1cbe9e0e6e5ea03160a63719fa391408e6f83b42 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:29:21 -0500 Subject: [PATCH 083/293] Update Mathematics.NET.Benchmarks.csproj - Add project reference --- .../Mathematics.NET.Benchmarks.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj index 4733d1ff..08806041 100644 --- a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj +++ b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj @@ -8,4 +8,8 @@ x64 + + + + From 8f99b8557db2dd2d2d406fad5b998eb9162030a6 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:32:35 -0500 Subject: [PATCH 084/293] Add BenchmarkDotNet --- .../Mathematics.NET.Benchmarks.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj index 08806041..9b92f3a5 100644 --- a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj +++ b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj @@ -8,6 +8,10 @@ x64 + + + + From f858d1605536ab52a8d71f6b3eecd9e7b6a2bb8b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:33:27 -0500 Subject: [PATCH 085/293] Add global usings --- .../Mathematics.NET.Benchmarks.csproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj index 9b92f3a5..7f898c95 100644 --- a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj +++ b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj @@ -16,4 +16,10 @@ + + + + + + From e8693225cb992249169120a79b01295b4c3aa215 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 14:35:29 -0500 Subject: [PATCH 086/293] Update Complex.cs - Add attribute to hint aggressive inlining --- src/Mathematics.NET/Core/Complex.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 501743ec..ca508c24 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -30,6 +30,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Numerics; +using System.Runtime.CompilerServices; namespace Mathematics.NET.Core; @@ -106,6 +107,7 @@ public Complex(Real real, Real imaginary) return new(reResult, imResult); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void DivisionHelper(T x, T y, T maxW, T minW, out T real, out T imaginary) { var ratio = minW / maxW; From 8e6331f3e8d56a783dc8f3595ef50f2e7c388afd Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 14:35:34 -0500 Subject: [PATCH 087/293] Update Mathematics.NET.sln --- Mathematics.NET.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index 0ac10aed..91ab9b11 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -23,7 +23,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application", "src\Applicat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.Tests", "tests\Mathematics.NET.Tests\Mathematics.NET.Tests.csproj", "{A608C0E2-D431-45E9-AD05-A49115BE59AB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET.Benchmarks", "tests\Mathematics.NET.Benchmarks\Mathematics.NET.Benchmarks.csproj", "{DD2741ED-C10C-4D76-8CEB-C378F3626D0D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.Benchmarks", "tests\Mathematics.NET.Benchmarks\Mathematics.NET.Benchmarks.csproj", "{DD2741ED-C10C-4D76-8CEB-C378F3626D0D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 6b6792a9752ed88db27a9f76be4169a48a320252 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 20:12:49 -0500 Subject: [PATCH 088/293] Add a simple benchmark for complex division --- .../Core/Complex/ComplexDivisionBenchmarks.cs | 48 +++++++++++++++++++ tests/Mathematics.NET.Benchmarks/Program.cs | 15 +++++- 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs diff --git a/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs b/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs new file mode 100644 index 00000000..1a923f9b --- /dev/null +++ b/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs @@ -0,0 +1,48 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Benchmarks.Core.Complex; + +[MemoryDiagnoser] +public class ComplexDivisionBenchmarks +{ + public Complex Z { get; set; } + public Complex W { get; set; } + + [GlobalSetup] + public void GlobalSetup() + { + Z = new(1.23, 2.34); + W = new(4.56, 3.45); + } + + [Benchmark] + public Complex ComplexDivision_WithAggressiveInlining() + { + return Z / W; + } +} diff --git a/tests/Mathematics.NET.Benchmarks/Program.cs b/tests/Mathematics.NET.Benchmarks/Program.cs index c796ec43..db565a04 100644 --- a/tests/Mathematics.NET.Benchmarks/Program.cs +++ b/tests/Mathematics.NET.Benchmarks/Program.cs @@ -25,4 +25,17 @@ // SOFTWARE. // -Console.WriteLine("Hello, World!"); +#if RELEASE +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Running; +using Mathematics.NET.Benchmarks.Core.Complex; + +var benchmarkSwitcher = new BenchmarkSwitcher(new[] +{ + typeof(ComplexDivisionBenchmarks) +}); + +benchmarkSwitcher.Run(args, new DebugInProcessConfig()); +#else +Console.WriteLine("Must be in release mode to run benchmarks"); +#endif From ed9ac0f662e8760f33be6caecbadd847e3997186 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 20:33:54 -0500 Subject: [PATCH 089/293] Update test name for clarity --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 245a58ca..6b338c8c 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -138,7 +138,7 @@ public void TryFormat_ComplexOfDoubleWithInadequateDestinationLength_ReturnsFals [DataRow(1.2345, 0, 6, 1)] [DataRow(1.2345, 0, 7, 7)] [DataRow(1.2345, 0, 8, 8)] - public void TryFormat_ComplexOfDoubleWithShortDestinationSpan_ReturnsCorrectNumberOfCharsWritten(double inReal, double inImaginary, int length, int expected) + public void TryFormat_ComplexOfDoubleWithInadequateDestinationLength_ReturnsCorrectNumberOfCharsWritten(double inReal, double inImaginary, int length, int expected) { Complex z = new(inReal, inImaginary); From 6cd7a9a6bfa0147db0d662b75e8393e8a6687030 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 20:53:17 -0500 Subject: [PATCH 090/293] Rename field to something more accurate --- src/Mathematics.NET/Core/Complex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index ca508c24..b2841a95 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -41,7 +41,7 @@ namespace Mathematics.NET.Core; { public static readonly Complex Zero = new(Real.Zero, Real.Zero); public static readonly Complex One = new(Real.One, Real.Zero); - public static readonly Complex ImaginaryUnit = new(Real.Zero, Real.One); + public static readonly Complex ImaginaryOne = new(Real.Zero, Real.One); public static readonly Complex NaN = new(Real.NaN, Real.NaN); private readonly Real _real; From 70ae405c9e9f76c44ecf21665d392b1c41fbdccc Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 21:34:03 -0500 Subject: [PATCH 091/293] Update .editorconfig --- .editorconfig | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index 0aeaf666..e5332968 100644 --- a/.editorconfig +++ b/.editorconfig @@ -80,6 +80,30 @@ csharp_style_prefer_range_operator = true:suggestion csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion csharp_style_prefer_tuple_swap = true:suggestion csharp_space_around_binary_operators = before_and_after +csharp_style_unused_value_expression_statement_preference = discard_variable:silent +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent +csharp_style_prefer_readonly_struct_member = true:suggestion +csharp_style_prefer_readonly_struct = true:suggestion +csharp_prefer_static_local_function = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_prefer_switch_expression = true:suggestion +csharp_style_var_elsewhere = false:silent +csharp_style_var_when_type_is_apparent = false:silent +csharp_style_var_for_built_in_types = false:silent # C# and Visual Basic [*.{cs,vb}] @@ -139,8 +163,8 @@ dotnet_style_prefer_auto_properties = true:silent dotnet_style_object_initializer = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_prefer_simplified_boolean_expressions = true:suggestion -dotnet_style_prefer_conditional_expression_over_assignment = true:silent -dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = false:silent +dotnet_style_prefer_conditional_expression_over_return = false:silent dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_prefer_inferred_tuple_names = true:suggestion dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion @@ -158,3 +182,18 @@ dotnet_diagnostic.IDE0073.severity = warning # IDE0008: Use explicit type dotnet_diagnostic.IDE0008.severity = none +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_readonly_field = false:suggestion +dotnet_style_allow_statement_immediately_after_block_experimental = true:silent +dotnet_style_allow_multiple_blank_lines_experimental = false:silent +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_predefined_type_for_member_access = true:silent +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:silent +dotnet_code_quality_unused_parameters = all:suggestion +dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_property = false:silent From c8e118ee030b25c7454bb27aad580b53bea85879 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 14 Sep 2023 21:34:13 -0500 Subject: [PATCH 092/293] Update IComplex.cs - Update comment --- src/Mathematics.NET/Core/IComplex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 33496b37..c707580a 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -60,7 +60,7 @@ public interface IComplex static abstract T One { get; } /// Represents NaN for the type static abstract T NaN { get; } - /// Compute the complex conjugate of the number + /// Compute the complex conjugate of a number /// A complex number /// The complex conjugate static abstract T Conjugate(T z); From 64b3c8bf1f0feed6a2546baafb94b1755de63846 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 15 Sep 2023 00:28:28 -0500 Subject: [PATCH 093/293] Update Complex.cs - Add Infinity field for complex numbers --- src/Mathematics.NET/Core/Complex.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index b2841a95..ad87decd 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -43,6 +43,7 @@ namespace Mathematics.NET.Core; public static readonly Complex One = new(Real.One, Real.Zero); public static readonly Complex ImaginaryOne = new(Real.Zero, Real.One); public static readonly Complex NaN = new(Real.NaN, Real.NaN); + public static readonly Complex Infinity = new(Real.PositiveInfinity, Real.PositiveInfinity); private readonly Real _real; private readonly Real _imaginary; From b54d67f62cca94640b14ac96cf8cff62dafbff88 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 15 Sep 2023 00:39:15 -0500 Subject: [PATCH 094/293] Add methods to compute reciprocals - Add test - Update interface --- src/Mathematics.NET/Core/Complex.cs | 25 +++++++++++++++++++ src/Mathematics.NET/Core/IComplex.cs | 4 +++ src/Mathematics.NET/Core/Real.cs | 9 +++++++ .../Core/ComplexTests.cs | 13 ++++++++++ 4 files changed, 51 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index ad87decd..13ce88e6 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -233,6 +233,31 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); + public static Complex Reciprocate(Complex w) + { + if (w._real == T.Zero && w._imaginary == T.Zero) + { + return Infinity; + } + + var re = w._real.Value; + var im = w._imaginary.Value; + + T reResult; + T imResult; + if (T.Abs(im) <= T.Abs(re)) + { + DivisionHelper(T.One, T.Zero, re, im, out reResult, out imResult); + } + else + { + DivisionHelper(T.Zero, T.One, im, re, out reResult, out imResult); + imResult = -imResult; + } + + return new(reResult, imResult); + } + // Implicit Operators public static implicit operator Complex(T x) => new(x); diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index c707580a..7918ed25 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -64,6 +64,10 @@ public interface IComplex /// A complex number /// The complex conjugate static abstract T Conjugate(T z); + /// Compute the reciprocal of a number + /// A complex number + /// The reciprocal + static abstract T Reciprocate(T z); /// Convert a value of type to one of type /// The value to convert static abstract implicit operator T(U x); diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 109b9a16..ca1de397 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -120,6 +120,15 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan public static Real Conjugate(Real x) => x; + public static Real Reciprocate(Real x) + { + if (x._value == T.Zero) + { + return PositiveInfinity; + } + return T.One / x; + } + // Implicit operators public static implicit operator Real(T x) => new(x); diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 6b338c8c..a949095f 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -86,6 +86,19 @@ public void Phase_ComplexOfDouble_ReturnsAngleInCorrectQuadrant(double inReal, d Assert.IsTrue(expectedMin <= actual && actual <= expectedMax); } + [TestMethod] + [DataRow(2, 0, 0.5, 0)] + [DataRow(1.5, 2.5, 1.76470588235294117e-1, -2.94117647058823529e-1)] + public void Reciprocate_ComplexOfDouble_ReturnsReciprocal(double inReal, double inImaginary, double expectedRe, double expectedIm) + { + Complex z = new(inReal, inImaginary); + Complex expected = new(expectedRe, expectedIm); + + var actual = Complex.Reciprocate(z); + + Assert.AreEqual(expected, actual); + } + [TestMethod] [DataRow(1.23, 4.567, null, "(1.23, 4.567)")] [DataRow(24.56, 9.23, "ALL", "(24.56, 9.23)")] From 85c1d812e54e793bc373a7a549e362e0b6eedcb7 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 15 Sep 2023 17:56:28 -0500 Subject: [PATCH 095/293] Update ComplexTests.cs - Add tests for parsing spans of characters into complex numbers --- .../Core/ComplexTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index a949095f..59caabfc 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -139,6 +139,33 @@ public void TryFormat_ComplexOfDoubleWithInadequateDestinationLength_ReturnsFals Assert.IsFalse(actual); } + [TestMethod] + [DataRow("(0,0)", 0, 0)] + [DataRow(" (0, 0) ", 0, 0)] + [DataRow("(1.23, 3.456)", 1.23, 3.456)] + [DataRow("( 1.23 , 3.45 )", 1.23, 3.45)] + public void TryParse_SpanOfChar_ReturnsComplexOfDouble(string s, double expectedRe, double expectedIm) + { + + Complex expected = new(expectedRe, expectedIm); + + _ = Complex.TryParse(s.AsSpan(), null, out Complex actual); + + Assert.AreEqual(expected, actual); + } + + [TestMethod] + [DataRow("(,)")] + [DataRow("(0,,0)")] + [DataRow("0,0)")] + [DataRow("(0,0")] + public void TryParse_SpanOfChar_ReturnsFalse(string s) + { + var actual = Complex.TryParse(s.AsSpan(), null, out _); + + Assert.IsFalse(actual); + } + [TestMethod] [DataRow(0, 0, 6, 6)] [DataRow(1.23, 45.678, 14, 14)] From 89d86f7549b2449bb0decf3c97af2a1d9c373c2e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 15 Sep 2023 21:50:41 -0500 Subject: [PATCH 096/293] Add parsing to complex and real numbers - Add parsing of spans of characters and strings into complex and real numbers - Update IComplex interface --- src/Mathematics.NET/Core/Complex.cs | 63 ++++++++++++++++++++++++++++ src/Mathematics.NET/Core/IComplex.cs | 9 +++- src/Mathematics.NET/Core/Real.cs | 53 +++++++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 13ce88e6..34ad9bf8 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -229,6 +229,69 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan } } + // Parsing + + public static Complex Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); + + public static Complex Parse(ReadOnlySpan s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); + + public static Complex Parse(string s, NumberStyles style, IFormatProvider? provider) + { + if (s is null) + { + throw new ArgumentNullException("Cannot parse null string"); + } + return Parse((ReadOnlySpan)s, style, provider); + } + + public static Complex Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) + { + if (!TryParse(s, style, provider, out Complex result)) + { + return Infinity; + } + return result; + } + + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out Complex result) + => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); + + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out Complex result) + => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); + + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Complex result) + => TryParse((ReadOnlySpan)s, style, provider, out result); + + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out Complex result) + { + s = s.Trim(); + int openParenthesis = s.IndexOf('('); + int split = s.IndexOf(','); + int closeParenthesis = s.IndexOf(')'); + + // There a minimum of 5 characters for "(0,0)". + if (s.Length < 5 || openParenthesis == -1 || split == -1 || closeParenthesis == -1 || openParenthesis > split || openParenthesis > closeParenthesis || split > closeParenthesis) + { + result = Zero; + return false; + } + + if (!Real.TryParse(s.Slice(openParenthesis + 1, split - 1), style, provider, out Real real)) + { + result = Zero; + return false; + } + + if (!Real.TryParse(s.Slice(split + 1, closeParenthesis - split - 1), style, provider, out Real imaginary)) + { + result = Zero; + return false; + } + + result = new(real, imaginary); + return true; + } + // Methods public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 7918ed25..df4ac7aa 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -25,6 +25,8 @@ // SOFTWARE. // +using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Numerics; using Mathematics.NET.Core.Operations; using Mathematics.NET.Core.Relations; @@ -42,7 +44,8 @@ public interface IComplex ISubtractionOperation, IEqualityRelation, IEquatable, - ISpanFormattable + ISpanFormattable, + ISpanParsable where T : IComplex where U : IFloatingPointIeee754 { @@ -60,6 +63,10 @@ public interface IComplex static abstract T One { get; } /// Represents NaN for the type static abstract T NaN { get; } + static abstract T Parse(string s, NumberStyles style, IFormatProvider? provider); + static abstract T Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider); + static abstract bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out T result); + static abstract bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out T result); /// Compute the complex conjugate of a number /// A complex number /// The complex conjugate diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index ca1de397..755e11d9 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -28,6 +28,7 @@ #pragma warning disable IDE0032 using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Numerics; namespace Mathematics.NET.Core; @@ -116,6 +117,58 @@ public int CompareTo(object? obj) public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => _value.TryFormat(destination, out charsWritten, null, provider); + // Parsing + + public static Real Parse(string s, IFormatProvider? provider) => T.Parse(s, provider); + + public static Real Parse(ReadOnlySpan s, IFormatProvider? provider) => T.Parse(s, provider); + + public static Real Parse(string s, NumberStyles style, IFormatProvider? provider) + => T.Parse(s, style, provider); + + public static Real Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) + => T.Parse(s, style, provider); + + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out Real result) + { + var succeeded = T.TryParse(s, provider, out T? number); + result = number!; + return succeeded; + } + + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out Real result) + { + var succeeded = T.TryParse(s, provider, out T? number); + result = number!; + return succeeded; + } + + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Real result) + { + if (s is null) + { + result = T.Zero; + return false; + } + + var succeeded = T.TryParse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider), out T? number); + result = number!; + return succeeded; + } + + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out Real result) + { + if (s.IsEmpty) + { + result = T.Zero; + return false; + } + + var succeeded = T.TryParse(s, style, NumberFormatInfo.GetInstance(provider), out T? number); + result = number!; + return succeeded; + } + // Methods public static Real Conjugate(Real x) => x; From fa1f55f9b0a1f146d29ded105a679ebb030ed915 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 15 Sep 2023 21:56:28 -0500 Subject: [PATCH 097/293] Add attributes - Add Serializable attribute - Add StructLayout attribute - Remove disable style warning --- src/Mathematics.NET/Core/Complex.cs | 5 +++-- src/Mathematics.NET/Core/Real.cs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 34ad9bf8..044f0159 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -25,17 +25,18 @@ // SOFTWARE. // -#pragma warning disable IDE0032 - using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Mathematics.NET.Core; /// Represents a complex number /// A type that implements +[Serializable] +[StructLayout(LayoutKind.Sequential)] public readonly struct Complex : IComplex, T> where T : IFloatingPointIeee754 { diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 755e11d9..6990d945 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -25,16 +25,17 @@ // SOFTWARE. // -#pragma warning disable IDE0032 - using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Numerics; +using System.Runtime.InteropServices; namespace Mathematics.NET.Core; /// Represents a real number /// A type that implements +[Serializable] +[StructLayout(LayoutKind.Sequential)] public readonly struct Real : IReal, T> where T : IFloatingPointIeee754 { From 81743900ba99264a359ff6ae5ff90f635a59a2aa Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 15 Sep 2023 22:25:00 -0500 Subject: [PATCH 098/293] Add documentation comments --- src/Mathematics.NET/Core/IComplex.cs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index df4ac7aa..08a180d2 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -63,9 +63,37 @@ public interface IComplex static abstract T One { get; } /// Represents NaN for the type static abstract T NaN { get; } + /// Parse a string into a value + /// The string to parse + /// The number style + /// The culture-specific formatting information about the string + /// The parse result + /// is not a supported + /// is null static abstract T Parse(string s, NumberStyles style, IFormatProvider? provider); + /// Parse a span of characters into a value + /// The span of characters to parse + /// The number style + /// The culture-specific formatting information about the span of characters + /// The parse result + /// is not a supported + /// is null static abstract T Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider); + /// Try to parse a string into a value + /// The string to parse + /// The number style + /// The culture-specific formatting information about the string + /// The result of the parse or a default value if the parse was unsuccessful + /// True if the parse was successful; otherwise, false + /// is not a supported static abstract bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out T result); + /// Try to parse a span of characters into a value + /// The span of characters to parse + /// The number style + /// The culture-specific formatting information about the span of characters + /// The result of the parse or a default value if the parse was unsuccessful + /// True if the parse was successful; otherwise, false + /// is not a supported static abstract bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out T result); /// Compute the complex conjugate of a number /// A complex number From 650d122fb34a5dc95d13d2ab871d8971d8e8e334 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 15 Sep 2023 22:27:36 -0500 Subject: [PATCH 099/293] Update IComplex.cs - Add new lines for clarity - Sort declarations --- src/Mathematics.NET/Core/IComplex.cs | 29 ++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 08a180d2..0450a3a4 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -51,18 +51,30 @@ public interface IComplex { /// The real part of the complex number public Real Re { get; } + /// The imaginary part of the complex number public virtual Real Im => Real.Zero; + /// The magnitude of the complex number in polar coordinates public virtual Real Magnitude => U.Hypot(Re.Value, Im.Value); + /// The phase of the complex number in polar coordinates public virtual Real Phase => U.Atan2(Im.Value, Re.Value); + /// Reprsents zero for the type static abstract T Zero { get; } + /// Represents one for the type static abstract T One { get; } + /// Represents NaN for the type static abstract T NaN { get; } + + /// Compute the complex conjugate of a number + /// A complex number + /// The complex conjugate + static abstract T Conjugate(T z); + /// Parse a string into a value /// The string to parse /// The number style @@ -71,6 +83,7 @@ public interface IComplex /// is not a supported /// is null static abstract T Parse(string s, NumberStyles style, IFormatProvider? provider); + /// Parse a span of characters into a value /// The span of characters to parse /// The number style @@ -79,6 +92,12 @@ public interface IComplex /// is not a supported /// is null static abstract T Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider); + + /// Compute the reciprocal of a number + /// A complex number + /// The reciprocal + static abstract T Reciprocate(T z); + /// Try to parse a string into a value /// The string to parse /// The number style @@ -87,6 +106,7 @@ public interface IComplex /// True if the parse was successful; otherwise, false /// is not a supported static abstract bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out T result); + /// Try to parse a span of characters into a value /// The span of characters to parse /// The number style @@ -95,14 +115,7 @@ public interface IComplex /// True if the parse was successful; otherwise, false /// is not a supported static abstract bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out T result); - /// Compute the complex conjugate of a number - /// A complex number - /// The complex conjugate - static abstract T Conjugate(T z); - /// Compute the reciprocal of a number - /// A complex number - /// The reciprocal - static abstract T Reciprocate(T z); + /// Convert a value of type to one of type /// The value to convert static abstract implicit operator T(U x); From 96ecbbc979b801c8ef4260841667e63b44e231df Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 15 Sep 2023 22:32:46 -0500 Subject: [PATCH 100/293] Update Complex.cs --- src/Mathematics.NET/Core/Complex.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 044f0159..f1f1bf73 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -61,7 +61,9 @@ public Complex(Real real, Real imaginary) _imaginary = imaginary; } + // // Complex number properties + // public Real Re => _real; public Real Im => _imaginary; @@ -69,13 +71,17 @@ public Complex(Real real, Real imaginary) public Real Magnitude => T.Hypot(_real.Value, _imaginary.Value); public Real Phase => T.Atan2(_imaginary.Value, _real.Value); + // // Constants + // static Complex IComplex, T>.Zero => Zero; static Complex IComplex, T>.One => One; static Complex IComplex, T>.NaN => NaN; + // // Operators + // public static Complex operator -(Complex z) => new(-z._real, -z._imaginary); @@ -126,7 +132,9 @@ private static void DivisionHelper(T x, T y, T maxW, T minW, out T real, out T i } } + // // Equality + // public static bool operator ==(Complex left, Complex right) => left.Re == right.Re && left.Im == right.Im; @@ -138,7 +146,9 @@ private static void DivisionHelper(T x, T y, T maxW, T minW, out T real, out T i public override int GetHashCode() => HashCode.Combine(_real, _imaginary); + // // Formatting + // public override string ToString() => ToString(null, null); @@ -230,7 +240,9 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan } } + // // Parsing + // public static Complex Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); @@ -293,7 +305,9 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro return true; } + // // Methods + // public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); @@ -322,7 +336,9 @@ public static Complex Reciprocate(Complex w) return new(reResult, imResult); } + // // Implicit Operators + // public static implicit operator Complex(T x) => new(x); } From ed069025c4dcfce017b81ee7adae3f6f55ebb4db Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 15 Sep 2023 22:32:49 -0500 Subject: [PATCH 101/293] Update Real.cs --- src/Mathematics.NET/Core/Real.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 6990d945..ad77a408 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -52,12 +52,16 @@ public Real(T real) _value = real; } + // // Real number properties + // public Real Re => _value; public T Value => _value; + // // Constants + // static Real IComplex, T>.Zero => Zero; static Real IComplex, T>.One => One; @@ -65,7 +69,9 @@ public Real(T real) static Real IReal, T>.NegativeInfinity => NegativeInfinity; static Real IReal, T>.PositiveInfinity => PositiveInfinity; + // // Operators + // public static Real operator -(Real value) => -value._value; public static Real operator +(Real left, Real right) => left._value + right._value; @@ -73,7 +79,9 @@ public Real(T real) public static Real operator *(Real left, Real right) => left._value * right._value; public static Real operator /(Real left, Real right) => left._value / right._value; + // // Equality + // public static bool operator ==(Real left, Real right) => left._value == right._value; @@ -85,7 +93,9 @@ public Real(T real) public override int GetHashCode() => HashCode.Combine(_value); + // // Comparison + // public static bool operator <(Real left, Real right) => left._value < right._value; public static bool operator >(Real left, Real right) => left._value > right._value; @@ -109,7 +119,9 @@ public int CompareTo(object? obj) public int CompareTo(Real value) => _value.CompareTo(value._value); + // // Formatting + // public override string ToString() => ToString(null, null); @@ -118,7 +130,9 @@ public int CompareTo(object? obj) public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => _value.TryFormat(destination, out charsWritten, null, provider); + // // Parsing + // public static Real Parse(string s, IFormatProvider? provider) => T.Parse(s, provider); @@ -170,7 +184,9 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro return succeeded; } + // // Methods + // public static Real Conjugate(Real x) => x; @@ -183,7 +199,9 @@ public static Real Reciprocate(Real x) return T.One / x; } + // // Implicit operators + // public static implicit operator Real(T x) => new(x); } From e98cc2a35a016f2149388d35ddf4d664151b8805 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 16 Sep 2023 15:53:21 -0500 Subject: [PATCH 102/293] Add methods to check the properties of a value --- src/Mathematics.NET/Core/Complex.cs | 6 ++++++ src/Mathematics.NET/Core/IComplex.cs | 15 +++++++++++++++ src/Mathematics.NET/Core/Real.cs | 6 ++++++ 3 files changed, 27 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index f1f1bf73..c6db3aa9 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -311,6 +311,12 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); + public static bool IsFinite(Complex z) => Real.IsFinite(z._real) && Real.IsFinite(z._imaginary); + + public static bool IsInfinity(Complex z) => Real.IsInfinity(z._real) || Real.IsInfinity(z._imaginary); + + public static bool IsNaN(Complex z) => !IsInfinity(z) && !IsFinite(z); + public static Complex Reciprocate(Complex w) { if (w._real == T.Zero && w._imaginary == T.Zero) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 0450a3a4..0bf7cf0d 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -75,6 +75,21 @@ public interface IComplex /// The complex conjugate static abstract T Conjugate(T z); + /// Check if a value is finite + /// The value to check + /// true if the value is finite; otherwise, false + static abstract bool IsFinite(T z); + + /// Check if a value is infinity + /// The value to check + /// true if the value is infinity; otherwise, false + static abstract bool IsInfinity(T z); + + /// Checks if a value is not a number + /// The value to check + /// true if the value is not a number; otherwise, false + static abstract bool IsNaN(T z); + /// Parse a string into a value /// The string to parse /// The number style diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index ad77a408..a3d85f8c 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -190,6 +190,12 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static Real Conjugate(Real x) => x; + public static bool IsFinite(Real x) => T.IsFinite(x._value); + + public static bool IsInfinity(Real x) => T.IsInfinity(x._value); + + public static bool IsNaN(Real x) => T.IsNaN(x._value); + public static Real Reciprocate(Real x) { if (x._value == T.Zero) From 8d11e9235d9cada5b5f78d5714bfc374c76560e4 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 16 Sep 2023 15:57:53 -0500 Subject: [PATCH 103/293] Update Complex.cs - Change parameter name --- src/Mathematics.NET/Core/Complex.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index c6db3aa9..54d86662 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -317,15 +317,15 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static bool IsNaN(Complex z) => !IsInfinity(z) && !IsFinite(z); - public static Complex Reciprocate(Complex w) + public static Complex Reciprocate(Complex z) { - if (w._real == T.Zero && w._imaginary == T.Zero) + if (z._real == T.Zero && z._imaginary == T.Zero) { return Infinity; } - var re = w._real.Value; - var im = w._imaginary.Value; + var re = z._real.Value; + var im = z._imaginary.Value; T reResult; T imResult; From 1686f708c44bbd8034305d918addc9a42d7f7f8d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 16 Sep 2023 18:02:11 -0500 Subject: [PATCH 104/293] Update IReal.cs - Add new lines for clarity --- src/Mathematics.NET/Core/IReal.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 5b30f5c0..635266bb 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -43,8 +43,10 @@ public interface IReal { /// The backing value of the type U Value { get; } + /// Represents negative infinty for the type static abstract T NegativeInfinity { get; } + /// Represents positive infinity for the type static abstract T PositiveInfinity { get; } } From fb68f33f0f711d404cdcc7164b7955054dbad24d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 16 Sep 2023 18:07:54 -0500 Subject: [PATCH 105/293] Add methods to check the properties of a value --- src/Mathematics.NET/Core/IReal.cs | 10 ++++++++++ src/Mathematics.NET/Core/Real.cs | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 635266bb..019f58ce 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -49,4 +49,14 @@ public interface IReal /// Represents positive infinity for the type static abstract T PositiveInfinity { get; } + + /// Check if a value is negative infinity + /// The value to check + /// true if the value is negative infinity; otherwise, false + static abstract bool IsNegativeInfinity(T x); + + /// Check if a valule is positive infinity + /// The value to check + /// true if the value is positive infinity; otherwise, false + static abstract bool IsPositiveInfinity(T x); } diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index a3d85f8c..cde7a24f 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -196,6 +196,10 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static bool IsNaN(Real x) => T.IsNaN(x._value); + public static bool IsNegativeInfinity(Real x) => T.IsNegativeInfinity(x._value); + + public static bool IsPositiveInfinity(Real x) => T.IsPositiveInfinity(x._value); + public static Real Reciprocate(Real x) { if (x._value == T.Zero) From 7238d7b1419d6d8cf78e4e833a4f9c950cbdc799 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 16 Sep 2023 18:18:50 -0500 Subject: [PATCH 106/293] Add methods to check if a value is zero --- src/Mathematics.NET/Core/Complex.cs | 2 ++ src/Mathematics.NET/Core/IComplex.cs | 5 +++++ src/Mathematics.NET/Core/Real.cs | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 54d86662..1bc3a3ee 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -317,6 +317,8 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static bool IsNaN(Complex z) => !IsInfinity(z) && !IsFinite(z); + public static bool IsZero(Complex z) => Real.IsZero(z._real) && Real.IsZero(z._imaginary); + public static Complex Reciprocate(Complex z) { if (z._real == T.Zero && z._imaginary == T.Zero) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 0bf7cf0d..2a4f731e 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -90,6 +90,11 @@ public interface IComplex /// true if the value is not a number; otherwise, false static abstract bool IsNaN(T z); + /// Check if a value is zero + /// The value to check + /// true if the value is zero; otherwise, false + static abstract bool IsZero(T z); + /// Parse a string into a value /// The string to parse /// The number style diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index cde7a24f..f814eec6 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -196,6 +196,8 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static bool IsNaN(Real x) => T.IsNaN(x._value); + public static bool IsZero(Real x) => T.IsZero(x._value); + public static bool IsNegativeInfinity(Real x) => T.IsNegativeInfinity(x._value); public static bool IsPositiveInfinity(Real x) => T.IsPositiveInfinity(x._value); From ec02e8862318aaa7546bd2de7931028346a4120b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 16 Sep 2023 19:10:00 -0500 Subject: [PATCH 107/293] Update IComplex.cs - Rearrange interfaces --- src/Mathematics.NET/Core/IComplex.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 2a4f731e..48bfbd3e 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -37,10 +37,10 @@ namespace Mathematics.NET.Core; /// The type that implements the interface /// A type that implements public interface IComplex - : INegationOperation, - IAdditionOperation, + : IAdditionOperation, IDivisionOperation, IMultiplicationOperation, + INegationOperation, ISubtractionOperation, IEqualityRelation, IEquatable, From a6d0a292bdbf716d2420ff49b1ef873ddddb3126 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 16 Sep 2023 20:26:14 -0500 Subject: [PATCH 108/293] Update Complex.cs - Add method to convert a complex number from polar to cartesian form --- src/Mathematics.NET/Core/Complex.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 1bc3a3ee..0c835592 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -311,6 +311,9 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); + public static Complex FromPolarForm(Real magnitude, Real phase) + => new(magnitude * T.Cos(phase.Value), magnitude * T.Sin(phase.Value)); + public static bool IsFinite(Complex z) => Real.IsFinite(z._real) && Real.IsFinite(z._imaginary); public static bool IsInfinity(Complex z) => Real.IsInfinity(z._real) || Real.IsInfinity(z._imaginary); From 7ca7700b0f82d394b64eb874fb939bd9b9ae2ee2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 17 Sep 2023 01:49:32 -0500 Subject: [PATCH 109/293] Implement common functions - Create IDifferentiableFunctions interface --- src/Mathematics.NET/Core/Complex.cs | 70 ++++++++++- .../Core/IDifferentiableFunctions.cs | 113 ++++++++++++++++++ src/Mathematics.NET/Core/Real.cs | 72 ++++++++++- 3 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 src/Mathematics.NET/Core/IDifferentiableFunctions.cs diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 0c835592..17ee9bb2 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -37,7 +37,9 @@ namespace Mathematics.NET.Core; /// A type that implements [Serializable] [StructLayout(LayoutKind.Sequential)] -public readonly struct Complex : IComplex, T> +public readonly struct Complex + : IComplex, T>, + IDifferentiableFunctions, T> where T : IFloatingPointIeee754 { public static readonly Complex Zero = new(Real.Zero, Real.Zero); @@ -347,6 +349,72 @@ public static Complex Reciprocate(Complex z) return new(reResult, imResult); } + // + // IDifferentiableFunctions interface + // + + // Exponential functions + + public static Complex Exp(Complex z) => throw new NotImplementedException(); + + public static Complex Exp2(Complex z) => throw new NotImplementedException(); + + public static Complex Exp10(Complex z) => throw new NotImplementedException(); + + // Hyperbolic functions + + public static Complex Acosh(Complex z) => throw new NotImplementedException(); + + public static Complex Asinh(Complex z) => throw new NotImplementedException(); + + public static Complex Atanh(Complex z) => throw new NotImplementedException(); + + public static Complex Cosh(Complex z) => throw new NotImplementedException(); + + public static Complex Sinh(Complex z) => throw new NotImplementedException(); + + public static Complex Tanh(Complex z) => throw new NotImplementedException(); + + // Logarithmic functions + + public static Complex Ln(Complex z) => throw new NotImplementedException(); + + public static Complex Log(Complex z, Complex b) => throw new NotImplementedException(); + + public static Complex Log2(Complex z) => throw new NotImplementedException(); + + public static Complex Log10(Complex z) => throw new NotImplementedException(); + + // Power functions + + public static Complex Pow(Complex z, Complex w) => throw new NotImplementedException(); + + // Root functions + + public static Complex Cbrt(Complex z) => throw new NotImplementedException(); + + public static Complex Hypot(Complex z, Complex w) => throw new NotImplementedException(); + + public static Complex NthRoot(Complex z, int n) => throw new NotImplementedException(); + + public static Complex Root(Complex z, Complex w) => throw new NotImplementedException(); + + public static Complex Sqrt(Complex z) => throw new NotImplementedException(); + + // Trigonometric functions + + public static Complex Acos(Complex z) => throw new NotImplementedException(); + + public static Complex Asin(Complex z) => throw new NotImplementedException(); + + public static Complex Atan(Complex z) => throw new NotImplementedException(); + + public static Complex Cos(Complex z) => throw new NotImplementedException(); + + public static Complex Sin(Complex z) => throw new NotImplementedException(); + + public static Complex Tan(Complex z) => throw new NotImplementedException(); + // // Implicit Operators // diff --git a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs new file mode 100644 index 00000000..ea0425fb --- /dev/null +++ b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs @@ -0,0 +1,113 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Numerics; + +namespace Mathematics.NET.Core; + +/// Defines support for common differentiable functions +/// The type that implements the interface +/// A type that implements +public interface IDifferentiableFunctions + : IComplex + where T : IDifferentiableFunctions + where U : IFloatingPointIeee754 +{ + // + // Exponential functions + // + + static abstract T Exp(T x); + + static abstract T Exp2(T x); + + static abstract T Exp10(T x); + + // + // Hyperbolic functions + // + + static abstract T Acosh(T x); + + static abstract T Asinh(T x); + + static abstract T Atanh(T x); + + static abstract T Cosh(T x); + + static abstract T Sinh(T x); + + static abstract T Tanh(T x); + + // + // Logarithmic functions + // + + static abstract T Ln(T x); + + static abstract T Log(T x, T b); + + static abstract T Log2(T x); + + static abstract T Log10(T x); + + // + // Power functions + // + + static abstract T Pow(T x, T y); + + // + // Root functions + // + + static abstract T Cbrt(T x); + + static abstract T Hypot(T x, T y); + + static abstract T NthRoot(T x, int n); + + static abstract T Root(T x, T r); + + static abstract T Sqrt(T x); + + // + // Trigonometric functions + // + + static abstract T Acos(T x); + + static abstract T Asin(T x); + + static abstract T Atan(T x); + + static abstract T Cos(T x); + + static abstract T Sin(T x); + + static abstract T Tan(T x); +} diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index f814eec6..cdface08 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -36,7 +36,9 @@ namespace Mathematics.NET.Core; /// A type that implements [Serializable] [StructLayout(LayoutKind.Sequential)] -public readonly struct Real : IReal, T> +public readonly struct Real + : IReal, T>, + IDifferentiableFunctions, T> where T : IFloatingPointIeee754 { public static readonly Real Zero = T.Zero; @@ -211,6 +213,74 @@ public static Real Reciprocate(Real x) return T.One / x; } + // + // IDifferentiableFunctions interface + // + + // Exponential functions + + public static Real Exp(Real x) => T.Exp(x._value); + + public static Real Exp2(Real x) => T.Exp2(x._value); + + public static Real Exp10(Real x) => T.Exp10(x._value); + + // Hyperbolic functions + + public static Real Acosh(Real x) => T.Acosh(x._value); + + public static Real Asinh(Real x) => T.Asinh(x._value); + + public static Real Atanh(Real x) => T.Atanh(x._value); + + public static Real Cosh(Real x) => T.Cosh(x._value); + + public static Real Sinh(Real x) => T.Sinh(x._value); + + public static Real Tanh(Real x) => T.Tanh(x._value); + + // Logarithmic functions + + public static Real Ln(Real x) => T.Log(x._value); + + public static Real Log(Real x, Real b) => T.Log(x._value, b._value); + + public static Real Log2(Real x) => T.Log2(x._value); + + public static Real Log10(Real x) => T.Log10(x._value); + + // Power functions + + public static Real Pow(Real x, Real y) => T.Pow(x._value, y._value); + + // Root functions + + public static Real Cbrt(Real x) => T.Cbrt(x._value); + + public static Real Hypot(Real x, Real y) => T.Hypot(x._value, y._value); + + public static Real NthRoot(Real x, int n) => T.RootN(x._value, n); + + public static Real Root(Real x, Real y) => T.Exp(y._value * T.Log(x._value)); + + public static Real Sqrt(Real x) => T.Sqrt(x._value); + + // Trigonometric functions + + public static Real Acos(Real x) => T.Acos(x._value); + + public static Real Asin(Real x) => T.Asin(x._value); + + public static Real Atan(Real x) => T.Atan(x._value); + + public static Real Atan2(Real y, Real x) => T.Atan2(y._value, x._value); + + public static Real Cos(Real x) => T.Cos(x._value); + + public static Real Sin(Real x) => T.Sin(x._value); + + public static Real Tan(Real x) => T.Tan(x._value); + // // Implicit operators // From 0ae741a6bfdb87d8c5689efeff06e4e7d57710dd Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 17 Sep 2023 01:55:38 -0500 Subject: [PATCH 110/293] Create EquationAttribute.cs --- .../Core/Attributes/EquationAttribute.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/Mathematics.NET/Core/Attributes/EquationAttribute.cs diff --git a/src/Mathematics.NET/Core/Attributes/EquationAttribute.cs b/src/Mathematics.NET/Core/Attributes/EquationAttribute.cs new file mode 100644 index 00000000..4d3f558c --- /dev/null +++ b/src/Mathematics.NET/Core/Attributes/EquationAttribute.cs @@ -0,0 +1,34 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Attributes; + +/// Indicates that a method represents an equation +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public sealed class EquationAttribute : Attribute +{ +} From b62878f97247d5f36cd9cb3d00b08458b61d1da2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 17 Sep 2023 13:29:34 -0500 Subject: [PATCH 111/293] Update ComplexTests.cs - Remove empty line --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 59caabfc..5735ab26 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -146,7 +146,6 @@ public void TryFormat_ComplexOfDoubleWithInadequateDestinationLength_ReturnsFals [DataRow("( 1.23 , 3.45 )", 1.23, 3.45)] public void TryParse_SpanOfChar_ReturnsComplexOfDouble(string s, double expectedRe, double expectedIm) { - Complex expected = new(expectedRe, expectedIm); _ = Complex.TryParse(s.AsSpan(), null, out Complex actual); From 31f109815450ce842d4ddf05ee8969e7d0ad0b6d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 17 Sep 2023 18:12:21 -0500 Subject: [PATCH 112/293] Add documentation - Use DocFX - Add basic pages --- docs/.gitignore | 9 ++++ docs/api/.gitignore | 5 ++ docs/api/index.md | 3 ++ docs/articles/getstarted/installation.md | 14 ++++++ docs/articles/intro.md | 3 ++ docs/articles/toc.yml | 6 +++ docs/docfx.json | 64 ++++++++++++++++++++++++ docs/index.md | 6 +++ docs/toc.yml | 5 ++ 9 files changed, 115 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/api/.gitignore create mode 100644 docs/api/index.md create mode 100644 docs/articles/getstarted/installation.md create mode 100644 docs/articles/intro.md create mode 100644 docs/articles/toc.yml create mode 100644 docs/docfx.json create mode 100644 docs/index.md create mode 100644 docs/toc.yml diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..4378419e --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,9 @@ +############### +# folder # +############### +/**/DROP/ +/**/TEMP/ +/**/packages/ +/**/bin/ +/**/obj/ +_site diff --git a/docs/api/.gitignore b/docs/api/.gitignore new file mode 100644 index 00000000..e8079a3b --- /dev/null +++ b/docs/api/.gitignore @@ -0,0 +1,5 @@ +############### +# temp file # +############### +*.yml +.manifest diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 00000000..a195bc2b --- /dev/null +++ b/docs/api/index.md @@ -0,0 +1,3 @@ +# Mathematics.NET API Documentation + +API documentation for Mathematics.NET diff --git a/docs/articles/getstarted/installation.md b/docs/articles/getstarted/installation.md new file mode 100644 index 00000000..9b59d610 --- /dev/null +++ b/docs/articles/getstarted/installation.md @@ -0,0 +1,14 @@ +# Installation + +Mathematics.NET is available to download from [nuget](https://www.nuget.org). + +## Polyglot Notebooks + +Please have [Visual Studio Code](https://code.visualstudio.com/) installed as well as the [Polyglot Notebooks](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.dotnet-interactive-vscode) extension installed to begin using Mathematics.NET. When that is complete, create a new .ipynb file and add the following line to import the package: +```csharp +#r "nuget: Mathematics.NET" +``` +To get a specific version of Mathematics.NET, use, for example, +```csharp +#r "nuget: Mathematics.NET, 1.0.0" +``` diff --git a/docs/articles/intro.md b/docs/articles/intro.md new file mode 100644 index 00000000..1250a50b --- /dev/null +++ b/docs/articles/intro.md @@ -0,0 +1,3 @@ +# Mathematics.NET Articles + +Welcome to Mathematics.NET. diff --git a/docs/articles/toc.yml b/docs/articles/toc.yml new file mode 100644 index 00000000..f186e953 --- /dev/null +++ b/docs/articles/toc.yml @@ -0,0 +1,6 @@ +- name: Introduction + href: intro.md +- name: Get Started + items: + - name: Installation + href: getstarted/installation.md diff --git a/docs/docfx.json b/docs/docfx.json new file mode 100644 index 00000000..66202be3 --- /dev/null +++ b/docs/docfx.json @@ -0,0 +1,64 @@ +{ + "metadata": [ + { + "src": [ + { + "files": [ + "Mathematics.NET/Mathematics.NET.csproj" + ], + "src": "../src" + } + ], + "dest": "api", + "includePrivateMembers": false, + "disableGitFeatures": false, + "disableDefaultFilter": false, + "noRestore": false, + "namespaceLayout": "flattened", + "memberLayout": "samePage", + "EnumSortOrder": "alphabetic", + "allowCompilationErrors": false + } + ], + "build": { + "content": [ + { + "files": [ + "api/**.yml", + "api/index.md" + ] + }, + { + "files": [ + "articles/**.md", + "articles/**/toc.yml", + "toc.yml", + "*.md" + ] + } + ], + "resource": [ + { + "files": [ + "images/**" + ] + } + ], + "output": "_site", + "globalMetadataFiles": [], + "fileMetadataFiles": [], + "template": [ + "default", + "modern" + ], + "postProcessors": [ "ExtractSearchIndex" ], + "keepFileLink": false, + "disableGitFeatures": false, + "globalMetadata" :{ + "_appTitle": "Mathematics.NET", + "_appFooter": "Copyright © 2023 Hamlet Tanyavong", + "_disableContribution": true, + "_enableSearch": true + } + } +} diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..3ef62c24 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,6 @@ +# Mathematics.NET + +Mathematics.NET is a C# class library that provides tools for solving mathematical problems. + +[![GitHub](https://img.shields.io/github/license/HamletTanyavong/Mathematics.NET?style=flat-square&logo=github&labelColor=87cefa&color=ffd700)](https://github.com/HamletTanyavong/Mathematics.NET) +[![GitHub Repo Stars](https://img.shields.io/github/stars/HamletTanyavong/Mathematics.NET?color=87cefa&style=flat-square&logo=github)](https://github.com/HamletTanyavong/Mathematics.NET/stargazers) diff --git a/docs/toc.yml b/docs/toc.yml new file mode 100644 index 00000000..59f80104 --- /dev/null +++ b/docs/toc.yml @@ -0,0 +1,5 @@ +- name: Articles + href: articles/ +- name: Api Documentation + href: api/ + homepage: api/index.md From 580f94c4b641e2a0443b7de5006e5d9ad3f20eda Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:48:56 -0500 Subject: [PATCH 113/293] Update Mathematics.NET.SourceGenerators.csproj - Add global usings --- .../Mathematics.NET.SourceGenerators.csproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj b/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj index 6a6637e7..04fc35d2 100644 --- a/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj +++ b/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj @@ -6,6 +6,7 @@ latest netstandard2.0 x64 + enable @@ -16,4 +17,9 @@ + + + + + From 24d637c571eeee73234a532064d782009a5bfcae Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:50:10 -0500 Subject: [PATCH 114/293] Update .gitignore - Temporarily add source generators project to git ignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 7fed5599..14b596a1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ /src/Application/ *.runsettings + # Temporary +/src/Mathematics.NET.SourceGenerators/ + # User-specific files *.rsuser *.suo From 404cd51db8b4006920d49e424627eece5d2513c1 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:48:40 -0500 Subject: [PATCH 115/293] Add benchmark for complex abs value calculation --- .../Complex/SystemComplexAbsVsComplexAbs.cs | 56 +++++++++++++++++++ tests/Mathematics.NET.Benchmarks/Program.cs | 3 +- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbs.cs diff --git a/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbs.cs b/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbs.cs new file mode 100644 index 00000000..8a597fba --- /dev/null +++ b/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbs.cs @@ -0,0 +1,56 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Benchmarks.Core.Complex; + +[MemoryDiagnoser] +[RankColumn] +[Orderer(SummaryOrderPolicy.FastestToSlowest)] +public class SystemComplexAbsVsComplexAbs +{ + public System.Numerics.Complex Z { get; set; } + public Complex W { get; set; } + + [GlobalSetup] + public void GlobalSetup() + { + Z = new(4, 5); + W = new(4, 5); + } + + [Benchmark(Baseline = true)] + public Real SystemComplexAbs() + { + return System.Numerics.Complex.Abs(Z); + } + + [Benchmark] + public Real ComplexAbs() + { + return Complex.Abs(W); + } +} diff --git a/tests/Mathematics.NET.Benchmarks/Program.cs b/tests/Mathematics.NET.Benchmarks/Program.cs index db565a04..dee60192 100644 --- a/tests/Mathematics.NET.Benchmarks/Program.cs +++ b/tests/Mathematics.NET.Benchmarks/Program.cs @@ -32,7 +32,8 @@ var benchmarkSwitcher = new BenchmarkSwitcher(new[] { - typeof(ComplexDivisionBenchmarks) + typeof(ComplexDivisionBenchmarks), + typeof(SystemComplexAbsVsComplexAbs) }); benchmarkSwitcher.Run(args, new DebugInProcessConfig()); From fbbde58bb9d1bce091912bb3af105c00f5e618c8 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 18 Sep 2023 17:42:02 -0500 Subject: [PATCH 116/293] Add LaTeX to documentation comments --- src/Mathematics.NET/Core/Constants.cs | 30 +++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Mathematics.NET/Core/Constants.cs b/src/Mathematics.NET/Core/Constants.cs index a650eda8..df652285 100644 --- a/src/Mathematics.NET/Core/Constants.cs +++ b/src/Mathematics.NET/Core/Constants.cs @@ -30,34 +30,34 @@ namespace Mathematics.NET.Core; /// Common mathematical constants public static class Constants { - /// Represents the natural logarithmic base, e + /// Represents the natural logarithmic base, $ e $ public const double E = 2.71828182845904523; - /// Represents the ratio of the circumference of a circle to its diameter, π + /// Represents the ratio of the circumference of a circle to its diameter, $ π $ public const double Pi = 3.14159265358979323; - /// Represents π/2 + /// Represents $ π/2 $ public const double PiHalf = 1.57079632679489661; - /// Represents π squared + /// Represents $ π^2 $ public const double PiSquared = 9.86960440108935861; - /// Represents 2π + /// Represents $ 2π $ public const double Tau = 6.28318530717958647; - /// Represents the Euler-Mascheroni constant, γ + /// Represents the Euler-Mascheroni constant, $ \gamma $ public const double EulerMascheroni = 5.77215664901532860e-1; - /// Represents the golden ratio, φ + /// Represents the golden ratio, $ \phi $ public const double GoldenRatio = 1.61803398874989484; - /// Represents the natural logarithm of 2 + /// Represents the natural logarithm of 2, $ \ln(2) $ public const double Ln2 = 6.93147180559945309e-1; - /// Represents the natural logarithm of 3 + /// Represents the natural logarithm of 3, $ \ln(3) $ public const double Ln3 = 1.09861228866810969; - /// Represents the natural logarithm of 4 + /// Represents the natural logarithm of 4, $ \ln(4) $ public const double Ln4 = 1.38629436111989061; - /// Represents the natural logarithm of 5 + /// Represents the natural logarithm of 5, $ \ln(5) $ public const double Ln5 = 1.60943791243410037; - /// Represents the natural logarithm of 10 + /// Represents the natural logarithm of 10, $ \ln(10) $ public const double Ln10 = 2.30258509299404568; - /// Represents the square root of 2 + /// Represents the square root of 2, $ \sqrt{2} $ public const double Sqrt2 = 1.41421356237309504; - /// Represents the square root of 3 + /// Represents the square root of 3, $ \sqrt{3} $ public const double Sqrt3 = 1.73205080756887729; - /// Represents the square root of 5 + /// Represents the square root of 5, $ \sqrt{5} $ public const double Sqrt5 = 2.23606797749978969; } From bdbd143916c7fec6dff9f0e78c700ebcba076c47 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 18 Sep 2023 23:58:32 -0500 Subject: [PATCH 117/293] Create attributes --- .../Core/Attributes/FunctionAttribute.cs | 38 ++++++++++++++++ .../Core/Attributes/OperationAttribute.cs | 38 ++++++++++++++++ .../Core/Attributes/RelationAttribute.cs | 43 +++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 src/Mathematics.NET/Core/Attributes/FunctionAttribute.cs create mode 100644 src/Mathematics.NET/Core/Attributes/OperationAttribute.cs create mode 100644 src/Mathematics.NET/Core/Attributes/RelationAttribute.cs diff --git a/src/Mathematics.NET/Core/Attributes/FunctionAttribute.cs b/src/Mathematics.NET/Core/Attributes/FunctionAttribute.cs new file mode 100644 index 00000000..3be11425 --- /dev/null +++ b/src/Mathematics.NET/Core/Attributes/FunctionAttribute.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Attributes; + +/// Indicates that a method represents a mathematical function +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public class FunctionAttribute : RelationAttribute +{ + public FunctionAttribute(uint arity, string name) + : base(arity, name) + { + } +} diff --git a/src/Mathematics.NET/Core/Attributes/OperationAttribute.cs b/src/Mathematics.NET/Core/Attributes/OperationAttribute.cs new file mode 100644 index 00000000..4e95295d --- /dev/null +++ b/src/Mathematics.NET/Core/Attributes/OperationAttribute.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Attributes; + +/// Indicates that a method represents a mathematical operation +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public class OperationAttribute : FunctionAttribute +{ + public OperationAttribute(uint arity, string name) + : base(arity, name) + { + } +} diff --git a/src/Mathematics.NET/Core/Attributes/RelationAttribute.cs b/src/Mathematics.NET/Core/Attributes/RelationAttribute.cs new file mode 100644 index 00000000..1ef2088e --- /dev/null +++ b/src/Mathematics.NET/Core/Attributes/RelationAttribute.cs @@ -0,0 +1,43 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Attributes; + +/// Indicates that a method represents a mathematical relation +[AttributeUsage(AttributeTargets.Method)] +public class RelationAttribute : Attribute +{ + public RelationAttribute(uint arity, string name) + { + Arity = arity; + Name = name; + } + + public uint Arity { get; } + + public string Name { get; } +} From 5fd2f0cf50df1749612ac3f7946ff31beac42583 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 19 Sep 2023 00:01:09 -0500 Subject: [PATCH 118/293] Add Abs method --- src/Mathematics.NET/Core/Complex.cs | 35 ++++++++++++++++++++++++++++ src/Mathematics.NET/Core/IComplex.cs | 5 ++++ src/Mathematics.NET/Core/Real.cs | 2 ++ 3 files changed, 42 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 17ee9bb2..6da48b23 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -311,6 +311,41 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // Methods // + public static Real Abs(Complex z) => Hypot(z._real.Value, z._imaginary.Value); + + private static T Hypot(T x, T y) + { + // Factor out the larger value to avoid possible overflow + x = T.Abs(x); + y = T.Abs(y); + + T small, large; + if (x < y) + { + small = x; + large = y; + } + else + { + small = y; + large = x; + } + + if (small == T.Zero) + { + return large; + } + else if (T.IsPositiveInfinity(large) && !T.IsNaN(small)) + { + return T.PositiveInfinity; + } + else + { + T ratio = small / large; + return large * T.Sqrt(T.One + ratio * ratio); + } + } + public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); public static Complex FromPolarForm(Real magnitude, Real phase) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 48bfbd3e..5043aa3d 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -70,6 +70,11 @@ public interface IComplex /// Represents NaN for the type static abstract T NaN { get; } + /// Compute the absolute value of a number + /// A complex number + /// The absolute value + static abstract Real Abs(T z); + /// Compute the complex conjugate of a number /// A complex number /// The complex conjugate diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index cdface08..eeb7de04 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -190,6 +190,8 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // Methods // + public static Real Abs(Real x) => T.Abs(x._value); + public static Real Conjugate(Real x) => x; public static bool IsFinite(Real x) => T.IsFinite(x._value); From a0d21a67af3297116556cfaaa15bea965e25f786 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 19 Sep 2023 00:03:39 -0500 Subject: [PATCH 119/293] Remove Hypot --- src/Mathematics.NET/Core/IDifferentiableFunctions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs index ea0425fb..cb02bc7a 100644 --- a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs +++ b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs @@ -87,8 +87,6 @@ public interface IDifferentiableFunctions static abstract T Cbrt(T x); - static abstract T Hypot(T x, T y); - static abstract T NthRoot(T x, int n); static abstract T Root(T x, T r); From f8899e37d9a3d786d35745a9a3b42e20be880e2b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 19 Sep 2023 00:03:48 -0500 Subject: [PATCH 120/293] Move method --- src/Mathematics.NET/Core/Real.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index eeb7de04..ba1cce7d 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -194,6 +194,8 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static Real Conjugate(Real x) => x; + public static Real Hypot(Real x, Real y) => T.Hypot(x._value, y._value); + public static bool IsFinite(Real x) => T.IsFinite(x._value); public static bool IsInfinity(Real x) => T.IsInfinity(x._value); @@ -259,8 +261,6 @@ public static Real Reciprocate(Real x) public static Real Cbrt(Real x) => T.Cbrt(x._value); - public static Real Hypot(Real x, Real y) => T.Hypot(x._value, y._value); - public static Real NthRoot(Real x, int n) => T.RootN(x._value, n); public static Real Root(Real x, Real y) => T.Exp(y._value * T.Log(x._value)); From 1101a794c65f5600ccab5fbc4540d2f3bba54d7d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 19 Sep 2023 00:07:08 -0500 Subject: [PATCH 121/293] Implement methods --- src/Mathematics.NET/Core/Complex.cs | 24 +++++++++++++++++++++--- src/Mathematics.NET/Core/Real.cs | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 6da48b23..b1f4fc3f 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -390,7 +390,11 @@ public static Complex Reciprocate(Complex z) // Exponential functions - public static Complex Exp(Complex z) => throw new NotImplementedException(); + public static Complex Exp(Complex z) + { + Real expReal = Real.Exp(z._real); + return new(expReal * Real.Cos(z._imaginary), expReal * Real.Sin(z._imaginary)); + } public static Complex Exp2(Complex z) => throw new NotImplementedException(); @@ -444,9 +448,23 @@ public static Complex Reciprocate(Complex z) public static Complex Atan(Complex z) => throw new NotImplementedException(); - public static Complex Cos(Complex z) => throw new NotImplementedException(); + public static Complex Cos(Complex z) + { + Real p = Real.Exp(z._imaginary); + Real q = Real.One / p; + Real sinh = (p - q) * Real.OneHalf; + Real cosh = (p + q) * Real.OneHalf; + return new(Real.Cos(z._real) * cosh, -Real.Sin(z._real) * sinh); + } - public static Complex Sin(Complex z) => throw new NotImplementedException(); + public static Complex Sin(Complex z) + { + Real p = Real.Exp(z._imaginary); + Real q = Real.One / p; + Real sinh = (p - q) * Real.OneHalf; + Real cosh = (p + q) * Real.OneHalf; + return new(Real.Sin(z._real) * cosh, Real.Cos(z._real) * sinh); + } public static Complex Tan(Complex z) => throw new NotImplementedException(); diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index ba1cce7d..bdca9579 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -43,6 +43,8 @@ public readonly struct Real { public static readonly Real Zero = T.Zero; public static readonly Real One = T.One; + public static readonly Real OneHalf = T.Parse("0.5", null); + public static readonly Real NaN = T.NaN; public static readonly Real NegativeInfinity = T.NegativeInfinity; public static readonly Real PositiveInfinity = T.PositiveInfinity; From 360a01a4c1d57506befc6239199019789536b4dd Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 19 Sep 2023 21:22:08 -0500 Subject: [PATCH 122/293] Add IMinMaxValue to generic constraint --- src/Mathematics.NET/Core/Complex.cs | 2 +- src/Mathematics.NET/Core/IComplex.cs | 2 +- src/Mathematics.NET/Core/IDifferentiableFunctions.cs | 2 +- src/Mathematics.NET/Core/IReal.cs | 2 +- src/Mathematics.NET/Core/Real.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index b1f4fc3f..7d9a263e 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -40,7 +40,7 @@ namespace Mathematics.NET.Core; public readonly struct Complex : IComplex, T>, IDifferentiableFunctions, T> - where T : IFloatingPointIeee754 + where T : IFloatingPointIeee754, IMinMaxValue { public static readonly Complex Zero = new(Real.Zero, Real.Zero); public static readonly Complex One = new(Real.One, Real.Zero); diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 5043aa3d..e956636f 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -47,7 +47,7 @@ public interface IComplex ISpanFormattable, ISpanParsable where T : IComplex - where U : IFloatingPointIeee754 + where U : IFloatingPointIeee754, IMinMaxValue { /// The real part of the complex number public Real Re { get; } diff --git a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs index cb02bc7a..212c1d1b 100644 --- a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs +++ b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs @@ -35,7 +35,7 @@ namespace Mathematics.NET.Core; public interface IDifferentiableFunctions : IComplex where T : IDifferentiableFunctions - where U : IFloatingPointIeee754 + where U : IFloatingPointIeee754, IMinMaxValue { // // Exponential functions diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 019f58ce..05b962b8 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -39,7 +39,7 @@ public interface IReal IComparable, IComparable where T : IReal - where U : IFloatingPointIeee754 + where U : IFloatingPointIeee754, IMinMaxValue { /// The backing value of the type U Value { get; } diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index bdca9579..ca6c4065 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -39,7 +39,7 @@ namespace Mathematics.NET.Core; public readonly struct Real : IReal, T>, IDifferentiableFunctions, T> - where T : IFloatingPointIeee754 + where T : IFloatingPointIeee754, IMinMaxValue { public static readonly Real Zero = T.Zero; public static readonly Real One = T.One; From b039b0abdf1632f114a15a4ece695d1c49a026ef Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 19 Sep 2023 21:23:12 -0500 Subject: [PATCH 123/293] Implement IMinMaxValue for real numbers --- src/Mathematics.NET/Core/IReal.cs | 3 ++- src/Mathematics.NET/Core/Real.cs | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 05b962b8..baf69a4e 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -37,7 +37,8 @@ public interface IReal : IComplex, IInequalityRelations, IComparable, - IComparable + IComparable, + IMinMaxValue where T : IReal where U : IFloatingPointIeee754, IMinMaxValue { diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index ca6c4065..13a5a7f4 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -45,6 +45,9 @@ public readonly struct Real public static readonly Real One = T.One; public static readonly Real OneHalf = T.Parse("0.5", null); + public static readonly Real MaxValue = T.MaxValue; + public static readonly Real MinValue = T.MinValue; + public static readonly Real NaN = T.NaN; public static readonly Real NegativeInfinity = T.NegativeInfinity; public static readonly Real PositiveInfinity = T.PositiveInfinity; @@ -70,6 +73,8 @@ public Real(T real) static Real IComplex, T>.Zero => Zero; static Real IComplex, T>.One => One; static Real IComplex, T>.NaN => NaN; + static Real IMinMaxValue>.MaxValue => MaxValue; + static Real IMinMaxValue>.MinValue => MinValue; static Real IReal, T>.NegativeInfinity => NegativeInfinity; static Real IReal, T>.PositiveInfinity => PositiveInfinity; From 9d5e27ac7a694b30d94410346584be4590e051a8 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 19 Sep 2023 22:30:16 -0500 Subject: [PATCH 124/293] Update Complex.cs - Remove unnecessary method --- src/Mathematics.NET/Core/Complex.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 7d9a263e..23acafc7 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -432,8 +432,6 @@ public static Complex Exp(Complex z) public static Complex Cbrt(Complex z) => throw new NotImplementedException(); - public static Complex Hypot(Complex z, Complex w) => throw new NotImplementedException(); - public static Complex NthRoot(Complex z, int n) => throw new NotImplementedException(); public static Complex Root(Complex z, Complex w) => throw new NotImplementedException(); From e9b4f84b908d1a647273ba5e1fb197bf561e7c0b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 00:04:59 -0500 Subject: [PATCH 125/293] Update documentation comments --- src/Mathematics.NET/Core/Complex.cs | 2 +- src/Mathematics.NET/Core/IComplex.cs | 2 +- src/Mathematics.NET/Core/IDifferentiableFunctions.cs | 2 +- src/Mathematics.NET/Core/IReal.cs | 2 +- src/Mathematics.NET/Core/Real.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 23acafc7..26fa266c 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -34,7 +34,7 @@ namespace Mathematics.NET.Core; /// Represents a complex number -/// A type that implements +/// A type that implements and [Serializable] [StructLayout(LayoutKind.Sequential)] public readonly struct Complex diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index e956636f..1db2cde8 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -35,7 +35,7 @@ namespace Mathematics.NET.Core; /// Defines support for complex numbers /// The type that implements the interface -/// A type that implements +/// A type that implements and public interface IComplex : IAdditionOperation, IDivisionOperation, diff --git a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs index 212c1d1b..0ff01a6e 100644 --- a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs +++ b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs @@ -31,7 +31,7 @@ namespace Mathematics.NET.Core; /// Defines support for common differentiable functions /// The type that implements the interface -/// A type that implements +/// A type that implements and public interface IDifferentiableFunctions : IComplex where T : IDifferentiableFunctions diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index baf69a4e..d406c386 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -32,7 +32,7 @@ namespace Mathematics.NET.Core; /// Defines support for real numbers /// A type that implements the interface -/// A type that implements +/// A type that implements and public interface IReal : IComplex, IInequalityRelations, diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 13a5a7f4..c7727946 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -33,7 +33,7 @@ namespace Mathematics.NET.Core; /// Represents a real number -/// A type that implements +/// A type that implements and [Serializable] [StructLayout(LayoutKind.Sequential)] public readonly struct Real From e995dd82100427c440ba0c4ea10d3215bdd4b66c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 00:14:27 -0500 Subject: [PATCH 126/293] Add benchmark --- .../Core/Real/RealvsDouble.cs | 66 +++++++++++++++++++ tests/Mathematics.NET.Benchmarks/Program.cs | 2 + 2 files changed, 68 insertions(+) create mode 100644 tests/Mathematics.NET.Benchmarks/Core/Real/RealvsDouble.cs diff --git a/tests/Mathematics.NET.Benchmarks/Core/Real/RealvsDouble.cs b/tests/Mathematics.NET.Benchmarks/Core/Real/RealvsDouble.cs new file mode 100644 index 00000000..4dacfc77 --- /dev/null +++ b/tests/Mathematics.NET.Benchmarks/Core/Real/RealvsDouble.cs @@ -0,0 +1,66 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Benchmarks.Core.Real; + +[MemoryDiagnoser] +[RankColumn] +[Orderer(SummaryOrderPolicy.FastestToSlowest)] +public class RealvsDouble +{ + public Real XReal { get; set; } + public double XDouble { get; set; } + + [GlobalSetup] + public void GlobalSetup() + { + XReal = Math.PI; + XDouble = Math.PI; + } + + [Benchmark(Baseline = true)] + public double AdditionsWithDouble() + { + double result = 0; + for (int i = 0; i < 100_000; i++) + { + result += XDouble; + } + return result; + } + + [Benchmark] + public Real AdditionsWithReal() + { + Real result = 0.0; + for (int i = 0; i < 100_000; i++) + { + result += XReal; + } + return result; + } +} diff --git a/tests/Mathematics.NET.Benchmarks/Program.cs b/tests/Mathematics.NET.Benchmarks/Program.cs index dee60192..ec5ace5f 100644 --- a/tests/Mathematics.NET.Benchmarks/Program.cs +++ b/tests/Mathematics.NET.Benchmarks/Program.cs @@ -29,10 +29,12 @@ using BenchmarkDotNet.Configs; using BenchmarkDotNet.Running; using Mathematics.NET.Benchmarks.Core.Complex; +using Mathematics.NET.Benchmarks.Core.Real; var benchmarkSwitcher = new BenchmarkSwitcher(new[] { typeof(ComplexDivisionBenchmarks), + typeof(RealvsDouble), typeof(SystemComplexAbsVsComplexAbs) }); From 6e437cd776e73cc8a9fa7c361881cff3a25f8171 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 00:28:32 -0500 Subject: [PATCH 127/293] Use Two field instead of OneHalf --- src/Mathematics.NET/Core/Complex.cs | 8 ++++---- src/Mathematics.NET/Core/Real.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 26fa266c..342bacbc 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -450,8 +450,8 @@ public static Complex Cos(Complex z) { Real p = Real.Exp(z._imaginary); Real q = Real.One / p; - Real sinh = (p - q) * Real.OneHalf; - Real cosh = (p + q) * Real.OneHalf; + Real sinh = (p - q) / Real.Two; + Real cosh = (p + q) / Real.Two; return new(Real.Cos(z._real) * cosh, -Real.Sin(z._real) * sinh); } @@ -459,8 +459,8 @@ public static Complex Sin(Complex z) { Real p = Real.Exp(z._imaginary); Real q = Real.One / p; - Real sinh = (p - q) * Real.OneHalf; - Real cosh = (p + q) * Real.OneHalf; + Real sinh = (p - q) / Real.Two; + Real cosh = (p + q) / Real.Two; return new(Real.Sin(z._real) * cosh, Real.Cos(z._real) * sinh); } diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index c7727946..a9123069 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -43,7 +43,7 @@ public readonly struct Real { public static readonly Real Zero = T.Zero; public static readonly Real One = T.One; - public static readonly Real OneHalf = T.Parse("0.5", null); + public static readonly Real Two = T.One + T.One; public static readonly Real MaxValue = T.MaxValue; public static readonly Real MinValue = T.MinValue; From 1c00cdd77ff4eb408edc44e1584bb3a0e34fe8aa Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 00:55:38 -0500 Subject: [PATCH 128/293] Implement increment and decrement operations --- src/Mathematics.NET/Core/IReal.cs | 3 +++ src/Mathematics.NET/Core/Real.cs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index d406c386..0a786586 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -26,6 +26,7 @@ // using System.Numerics; +using Mathematics.NET.Core.Operations; using Mathematics.NET.Core.Relations; namespace Mathematics.NET.Core; @@ -36,6 +37,8 @@ namespace Mathematics.NET.Core; public interface IReal : IComplex, IInequalityRelations, + IDecrementOperation, + IIncrementOperation, IComparable, IComparable, IMinMaxValue diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index a9123069..6ed53e0e 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -83,6 +83,8 @@ public Real(T real) // public static Real operator -(Real value) => -value._value; + public static Real operator --(Real value) => value._value - One; + public static Real operator ++(Real value) => value._value + One; public static Real operator +(Real left, Real right) => left._value + right._value; public static Real operator -(Real left, Real right) => left._value - right._value; public static Real operator *(Real left, Real right) => left._value * right._value; From f9495af0b7ba4d5c303e6c25feb1d48222cdb7b8 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 02:24:41 -0500 Subject: [PATCH 129/293] Remove new line --- src/Mathematics.NET/Core/IDifferentiableFunctions.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs index 0ff01a6e..d87f96c6 100644 --- a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs +++ b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs @@ -32,8 +32,7 @@ namespace Mathematics.NET.Core; /// Defines support for common differentiable functions /// The type that implements the interface /// A type that implements and -public interface IDifferentiableFunctions - : IComplex +public interface IDifferentiableFunctions : IComplex where T : IDifferentiableFunctions where U : IFloatingPointIeee754, IMinMaxValue { From d4bf22f1981c5cade8904346880d0b0ef1f98534 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 03:20:16 -0500 Subject: [PATCH 130/293] Rename constant --- src/Mathematics.NET/Core/Constants.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Constants.cs b/src/Mathematics.NET/Core/Constants.cs index df652285..2d233e6e 100644 --- a/src/Mathematics.NET/Core/Constants.cs +++ b/src/Mathematics.NET/Core/Constants.cs @@ -35,7 +35,7 @@ public static class Constants /// Represents the ratio of the circumference of a circle to its diameter, $ π $ public const double Pi = 3.14159265358979323; /// Represents $ π/2 $ - public const double PiHalf = 1.57079632679489661; + public const double PiOverTwo = 1.57079632679489661; /// Represents $ π^2 $ public const double PiSquared = 9.86960440108935861; /// Represents $ 2π $ From a8eb49ab6776a7853459211e4a7ce7ad535c65ad Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 03:48:56 -0500 Subject: [PATCH 131/293] Add constants --- src/Mathematics.NET/Core/Constants.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Mathematics.NET/Core/Constants.cs b/src/Mathematics.NET/Core/Constants.cs index 2d233e6e..15499113 100644 --- a/src/Mathematics.NET/Core/Constants.cs +++ b/src/Mathematics.NET/Core/Constants.cs @@ -60,4 +60,10 @@ public static class Constants public const double Sqrt3 = 1.73205080756887729; /// Represents the square root of 5, $ \sqrt{5} $ public const double Sqrt5 = 2.23606797749978969; + /// Represents the solution to the Basel problem, $ \zeta(2) = \pi^2/6 $ + public const double ZetaOf2 = 1.64493406684822643; + /// Represents Apéry's constant, $ \zeta(3) $ + public const double ZetaOf3 = 1.20205690315959428; + /// Represents $ \zeta(4) = \pi^4/90 $ + public const double ZetaOf4 = 1.08232323371113819; } From d474f69a45f8a9c09ec4f1b3938512ae3c4bc1cb Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 03:53:08 -0500 Subject: [PATCH 132/293] Create IConstants interface and implement - Add documentation comments --- src/Mathematics.NET/Core/IConstants.cs | 83 ++++++++++++++++++++++++++ src/Mathematics.NET/Core/IReal.cs | 1 + src/Mathematics.NET/Core/Real.cs | 63 +++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 src/Mathematics.NET/Core/IConstants.cs diff --git a/src/Mathematics.NET/Core/IConstants.cs b/src/Mathematics.NET/Core/IConstants.cs new file mode 100644 index 00000000..b9cbd048 --- /dev/null +++ b/src/Mathematics.NET/Core/IConstants.cs @@ -0,0 +1,83 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Numerics; + +namespace Mathematics.NET.Core; + +/// Defines support for common mathematical constants +/// The type that implements the interface +/// A type that implements and +public interface IConstants : IComplex + where T : IConstants + where U : IFloatingPointIeee754, IMinMaxValue +{ + /// + static abstract T E { get; } + + /// + static abstract T Pi { get; } + + /// + static abstract T PiOverTwo { get; } + + /// + static abstract T PiSquared { get; } + + /// + static abstract T Tau { get; } + + /// + static abstract T EulerMascheroni { get; } + + /// + static abstract T GoldenRatio { get; } + + /// + static abstract T Ln2 { get; } + + /// + static abstract T Ln10 { get; } + + /// + static abstract T Sqrt2 { get; } + + /// + static abstract T Sqrt3 { get; } + + /// + static abstract T Sqrt5 { get; } + + /// + static abstract T ZetaOf2 { get; } + + /// + static abstract T ZetaOf3 { get; } + + /// + static abstract T ZetaOf4 { get; } +} diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 0a786586..b948f325 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -39,6 +39,7 @@ public interface IReal IInequalityRelations, IDecrementOperation, IIncrementOperation, + IConstants, IComparable, IComparable, IMinMaxValue diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 6ed53e0e..4c0cdaad 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -52,6 +52,51 @@ public readonly struct Real public static readonly Real NegativeInfinity = T.NegativeInfinity; public static readonly Real PositiveInfinity = T.PositiveInfinity; + /// + public static readonly Real E = T.CreateTruncating(Constants.E); + + /// + public static readonly Real Pi = T.CreateTruncating(Constants.Pi); + + /// + public static readonly Real PiOverTwo = T.CreateTruncating(Constants.PiOverTwo); + + /// + public static readonly Real PiSquared = T.CreateTruncating(Constants.PiSquared); + + /// + public static readonly Real Tau = T.CreateTruncating(Constants.Tau); + + /// + public static readonly Real EulerMascheroni = T.CreateTruncating(Constants.EulerMascheroni); + + /// + public static readonly Real GoldenRatio = T.CreateTruncating(Constants.GoldenRatio); + + /// + public static readonly Real Ln2 = T.CreateTruncating(Constants.Ln2); + + /// + public static readonly Real Ln10 = T.CreateTruncating(Constants.Ln10); + + /// + public static readonly Real Sqrt2 = T.CreateTruncating(Constants.Sqrt2); + + /// + public static readonly Real Sqrt3 = T.CreateTruncating(Constants.Sqrt3); + + /// + public static readonly Real Sqrt5 = T.CreateTruncating(Constants.Sqrt5); + + /// + public static readonly Real ZetaOf2 = T.CreateTruncating(Constants.ZetaOf2); + + /// + public static readonly Real ZetaOf3 = T.CreateTruncating(Constants.ZetaOf3); + + /// + public static readonly Real ZetaOf4 = T.CreateTruncating(Constants.ZetaOf4); + private readonly T _value; public Real(T real) @@ -78,6 +123,24 @@ public Real(T real) static Real IReal, T>.NegativeInfinity => NegativeInfinity; static Real IReal, T>.PositiveInfinity => PositiveInfinity; + // IConstants interface + + static Real IConstants, T>.E => E; + static Real IConstants, T>.Pi => Pi; + static Real IConstants, T>.PiOverTwo => PiOverTwo; + static Real IConstants, T>.PiSquared => PiSquared; + static Real IConstants, T>.Tau => Tau; + static Real IConstants, T>.EulerMascheroni => EulerMascheroni; + static Real IConstants, T>.GoldenRatio => GoldenRatio; + static Real IConstants, T>.Ln2 => Ln2; + static Real IConstants, T>.Ln10 => Ln10; + static Real IConstants, T>.Sqrt2 => Sqrt2; + static Real IConstants, T>.Sqrt3 => Sqrt3; + static Real IConstants, T>.Sqrt5 => Sqrt5; + static Real IConstants, T>.ZetaOf2 => ZetaOf2; + static Real IConstants, T>.ZetaOf3 => ZetaOf3; + static Real IConstants, T>.ZetaOf4 => ZetaOf4; + // // Operators // From 4cf91a6e29c607a96ee208b05f0707edd392f17a Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 04:45:12 -0500 Subject: [PATCH 133/293] Implement natural logarithm --- src/Mathematics.NET/Core/Complex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 342bacbc..c32134d6 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -416,7 +416,7 @@ public static Complex Exp(Complex z) // Logarithmic functions - public static Complex Ln(Complex z) => throw new NotImplementedException(); + public static Complex Ln(Complex z) => new(Real.Ln(Abs(z)), Real.Atan2(z._imaginary, z._real)); public static Complex Log(Complex z, Complex b) => throw new NotImplementedException(); From 35c2b8e07a04ef5b6fa6600f2717320e072d437f Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 12:28:08 -0500 Subject: [PATCH 134/293] Resolve CA2208 warning --- src/Mathematics.NET/Core/Complex.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index c32134d6..aff1d691 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -252,10 +252,7 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan public static Complex Parse(string s, NumberStyles style, IFormatProvider? provider) { - if (s is null) - { - throw new ArgumentNullException("Cannot parse null string"); - } + ArgumentNullException.ThrowIfNull(s); return Parse((ReadOnlySpan)s, style, provider); } From 3885cf155b8bf65d3b054c75d9cc95ed6616d379 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:17:31 -0500 Subject: [PATCH 135/293] Implement Atan - Add field for the value two --- src/Mathematics.NET/Core/Complex.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index aff1d691..06d485c3 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -44,6 +44,7 @@ public readonly struct Complex { public static readonly Complex Zero = new(Real.Zero, Real.Zero); public static readonly Complex One = new(Real.One, Real.Zero); + public static readonly Complex Two = new(Real.Two, Real.Zero); public static readonly Complex ImaginaryOne = new(Real.Zero, Real.One); public static readonly Complex NaN = new(Real.NaN, Real.NaN); public static readonly Complex Infinity = new(Real.PositiveInfinity, Real.PositiveInfinity); @@ -441,7 +442,7 @@ public static Complex Exp(Complex z) public static Complex Asin(Complex z) => throw new NotImplementedException(); - public static Complex Atan(Complex z) => throw new NotImplementedException(); + public static Complex Atan(Complex z) => ImaginaryOne / Two * Ln((ImaginaryOne + z) / (ImaginaryOne - z)); public static Complex Cos(Complex z) { From f22b0581b74ca067d6f64095e7fbe8f1095afd26 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 17:18:15 -0500 Subject: [PATCH 136/293] Rename ImaginaryOne and make it private - Apply changes to existing method/s --- src/Mathematics.NET/Core/Complex.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 06d485c3..52989666 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -42,10 +42,11 @@ public readonly struct Complex IDifferentiableFunctions, T> where T : IFloatingPointIeee754, IMinMaxValue { + private static readonly Complex s_im = new(Real.Zero, Real.One); + public static readonly Complex Zero = new(Real.Zero, Real.Zero); public static readonly Complex One = new(Real.One, Real.Zero); public static readonly Complex Two = new(Real.Two, Real.Zero); - public static readonly Complex ImaginaryOne = new(Real.Zero, Real.One); public static readonly Complex NaN = new(Real.NaN, Real.NaN); public static readonly Complex Infinity = new(Real.PositiveInfinity, Real.PositiveInfinity); @@ -442,7 +443,7 @@ public static Complex Exp(Complex z) public static Complex Asin(Complex z) => throw new NotImplementedException(); - public static Complex Atan(Complex z) => ImaginaryOne / Two * Ln((ImaginaryOne + z) / (ImaginaryOne - z)); + public static Complex Atan(Complex z) => s_im / Two * Ln((s_im + z) / (s_im - z)); public static Complex Cos(Complex z) { From d6a940f15a688e7629613d21aa932324d6c72b16 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 17:18:48 -0500 Subject: [PATCH 137/293] Create Math.cs --- src/Mathematics.NET/Math.cs | 91 +++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/Mathematics.NET/Math.cs diff --git a/src/Mathematics.NET/Math.cs b/src/Mathematics.NET/Math.cs new file mode 100644 index 00000000..ca4b74d1 --- /dev/null +++ b/src/Mathematics.NET/Math.cs @@ -0,0 +1,91 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Numerics; +using Mathematics.NET.Core; + +namespace Mathematics.NET; + +/// Provides Mathematics.NET functionality +/// A type that implements and +/// +/// This class contains constants and static methods for general mathematical purposes. Complicated mathematical operations may be found in their respective classes, and a list of all available operations can be found in the documentation. +/// +public static class Math where T : IFloatingPointIeee754, IMinMaxValue +{ + // + // Constants + // + + /// Represents the imaginary unit, $ i $ + public static Complex Im => new(Real.Zero, Real.One); + + /// + public static Real E => Real.E; + + /// + public static Real Pi => Real.Pi; + + /// + public static Real PiOverTwo => Real.PiOverTwo; + + /// + public static Real PiSquared => Real.PiSquared; + + /// + public static Real Tau => Real.Tau; + + /// + public static Real EulerMascheroni => Real.EulerMascheroni; + + /// + public static Real GoldenRatio => Real.GoldenRatio; + + /// + public static Real Ln2 => Real.Ln2; + + /// + public static Real Ln10 => Real.Ln10; + + /// + public static Real Sqrt2 => Real.Sqrt2; + + /// + public static Real Sqrt3 => Real.Sqrt3; + + /// + public static Real Sqrt5 => Real.Sqrt5; + + /// + public static Real ZetaOf2 => Real.ZetaOf2; + + /// + public static Real ZetaOf3 => Real.ZetaOf3; + + /// + public static Real ZetaOf4 => Real.ZetaOf4; +} From c5484eaa65a4d35a0775400231c3881086412e5d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:09:31 -0500 Subject: [PATCH 138/293] Add tests for Acos and Asin --- .../Core/ComplexTests.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 5735ab26..5bb81904 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -31,6 +31,34 @@ namespace Mathematics.NET.Tests.Core; [TestCategory("Core"), TestCategory("Complex Number")] public sealed class ComplexTests { + [TestMethod] + [DataRow(1.23, 2.34, 1.114564084931578, -1.686112230652994)] + public void Acos_ComplexOfDouble_ReturnsComplexOfDouble(double inReal, double inImaginary, double expectedRe, double expectedIm) + { + Complex input = new(inReal, inImaginary); + + var actualResult = Complex.Acos(input); + var actualRe = actualResult.Re.Value; + var actualIm = actualResult.Im.Value; + + Assert.AreEqual(expectedRe, actualRe, 1e-15); + Assert.AreEqual(expectedIm, actualIm, 1e-15); + } + + [TestMethod] + [DataRow(1.23, 2.34, 4.562322418633185e-1, 1.686112230652994)] + public void Asin_ComplexOfDouble_ReturnsComplexOfDouble(double inReal, double inImaginary, double expectedRe, double expectedIm) + { + Complex input = new(inReal, inImaginary); + + var actualResult = Complex.Asin(input); + var actualRe = actualResult.Re.Value; + var actualIm = actualResult.Im.Value; + + Assert.AreEqual(expectedRe, actualRe, 1e-15); + Assert.AreEqual(expectedIm, actualIm, 1e-15); + } + [TestMethod] [DataRow(1.2, 2.3, 1.2, -2.3)] public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inImaginary, double outReal, double outImaginary) From 6175cbea3f90d7c0751b00c90e40c2961fbeb474 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:10:38 -0500 Subject: [PATCH 139/293] Add test for Atan --- tests/Mathematics.NET.Tests/Core/ComplexTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 5bb81904..00398916 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -59,6 +59,20 @@ public void Asin_ComplexOfDouble_ReturnsComplexOfDouble(double inReal, double in Assert.AreEqual(expectedIm, actualIm, 1e-15); } + [TestMethod] + [DataRow(1.23, 2.34, 1.37591078602063, 3.356559207392595e-1)] + public void Atan_ComplexOfDouble_ReturnsComplexOfDouble(double inReal, double inImaginary, double expectedRe, double expectedIm) + { + Complex input = new(inReal, inImaginary); + + var actualResult = Complex.Atan(input); + var actualRe = actualResult.Re.Value; + var actualIm = actualResult.Im.Value; + + Assert.AreEqual(expectedRe, actualRe, 1e-15); + Assert.AreEqual(expectedIm, actualIm, 1e-15); + } + [TestMethod] [DataRow(1.2, 2.3, 1.2, -2.3)] public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inImaginary, double outReal, double outImaginary) From 7868a429c4cfc1e7a9c66e52b7ed82f7d02c66d2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:11:43 -0500 Subject: [PATCH 140/293] Implement Asin and Acos --- src/Mathematics.NET/Core/Complex.cs | 127 +++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 52989666..d82c5575 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -44,6 +44,11 @@ public readonly struct Complex { private static readonly Complex s_im = new(Real.Zero, Real.One); + // For computing Asin and Acos + private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / Real.Two; + private static readonly Real s_threeOverFour = T.CreateTruncating(0.75); + private static readonly Real s_threeOverTwo = T.CreateTruncating(1.5); + public static readonly Complex Zero = new(Real.Zero, Real.Zero); public static readonly Complex One = new(Real.One, Real.Zero); public static readonly Complex Two = new(Real.Two, Real.Zero); @@ -439,9 +444,127 @@ public static Complex Exp(Complex z) // Trigonometric functions - public static Complex Acos(Complex z) => throw new NotImplementedException(); + public static Complex Acos(Complex z) + { + AsinInternal(Real.Abs(z._real), Real.Abs(z._imaginary), out Real b, out Real bPrime, out Real v); + + Real u; + if (bPrime < Real.Zero) + { + u = Real.Acos(b); + } + else + { + u = Real.Atan(Real.One / bPrime); + } + + if (z._real < Real.Zero) + { + u = Real.Pi - u; + } + if (z._imaginary > Real.Zero) + { + v = -v; + } - public static Complex Asin(Complex z) => throw new NotImplementedException(); + return new(u, v); + } + + public static Complex Asin(Complex z) + { + AsinInternal(Real.Abs(z._real), Real.Abs(z._imaginary), out Real b, out Real bPrime, out Real v); + + Real u; + if (bPrime < Real.Zero) + { + u = Real.Asin(b); + } + else + { + u = Real.Atan(bPrime); + } + + if (z._real < Real.Zero) + { + u = -u; + } + if (z._imaginary < Real.Zero) + { + v = -v; + } + + return new(u, v); + } + + public static void AsinInternal(Real x, Real y, out Real b, out Real bPrime, out Real v) + { + // This is the same method described by Hull, Fairgrieve, and Tang in "Implementing the Complex + // ArcSine and Arccosine Functions Using Exception Handling" that is used in System.Numerics.Complex. + if (x > s_asinOverflowThreshold || y > s_asinOverflowThreshold) + { + b = -Real.One; + bPrime = x / y; + + Real small, big; + if (x < y) + { + small = x; + big = y; + } + else + { + small = y; + big = x; + } + Real ratio = small / big; + v = Real.Ln2 + Real.Ln(big) + Real.Ln(ratio * ratio + Real.One) / Real.Two; + } + else + { + Real r = Hypot((x + Real.One).Value, y.Value); + Real s = Hypot((x - Real.One).Value, y.Value); + + Real a = (r + s) / Real.Two; + b = x / a; + + if (b > s_threeOverFour) + { + if (x <= Real.One) + { + Real amx = (y * y / (r + (x + Real.One)) + (s + (Real.One - x))) / Real.Two; + bPrime = x / Real.Sqrt((a + x) * amx); + } + else + { + Real t = (Real.One / (r + (x + Real.One)) + Real.One / (s + (x - Real.One))) / Real.Two; + bPrime = x / y / Real.Sqrt((a + x) * t); + } + } + else + { + bPrime = -Real.One; + } + + if (a < s_threeOverTwo) + { + if (x < Real.One) + { + Real t = (Real.One / (r + (x + Real.One)) + Real.One / (s + (Real.One - x))) / Real.Two; + Real am1 = y * y * t; + v = Real.Ln(am1 + y * Real.Sqrt(t * (a + Real.One)) + Real.One); + } + else + { + Real am1 = (y * y / (r + (x + Real.One)) + (s + (x - Real.One))) / Real.Two; + v = Real.Ln(am1 + Real.Sqrt(am1 * (a + Real.One)) + Real.One); + } + } + else + { + v = Real.Ln(a + Real.Sqrt((a - Real.One) * (a + Real.One))); + } + } + } public static Complex Atan(Complex z) => s_im / Two * Ln((s_im + z) / (s_im - z)); From 2018874deb22c23613105198f4f5bb5710618667 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:20:32 -0500 Subject: [PATCH 141/293] Make method private --- src/Mathematics.NET/Core/Complex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index d82c5575..937b3982 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -496,7 +496,7 @@ public static Complex Asin(Complex z) return new(u, v); } - public static void AsinInternal(Real x, Real y, out Real b, out Real bPrime, out Real v) + private static void AsinInternal(Real x, Real y, out Real b, out Real bPrime, out Real v) { // This is the same method described by Hull, Fairgrieve, and Tang in "Implementing the Complex // ArcSine and Arccosine Functions Using Exception Handling" that is used in System.Numerics.Complex. From e09b1b1cb6b844bd5a7f8c2780f21fe75a1d83cd Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:27:34 -0500 Subject: [PATCH 142/293] Rename benchmark class --- ...omplexAbs.cs => SystemComplexAbsVsComplexAbsBenchmarks.cs} | 4 ++-- tests/Mathematics.NET.Benchmarks/Program.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename tests/Mathematics.NET.Benchmarks/Core/Complex/{SystemComplexAbsVsComplexAbs.cs => SystemComplexAbsVsComplexAbsBenchmarks.cs} (92%) diff --git a/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbs.cs b/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbsBenchmarks.cs similarity index 92% rename from tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbs.cs rename to tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbsBenchmarks.cs index 8a597fba..e78f0ecd 100644 --- a/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbs.cs +++ b/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbsBenchmarks.cs @@ -1,4 +1,4 @@ -// +// // Mathematics.NET // https://github.com/HamletTanyavong/Mathematics.NET // @@ -30,7 +30,7 @@ namespace Mathematics.NET.Benchmarks.Core.Complex; [MemoryDiagnoser] [RankColumn] [Orderer(SummaryOrderPolicy.FastestToSlowest)] -public class SystemComplexAbsVsComplexAbs +public class SystemComplexAbsVsComplexAbsBenchmarks { public System.Numerics.Complex Z { get; set; } public Complex W { get; set; } diff --git a/tests/Mathematics.NET.Benchmarks/Program.cs b/tests/Mathematics.NET.Benchmarks/Program.cs index ec5ace5f..84606de6 100644 --- a/tests/Mathematics.NET.Benchmarks/Program.cs +++ b/tests/Mathematics.NET.Benchmarks/Program.cs @@ -35,7 +35,7 @@ { typeof(ComplexDivisionBenchmarks), typeof(RealvsDouble), - typeof(SystemComplexAbsVsComplexAbs) + typeof(SystemComplexAbsVsComplexAbsBenchmarks) }); benchmarkSwitcher.Run(args, new DebugInProcessConfig()); From 4b8da6b3bfbd3b5a1d9bbadeaccb5081b4f10d9e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:34:53 -0500 Subject: [PATCH 143/293] Add the number two to IComplex - Implement Two if not already implemented --- src/Mathematics.NET/Core/Complex.cs | 1 + src/Mathematics.NET/Core/IComplex.cs | 3 +++ src/Mathematics.NET/Core/Real.cs | 1 + 3 files changed, 5 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 937b3982..522ab177 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -86,6 +86,7 @@ public Complex(Real real, Real imaginary) static Complex IComplex, T>.Zero => Zero; static Complex IComplex, T>.One => One; + static Complex IComplex, T>.Two => Two; static Complex IComplex, T>.NaN => NaN; // diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 1db2cde8..4ec48d2b 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -67,6 +67,9 @@ public interface IComplex /// Represents one for the type static abstract T One { get; } + /// Represents two for the type + static abstract T Two { get; } + /// Represents NaN for the type static abstract T NaN { get; } diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 4c0cdaad..dc47b46b 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -117,6 +117,7 @@ public Real(T real) static Real IComplex, T>.Zero => Zero; static Real IComplex, T>.One => One; + static Real IComplex, T>.Two => Two; static Real IComplex, T>.NaN => NaN; static Real IMinMaxValue>.MaxValue => MaxValue; static Real IMinMaxValue>.MinValue => MinValue; From 9579e690b0f55b30e472569b263bc0ee7b52167f Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:35:41 -0500 Subject: [PATCH 144/293] Update Complex.cs - Add new line for clarity --- src/Mathematics.NET/Core/Complex.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 522ab177..a9473d69 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -52,6 +52,7 @@ public readonly struct Complex public static readonly Complex Zero = new(Real.Zero, Real.Zero); public static readonly Complex One = new(Real.One, Real.Zero); public static readonly Complex Two = new(Real.Two, Real.Zero); + public static readonly Complex NaN = new(Real.NaN, Real.NaN); public static readonly Complex Infinity = new(Real.PositiveInfinity, Real.PositiveInfinity); From 12e04508b7115dc096fc0ce47087df2da32a7919 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 19:02:25 -0500 Subject: [PATCH 145/293] Add s_imOverTwo field and use for Atan performance --- src/Mathematics.NET/Core/Complex.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index a9473d69..37490cd7 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -43,6 +43,7 @@ public readonly struct Complex where T : IFloatingPointIeee754, IMinMaxValue { private static readonly Complex s_im = new(Real.Zero, Real.One); + private static readonly Complex s_imOverTwo = s_im / Two; // For computing Asin and Acos private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / Real.Two; @@ -568,7 +569,7 @@ private static void AsinInternal(Real x, Real y, out Real b, out Real Atan(Complex z) => s_im / Two * Ln((s_im + z) / (s_im - z)); + public static Complex Atan(Complex z) => s_imOverTwo * Ln((s_im + z) / (s_im - z)); public static Complex Cos(Complex z) { From cebe7698ae797d1f2f9ae823d2a16853e1416bfe Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 20:27:49 -0500 Subject: [PATCH 146/293] Implement inverse hyperbolic methods - Add field representing one half --- src/Mathematics.NET/Core/Complex.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 37490cd7..a85d60ee 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -45,6 +45,8 @@ public readonly struct Complex private static readonly Complex s_im = new(Real.Zero, Real.One); private static readonly Complex s_imOverTwo = s_im / Two; + private static readonly Complex s_oneOverTwo = One / Two; + // For computing Asin and Acos private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / Real.Two; private static readonly Real s_threeOverFour = T.CreateTruncating(0.75); @@ -409,11 +411,11 @@ public static Complex Exp(Complex z) // Hyperbolic functions - public static Complex Acosh(Complex z) => throw new NotImplementedException(); + public static Complex Acosh(Complex z) => Ln(z + Sqrt(z * z - One)); - public static Complex Asinh(Complex z) => throw new NotImplementedException(); + public static Complex Asinh(Complex z) => Ln(z + Sqrt(z * z + One)); - public static Complex Atanh(Complex z) => throw new NotImplementedException(); + public static Complex Atanh(Complex z) => s_oneOverTwo * Ln((One + z) / (One - z)); public static Complex Cosh(Complex z) => throw new NotImplementedException(); From c8721884bf77cbcc2dc7533d877380a19ee7959f Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 20:39:50 -0500 Subject: [PATCH 147/293] Add benchmarks --- .../Complex/ComplexTrigonometryBenchmarks.cs | 72 +++++++++++++++++++ tests/Mathematics.NET.Benchmarks/Program.cs | 1 + 2 files changed, 73 insertions(+) create mode 100644 tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexTrigonometryBenchmarks.cs diff --git a/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexTrigonometryBenchmarks.cs b/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexTrigonometryBenchmarks.cs new file mode 100644 index 00000000..8474df8a --- /dev/null +++ b/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexTrigonometryBenchmarks.cs @@ -0,0 +1,72 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Benchmarks.Core.Complex; + +[MemoryDiagnoser] +[RankColumn] +[Orderer(SummaryOrderPolicy.FastestToSlowest)] +public class ComplexTrigonometryBenchmarks +{ + public Complex Z { get; set; } + public Complex ImOverTwo { get; set; } + + public System.Numerics.Complex W { get; set; } + + [GlobalSetup] + public void GlobalSetup() + { + Z = new(1.23, 2.34); + ImOverTwo = Math.Im / Complex.Two; + + W = new(1.23, 2.34); + } + + [Benchmark(Baseline = true)] + public System.Numerics.Complex Atan_System() + { + return System.Numerics.Complex.Atan(W); + } + + [Benchmark] + public Complex Atan_MathNET() + { + return Complex.Atan(Z); + } + + //[Benchmark] + public Complex Atan_WithoutConstImOverTwo() + { + return Math.Im / Complex.Two * Complex.Ln((Math.Im + Z) / (Math.Im - Z)); + } + + //[Benchmark] + public Complex Atan_WithConstImOverTwo() + { + return ImOverTwo * Complex.Ln((Math.Im + Z) / (Math.Im - Z)); + } +} diff --git a/tests/Mathematics.NET.Benchmarks/Program.cs b/tests/Mathematics.NET.Benchmarks/Program.cs index 84606de6..caf4c3b9 100644 --- a/tests/Mathematics.NET.Benchmarks/Program.cs +++ b/tests/Mathematics.NET.Benchmarks/Program.cs @@ -34,6 +34,7 @@ var benchmarkSwitcher = new BenchmarkSwitcher(new[] { typeof(ComplexDivisionBenchmarks), + typeof(ComplexTrigonometryBenchmarks), typeof(RealvsDouble), typeof(SystemComplexAbsVsComplexAbsBenchmarks) }); From a4c89bddd53f42917c3d5c05736b2f5e2e39ea92 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 21:31:30 -0500 Subject: [PATCH 148/293] Fix field initialization values --- src/Mathematics.NET/Core/Complex.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index a85d60ee..76fa4f3e 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -43,9 +43,9 @@ public readonly struct Complex where T : IFloatingPointIeee754, IMinMaxValue { private static readonly Complex s_im = new(Real.Zero, Real.One); - private static readonly Complex s_imOverTwo = s_im / Two; + private static readonly Complex s_imOverTwo = new(Real.Zero, Real.One / Real.Two); - private static readonly Complex s_oneOverTwo = One / Two; + private static readonly Complex s_oneOverTwo = new(Real.One / Real.Two, Real.Zero); // For computing Asin and Acos private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / Real.Two; From c4e4c43a7b88dff3f65ff5fe382cdc6244a960f5 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 21:41:49 -0500 Subject: [PATCH 149/293] Implement Cosh, Sinh, and Tanh - These are not the most performant implementations. Optimize later --- src/Mathematics.NET/Core/Complex.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 76fa4f3e..e52d3b02 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -417,11 +417,13 @@ public static Complex Exp(Complex z) public static Complex Atanh(Complex z) => s_oneOverTwo * Ln((One + z) / (One - z)); - public static Complex Cosh(Complex z) => throw new NotImplementedException(); + public static Complex Cosh(Complex z) + => new(Real.Cosh(z._real) * Real.Cos(z._imaginary), Real.Sinh(z._real) * Real.Sin(z._imaginary)); - public static Complex Sinh(Complex z) => throw new NotImplementedException(); + public static Complex Sinh(Complex z) + => new(Real.Sinh(z._real) * Real.Cos(z._imaginary), Real.Cosh(z._real) * Real.Sin(z._imaginary)); - public static Complex Tanh(Complex z) => throw new NotImplementedException(); + public static Complex Tanh(Complex z) => Sinh(z) / Cosh(z); // Logarithmic functions From faad164a91850a2e41450401e37d73e57035944d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 22:28:21 -0500 Subject: [PATCH 150/293] Add the value Three --- src/Mathematics.NET/Core/Complex.cs | 1 + src/Mathematics.NET/Core/Real.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index e52d3b02..033d4a69 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -46,6 +46,7 @@ public readonly struct Complex private static readonly Complex s_imOverTwo = new(Real.Zero, Real.One / Real.Two); private static readonly Complex s_oneOverTwo = new(Real.One / Real.Two, Real.Zero); + private static readonly Complex s_three = Real.Three; // For computing Asin and Acos private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / Real.Two; diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index dc47b46b..4e368442 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -44,6 +44,7 @@ public readonly struct Real public static readonly Real Zero = T.Zero; public static readonly Real One = T.One; public static readonly Real Two = T.One + T.One; + public static readonly Real Three = T.One + Two; public static readonly Real MaxValue = T.MaxValue; public static readonly Real MinValue = T.MinValue; From 2edc59273c81a1daabf32f580aef241279bd98b6 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 22:29:41 -0500 Subject: [PATCH 151/293] Add implicit operator --- src/Mathematics.NET/Core/Complex.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 033d4a69..9490b4f6 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -601,4 +601,8 @@ public static Complex Sin(Complex z) // public static implicit operator Complex(T x) => new(x); + + /// Convert a value of type to one of type + /// The value to convert + public static implicit operator Complex(Real x) => new(x); } From db16480d1493d7e20c72a5f6eabe0668961eb6b7 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 20 Sep 2023 22:29:53 -0500 Subject: [PATCH 152/293] Implement methods --- src/Mathematics.NET/Core/Complex.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 9490b4f6..465dd91d 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -406,9 +406,9 @@ public static Complex Exp(Complex z) return new(expReal * Real.Cos(z._imaginary), expReal * Real.Sin(z._imaginary)); } - public static Complex Exp2(Complex z) => throw new NotImplementedException(); + public static Complex Exp2(Complex z) => Exp(Real.Ln2 * z); - public static Complex Exp10(Complex z) => throw new NotImplementedException(); + public static Complex Exp10(Complex z) => Exp(Real.Ln10 * z); // Hyperbolic functions @@ -430,23 +430,23 @@ public static Complex Sinh(Complex z) public static Complex Ln(Complex z) => new(Real.Ln(Abs(z)), Real.Atan2(z._imaginary, z._real)); - public static Complex Log(Complex z, Complex b) => throw new NotImplementedException(); + public static Complex Log(Complex z, Complex b) => Ln(z) / Ln(b); - public static Complex Log2(Complex z) => throw new NotImplementedException(); + public static Complex Log2(Complex z) => Ln(z) / Ln(Real.Ln2); - public static Complex Log10(Complex z) => throw new NotImplementedException(); + public static Complex Log10(Complex z) => Ln(z) / Ln(Real.Ln10); // Power functions - public static Complex Pow(Complex z, Complex w) => throw new NotImplementedException(); + public static Complex Pow(Complex z, Complex w) => Exp(w * Ln(z)); // Root functions - public static Complex Cbrt(Complex z) => throw new NotImplementedException(); + public static Complex Cbrt(Complex z) => Exp(Ln(z) / s_three); public static Complex NthRoot(Complex z, int n) => throw new NotImplementedException(); - public static Complex Root(Complex z, Complex w) => throw new NotImplementedException(); + public static Complex Root(Complex z, Complex w) => Exp(Ln(z) / w); public static Complex Sqrt(Complex z) => throw new NotImplementedException(); From 64c4558eb1c62605b8ed3292bc615510cbe526f4 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 21 Sep 2023 00:57:23 -0500 Subject: [PATCH 153/293] Implement Tan - Add constant four --- src/Mathematics.NET/Core/Complex.cs | 21 ++++++++++++++++++++- src/Mathematics.NET/Core/Real.cs | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 465dd91d..0264d16b 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -47,6 +47,7 @@ public readonly struct Complex private static readonly Complex s_oneOverTwo = new(Real.One / Real.Two, Real.Zero); private static readonly Complex s_three = Real.Three; + private static readonly Real s_four = Real.Four; // For computing Asin and Acos private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / Real.Two; @@ -594,7 +595,25 @@ public static Complex Sin(Complex z) return new(Real.Sin(z._real) * cosh, Real.Cos(z._real) * sinh); } - public static Complex Tan(Complex z) => throw new NotImplementedException(); + public static Complex Tan(Complex z) + { + Real x2 = Real.Two * z._real; + Real y2 = Real.Two * z._imaginary; + Real p = Real.Exp(y2); + Real q = Real.One / p; + Real cosh = (p + q) / Real.Two; + if (Real.Abs(z._imaginary) <= s_four) + { + Real sinh = (p - q) / Real.Two; + Real D = Real.Cos(x2) + cosh; + return new(Real.Sin(x2) / D, sinh / D); + } + else + { + Real D = Real.One + Real.Cos(x2) / cosh; + return new(Real.Sin(x2) / cosh / D, Real.Tanh(y2) / D); + } + } // // Implicit Operators diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 4e368442..01d0aa5b 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -45,6 +45,7 @@ public readonly struct Real public static readonly Real One = T.One; public static readonly Real Two = T.One + T.One; public static readonly Real Three = T.One + Two; + public static readonly Real Four = T.CreateTruncating(4.0); public static readonly Real MaxValue = T.MaxValue; public static readonly Real MinValue = T.MinValue; From 634f6897e2e9268dfd3bf9bfd4d9d601945f87e6 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 21 Sep 2023 00:59:10 -0500 Subject: [PATCH 154/293] Implement Sqrt --- src/Mathematics.NET/Core/Complex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 0264d16b..1c63d6f7 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -449,7 +449,7 @@ public static Complex Sinh(Complex z) public static Complex Root(Complex z, Complex w) => Exp(Ln(z) / w); - public static Complex Sqrt(Complex z) => throw new NotImplementedException(); + public static Complex Sqrt(Complex z) => Exp(s_oneOverTwo * Ln(z)); // Trigonometric functions From 09fe701f6a47d0a00e7477535c5cafb9202c8e28 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 21 Sep 2023 01:00:12 -0500 Subject: [PATCH 155/293] Remove NthRoot --- src/Mathematics.NET/Core/Complex.cs | 2 -- src/Mathematics.NET/Core/IDifferentiableFunctions.cs | 2 -- src/Mathematics.NET/Core/Real.cs | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 1c63d6f7..b6f34ad3 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -445,8 +445,6 @@ public static Complex Sinh(Complex z) public static Complex Cbrt(Complex z) => Exp(Ln(z) / s_three); - public static Complex NthRoot(Complex z, int n) => throw new NotImplementedException(); - public static Complex Root(Complex z, Complex w) => Exp(Ln(z) / w); public static Complex Sqrt(Complex z) => Exp(s_oneOverTwo * Ln(z)); diff --git a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs index d87f96c6..60011e7e 100644 --- a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs +++ b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs @@ -86,8 +86,6 @@ public interface IDifferentiableFunctions : IComplex static abstract T Cbrt(T x); - static abstract T NthRoot(T x, int n); - static abstract T Root(T x, T r); static abstract T Sqrt(T x); diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 01d0aa5b..03e09663 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -336,8 +336,6 @@ public static Real Reciprocate(Real x) public static Real Cbrt(Real x) => T.Cbrt(x._value); - public static Real NthRoot(Real x, int n) => T.RootN(x._value, n); - public static Real Root(Real x, Real y) => T.Exp(y._value * T.Log(x._value)); public static Real Sqrt(Real x) => T.Sqrt(x._value); From bc230d39e1ecd641cec915d63f65a2819e1bfbe0 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 21 Sep 2023 01:18:06 -0500 Subject: [PATCH 156/293] Clean up fields - Remove unnecessary fields --- src/Mathematics.NET/Core/Complex.cs | 12 ++++++------ src/Mathematics.NET/Core/Real.cs | 2 -- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index b6f34ad3..12b7010a 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -45,18 +45,18 @@ public readonly struct Complex private static readonly Complex s_im = new(Real.Zero, Real.One); private static readonly Complex s_imOverTwo = new(Real.Zero, Real.One / Real.Two); - private static readonly Complex s_oneOverTwo = new(Real.One / Real.Two, Real.Zero); - private static readonly Complex s_three = Real.Three; - private static readonly Real s_four = Real.Four; + private static readonly Complex s_oneOverTwo = T.CreateTruncating(0.5); + private static readonly Complex s_three = T.CreateTruncating(3.0); + private static readonly Real s_four = T.CreateTruncating(4.0); // For computing Asin and Acos private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / Real.Two; private static readonly Real s_threeOverFour = T.CreateTruncating(0.75); private static readonly Real s_threeOverTwo = T.CreateTruncating(1.5); - public static readonly Complex Zero = new(Real.Zero, Real.Zero); - public static readonly Complex One = new(Real.One, Real.Zero); - public static readonly Complex Two = new(Real.Two, Real.Zero); + public static readonly Complex Zero = Real.Zero; + public static readonly Complex One = Real.One; + public static readonly Complex Two = Real.Two; public static readonly Complex NaN = new(Real.NaN, Real.NaN); public static readonly Complex Infinity = new(Real.PositiveInfinity, Real.PositiveInfinity); diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 03e09663..5d5e2144 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -44,8 +44,6 @@ public readonly struct Real public static readonly Real Zero = T.Zero; public static readonly Real One = T.One; public static readonly Real Two = T.One + T.One; - public static readonly Real Three = T.One + Two; - public static readonly Real Four = T.CreateTruncating(4.0); public static readonly Real MaxValue = T.MaxValue; public static readonly Real MinValue = T.MinValue; From bc4972e45a0f83b7258953c5163f23725bcd965e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 21 Sep 2023 01:24:26 -0500 Subject: [PATCH 157/293] Create IRational.cs --- src/Mathematics.NET/Core/IRational.cs | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/Mathematics.NET/Core/IRational.cs diff --git a/src/Mathematics.NET/Core/IRational.cs b/src/Mathematics.NET/Core/IRational.cs new file mode 100644 index 00000000..1acce62f --- /dev/null +++ b/src/Mathematics.NET/Core/IRational.cs @@ -0,0 +1,41 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Numerics; + +namespace Mathematics.NET.Core; + +/// Defines support for rational numbers +/// A type that implements the interface +/// A type that implements and +/// A type that implements and +public interface IRational : IReal + where T : IRational + where U : IBinaryInteger, IMinMaxValue + where V : IFloatingPointIeee754, IMinMaxValue +{ +} From c563e90b31f10e5080b25d33a06565a722583784 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 21 Sep 2023 04:28:56 -0500 Subject: [PATCH 158/293] Create RationalTests.cs --- .../Core/RationalTests.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/Mathematics.NET.Tests/Core/RationalTests.cs diff --git a/tests/Mathematics.NET.Tests/Core/RationalTests.cs b/tests/Mathematics.NET.Tests/Core/RationalTests.cs new file mode 100644 index 00000000..e05ea661 --- /dev/null +++ b/tests/Mathematics.NET.Tests/Core/RationalTests.cs @@ -0,0 +1,34 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Tests.Core; + +[TestClass] +[TestCategory("Core"), TestCategory("Rational Number")] +public sealed class RationalTests +{ +} From cf0b9586585ebc98b59837c9f3d042de88e5166f Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 21 Sep 2023 16:34:14 -0500 Subject: [PATCH 159/293] Change return type of Abs - Update method that uses Abs and use Hypot instead --- src/Mathematics.NET/Core/Complex.cs | 4 ++-- src/Mathematics.NET/Core/IComplex.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 12b7010a..df01181e 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -322,7 +322,7 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // Methods // - public static Real Abs(Complex z) => Hypot(z._real.Value, z._imaginary.Value); + public static Complex Abs(Complex z) => Hypot(z._real.Value, z._imaginary.Value); private static T Hypot(T x, T y) { @@ -429,7 +429,7 @@ public static Complex Sinh(Complex z) // Logarithmic functions - public static Complex Ln(Complex z) => new(Real.Ln(Abs(z)), Real.Atan2(z._imaginary, z._real)); + public static Complex Ln(Complex z) => new(Real.Ln(Hypot(z._real.Value, z._imaginary.Value)), Real.Atan2(z._imaginary, z._real)); public static Complex Log(Complex z, Complex b) => Ln(z) / Ln(b); diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 4ec48d2b..6430144b 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -76,7 +76,7 @@ public interface IComplex /// Compute the absolute value of a number /// A complex number /// The absolute value - static abstract Real Abs(T z); + static abstract T Abs(T z); /// Compute the complex conjugate of a number /// A complex number From b3f2ae45593dc174a0c17483fcc69dd3992ac561 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 21 Sep 2023 16:36:22 -0500 Subject: [PATCH 160/293] Update IReal and Real - Inherit IConstants from IReal instead of Real since Rational cant implement it --- src/Mathematics.NET/Core/IReal.cs | 1 - src/Mathematics.NET/Core/Real.cs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index b948f325..0a786586 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -39,7 +39,6 @@ public interface IReal IInequalityRelations, IDecrementOperation, IIncrementOperation, - IConstants, IComparable, IComparable, IMinMaxValue diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 5d5e2144..f08b4995 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -38,6 +38,7 @@ namespace Mathematics.NET.Core; [StructLayout(LayoutKind.Sequential)] public readonly struct Real : IReal, T>, + IConstants, T>, IDifferentiableFunctions, T> where T : IFloatingPointIeee754, IMinMaxValue { From 188114a4e6fd3d2002c220e12f305bde233a4de1 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:06:28 -0500 Subject: [PATCH 161/293] Remove declarations from interface - Remove NegativeInfinity and PositiveInfinity since this does not apply to Rational --- src/Mathematics.NET/Core/IReal.cs | 6 ------ src/Mathematics.NET/Core/Real.cs | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 0a786586..21698570 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -48,12 +48,6 @@ public interface IReal /// The backing value of the type U Value { get; } - /// Represents negative infinty for the type - static abstract T NegativeInfinity { get; } - - /// Represents positive infinity for the type - static abstract T PositiveInfinity { get; } - /// Check if a value is negative infinity /// The value to check /// true if the value is negative infinity; otherwise, false diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index f08b4995..55920113 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -122,8 +122,6 @@ public Real(T real) static Real IComplex, T>.NaN => NaN; static Real IMinMaxValue>.MaxValue => MaxValue; static Real IMinMaxValue>.MinValue => MinValue; - static Real IReal, T>.NegativeInfinity => NegativeInfinity; - static Real IReal, T>.PositiveInfinity => PositiveInfinity; // IConstants interface From b3313b26faafd11b4b582f24ce86992a14268556 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:07:21 -0500 Subject: [PATCH 162/293] Add declarations --- src/Mathematics.NET/Core/IRational.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Mathematics.NET/Core/IRational.cs b/src/Mathematics.NET/Core/IRational.cs index 1acce62f..e1bddc1e 100644 --- a/src/Mathematics.NET/Core/IRational.cs +++ b/src/Mathematics.NET/Core/IRational.cs @@ -38,4 +38,14 @@ public interface IRational : IReal where U : IBinaryInteger, IMinMaxValue where V : IFloatingPointIeee754, IMinMaxValue { + /// Get the numerator of the rational number + U Num { get; } + + /// Get the denominator of the rational number + U Den { get; } + + /// Reduce a rational number + /// The value to reduce + /// A reduced fraction if the number was reducible; otherwise, itself + static abstract T Reduce(T x); } From b1069ea48acf2005733a07dbd180d2ccd3f4a3cf Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 23 Sep 2023 03:23:12 -0500 Subject: [PATCH 163/293] Update IComplex.cs - Define conversion methods --- src/Mathematics.NET/Core/IComplex.cs | 120 +++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 6430144b..ae35f03c 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -28,6 +28,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Numerics; +using System.Runtime.CompilerServices; using Mathematics.NET.Core.Operations; using Mathematics.NET.Core.Relations; @@ -83,6 +84,75 @@ public interface IComplex /// The complex conjugate static abstract T Conjugate(T z); + /// Convert a value to one of the current type, and throw and overflow exception if the value falls outside the representable range. + /// The type from which to convert + /// The value to convert + /// The result of the conversion + /// Conversions from the type are not supported. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static virtual T CreateChecked(V value) + where V : INumberBase + { + T? result; + + if (typeof(V) == typeof(T)) + { + result = (T)(object)value; + } + else if (!T.TryConvertFromChecked(value, out result)) + { + throw new NotSupportedException(); + } + + return result; + } + + /// Convert a value to one of the current type, and saturate values that fall outside the representable range. + /// The type from which to convert + /// The value to convert + /// The result of the conversion + /// Conversions from the type are not supported. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static virtual T CreateSaturating(V value) + where V : INumberBase + { + T? result; + + if (typeof(V) == typeof(T)) + { + result = (T)(object)value; + } + else if (!T.TryConvertFromSaturating(value, out result)) + { + throw new NotSupportedException(); + } + + return result; + } + + /// Convert a value to one of another type, and truncate values that fall outside of the representable range. + /// The type from which to convert + /// The value to convert + /// The result of the conversion + /// Conversions from the type are not supported. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static virtual T CreateTruncating(V value) + where V : INumberBase + { + T? result; + + if (typeof(V) == typeof(T)) + { + result = (T)(object)value; + } + else if (!T.TryConvertFromTruncating(value, out result)) + { + throw new NotSupportedException(); + } + + return result; + } + /// Check if a value is finite /// The value to check /// true if the value is finite; otherwise, false @@ -126,6 +196,56 @@ public interface IComplex /// The reciprocal static abstract T Reciprocate(T z); + /// Try to convert a value to one of the current type, and throw and overflow exception if the value falls outside the representable range. + /// The type from which to convert + /// The value to convert + /// The result of the conversion + /// true if the conversion was successful; otherwise, false + /// The value is not representable by the type . + protected static abstract bool TryConvertFromChecked(V value, [MaybeNullWhen(false)] out T result) + where V : INumberBase; + + /// Try to convert a value to one of the current type, and saturate values that fall outside the representable range. + /// The type from which to convert + /// The value to convert + /// The result of the conversion + /// true if the conversion was successful; otherwise, false + protected static abstract bool TryConvertFromSaturating(V value, [MaybeNullWhen(false)] out T result) + where V : INumberBase; + + /// Try to convert a value to one of the current type, and truncate values that fall outside the representable range. + /// The type from which to convert + /// The value to convert + /// The result of the conversion + /// true if the conversion was successful; otherwise, false + protected static abstract bool TryConvertFromTruncating(V value, [MaybeNullWhen(false)] out T result) + where V : INumberBase; + + /// Try to convert a value to one of another type, and throw and overflow exception if the value falls outside the representable range. + /// The target type + /// The value to convert + /// The result of the conversion + /// true if the conversion was successful; otherwise, false + /// The value is not representable by the type . + protected static abstract bool TryConvertToChecked(T value, [MaybeNullWhen(false)] out V result) + where V : INumberBase; + + /// Try to convert a value to one of another type, and saturate values that fall outside of the representable range. + /// The target type + /// The value to convert + /// The result of the conversion + /// true if the conversion was successful; otherwise, false + protected static abstract bool TryConvertToSaturating(T value, [MaybeNullWhen(false)] out V result) + where V : INumberBase; + + /// Try to convert a value to one of another type, and truncate values that fall outside of the representable range. + /// The target type + /// The value to convert + /// The result of the conversion + /// true if the conversion was successful; otherwise, false + protected static abstract bool TryConvertToTruncating(T value, [MaybeNullWhen(false)] out V result) + where V : INumberBase; + /// Try to parse a string into a value /// The string to parse /// The number style From f7ce495cd9e7f4a8272cc8c7c11bb915807191c5 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 23 Sep 2023 04:09:33 -0500 Subject: [PATCH 164/293] Implementing conversion methods --- src/Mathematics.NET/Core/Real.cs | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 55920113..48fef501 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -289,6 +289,48 @@ public static Real Reciprocate(Real x) return T.One / x; } + public static bool TryConvertFromChecked(V value, out Real result) + where V : INumberBase + { + result = T.CreateChecked(value); + return true; + } + + public static bool TryConvertFromSaturating(V value, out Real result) + where V : INumberBase + { + result = T.CreateSaturating(value); + return true; + } + + public static bool TryConvertFromTruncating(V value, out Real result) + where V : INumberBase + { + result = T.CreateTruncating(value); + return true; + } + + public static bool TryConvertToChecked(Real value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + result = V.CreateChecked(value._value); + return true; + } + + public static bool TryConvertToSaturating(Real value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + result = V.CreateSaturating(value._value); + return true; + } + + public static bool TryConvertToTruncating(Real value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + result = V.CreateTruncating(value._value); + return true; + } + // // IDifferentiableFunctions interface // From aacad54cdeb2674b6605c98b84e0cac7e8ed07b8 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 23 Sep 2023 06:05:58 -0500 Subject: [PATCH 165/293] Implement conversion methods --- src/Mathematics.NET/Core/Complex.cs | 49 +++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index df01181e..ef261aab 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -395,6 +395,55 @@ public static Complex Reciprocate(Complex z) return new(reResult, imResult); } + // We will only consider the real part of complex numbers for these conversions. + + public static bool TryConvertFromChecked(V value, out Complex result) + where V : INumberBase + { + result = T.CreateChecked(value); + return true; + } + + public static bool TryConvertFromSaturating(V value, out Complex result) + where V : INumberBase + { + result = T.CreateSaturating(value); + return true; + } + + public static bool TryConvertFromTruncating(V value, out Complex result) + where V : INumberBase + { + result = T.CreateTruncating(value); + return true; + } + + public static bool TryConvertToChecked(Complex value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + if (value._imaginary == Real.Zero) + { + throw new OverflowException(); + } + + result = V.CreateChecked(value._real.Value); + return true; + } + + public static bool TryConvertToSaturating(Complex value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + result = V.CreateSaturating(value._real.Value); + return true; + } + + public static bool TryConvertToTruncating(Complex value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + result = V.CreateTruncating(value._real.Value); + return true; + } + // // IDifferentiableFunctions interface // From 7da8d9f4189adfd860eb8e58b8ae8260b437254b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 23 Sep 2023 06:06:20 -0500 Subject: [PATCH 166/293] Make virtual --- src/Mathematics.NET/Core/IComplex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index ae35f03c..bcf1c5cd 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -266,5 +266,5 @@ protected static abstract bool TryConvertToTruncating(T value, [MaybeNullWhen /// Convert a value of type to one of type /// The value to convert - static abstract implicit operator T(U x); + static virtual implicit operator T(U x) => T.CreateTruncating(x); } From b109d495cea2c10a231968433c50137d9553e96d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 23 Sep 2023 06:48:19 -0500 Subject: [PATCH 167/293] Create implementation of rational numbers --- src/Mathematics.NET/Core/Rational.cs | 527 +++++++++++++++++++++++++++ 1 file changed, 527 insertions(+) create mode 100644 src/Mathematics.NET/Core/Rational.cs diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs new file mode 100644 index 00000000..46cbb1c5 --- /dev/null +++ b/src/Mathematics.NET/Core/Rational.cs @@ -0,0 +1,527 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Mathematics.NET.Core; + +/// Represents a rational number +/// A type that implements and +/// A type that implements and +[Serializable] +[StructLayout(LayoutKind.Sequential)] +public readonly struct Rational : IRational, T, U> + where T : IBinaryInteger, IMinMaxValue + where U : IFloatingPointIeee754, IMinMaxValue +{ + private static U s_ten = U.Exp10(U.One); + + public static readonly Rational Zero = T.Zero; + public static readonly Rational One = T.One; + public static readonly Rational Two = T.One + T.One; + + public static readonly Rational MaxValue = T.MaxValue; + public static readonly Rational MinValue = T.MinValue; + + public static readonly Rational NaN = new(T.Zero, T.Zero); + public static readonly Rational NegativeInfinity = new(T.MinValue, T.Zero); + public static readonly Rational PositiveInfinity = new(T.MaxValue, T.Zero); + + private readonly T _numerator; + private readonly T _denominator; + + public Rational(T p) + { + _numerator = p; + _denominator = T.One; + } + + /// This construct prevents negative numbers from being in the denominator; some methods, such as the ones inherited from , have been written to rely on this fact. + /// The numerator + /// The denominator + public Rational(T p, T q) + { + if (q == T.Zero) + { + _numerator = T.Zero; + _denominator = T.Zero; + } + else + { + if (q > T.Zero) + { + _numerator = p; + _denominator = q; + } + else + { + _numerator = -p; + _denominator = -q; + } + } + } + + // + // Rational number properties + // + + public T Num => _numerator; + public T Den => _denominator; + + public Real Re => (U)this; + public U Value => (U)this; + + // + // Constants + // + + static Rational IComplex, U>.Zero => Zero; + static Rational IComplex, U>.One => One; + static Rational IComplex, U>.Two => Zero; + static Rational IComplex, U>.NaN => NaN; + static Rational IMinMaxValue>.MaxValue => MaxValue; + static Rational IMinMaxValue>.MinValue => MinValue; + + // + // Operators + // + + public static Rational operator -(Rational x) => x + One; + + public static Rational operator --(Rational x) => new(x._numerator, x._denominator); + + public static Rational operator ++(Rational x) => new(x._numerator, x._denominator); + + public static Rational operator +(Rational x, Rational y) + { + var lcm = LCM(x._denominator, y._denominator); + return new(lcm / x._denominator * x._numerator + lcm / y._denominator * y._numerator, lcm); + } + public static Rational operator -(Rational x, Rational y) + { + var lcm = LCM(x._denominator, y._denominator); + return new(lcm / x._denominator * x._numerator - lcm / y._denominator * y._numerator, lcm); + } + + public static Rational operator *(Rational x, Rational y) + { + var num = x._numerator * y._numerator; + var den = x._denominator * y._denominator; + var gcd = GCD(num, den); + return new(num / gcd, den / gcd); + } + + public static Rational operator /(Rational x, Rational y) + { + if (y._denominator == T.Zero) + { + return NaN; + } + + var num = x._numerator * y._denominator; + var den = x._denominator * y._numerator; + var gcd = GCD(num, den); + return new(num / gcd, den / gcd); + } + + // + // Equality + // + + public static bool operator ==(Rational left, Rational right) + { + return left._numerator == right._numerator && left._denominator == right._denominator; + } + + public static bool operator !=(Rational left, Rational right) + { + return left._numerator != right._numerator || left._denominator != right._denominator; + } + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Rational other && Equals(other); + + public bool Equals(Rational value) + { + return _numerator.Equals(value._numerator) && _denominator.Equals(value._denominator); + } + + public override int GetHashCode() => HashCode.Combine(_numerator, _denominator); + + // + // Comparison + // + + public static bool operator <(Rational x, Rational y) + { + return x._numerator * y._denominator < y._numerator * x._denominator; + } + + public static bool operator >(Rational x, Rational y) + { + return x._numerator * y._denominator > y._numerator * x._denominator; + } + + public static bool operator <=(Rational x, Rational y) + { + return x._numerator * y._denominator <= y._numerator * x._denominator; + } + + public static bool operator >=(Rational x, Rational y) + { + return x._numerator * y._denominator >= y._numerator * x._denominator; + } + + public int CompareTo(object? obj) + { + if (obj is null) + { + return 1; + } + + if (obj is Rational other) + { + return CompareTo(other); + } + + throw new ArgumentException("Argument is not a rational number"); + } + + public int CompareTo(Rational value) + { + if (this < value) + { + return -1; + } + else if (this > value) + { + return 1; + } + else + { + return 0; + } + } + + // + // Formatting + // + + public override string ToString() => ToString(null, null); + + public string ToString(string? format, IFormatProvider? provider) + { + format = string.IsNullOrEmpty(format) ? "MINIMAL" : format.ToUpperInvariant(); + provider ??= NumberFormatInfo.InvariantInfo; + + if (format is "MINIMAL") + { + if (_numerator == T.Zero || _denominator == T.One) + { + return string.Format(provider, "{0}", _numerator.ToString(null, provider)); + } + return string.Format(provider, "({0} / {1})", _numerator.ToString(null, provider), _denominator.ToString(null, provider)); + } + else if (format is "ALL") + { + return string.Format(provider, "({0} / {1})", _numerator.ToString(null, provider), _denominator.ToString(null, provider)); + } + else + { + throw new FormatException($"The \"{format}\" format is not supported."); + } + } + + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + format = format.IsEmpty ? "MINIMAL" : format.ToString().ToUpperInvariant(); + provider ??= NumberFormatInfo.InvariantInfo; + + throw new NotImplementedException(); + } + + // + // Parsing + // + + public static Rational Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); + + public static Rational Parse(ReadOnlySpan s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); + + public static Rational Parse(string s, NumberStyles style, IFormatProvider? provider) + { + ArgumentNullException.ThrowIfNull(s); + return Parse((ReadOnlySpan)s, style, provider); + } + + public static Rational Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) + { + if (!TryParse(s, style, provider, out Rational result)) + { + return NaN; + } + return result; + } + + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out Rational result) + => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); + + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out Rational result) + => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); + + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Rational result) + => TryParse((ReadOnlySpan)s, style, provider, out result); + + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out Rational result) + { + s = s.Trim(); + int openParenthesis = s.IndexOf('('); + int split = s.IndexOf('/'); + int closeParenthesis = s.IndexOf(')'); + + // There a minimum of 5 characters for "(0/0)". + if (s.Length < 5 || openParenthesis == -1 || split == -1 || closeParenthesis == -1 || openParenthesis > split || openParenthesis > closeParenthesis || split > closeParenthesis) + { + result = Zero; + return false; + } + + if (!T.TryParse(s.Slice(openParenthesis + 1, split - 1), style, provider, out T? numerator)) + { + result = Zero; + return false; + } + + if (!T.TryParse(s.Slice(split + 1, closeParenthesis - split - 1), style, provider, out T? denominator)) + { + result = Zero; + return false; + } + + result = new(numerator, denominator); + return true; + } + + // + // Methods + // + + public static Rational Abs(Rational x) => new(T.Abs(x._numerator), T.Abs(x._denominator)); + + public static Rational Conjugate(Rational x) => x; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static T GCD(T p, T q) + { + p = T.Abs(p); + q = T.Abs(q); + while (p != T.Zero && q != T.Zero) + { + if (p > q) + { + p %= q; + } + else + { + q %= p; + } + } + return p | q; + } + + public static bool IsFinite(Rational x) => !T.IsZero(x._denominator); + + public static bool IsInfinity(Rational x) => T.IsZero(x._denominator); + + public static bool IsNaN(Rational x) => T.IsZero(x._numerator) && T.IsZero(x._denominator); + + public static bool IsZero(Rational x) => T.IsZero(x._numerator); + + public static bool IsNegativeInfinity(Rational x) => x._numerator == T.MinValue && T.IsZero(x._denominator); + + public static bool IsPositiveInfinity(Rational x) => x._numerator == T.MaxValue && T.IsZero(x._denominator); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static T LCM(T p, T q) + { + p = T.Abs(p); + q = T.Abs(q); + T holdP = p; + T holdQ = q; + while (p != T.Zero && q != T.Zero) + { + if (p > q) + { + p %= q; + } + else + { + q %= p; + } + } + return holdP / (p | q) * holdQ; + } + + public static Rational Reciprocate(Rational x) + { + if (x._numerator == T.Zero) + { + return NaN; + } + return new(x._denominator, x._numerator); + } + + public static Rational Reduce(Rational x) + { + var gcd = GCD(x._numerator, x._denominator); + if (gcd == T.One) + { + return x; + } + return new(x._numerator / gcd, x._denominator / gcd); + } + + public static bool TryConvertFromChecked(V value, out Rational result) + where V : INumberBase + { + if (V.IsInteger(value)) + { + result = T.CreateChecked(value); + return true; + } + else if (value is IFloatingPointIeee754 floatingPointNumber) + { + result = (Rational)(U)floatingPointNumber; + return true; + } + else + { + result = default; + return false; + } + } + + public static bool TryConvertFromSaturating(V value, out Rational result) + where V : INumberBase + { + if (V.IsInteger(value)) + { + result = T.CreateSaturating(value); + return true; + } + else if (value is IFloatingPointIeee754 floatingPointNumber) + { + result = (Rational)(U)floatingPointNumber; + return true; + } + else + { + result = default; + return false; + } + } + + public static bool TryConvertFromTruncating(V value, out Rational result) + where V : INumberBase + { + if (V.IsInteger(value)) + { + result = T.CreateTruncating(value); + return true; + } + else if (value is IFloatingPointIeee754 floatingPointNumber) + { + result = (Rational)(U)floatingPointNumber; + return true; + } + else + { + result = default; + return false; + } + } + + public static bool TryConvertToChecked(Rational value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + result = V.CreateChecked(checked((U)value)); + return true; + } + + public static bool TryConvertToSaturating(Rational value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + result = V.CreateSaturating(U.CreateSaturating(value._numerator) / U.CreateSaturating(value._denominator)); + return true; + } + + public static bool TryConvertToTruncating(Rational value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + result = V.CreateTruncating(U.CreateTruncating(value._numerator) / U.CreateTruncating(value._denominator)); + return true; + } + + // + // Implicit operators + // + + public static implicit operator Rational(T p) => new(p); + + // + // Explicit operators + // + + // TODO: Find a better implementation + public static explicit operator Rational(U x) + { + if (U.IsNaN(x) || U.IsInfinity(x)) + { + return NaN; + } + + var n = U.Zero; + while (x != U.Floor(x)) + { + x *= s_ten; + n++; + } + + T num = T.CreateChecked(x); + T den = T.CreateChecked(U.Pow(s_ten, n)); + var gcd = GCD(num, den); + + return new(num / gcd, den / gcd); + } + + public static explicit operator checked U(Rational x) => checked(U.CreateChecked(x._numerator) / U.CreateChecked(x._denominator)); + + public static explicit operator U(Rational x) => U.CreateChecked(x._numerator) / U.CreateChecked(x._denominator); +} From 641775cf139749da08973b179c6130c8e18a63e5 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 24 Sep 2023 09:24:57 -0500 Subject: [PATCH 168/293] Update documentation comment --- src/Mathematics.NET/Core/IComplex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index bcf1c5cd..0c0f4d18 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -226,7 +226,7 @@ protected static abstract bool TryConvertFromTruncating(V value, [MaybeNullWh /// The value to convert /// The result of the conversion /// true if the conversion was successful; otherwise, false - /// The value is not representable by the type . + /// The value is not representable by the target type. protected static abstract bool TryConvertToChecked(T value, [MaybeNullWhen(false)] out V result) where V : INumberBase; From 7c0eb69f4b3403da3d1c92d6278462f1334d422c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 24 Sep 2023 09:25:05 -0500 Subject: [PATCH 169/293] Add test for TryFormat --- tests/Mathematics.NET.Tests/Core/RationalTests.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/RationalTests.cs b/tests/Mathematics.NET.Tests/Core/RationalTests.cs index e05ea661..47ea9559 100644 --- a/tests/Mathematics.NET.Tests/Core/RationalTests.cs +++ b/tests/Mathematics.NET.Tests/Core/RationalTests.cs @@ -31,4 +31,15 @@ namespace Mathematics.NET.Tests.Core; [TestCategory("Core"), TestCategory("Rational Number")] public sealed class RationalTests { + [TestMethod] + [DataRow(3, 4, 7)] + public void TryFormat_RationalOfIntAndDoubleWithAdequateDestinationLength_ReturnsTrue(int inNum, int inDen, int length) + { + Rational p = new(inNum, inDen); + + Span span = new char[length]; + var actual = p.TryFormat(span, out int _, null, null); + + Assert.IsTrue(actual); + } } From 7112cbb68d0b153cbcaa480de364a1b3641d4942 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 24 Sep 2023 09:25:35 -0500 Subject: [PATCH 170/293] Implement TryFormat --- src/Mathematics.NET/Core/Rational.cs | 105 ++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs index 46cbb1c5..aa030fe4 100644 --- a/src/Mathematics.NET/Core/Rational.cs +++ b/src/Mathematics.NET/Core/Rational.cs @@ -264,7 +264,110 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = format.IsEmpty ? "MINIMAL" : format.ToString().ToUpperInvariant(); provider ??= NumberFormatInfo.InvariantInfo; - throw new NotImplementedException(); + if (format is "MINIMAL") + { + int charsCurrentlyWritten = 0; + + bool tryFormatSucceeded; + int tryFormatCharsWritten; + + if (_numerator == T.Zero) + { + if (destination.Length < 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + charsWritten = 1; + destination[0] = '0'; + return true; + } + + if (_denominator == T.One) + { + if (destination.Length < 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + tryFormatSucceeded = _numerator.TryFormat(destination[charsCurrentlyWritten..], out tryFormatCharsWritten, null, provider); + charsCurrentlyWritten += tryFormatCharsWritten; + if (!tryFormatSucceeded || destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + charsWritten = charsCurrentlyWritten; + return true; + } + + return TryFormatAllInternal(_numerator, _denominator, destination, out charsWritten, provider); + } + else if (format is "ALL") + { + return TryFormatAllInternal(_numerator, _denominator, destination, out charsWritten, provider); + } + else + { + throw new FormatException($"The \"{format}\" format is not supported."); + } + + static bool TryFormatAllInternal(T num, T den, Span destination, out int charsWritten, IFormatProvider? provider) + { + var charsCurrentlyWritten = 0; + + // There are a minimum of 7 characters for "(0 / 0)" + if (destination.Length < 7) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + destination[charsCurrentlyWritten++] = '('; + + bool tryFormatSucceeded = num.TryFormat(destination[charsCurrentlyWritten..], out int tryFormatCharsWritten, null, provider); + charsCurrentlyWritten += tryFormatCharsWritten; + if (!tryFormatSucceeded || destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + destination[charsCurrentlyWritten++] = ' '; + if (destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + destination[charsCurrentlyWritten++] = '/'; + if (destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + destination[charsCurrentlyWritten++] = ' '; + if (destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + tryFormatSucceeded = den.TryFormat(destination[charsCurrentlyWritten..], out tryFormatCharsWritten, null, provider); + charsCurrentlyWritten += tryFormatCharsWritten; + if (!tryFormatSucceeded || destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + destination[charsCurrentlyWritten++] = ')'; + + charsWritten = charsCurrentlyWritten; + return true; + } } // From 007f442232cc57ab5a6e97b370927c32377b670b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 25 Sep 2023 03:45:17 -0500 Subject: [PATCH 171/293] Use local method --- src/Mathematics.NET/Core/Complex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index ef261aab..2182c844 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -83,7 +83,7 @@ public Complex(Real real, Real imaginary) public Real Re => _real; public Real Im => _imaginary; - public Real Magnitude => T.Hypot(_real.Value, _imaginary.Value); + public Real Magnitude => Hypot(_real.Value, _imaginary.Value); public Real Phase => T.Atan2(_imaginary.Value, _real.Value); // From 23fb19fec4dff39403dc5e08917df5feada5dcdd Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 25 Sep 2023 03:46:06 -0500 Subject: [PATCH 172/293] Move method --- src/Mathematics.NET/Core/Complex.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs index 2182c844..f7474e9d 100644 --- a/src/Mathematics.NET/Core/Complex.cs +++ b/src/Mathematics.NET/Core/Complex.cs @@ -324,6 +324,11 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static Complex Abs(Complex z) => Hypot(z._real.Value, z._imaginary.Value); + public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); + + public static Complex FromPolarForm(Real magnitude, Real phase) + => new(magnitude * T.Cos(phase.Value), magnitude * T.Sin(phase.Value)); + private static T Hypot(T x, T y) { // Factor out the larger value to avoid possible overflow @@ -357,11 +362,6 @@ private static T Hypot(T x, T y) } } - public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); - - public static Complex FromPolarForm(Real magnitude, Real phase) - => new(magnitude * T.Cos(phase.Value), magnitude * T.Sin(phase.Value)); - public static bool IsFinite(Complex z) => Real.IsFinite(z._real) && Real.IsFinite(z._imaginary); public static bool IsInfinity(Complex z) => Real.IsInfinity(z._real) || Real.IsInfinity(z._imaginary); From 57499860916d6b6e1fd3bdd2d755516c9850433a Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 25 Sep 2023 04:57:03 -0500 Subject: [PATCH 173/293] Add GitHub workflow - Add solution folders --- .../workflows/generate-documentation-site.yml | 26 +++++++++++++++++++ Mathematics.NET.sln | 8 ++++++ 2 files changed, 34 insertions(+) create mode 100644 .github/workflows/generate-documentation-site.yml diff --git a/.github/workflows/generate-documentation-site.yml b/.github/workflows/generate-documentation-site.yml new file mode 100644 index 00000000..115a40ce --- /dev/null +++ b/.github/workflows/generate-documentation-site.yml @@ -0,0 +1,26 @@ +# Generate the documentation site for Mathematics.NET + +name: Generate Ducumentation Site for Mathematics.NET + +on: + workflow_dispatch: + +jobs: + publish-docs: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Dotnet Setup + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 7.x + + - run: dotnet tool update -g docfx + - run: docfx docs/docfx.json + + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: docs/_site diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index 91ab9b11..eff07d1d 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -25,6 +25,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.Tests", "te EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.Benchmarks", "tests\Mathematics.NET.Benchmarks\Mathematics.NET.Benchmarks.csproj", "{DD2741ED-C10C-4D76-8CEB-C378F3626D0D}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{9EB26D49-7E18-4404-BDCB-D26B827C4A22}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{1B32D7FF-257B-49BB-B495-D64E5E6C4C82}" + ProjectSection(SolutionItems) = preProject + .github\workflows\generate-gh-pages.yml = .github\workflows\generate-gh-pages.yml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -61,6 +68,7 @@ Global {173526DA-4560-4D64-81EF-5D757A44FBFA} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} {A608C0E2-D431-45E9-AD05-A49115BE59AB} = {91DB0FE7-BAA4-4D16-8A39-65332DD53662} {DD2741ED-C10C-4D76-8CEB-C378F3626D0D} = {91DB0FE7-BAA4-4D16-8A39-65332DD53662} + {1B32D7FF-257B-49BB-B495-D64E5E6C4C82} = {9EB26D49-7E18-4404-BDCB-D26B827C4A22} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {179D9282-B1D9-42EC-A6A0-C1970012ED73} From a3c2e52cf136df1805d9f98da82022e106083e28 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 25 Sep 2023 05:42:27 -0500 Subject: [PATCH 174/293] Update generate-documentation-site.yml --- .github/workflows/generate-documentation-site.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/generate-documentation-site.yml b/.github/workflows/generate-documentation-site.yml index 115a40ce..9a4a7315 100644 --- a/.github/workflows/generate-documentation-site.yml +++ b/.github/workflows/generate-documentation-site.yml @@ -1,10 +1,19 @@ -# Generate the documentation site for Mathematics.NET +# Generate documentation for Mathematics.NET -name: Generate Ducumentation Site for Mathematics.NET +name: Generate Ducumentation for Mathematics.NET on: workflow_dispatch: +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + jobs: publish-docs: runs-on: ubuntu-latest From 6dc16b94cd9fb4b5de98820225527c1983b61bea Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 25 Sep 2023 07:20:59 -0500 Subject: [PATCH 175/293] Update generate-documentation-site.yml --- .github/workflows/generate-documentation-site.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/generate-documentation-site.yml b/.github/workflows/generate-documentation-site.yml index 9a4a7315..f3b04979 100644 --- a/.github/workflows/generate-documentation-site.yml +++ b/.github/workflows/generate-documentation-site.yml @@ -6,13 +6,13 @@ on: workflow_dispatch: permissions: - contents: read + contents: write pages: write id-token: write concurrency: group: "pages" - cancel-in-progress: false + cancel-in-progress: true jobs: publish-docs: From 15fbb8e489f91e6ef30e4ecfb00a8736d0e470f2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 25 Sep 2023 07:36:57 -0500 Subject: [PATCH 176/293] Generate site on push to main --- .github/workflows/generate-documentation-site.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/generate-documentation-site.yml b/.github/workflows/generate-documentation-site.yml index f3b04979..0e10c6e9 100644 --- a/.github/workflows/generate-documentation-site.yml +++ b/.github/workflows/generate-documentation-site.yml @@ -3,6 +3,9 @@ name: Generate Ducumentation for Mathematics.NET on: + push: + branches: + - main workflow_dispatch: permissions: From 69ddff729a23a11ac71ff741dca9c7d292705f86 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 25 Sep 2023 08:05:15 -0500 Subject: [PATCH 177/293] Add cname - Add force_orphan option and set to true --- .github/workflows/generate-documentation-site.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/generate-documentation-site.yml b/.github/workflows/generate-documentation-site.yml index 0e10c6e9..c89105fe 100644 --- a/.github/workflows/generate-documentation-site.yml +++ b/.github/workflows/generate-documentation-site.yml @@ -36,3 +36,5 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: docs/_site + cname: mathematics.hamlettanyavong.com + force_orphan: true From c7f067716c4c12ff1f693e74d639dc648055c450 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 25 Sep 2023 08:12:36 -0500 Subject: [PATCH 178/293] Update generate-documentation-site.yml - Update name --- .github/workflows/generate-documentation-site.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-documentation-site.yml b/.github/workflows/generate-documentation-site.yml index c89105fe..5a871c04 100644 --- a/.github/workflows/generate-documentation-site.yml +++ b/.github/workflows/generate-documentation-site.yml @@ -1,6 +1,6 @@ # Generate documentation for Mathematics.NET -name: Generate Ducumentation for Mathematics.NET +name: generate-pages on: push: From 361e7d94e8fdcc5973de9b4516107f60e69ebfba Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:30:45 -0500 Subject: [PATCH 179/293] Update application project name - Rename project from Application to Mathematics.NET.DevApp - Update gitignore to reflect this change --- .gitignore | 2 +- Mathematics.NET.sln | 14 +++++++------- .../Mathematics.NET.DevApp.csproj | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 src/Mathematics.NET.DevApp/Mathematics.NET.DevApp.csproj diff --git a/.gitignore b/.gitignore index 14b596a1..b011f884 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore # Manually-added items -/src/Application/ +/src/Mathematics.NET.DevApp/*.cs *.runsettings # Temporary diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index eff07d1d..29fe8cd8 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -19,8 +19,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{91DB0FE7 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.SourceGenerators", "src\Mathematics.NET.SourceGenerators\Mathematics.NET.SourceGenerators.csproj", "{557642D0-685A-4846-AD31-DC764692E853}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application", "src\Application\Application.csproj", "{173526DA-4560-4D64-81EF-5D757A44FBFA}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.Tests", "tests\Mathematics.NET.Tests\Mathematics.NET.Tests.csproj", "{A608C0E2-D431-45E9-AD05-A49115BE59AB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.Benchmarks", "tests\Mathematics.NET.Benchmarks\Mathematics.NET.Benchmarks.csproj", "{DD2741ED-C10C-4D76-8CEB-C378F3626D0D}" @@ -32,6 +30,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .github\workflows\generate-gh-pages.yml = .github\workflows\generate-gh-pages.yml EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET.DevApp", "src\Mathematics.NET.DevApp\Mathematics.NET.DevApp.csproj", "{89C3482F-0027-483E-AAD7-5E12453915B3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -46,10 +46,6 @@ Global {557642D0-685A-4846-AD31-DC764692E853}.Debug|x64.Build.0 = Debug|x64 {557642D0-685A-4846-AD31-DC764692E853}.Release|x64.ActiveCfg = Release|x64 {557642D0-685A-4846-AD31-DC764692E853}.Release|x64.Build.0 = Release|x64 - {173526DA-4560-4D64-81EF-5D757A44FBFA}.Debug|x64.ActiveCfg = Debug|x64 - {173526DA-4560-4D64-81EF-5D757A44FBFA}.Debug|x64.Build.0 = Debug|x64 - {173526DA-4560-4D64-81EF-5D757A44FBFA}.Release|x64.ActiveCfg = Release|x64 - {173526DA-4560-4D64-81EF-5D757A44FBFA}.Release|x64.Build.0 = Release|x64 {A608C0E2-D431-45E9-AD05-A49115BE59AB}.Debug|x64.ActiveCfg = Debug|x64 {A608C0E2-D431-45E9-AD05-A49115BE59AB}.Debug|x64.Build.0 = Debug|x64 {A608C0E2-D431-45E9-AD05-A49115BE59AB}.Release|x64.ActiveCfg = Release|x64 @@ -58,6 +54,10 @@ Global {DD2741ED-C10C-4D76-8CEB-C378F3626D0D}.Debug|x64.Build.0 = Debug|x64 {DD2741ED-C10C-4D76-8CEB-C378F3626D0D}.Release|x64.ActiveCfg = Release|x64 {DD2741ED-C10C-4D76-8CEB-C378F3626D0D}.Release|x64.Build.0 = Release|x64 + {89C3482F-0027-483E-AAD7-5E12453915B3}.Debug|x64.ActiveCfg = Debug|x64 + {89C3482F-0027-483E-AAD7-5E12453915B3}.Debug|x64.Build.0 = Debug|x64 + {89C3482F-0027-483E-AAD7-5E12453915B3}.Release|x64.ActiveCfg = Release|x64 + {89C3482F-0027-483E-AAD7-5E12453915B3}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -65,10 +65,10 @@ Global GlobalSection(NestedProjects) = preSolution {558EB964-1CE7-4786-9656-6EEC36A7072E} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} {557642D0-685A-4846-AD31-DC764692E853} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} - {173526DA-4560-4D64-81EF-5D757A44FBFA} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} {A608C0E2-D431-45E9-AD05-A49115BE59AB} = {91DB0FE7-BAA4-4D16-8A39-65332DD53662} {DD2741ED-C10C-4D76-8CEB-C378F3626D0D} = {91DB0FE7-BAA4-4D16-8A39-65332DD53662} {1B32D7FF-257B-49BB-B495-D64E5E6C4C82} = {9EB26D49-7E18-4404-BDCB-D26B827C4A22} + {89C3482F-0027-483E-AAD7-5E12453915B3} = {DAD16084-D255-4DF4-A20D-077E92B88EC5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {179D9282-B1D9-42EC-A6A0-C1970012ED73} diff --git a/src/Mathematics.NET.DevApp/Mathematics.NET.DevApp.csproj b/src/Mathematics.NET.DevApp/Mathematics.NET.DevApp.csproj new file mode 100644 index 00000000..10014264 --- /dev/null +++ b/src/Mathematics.NET.DevApp/Mathematics.NET.DevApp.csproj @@ -0,0 +1,15 @@ + + + + Exe + net7.0 + enable + enable + x64 + + + + + + + From 800a2cc9ada5136d7ce9ce8c084a654cf12763ea Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 25 Sep 2023 20:22:53 -0500 Subject: [PATCH 180/293] Remove type parameter constraint - Remove IMinMaxValue from IRational. This will let us use BigInteger with rational numbers --- src/Mathematics.NET/Core/IRational.cs | 4 ++-- src/Mathematics.NET/Core/Rational.cs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Mathematics.NET/Core/IRational.cs b/src/Mathematics.NET/Core/IRational.cs index e1bddc1e..afabffbf 100644 --- a/src/Mathematics.NET/Core/IRational.cs +++ b/src/Mathematics.NET/Core/IRational.cs @@ -31,11 +31,11 @@ namespace Mathematics.NET.Core; /// Defines support for rational numbers /// A type that implements the interface -/// A type that implements and +/// A type that implements /// A type that implements and public interface IRational : IReal where T : IRational - where U : IBinaryInteger, IMinMaxValue + where U : IBinaryInteger where V : IFloatingPointIeee754, IMinMaxValue { /// Get the numerator of the rational number diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs index aa030fe4..80f38b74 100644 --- a/src/Mathematics.NET/Core/Rational.cs +++ b/src/Mathematics.NET/Core/Rational.cs @@ -34,12 +34,12 @@ namespace Mathematics.NET.Core; /// Represents a rational number -/// A type that implements and +/// A type that implements /// A type that implements and [Serializable] [StructLayout(LayoutKind.Sequential)] public readonly struct Rational : IRational, T, U> - where T : IBinaryInteger, IMinMaxValue + where T : IBinaryInteger where U : IFloatingPointIeee754, IMinMaxValue { private static U s_ten = U.Exp10(U.One); @@ -48,12 +48,12 @@ namespace Mathematics.NET.Core; public static readonly Rational One = T.One; public static readonly Rational Two = T.One + T.One; - public static readonly Rational MaxValue = T.MaxValue; - public static readonly Rational MinValue = T.MinValue; + public static readonly Rational MaxValue = T.CreateSaturating(U.MaxValue); + public static readonly Rational MinValue = T.CreateSaturating(U.MinValue); public static readonly Rational NaN = new(T.Zero, T.Zero); - public static readonly Rational NegativeInfinity = new(T.MinValue, T.Zero); - public static readonly Rational PositiveInfinity = new(T.MaxValue, T.Zero); + public static readonly Rational NegativeInfinity = new(-T.One, T.Zero); + public static readonly Rational PositiveInfinity = new(T.One, T.Zero); private readonly T _numerator; private readonly T _denominator; @@ -467,9 +467,9 @@ private static T GCD(T p, T q) public static bool IsZero(Rational x) => T.IsZero(x._numerator); - public static bool IsNegativeInfinity(Rational x) => x._numerator == T.MinValue && T.IsZero(x._denominator); + public static bool IsNegativeInfinity(Rational x) => x._numerator == -T.One && T.IsZero(x._denominator); - public static bool IsPositiveInfinity(Rational x) => x._numerator == T.MaxValue && T.IsZero(x._denominator); + public static bool IsPositiveInfinity(Rational x) => x._numerator == T.One && T.IsZero(x._denominator); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static T LCM(T p, T q) From a5f77161d6017241a153ecf281e820ed5ea905da Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:02:44 -0500 Subject: [PATCH 181/293] Create Extensions.cs --- src/Mathematics.NET/Core/Extensions.cs | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/Mathematics.NET/Core/Extensions.cs diff --git a/src/Mathematics.NET/Core/Extensions.cs b/src/Mathematics.NET/Core/Extensions.cs new file mode 100644 index 00000000..8ccd7740 --- /dev/null +++ b/src/Mathematics.NET/Core/Extensions.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Numerics; + +namespace Mathematics.NET.Core; + +public static class Extensions +{ + public static Rational Reduce(this Rational r) + where T : IBinaryInteger + where U : IFloatingPointIeee754, IMinMaxValue + => Rational.Reduce(r); +} From f4c023bc997352d7d42c997a783f737a6cc487d2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:03:51 -0500 Subject: [PATCH 182/293] Update RationalTests.cs - Add test for validating rational number reduction --- tests/Mathematics.NET.Tests/Core/RationalTests.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/RationalTests.cs b/tests/Mathematics.NET.Tests/Core/RationalTests.cs index 47ea9559..e52f200c 100644 --- a/tests/Mathematics.NET.Tests/Core/RationalTests.cs +++ b/tests/Mathematics.NET.Tests/Core/RationalTests.cs @@ -31,6 +31,18 @@ namespace Mathematics.NET.Tests.Core; [TestCategory("Core"), TestCategory("Rational Number")] public sealed class RationalTests { + [TestMethod] + [DataRow(6, 8, 3, 4)] + public void Reduce_RationalOfIntAndDouble_ReturnsReducedFraction(int inNum, int inDen, int expectedNum, int expectedDen) + { + Rational p = new(inNum, inDen); + Rational expected = new(expectedNum, expectedDen); + + var actual = p.Reduce(); + + Assert.AreEqual(expected, actual); + } + [TestMethod] [DataRow(3, 4, 7)] public void TryFormat_RationalOfIntAndDoubleWithAdequateDestinationLength_ReturnsTrue(int inNum, int inDen, int length) From bdd92dbb22407d447ea309a8726c3e10db7f9ff9 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:44:45 -0500 Subject: [PATCH 183/293] Update RationalTests.cs - Add test for validating rational number addition --- tests/Mathematics.NET.Tests/Core/RationalTests.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/RationalTests.cs b/tests/Mathematics.NET.Tests/Core/RationalTests.cs index e52f200c..a18d2b49 100644 --- a/tests/Mathematics.NET.Tests/Core/RationalTests.cs +++ b/tests/Mathematics.NET.Tests/Core/RationalTests.cs @@ -31,6 +31,19 @@ namespace Mathematics.NET.Tests.Core; [TestCategory("Core"), TestCategory("Rational Number")] public sealed class RationalTests { + [TestMethod] + [DataRow(2, 4, 5, 3, 13, 6)] + public void Add_TwoRationalsOfIntAndDouble_ReturnsReducedSum(int inANum, int inADen, int inBNum, int inBDen, int expectedNum, int expectedDen) + { + Rational a = new(inANum, inADen); + Rational b = new(inBNum, inBDen); + Rational expected = new(expectedNum, expectedDen); + + var actual = a + b; + + Assert.AreEqual(expected, actual); + } + [TestMethod] [DataRow(6, 8, 3, 4)] public void Reduce_RationalOfIntAndDouble_ReturnsReducedFraction(int inNum, int inDen, int expectedNum, int expectedDen) From 77c70f1632dc282771284141bf8636e5fa438202 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 27 Sep 2023 06:17:08 -0500 Subject: [PATCH 184/293] Update Rational.cs - Add new line --- src/Mathematics.NET/Core/Rational.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs index 80f38b74..b68e4868 100644 --- a/src/Mathematics.NET/Core/Rational.cs +++ b/src/Mathematics.NET/Core/Rational.cs @@ -125,6 +125,7 @@ public Rational(T p, T q) var lcm = LCM(x._denominator, y._denominator); return new(lcm / x._denominator * x._numerator + lcm / y._denominator * y._numerator, lcm); } + public static Rational operator -(Rational x, Rational y) { var lcm = LCM(x._denominator, y._denominator); From 5da936dcd79211589c10416f6d0771e3ad2f92c0 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:39:44 -0500 Subject: [PATCH 185/293] Update Rational.cs - Reduce fractions after addition and subtraction --- src/Mathematics.NET/Core/Rational.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs index b68e4868..6f18ea35 100644 --- a/src/Mathematics.NET/Core/Rational.cs +++ b/src/Mathematics.NET/Core/Rational.cs @@ -123,13 +123,17 @@ public Rational(T p, T q) public static Rational operator +(Rational x, Rational y) { var lcm = LCM(x._denominator, y._denominator); - return new(lcm / x._denominator * x._numerator + lcm / y._denominator * y._numerator, lcm); + var num = lcm / x._denominator * x._numerator + lcm / y._denominator * y._numerator; + var gcd = GCD(num, lcm); + return new(num / gcd, lcm / gcd); } public static Rational operator -(Rational x, Rational y) { var lcm = LCM(x._denominator, y._denominator); - return new(lcm / x._denominator * x._numerator - lcm / y._denominator * y._numerator, lcm); + var num = lcm / x._denominator * x._numerator - lcm / y._denominator * y._numerator; + var gcd = GCD(num, lcm); + return new(num / gcd, lcm / gcd); } public static Rational operator *(Rational x, Rational y) From 59c1ef2ff461024c7e53ecc8c8eeb1cdc746f335 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 27 Sep 2023 21:32:05 -0500 Subject: [PATCH 186/293] Add test for rational number multiplication --- tests/Mathematics.NET.Tests/Core/RationalTests.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/RationalTests.cs b/tests/Mathematics.NET.Tests/Core/RationalTests.cs index a18d2b49..25ae1955 100644 --- a/tests/Mathematics.NET.Tests/Core/RationalTests.cs +++ b/tests/Mathematics.NET.Tests/Core/RationalTests.cs @@ -44,6 +44,19 @@ public void Add_TwoRationalsOfIntAndDouble_ReturnsReducedSum(int inANum, int inA Assert.AreEqual(expected, actual); } + [TestMethod] + [DataRow(2, 3, 4, 8, 1, 3)] + public void Multiply_TwoRationalsOfIntAndDouble_ReturnsReducedProduct(int inANum, int inADen, int inBNum, int inBDen, int expectedNum, int expectedDen) + { + Rational x = new(inANum, inADen); + Rational y = new(inBNum, inBDen); + Rational expected = new(expectedNum, expectedDen); + + var actual = x * y; + + Assert.AreEqual(expected, actual); + } + [TestMethod] [DataRow(6, 8, 3, 4)] public void Reduce_RationalOfIntAndDouble_ReturnsReducedFraction(int inNum, int inDen, int expectedNum, int expectedDen) From a29a7ce4f59868ec23420c0366ffaf9f09acc6cb Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 27 Sep 2023 21:34:39 -0500 Subject: [PATCH 187/293] Update RationalTests.cs - Rename variables --- tests/Mathematics.NET.Tests/Core/RationalTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Mathematics.NET.Tests/Core/RationalTests.cs b/tests/Mathematics.NET.Tests/Core/RationalTests.cs index 25ae1955..94b075f1 100644 --- a/tests/Mathematics.NET.Tests/Core/RationalTests.cs +++ b/tests/Mathematics.NET.Tests/Core/RationalTests.cs @@ -35,11 +35,11 @@ public sealed class RationalTests [DataRow(2, 4, 5, 3, 13, 6)] public void Add_TwoRationalsOfIntAndDouble_ReturnsReducedSum(int inANum, int inADen, int inBNum, int inBDen, int expectedNum, int expectedDen) { - Rational a = new(inANum, inADen); - Rational b = new(inBNum, inBDen); + Rational x = new(inANum, inADen); + Rational y = new(inBNum, inBDen); Rational expected = new(expectedNum, expectedDen); - var actual = a + b; + var actual = x + y; Assert.AreEqual(expected, actual); } From d883da52c89a28f8771421e290331ccdf4020610 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 27 Sep 2023 22:00:33 -0500 Subject: [PATCH 188/293] Inline variable declaration --- src/Mathematics.NET/Core/Rational.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs index 6f18ea35..84896777 100644 --- a/src/Mathematics.NET/Core/Rational.cs +++ b/src/Mathematics.NET/Core/Rational.cs @@ -274,7 +274,6 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan int charsCurrentlyWritten = 0; bool tryFormatSucceeded; - int tryFormatCharsWritten; if (_numerator == T.Zero) { @@ -297,7 +296,7 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan return false; } - tryFormatSucceeded = _numerator.TryFormat(destination[charsCurrentlyWritten..], out tryFormatCharsWritten, null, provider); + tryFormatSucceeded = _numerator.TryFormat(destination[charsCurrentlyWritten..], out int tryFormatCharsWritten, null, provider); charsCurrentlyWritten += tryFormatCharsWritten; if (!tryFormatSucceeded || destination.Length < charsCurrentlyWritten + 1) { From e8c3beb01398dee8c42d87a437b7a2d56ee25b7d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 28 Sep 2023 02:51:46 -0500 Subject: [PATCH 189/293] Rename file --- Mathematics.NET.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index 29fe8cd8..97e59834 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -27,7 +27,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{9EB2 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{1B32D7FF-257B-49BB-B495-D64E5E6C4C82}" ProjectSection(SolutionItems) = preProject - .github\workflows\generate-gh-pages.yml = .github\workflows\generate-gh-pages.yml + .github\workflows\generate-documentation-site.yml = .github\workflows\generate-documentation-site.yml EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET.DevApp", "src\Mathematics.NET.DevApp\Mathematics.NET.DevApp.csproj", "{89C3482F-0027-483E-AAD7-5E12453915B3}" From 057963b0529fcc9769d92ddc9ee57ada28fb2445 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 28 Sep 2023 02:51:48 -0500 Subject: [PATCH 190/293] Update Mathematics.NET.sln --- Mathematics.NET.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index 97e59834..8ff6fe90 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -30,7 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .github\workflows\generate-documentation-site.yml = .github\workflows\generate-documentation-site.yml EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mathematics.NET.DevApp", "src\Mathematics.NET.DevApp\Mathematics.NET.DevApp.csproj", "{89C3482F-0027-483E-AAD7-5E12453915B3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mathematics.NET.DevApp", "src\Mathematics.NET.DevApp\Mathematics.NET.DevApp.csproj", "{89C3482F-0027-483E-AAD7-5E12453915B3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 02781bcebffa50083655fae27a9f7f9603091e9f Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 28 Sep 2023 02:51:53 -0500 Subject: [PATCH 191/293] Update RationalTests.cs --- tests/Mathematics.NET.Tests/Core/RationalTests.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/Mathematics.NET.Tests/Core/RationalTests.cs b/tests/Mathematics.NET.Tests/Core/RationalTests.cs index 94b075f1..83a127e1 100644 --- a/tests/Mathematics.NET.Tests/Core/RationalTests.cs +++ b/tests/Mathematics.NET.Tests/Core/RationalTests.cs @@ -44,6 +44,14 @@ public void Add_TwoRationalsOfIntAndDouble_ReturnsReducedSum(int inANum, int inA Assert.AreEqual(expected, actual); } + [TestMethod] + public void Divide_RationalOfIntAndDoubleByZero_ReturnsNaN() + { + var actual = Rational.One / Rational.Zero; + + Assert.AreEqual(Rational.NaN, actual); + } + [TestMethod] [DataRow(2, 3, 4, 8, 1, 3)] public void Multiply_TwoRationalsOfIntAndDouble_ReturnsReducedProduct(int inANum, int inADen, int inBNum, int inBDen, int expectedNum, int expectedDen) From d69d16639c9032ad5842fe020684f13c4021916f Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 28 Sep 2023 07:11:10 -0500 Subject: [PATCH 192/293] Rename folder --- docs/articles/{getstarted => get_started}/installation.md | 0 docs/articles/toc.yml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/articles/{getstarted => get_started}/installation.md (100%) diff --git a/docs/articles/getstarted/installation.md b/docs/articles/get_started/installation.md similarity index 100% rename from docs/articles/getstarted/installation.md rename to docs/articles/get_started/installation.md diff --git a/docs/articles/toc.yml b/docs/articles/toc.yml index f186e953..d1033fc3 100644 --- a/docs/articles/toc.yml +++ b/docs/articles/toc.yml @@ -3,4 +3,4 @@ - name: Get Started items: - name: Installation - href: getstarted/installation.md + href: get_started/installation.md From 68e05839f86135f323454668d1df23c9af847f09 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 28 Sep 2023 07:11:34 -0500 Subject: [PATCH 193/293] Add page --- docs/articles/fundamentals/numeric-types.md | 70 +++++++++++++++++++++ docs/articles/toc.yml | 4 ++ 2 files changed, 74 insertions(+) create mode 100644 docs/articles/fundamentals/numeric-types.md diff --git a/docs/articles/fundamentals/numeric-types.md b/docs/articles/fundamentals/numeric-types.md new file mode 100644 index 00000000..e36e8ac6 --- /dev/null +++ b/docs/articles/fundamentals/numeric-types.md @@ -0,0 +1,70 @@ +# Numeric Types + +There are three numeric types that can be used to represent complex, real, and rational numbers in Mathematics.NET. + +All Mathematics.NET numbers implement the [IComplex](https://mathematics.hamlettanyavong.com/api/Mathematics.NET.Core.IComplex-2.html) interface. Particularly useful is the fact that, unlike .NET runtime's [INumberBase\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs), `IComplex` defines the `Conjugate` method; this is incredibly helpful in avoiding code duplication for calculations involving complex and real numbers. + +## Floating-Point Types + +Floating-point Mathematics.NET numbers may be backed any number that implements [IFloatingPointIee754\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs) and [IMinMaxValue\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IMinMaxValue.cs), or more specifically, [float](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Single.cs), [double](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Double.cs), and [decimal](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Decimal.cs). + +### Complex Numbers + +To create a complex number, we choose a backing type, in this case `double`, and write +```csharp +Complex z = new(3, 4); +``` +This represents the number $ z = 3+i4 $. We can also specify only one number to create a complex number with no imaginary part +```csharp +Complex z = 3; +``` +which represents $ z = 3 $. + +### Real Numbers + +Likewise, to create a real number, write +```csharp +Real z = 1; +``` +With real numbers, we can also get maximum and minimum values which will depend on the backing type. +```csharp +Console.WriteLine("Max value with float backing type: {0}", Real.MaxValue); +Console.WriteLine("Max value with double backing type: {0}", Real.MaxValue); +``` +This will output `Max value with float backing type: 3.4028235E+38` +and `Max value with double backing type: 1.7976931348623157E+308`. + +## Binary Types + +Rational numbers are the only Mathematics.NET type in this category. + +### Rational Numbers + +Rational numbers require two backing types, one that implements [IBinaryInteger\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs) and one that implements both [IFloatingPointIee754\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs) and [IMinMaxValue\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IMinMaxValue.cs). + +With this information, we can create the following rational numbers: +```csharp +Rational a = 2; +Rational b = new(2, 3); +Rational c = new(3, 4); +``` +which represent $ a = 2 $, $ b = 2/3 $, and $ c = 3/4 $. + +The first type parameter indicates that the constructor only accepts values of that type. In these cases, `a` must be an int, `b` must be a byte, and `c` must be a BigInteger. The second parameter indicates the desired floating-point type with which we want to represent the rational number. We can get this value in two ways, e.g. +```csharp +Console.WriteLine(b.Value); +Console.WriteLine((float)b); +``` +which will both output `0.6666667`. + +> [!CAUTION] +> The floating-point representation of rational numbers may not be accurate in all cases. + +We can also convert a floating-point number into a rational number with an explicit cast +```csharp +Console.WriteLine((Rational)3.14); +``` +> [!NOTE] +> The conversion conversion is not guaranteed to create the "best" fraction; for instance, the value $ 0.3333333333333333 $ will not produce $ 1/3 $ but instead produce $ 8333333333333331 / 25000000000000000 $. + +Be aware that there are performance penalties with converting rationals to and from real numbers. An overflow exception will also be thrown if a value being converted cannot be represented by the target type. diff --git a/docs/articles/toc.yml b/docs/articles/toc.yml index d1033fc3..6aa3a720 100644 --- a/docs/articles/toc.yml +++ b/docs/articles/toc.yml @@ -4,3 +4,7 @@ items: - name: Installation href: get_started/installation.md +- name: Fundamentals + items: + - name: Numeric Types + href: fundamentals/numeric-types.md From 5dfe760841028242c9f79a54d5969b1839dc41ec Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 02:52:20 -0500 Subject: [PATCH 194/293] Create FUNDING.yml --- .github/FUNDING.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..70499867 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: HamletTanyavong +patreon: HamletTanyavong From 1c7ea3f472e10c3b9cb31011ca49cda5f3f59ba0 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 02:52:30 -0500 Subject: [PATCH 195/293] Fix benchmarks --- .../Core/Complex/ComplexDivisionBenchmarks.cs | 12 ++++++++++++ .../SystemComplexAbsVsComplexAbsBenchmarks.cs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs b/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs index 1a923f9b..c2e32c77 100644 --- a/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs +++ b/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs @@ -33,11 +33,23 @@ public class ComplexDivisionBenchmarks public Complex Z { get; set; } public Complex W { get; set; } + public System.Numerics.Complex X { get; set; } + public System.Numerics.Complex Y { get; set; } + [GlobalSetup] public void GlobalSetup() { Z = new(1.23, 2.34); W = new(4.56, 3.45); + + X = new(1.23, 2.34); + Y = new(4.56, 3.45); + } + + [Benchmark(Baseline = true)] + public System.Numerics.Complex SystemDivision() + { + return X / Y; } [Benchmark] diff --git a/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbsBenchmarks.cs b/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbsBenchmarks.cs index e78f0ecd..c31b0bd0 100644 --- a/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbsBenchmarks.cs +++ b/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbsBenchmarks.cs @@ -49,7 +49,7 @@ public Real SystemComplexAbs() } [Benchmark] - public Real ComplexAbs() + public Complex ComplexAbs() { return Complex.Abs(W); } From 558b19506384b072b3e23b1be55066b212239ce1 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 03:05:17 -0500 Subject: [PATCH 196/293] Add README --- Mathematics.NET.sln | 1 + README.md | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 README.md diff --git a/Mathematics.NET.sln b/Mathematics.NET.sln index 8ff6fe90..2cfa98d8 100644 --- a/Mathematics.NET.sln +++ b/Mathematics.NET.sln @@ -13,6 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .gitattributes = .gitattributes .gitignore = .gitignore LICENSE = LICENSE + README.md = README.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{91DB0FE7-BAA4-4D16-8A39-65332DD53662}" diff --git a/README.md b/README.md new file mode 100644 index 00000000..fd0f5d87 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# Mathematics.NET + +Mathematics.NET is a C# class library that provides tools for solving mathematical problems. + +[![GitHub](https://img.shields.io/github/license/HamletTanyavong/Mathematics.NET?style=flat-square&logo=github&labelColor=87cefa&color=ffd700)](https://github.com/HamletTanyavong/Mathematics.NET) +[![GitHub Repo Stars](https://img.shields.io/github/stars/HamletTanyavong/Mathematics.NET?color=87cefa&style=flat-square&logo=github)](https://github.com/HamletTanyavong/Mathematics.NET/stargazers) + +## Documentation + +Please visit the [documentation site](https://mathematics.hamlettanyavong.com) for detailed information. From 1ccef3b1acfb097b57814a96e94e2c3e8dc55f57 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 03:14:30 -0500 Subject: [PATCH 197/293] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fd0f5d87..c6091adc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Mathematics.NET +

Mathematics.NET

-Mathematics.NET is a C# class library that provides tools for solving mathematical problems. +

Mathematics.NET is a C# class library that provides tools for solving mathematical problems.

[![GitHub](https://img.shields.io/github/license/HamletTanyavong/Mathematics.NET?style=flat-square&logo=github&labelColor=87cefa&color=ffd700)](https://github.com/HamletTanyavong/Mathematics.NET) [![GitHub Repo Stars](https://img.shields.io/github/stars/HamletTanyavong/Mathematics.NET?color=87cefa&style=flat-square&logo=github)](https://github.com/HamletTanyavong/Mathematics.NET/stargazers) From 5276a10ebace74c7dccf4b96603c619b8d66f4bc Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 03:14:41 -0500 Subject: [PATCH 198/293] Add metadata --- src/Mathematics.NET/Mathematics.NET.csproj | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Mathematics.NET/Mathematics.NET.csproj b/src/Mathematics.NET/Mathematics.NET.csproj index e8022477..ac72bf03 100644 --- a/src/Mathematics.NET/Mathematics.NET.csproj +++ b/src/Mathematics.NET/Mathematics.NET.csproj @@ -5,8 +5,35 @@ enable enable x64 + Mathematics.NET + 0.1.0-alpha.1 + Hamlet Tanyavong + Mathematics.NET is a C# class library that provides tools for solving mathematical problems. + mathematics; math; maths + LICENSE + True + snupkg + https://mathematics.hamlettanyavong.com + Copyright (c) 2023 Hamlet Tanyavong + README.md + https://github.com/HamletTanyavong/Mathematics.NET + This project is in alpha and is not yet ready for release. + True + True + Physics.NET.Mathematics + + + True + \ + + + True + \ + + + From 30e2bdf5ae0f9dae47b76ddb08aff77fc10d278b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 04:50:09 -0500 Subject: [PATCH 199/293] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c6091adc..b59279e3 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ [![GitHub](https://img.shields.io/github/license/HamletTanyavong/Mathematics.NET?style=flat-square&logo=github&labelColor=87cefa&color=ffd700)](https://github.com/HamletTanyavong/Mathematics.NET) [![GitHub Repo Stars](https://img.shields.io/github/stars/HamletTanyavong/Mathematics.NET?color=87cefa&style=flat-square&logo=github)](https://github.com/HamletTanyavong/Mathematics.NET/stargazers) +[![NuGet](https://img.shields.io/nuget/v/Physics.NET.Mathematics?style=flat-square&logo=nuget)](https://www.nuget.org/packages/Physics.NET.Mathematics) +[![NuGet](https://img.shields.io/nuget/dt/Physics.NET.Mathematics?style=flat-square&logo=nuget)](https://www.nuget.org/packages/Physics.NET.Mathematics) ## Documentation From 87660d3f459a81117becf79c3b6ea1828ff72822 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 04:50:57 -0500 Subject: [PATCH 200/293] Update index.md --- docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/index.md b/docs/index.md index 3ef62c24..c2f72339 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,3 +4,5 @@ Mathematics.NET is a C# class library that provides tools for solving mathematic [![GitHub](https://img.shields.io/github/license/HamletTanyavong/Mathematics.NET?style=flat-square&logo=github&labelColor=87cefa&color=ffd700)](https://github.com/HamletTanyavong/Mathematics.NET) [![GitHub Repo Stars](https://img.shields.io/github/stars/HamletTanyavong/Mathematics.NET?color=87cefa&style=flat-square&logo=github)](https://github.com/HamletTanyavong/Mathematics.NET/stargazers) +[![NuGet](https://img.shields.io/nuget/v/Physics.NET.Mathematics?style=flat-square&logo=nuget)](https://www.nuget.org/packages/Physics.NET.Mathematics) +[![NuGet](https://img.shields.io/nuget/dt/Physics.NET.Mathematics?style=flat-square&logo=nuget)](https://www.nuget.org/packages/Physics.NET.Mathematics) From 111f9e2964e3ef4fb6b8e10f97aadaf3e8691301 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 05:11:04 -0500 Subject: [PATCH 201/293] Update installation.md --- docs/articles/get_started/installation.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/articles/get_started/installation.md b/docs/articles/get_started/installation.md index 9b59d610..8487e6ec 100644 --- a/docs/articles/get_started/installation.md +++ b/docs/articles/get_started/installation.md @@ -1,14 +1,21 @@ # Installation -Mathematics.NET is available to download from [nuget](https://www.nuget.org). +Mathematics.NET is available to download from [nuget](https://www.nuget.org/packages/Physics.NET.Mathematics). -## Polyglot Notebooks +# [Package Reference](#tab/package-reference) + +To use Mathematics.NET in you project, add the following line to your .csproj file: +```xml + +``` + +# [Polyglot Notebooks](#tab/polyglot-notebooks) Please have [Visual Studio Code](https://code.visualstudio.com/) installed as well as the [Polyglot Notebooks](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.dotnet-interactive-vscode) extension installed to begin using Mathematics.NET. When that is complete, create a new .ipynb file and add the following line to import the package: ```csharp -#r "nuget: Mathematics.NET" +#r "nuget: Physics.NET.Mathematics" ``` To get a specific version of Mathematics.NET, use, for example, ```csharp -#r "nuget: Mathematics.NET, 1.0.0" +#r "nuget: Physics.NET.Mathematics, 0.1.0-alpha.1" ``` From 386aa5a48c7057f3b5129414cea8a33d2e8d5ac0 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 06:55:20 -0500 Subject: [PATCH 202/293] Update installation.md - Fix typo --- docs/articles/get_started/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/articles/get_started/installation.md b/docs/articles/get_started/installation.md index 8487e6ec..39de7618 100644 --- a/docs/articles/get_started/installation.md +++ b/docs/articles/get_started/installation.md @@ -4,7 +4,7 @@ Mathematics.NET is available to download from [nuget](https://www.nuget.org/pack # [Package Reference](#tab/package-reference) -To use Mathematics.NET in you project, add the following line to your .csproj file: +To use Mathematics.NET in your project, add the following line to your .csproj file: ```xml ``` From 49034a312bfaf2bf5442788cc0df3f33fd7685b7 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 07:39:41 -0500 Subject: [PATCH 203/293] Update .gitignore - No longer ignore source generators project --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index b011f884..dedb186c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,9 +7,6 @@ /src/Mathematics.NET.DevApp/*.cs *.runsettings - # Temporary -/src/Mathematics.NET.SourceGenerators/ - # User-specific files *.rsuser *.suo From 3235cefa398c7f3c9270abd287672b8501aa9c27 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 07:43:29 -0500 Subject: [PATCH 204/293] Create DerivativeGenerator.cs --- .../DerivativeGenerator.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs diff --git a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs new file mode 100644 index 00000000..0542f4b7 --- /dev/null +++ b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs @@ -0,0 +1,35 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.SourceGenerators.IncrementalGenerators; + +/// A generator for calculating derivatives +[Generator] +public sealed class DerivativeGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) => throw new NotImplementedException(); +} From 3aa605b35e7803b3dcc984e61f41fc1d1e684a16 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 07:56:25 -0500 Subject: [PATCH 205/293] Update Mathematics.NET.SourceGenerators.csproj - Enable nullable --- .../Mathematics.NET.SourceGenerators.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj b/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj index 04fc35d2..ea490301 100644 --- a/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj +++ b/src/Mathematics.NET.SourceGenerators/Mathematics.NET.SourceGenerators.csproj @@ -4,6 +4,7 @@ true false latest + enable netstandard2.0 x64 enable From 701eb4e6d231e5715974ef7227fbee18264e2c75 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 07:57:19 -0500 Subject: [PATCH 206/293] Create Extensions.cs --- .../Extensions.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/Mathematics.NET.SourceGenerators/Extensions.cs diff --git a/src/Mathematics.NET.SourceGenerators/Extensions.cs b/src/Mathematics.NET.SourceGenerators/Extensions.cs new file mode 100644 index 00000000..82186f46 --- /dev/null +++ b/src/Mathematics.NET.SourceGenerators/Extensions.cs @@ -0,0 +1,41 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.SourceGenerators; + +public static class Extensions +{ + public static string? GetValue(this NameSyntax name) + { + return name switch + { + SimpleNameSyntax simpleNameSyntax => simpleNameSyntax.Identifier.Text, + QualifiedNameSyntax qualifiedNameSyntax => qualifiedNameSyntax.Right.Identifier.Text, + _ => null + }; + } +} From d595ebef5d6b411b5b432b1f9fd2c7f2cc0f3f8c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 08:10:32 -0500 Subject: [PATCH 207/293] Update DerivativeGenerator.cs - Add method for finding a specific attribute --- .../IncrementalGenerators/DerivativeGenerator.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs index 0542f4b7..4812090b 100644 --- a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs +++ b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs @@ -32,4 +32,7 @@ namespace Mathematics.NET.SourceGenerators.IncrementalGenerators; public sealed class DerivativeGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) => throw new NotImplementedException(); + + private static bool CouldBeFunctionAttribute(SyntaxNode syntaxNode, CancellationToken cancellationToken) + => syntaxNode is AttributeSyntax attributeSyntax && attributeSyntax.Name.GetValue() is "Function" or "FunctionAttribute"; } From 088f646f227f9a98d400501d5d762513eab0791d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 08:19:11 -0500 Subject: [PATCH 208/293] Create MethodInformation.cs --- .../Models/MethodInformation.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/Mathematics.NET.SourceGenerators/Models/MethodInformation.cs diff --git a/src/Mathematics.NET.SourceGenerators/Models/MethodInformation.cs b/src/Mathematics.NET.SourceGenerators/Models/MethodInformation.cs new file mode 100644 index 00000000..7bbe38ae --- /dev/null +++ b/src/Mathematics.NET.SourceGenerators/Models/MethodInformation.cs @@ -0,0 +1,42 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.SourceGenerators.Models; + +/// A class containing information about a specific method +public sealed class MethodInformation +{ + public MethodInformation(AttributeSyntax attributeSyntax, MethodDeclarationSyntax methodDeclaration) + { + AttributeSyntax = attributeSyntax; + MethodDeclaration = methodDeclaration; + } + + public AttributeSyntax AttributeSyntax { get; } + + public MethodDeclarationSyntax MethodDeclaration { get; } +} From 9f41619c1f9c49842d34f55cfbdfc6a6281b2bb0 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 08:22:10 -0500 Subject: [PATCH 209/293] Update DerivativeGenerator.cs - Add method for getting attribute and method information --- .../IncrementalGenerators/DerivativeGenerator.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs index 4812090b..a66d1574 100644 --- a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs +++ b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs @@ -25,14 +25,28 @@ // SOFTWARE. //
+using Mathematics.NET.SourceGenerators.Models; + namespace Mathematics.NET.SourceGenerators.IncrementalGenerators; /// A generator for calculating derivatives [Generator] public sealed class DerivativeGenerator : IIncrementalGenerator { - public void Initialize(IncrementalGeneratorInitializationContext context) => throw new NotImplementedException(); + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var provider = context.SyntaxProvider + .CreateSyntaxProvider(CouldBeFunctionAttribute, GetFunctionOrNull) + .Where(syntax => syntax is not null); + } private static bool CouldBeFunctionAttribute(SyntaxNode syntaxNode, CancellationToken cancellationToken) => syntaxNode is AttributeSyntax attributeSyntax && attributeSyntax.Name.GetValue() is "Function" or "FunctionAttribute"; + + public static MethodInformation? GetFunctionOrNull(GeneratorSyntaxContext context, CancellationToken cancellationToken) + { + // The method syntax will not be null if attribute syntax is not null since the attribute can only be applied to methods. + var attribute = (AttributeSyntax)context.Node; + return new(attribute, (MethodDeclarationSyntax)attribute.Parent!.Parent!); + } } From ea122234344d72c60a12fc0ddcaf08af02cfe12f Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 08:44:24 -0500 Subject: [PATCH 210/293] Update DerivativeGenerator.cs - Search for equation attributes instead --- .../IncrementalGenerators/DerivativeGenerator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs index a66d1574..2d2003bb 100644 --- a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs +++ b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs @@ -36,12 +36,12 @@ public sealed class DerivativeGenerator : IIncrementalGenerator public void Initialize(IncrementalGeneratorInitializationContext context) { var provider = context.SyntaxProvider - .CreateSyntaxProvider(CouldBeFunctionAttribute, GetFunctionOrNull) + .CreateSyntaxProvider(CouldBeEquationAttribute, GetFunctionOrNull) .Where(syntax => syntax is not null); } - private static bool CouldBeFunctionAttribute(SyntaxNode syntaxNode, CancellationToken cancellationToken) - => syntaxNode is AttributeSyntax attributeSyntax && attributeSyntax.Name.GetValue() is "Function" or "FunctionAttribute"; + private static bool CouldBeEquationAttribute(SyntaxNode syntaxNode, CancellationToken cancellationToken) + => syntaxNode is AttributeSyntax attributeSyntax && attributeSyntax.Name.GetValue() is "Equation" or "EquationAttribute"; public static MethodInformation? GetFunctionOrNull(GeneratorSyntaxContext context, CancellationToken cancellationToken) { From 9d265e8790efd0670760435cf10b26b170c7517a Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 09:00:57 -0500 Subject: [PATCH 211/293] Update DerivativeGenerator.cs - Get compilation --- .../IncrementalGenerators/DerivativeGenerator.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs index 2d2003bb..8427c23c 100644 --- a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs +++ b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs @@ -38,6 +38,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var provider = context.SyntaxProvider .CreateSyntaxProvider(CouldBeEquationAttribute, GetFunctionOrNull) .Where(syntax => syntax is not null); + var compilation = context.CompilationProvider.Combine(provider.Collect()); } private static bool CouldBeEquationAttribute(SyntaxNode syntaxNode, CancellationToken cancellationToken) From 7abed123af78766bf9d795f82504c6567cc44055 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 09:03:06 -0500 Subject: [PATCH 212/293] Update DerivativeGenerator.cs - Make private --- .../IncrementalGenerators/DerivativeGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs index 8427c23c..92366098 100644 --- a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs +++ b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs @@ -44,7 +44,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) private static bool CouldBeEquationAttribute(SyntaxNode syntaxNode, CancellationToken cancellationToken) => syntaxNode is AttributeSyntax attributeSyntax && attributeSyntax.Name.GetValue() is "Equation" or "EquationAttribute"; - public static MethodInformation? GetFunctionOrNull(GeneratorSyntaxContext context, CancellationToken cancellationToken) + private static MethodInformation? GetFunctionOrNull(GeneratorSyntaxContext context, CancellationToken cancellationToken) { // The method syntax will not be null if attribute syntax is not null since the attribute can only be applied to methods. var attribute = (AttributeSyntax)context.Node; From 2b3b75c6bfaa99427ecde20d1be6ace3a3f4da91 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 09:11:03 -0500 Subject: [PATCH 213/293] Update DerivativeGenerator.cs - Add method for generating code --- .../IncrementalGenerators/DerivativeGenerator.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs index 92366098..48ce5c2a 100644 --- a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs +++ b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs @@ -25,6 +25,7 @@ // SOFTWARE. //
+using System.Collections.Immutable; using Mathematics.NET.SourceGenerators.Models; namespace Mathematics.NET.SourceGenerators.IncrementalGenerators; @@ -39,6 +40,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .CreateSyntaxProvider(CouldBeEquationAttribute, GetFunctionOrNull) .Where(syntax => syntax is not null); var compilation = context.CompilationProvider.Combine(provider.Collect()); + context.RegisterSourceOutput(compilation, (context, source) => GenerateCode(context, source.Left, source.Right!)); } private static bool CouldBeEquationAttribute(SyntaxNode syntaxNode, CancellationToken cancellationToken) @@ -50,4 +52,8 @@ private static bool CouldBeEquationAttribute(SyntaxNode syntaxNode, Cancellation var attribute = (AttributeSyntax)context.Node; return new(attribute, (MethodDeclarationSyntax)attribute.Parent!.Parent!); } + + private void GenerateCode(SourceProductionContext context, Compilation compilation, ImmutableArray methodInformation) + { + } } From 66b1474096a2ab59af022fc055a17117ec051ec7 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 29 Sep 2023 09:12:00 -0500 Subject: [PATCH 214/293] Rename method --- .../IncrementalGenerators/DerivativeGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs index 48ce5c2a..5af35287 100644 --- a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs +++ b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs @@ -37,7 +37,7 @@ public sealed class DerivativeGenerator : IIncrementalGenerator public void Initialize(IncrementalGeneratorInitializationContext context) { var provider = context.SyntaxProvider - .CreateSyntaxProvider(CouldBeEquationAttribute, GetFunctionOrNull) + .CreateSyntaxProvider(CouldBeEquationAttribute, GetEquationOrNull) .Where(syntax => syntax is not null); var compilation = context.CompilationProvider.Combine(provider.Collect()); context.RegisterSourceOutput(compilation, (context, source) => GenerateCode(context, source.Left, source.Right!)); @@ -46,7 +46,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) private static bool CouldBeEquationAttribute(SyntaxNode syntaxNode, CancellationToken cancellationToken) => syntaxNode is AttributeSyntax attributeSyntax && attributeSyntax.Name.GetValue() is "Equation" or "EquationAttribute"; - private static MethodInformation? GetFunctionOrNull(GeneratorSyntaxContext context, CancellationToken cancellationToken) + private static MethodInformation? GetEquationOrNull(GeneratorSyntaxContext context, CancellationToken cancellationToken) { // The method syntax will not be null if attribute syntax is not null since the attribute can only be applied to methods. var attribute = (AttributeSyntax)context.Node; From 4bc6956d79f9c0a2bf8ddb185da64169aac4ad1c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 30 Sep 2023 05:46:58 -0500 Subject: [PATCH 215/293] Update DerivativeGenerator.cs - Change name --- .../IncrementalGenerators/DerivativeGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs index 5af35287..e64cd011 100644 --- a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs +++ b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs @@ -38,7 +38,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { var provider = context.SyntaxProvider .CreateSyntaxProvider(CouldBeEquationAttribute, GetEquationOrNull) - .Where(syntax => syntax is not null); + .Where(info => info is not null); var compilation = context.CompilationProvider.Combine(provider.Collect()); context.RegisterSourceOutput(compilation, (context, source) => GenerateCode(context, source.Left, source.Right!)); } From 38f3ec666f5495b91c150071847454d96589bf1d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 30 Sep 2023 05:47:28 -0500 Subject: [PATCH 216/293] Update Mathematics.NET.DevApp.csproj - Add project reference to test source generator --- src/Mathematics.NET.DevApp/Mathematics.NET.DevApp.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mathematics.NET.DevApp/Mathematics.NET.DevApp.csproj b/src/Mathematics.NET.DevApp/Mathematics.NET.DevApp.csproj index 10014264..db52578b 100644 --- a/src/Mathematics.NET.DevApp/Mathematics.NET.DevApp.csproj +++ b/src/Mathematics.NET.DevApp/Mathematics.NET.DevApp.csproj @@ -10,6 +10,7 @@ + From 39bbfa817bbe94f6e74eaad88cac36834d14fbb8 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 30 Sep 2023 09:14:46 -0500 Subject: [PATCH 217/293] Update Extensions.cs - Add method for removing Equation attribute --- .../Extensions.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Mathematics.NET.SourceGenerators/Extensions.cs b/src/Mathematics.NET.SourceGenerators/Extensions.cs index 82186f46..04e6a324 100644 --- a/src/Mathematics.NET.SourceGenerators/Extensions.cs +++ b/src/Mathematics.NET.SourceGenerators/Extensions.cs @@ -38,4 +38,21 @@ public static class Extensions _ => null }; } + + public static MethodDeclarationSyntax? RemoveEquationAttribute(this MethodDeclarationSyntax methodDeclarationSyntax) + { + var equationAttributeNode = methodDeclarationSyntax + .DescendantNodes() + .OfType() + .First(syntax => syntax.Name.GetValue() is "Equation" or "EquationAttribute"); + + if (equationAttributeNode.Parent!.ChildNodes().Count() > 1) + { + return methodDeclarationSyntax.RemoveNode(equationAttributeNode, SyntaxRemoveOptions.KeepNoTrivia); + } + else + { + return methodDeclarationSyntax.RemoveNode(equationAttributeNode.Parent, SyntaxRemoveOptions.KeepNoTrivia); + } + } } From dfaeee84de288005253c7329b18a2d261a4146d2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 3 Oct 2023 05:46:52 -0500 Subject: [PATCH 218/293] Create SymbolicsHelper.cs - Add derivatives map - Add DifSin - Add DifCos --- .../SymbolicsHelper.cs | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs diff --git a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs new file mode 100644 index 00000000..2e6cf12d --- /dev/null +++ b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs @@ -0,0 +1,77 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using Microsoft.CodeAnalysis.CSharp; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Mathematics.NET.SourceGenerators; + +public static class SymbolicsHelper +{ + private static InvocationExpressionSyntax DifSin(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) + public static ExpressionSyntax? TakeDerivative(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) + { + return memberAccessExpressionSyntax.Name.Identifier.ValueText switch + { + "Cos" => DifCos(memberAccessExpressionSyntax, argumentListSyntax), + "Sin" => DifSin(memberAccessExpressionSyntax, argumentListSyntax), + _ => null + }; + } + + private static ExpressionSyntax DifCos(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) + { + var sinNameSyntax = memberAccessExpressionSyntax + .DescendantNodes() + .OfType() + .First(x => x.Identifier.ValueText == "Cos"); + var newExpression = memberAccessExpressionSyntax.ReplaceNode(sinNameSyntax, IdentifierName("Sin")); + return BinaryExpression( + SyntaxKind.MultiplyExpression, + PrefixUnaryExpression( + SyntaxKind.UnaryMinusExpression, + LiteralExpression( + SyntaxKind.NumericLiteralExpression, + Literal(1))), + InvocationExpression( + newExpression, + argumentListSyntax)); + + } + + private static ExpressionSyntax DifSin(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) + { + var sinNameSyntax = memberAccessExpressionSyntax + .DescendantNodes() + .OfType() + .First(x => x.Identifier.ValueText == "Sin"); + var newExpression = memberAccessExpressionSyntax.ReplaceNode(sinNameSyntax, IdentifierName("Cos")); + return InvocationExpression( + newExpression, + argumentListSyntax); + } +} From 3f6bdd2a9da680392813942d7034640c9ba22b2e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:46:43 -0500 Subject: [PATCH 219/293] Update SymbolicsHelper.cs --- src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs index 2e6cf12d..ec030332 100644 --- a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs +++ b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs @@ -43,6 +43,8 @@ private static InvocationExpressionSyntax DifSin(MemberAccessExpressionSyntax me }; } + // Mathematical functions + private static ExpressionSyntax DifCos(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) { var sinNameSyntax = memberAccessExpressionSyntax From dcdb05e19f13caa2aa7cd8ced9dce86e45f5de00 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:51:55 -0500 Subject: [PATCH 220/293] Update SymbolicsHelper.cs - Add a method for retrieving derivative information from a list of syntax nodes --- src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs index ec030332..d667df53 100644 --- a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs +++ b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs @@ -33,6 +33,13 @@ namespace Mathematics.NET.SourceGenerators; public static class SymbolicsHelper { private static InvocationExpressionSyntax DifSin(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) + public static IEnumerable ExtractDerivativeExpressionList(IEnumerable syntaxNodes) + { + return syntaxNodes + .OfType() + .Where(x => x.Name.Identifier.ValueText == "Dif"); + } + public static ExpressionSyntax? TakeDerivative(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) { return memberAccessExpressionSyntax.Name.Identifier.ValueText switch From b7eeb14eb70482387cedcb2be9ce5b03c46554b1 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 3 Oct 2023 11:30:19 -0500 Subject: [PATCH 221/293] Update SymbolicsHelper.cs - Remove empty line - Change variable name --- src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs index d667df53..b7f6a375 100644 --- a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs +++ b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs @@ -54,11 +54,11 @@ public static IEnumerable ExtractDerivativeExpress private static ExpressionSyntax DifCos(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) { - var sinNameSyntax = memberAccessExpressionSyntax + var cosNameSyntax = memberAccessExpressionSyntax .DescendantNodes() .OfType() .First(x => x.Identifier.ValueText == "Cos"); - var newExpression = memberAccessExpressionSyntax.ReplaceNode(sinNameSyntax, IdentifierName("Sin")); + var newExpression = memberAccessExpressionSyntax.ReplaceNode(cosNameSyntax, IdentifierName("Sin")); return BinaryExpression( SyntaxKind.MultiplyExpression, PrefixUnaryExpression( @@ -69,7 +69,6 @@ private static ExpressionSyntax DifCos(MemberAccessExpressionSyntax memberAccess InvocationExpression( newExpression, argumentListSyntax)); - } private static ExpressionSyntax DifSin(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) From 4445d1bb6e76259b00a29841424d305bf2833b08 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:03:20 -0500 Subject: [PATCH 222/293] Update README.md - Left align items instead of center align items --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b59279e3..f43e657e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -

Mathematics.NET

+# Mathematics.NET -

Mathematics.NET is a C# class library that provides tools for solving mathematical problems.

+Mathematics.NET is a C# class library that provides tools for solving mathematical problems. [![GitHub](https://img.shields.io/github/license/HamletTanyavong/Mathematics.NET?style=flat-square&logo=github&labelColor=87cefa&color=ffd700)](https://github.com/HamletTanyavong/Mathematics.NET) [![GitHub Repo Stars](https://img.shields.io/github/stars/HamletTanyavong/Mathematics.NET?color=87cefa&style=flat-square&logo=github)](https://github.com/HamletTanyavong/Mathematics.NET/stargazers) From f1538856b7814bb43676198b059825d364d6f432 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 5 Oct 2023 21:00:12 -0500 Subject: [PATCH 223/293] Update SymbolicsHelper.cs - Add method for extracting the expression from an argument syntax --- src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs index b7f6a375..f808ed08 100644 --- a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs +++ b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs @@ -50,6 +50,15 @@ public static IEnumerable ExtractDerivativeExpress }; } + private static ExpressionSyntax? GetDifferentiableExpression(ArgumentSyntax argumentSyntax) + { + return argumentSyntax.Expression switch + { + SimpleLambdaExpressionSyntax simpleLambdaExpressionSyntax => simpleLambdaExpressionSyntax.ExpressionBody, + _ => null + }; + } + // Mathematical functions private static ExpressionSyntax DifCos(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) From e450814bbb837dcdf0f634c5d0096c7c45b0266b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 5 Oct 2023 22:02:31 -0500 Subject: [PATCH 224/293] Update SymbolicsHelper.cs - Add methods for taking derivatives --- .../SymbolicsHelper.cs | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs index f808ed08..425f463b 100644 --- a/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs +++ b/src/Mathematics.NET.SourceGenerators/SymbolicsHelper.cs @@ -32,20 +32,49 @@ namespace Mathematics.NET.SourceGenerators; public static class SymbolicsHelper { - private static InvocationExpressionSyntax DifSin(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) - public static IEnumerable ExtractDerivativeExpressionList(IEnumerable syntaxNodes) + // TODO: Reduce mathematical expressions after taking derivatives + public static MethodDeclarationSyntax TransformEquation(MethodDeclarationSyntax methodDeclarationSyntax) { - return syntaxNodes + MethodDeclarationSyntax transformation = methodDeclarationSyntax; + while (CanTakeInnerDerivatives(transformation, out var derivativeExpressions)) + { + foreach (var derivativeExpression in derivativeExpressions) + { + var flattenedDerivativeExpression = ComputeDerivative(derivativeExpression); + transformation = transformation.ReplaceNode(derivativeExpression.Parent!, flattenedDerivativeExpression ?? derivativeExpression); + } + } + return transformation; + } + + // We want to resolve the innermost derivative first, so we choose the derivative + // expression with no other derivative expressions present in its descendant nodes. + private static bool CanTakeInnerDerivatives(MethodDeclarationSyntax syntaxNode, out IEnumerable derivatives) + { + var descendantNodes = syntaxNode.DescendantNodes(); + derivatives = descendantNodes .OfType() - .Where(x => x.Name.Identifier.ValueText == "Dif"); + .Where(x => x.Name.Identifier.ValueText == "Dif" && !x + .DescendantNodes() + .OfType() + .Any(x => x.Name.Identifier.ValueText == "Dif")); + return derivatives.Count() > 0; } - public static ExpressionSyntax? TakeDerivative(MemberAccessExpressionSyntax memberAccessExpressionSyntax, ArgumentListSyntax argumentListSyntax) + // TODO: Account for higher order derivatives + // TODO: Take into account differentiating with respect to multiple variables + private static ExpressionSyntax? ComputeDerivative(MemberAccessExpressionSyntax memberAccessExpressionSyntax) { - return memberAccessExpressionSyntax.Name.Identifier.ValueText switch + // memberAccessExpressionSyntax is the Dif expression extracted + var invocationExpression = (InvocationExpressionSyntax)memberAccessExpressionSyntax.Parent!; + + var derivativeExpression = (InvocationExpressionSyntax)GetDifferentiableExpression(invocationExpression.ArgumentList.Arguments[0])!; + var method = (MemberAccessExpressionSyntax)derivativeExpression.Expression; + var args = derivativeExpression.ArgumentList; + return method.Name.Identifier.ValueText switch { - "Cos" => DifCos(memberAccessExpressionSyntax, argumentListSyntax), - "Sin" => DifSin(memberAccessExpressionSyntax, argumentListSyntax), + "Cos" => DifCos(method, args), + "Sin" => DifSin(method, args), _ => null }; } From 52686b470d110a4f1d08fde4440dad49426c1053 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 6 Oct 2023 07:29:13 -0500 Subject: [PATCH 225/293] Update Extensions.cs - Make return type non-nullable --- src/Mathematics.NET.SourceGenerators/Extensions.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Mathematics.NET.SourceGenerators/Extensions.cs b/src/Mathematics.NET.SourceGenerators/Extensions.cs index 04e6a324..cbd8e6a4 100644 --- a/src/Mathematics.NET.SourceGenerators/Extensions.cs +++ b/src/Mathematics.NET.SourceGenerators/Extensions.cs @@ -39,7 +39,8 @@ public static class Extensions }; } - public static MethodDeclarationSyntax? RemoveEquationAttribute(this MethodDeclarationSyntax methodDeclarationSyntax) + // TODO: Determine if every equation should/will have an attribute to remove. + public static MethodDeclarationSyntax RemoveEquationAttribute(this MethodDeclarationSyntax methodDeclarationSyntax) { var equationAttributeNode = methodDeclarationSyntax .DescendantNodes() @@ -48,11 +49,11 @@ public static class Extensions if (equationAttributeNode.Parent!.ChildNodes().Count() > 1) { - return methodDeclarationSyntax.RemoveNode(equationAttributeNode, SyntaxRemoveOptions.KeepNoTrivia); + return methodDeclarationSyntax.RemoveNode(equationAttributeNode, SyntaxRemoveOptions.KeepNoTrivia)!; } else { - return methodDeclarationSyntax.RemoveNode(equationAttributeNode.Parent, SyntaxRemoveOptions.KeepNoTrivia); + return methodDeclarationSyntax.RemoveNode(equationAttributeNode.Parent, SyntaxRemoveOptions.KeepNoTrivia)!; } } } From 97e413dd2ea4e24f1d0ffd23dbaf0eb6ffea025e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 6 Oct 2023 10:44:05 -0500 Subject: [PATCH 226/293] Create DerivativesBuilder.cs --- .../SourceBuilders/DerivativesBuilder.cs | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/Mathematics.NET.SourceGenerators/SourceBuilders/DerivativesBuilder.cs diff --git a/src/Mathematics.NET.SourceGenerators/SourceBuilders/DerivativesBuilder.cs b/src/Mathematics.NET.SourceGenerators/SourceBuilders/DerivativesBuilder.cs new file mode 100644 index 00000000..7b320346 --- /dev/null +++ b/src/Mathematics.NET.SourceGenerators/SourceBuilders/DerivativesBuilder.cs @@ -0,0 +1,99 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Collections.Immutable; +using Mathematics.NET.SourceGenerators.Models; +using Microsoft.CodeAnalysis.CSharp; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Mathematics.NET.SourceGenerators.SourceBuilders; + +/// Derivatives builder +public sealed class DerivativesBuilder +{ + private readonly string _assemblyName; + private readonly ImmutableArray _methodInformation; + + public DerivativesBuilder(Compilation compilationUnitSyntax, ImmutableArray methodInformation) + { + _assemblyName = compilationUnitSyntax.AssemblyName!; + _methodInformation = methodInformation; + } + + public CompilationUnitSyntax GenerateSource() + { + var members = GenerateMembers(); + return CreateCompilationUnit(members); + } + + private CompilationUnitSyntax CreateCompilationUnit(MemberDeclarationSyntax[] memberDeclarations) + { + return CompilationUnit() + .WithUsings( + SingletonList( + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("Mathematics"), + IdentifierName("NET")), + IdentifierName("Core"))) + .WithUsingKeyword( + Token( + TriviaList( + Comment("// Auto-generated code")), + SyntaxKind.UsingKeyword, + TriviaList())))) + .WithMembers( + SingletonList( + FileScopedNamespaceDeclaration( + QualifiedName( + IdentifierName(_assemblyName), + IdentifierName("Mathematics"))) + .WithMembers( + SingletonList( + ClassDeclaration("Equations") + .WithModifiers( + TokenList(new[] { + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.StaticKeyword) })) + .WithMembers( + List(memberDeclarations)))))) + .NormalizeWhitespace(); + } + + private MemberDeclarationSyntax[] GenerateMembers() + { + var result = new MemberDeclarationSyntax[_methodInformation.Length]; + for (int i = 0; i < _methodInformation.Length; i++) + { + var equation = _methodInformation[i].MethodDeclaration.RemoveEquationAttribute(); + var transformedEquation = SymbolicsHelper.TransformEquation(equation); + result[i] = transformedEquation; + } + return result; + } +} From 1f123067fc00abc39da8920c335ff3c3c55e88b8 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 6 Oct 2023 10:46:40 -0500 Subject: [PATCH 227/293] Update DerivativeGenerator.cs - Add generated code to source --- .../IncrementalGenerators/DerivativeGenerator.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs index e64cd011..034dfb0d 100644 --- a/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs +++ b/src/Mathematics.NET.SourceGenerators/IncrementalGenerators/DerivativeGenerator.cs @@ -26,7 +26,9 @@ // using System.Collections.Immutable; +using System.Text; using Mathematics.NET.SourceGenerators.Models; +using Mathematics.NET.SourceGenerators.SourceBuilders; namespace Mathematics.NET.SourceGenerators.IncrementalGenerators; @@ -55,5 +57,7 @@ private static bool CouldBeEquationAttribute(SyntaxNode syntaxNode, Cancellation private void GenerateCode(SourceProductionContext context, Compilation compilation, ImmutableArray methodInformation) { + var derivatives = new DerivativesBuilder(compilation, methodInformation); + context.AddSource("Equations.g.cs", derivatives.GenerateSource().GetText(Encoding.UTF8).ToString()); } } From a62d9173399823775ce43aeb25c22d86f03b21d7 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 6 Oct 2023 12:52:53 -0500 Subject: [PATCH 228/293] Update Math.cs --- src/Mathematics.NET/Math.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Mathematics.NET/Math.cs b/src/Mathematics.NET/Math.cs index ca4b74d1..10d5187f 100644 --- a/src/Mathematics.NET/Math.cs +++ b/src/Mathematics.NET/Math.cs @@ -88,4 +88,11 @@ public static class Math where T : IFloatingPointIeee754, IMinMaxValue /// public static Real ZetaOf4 => Real.ZetaOf4; + + // + // Methods + // + + // TODO: Account for fractional derivatives + public static Real Dif(Func, Real> function, (Real X, int N) args) => throw new NotImplementedException(); } From cf381d465c9a706bd7b2848b035ecaf9a7a7da3d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 6 Oct 2023 20:51:20 -0500 Subject: [PATCH 229/293] Fix ToString implementation --- src/Mathematics.NET/Core/Real.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 48fef501..49f033b0 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -199,7 +199,7 @@ public int CompareTo(object? obj) public override string ToString() => ToString(null, null); - public string ToString(string? format, IFormatProvider? provider) => string.Format(provider, "{0}", _value.ToString(format, provider)); + public string ToString(string? format, IFormatProvider? provider) => string.Format(provider, "{0}", _value); public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => _value.TryFormat(destination, out charsWritten, null, provider); From 4eaf0c76f4bc4b5ef6aed195706b879690612bc2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 6 Oct 2023 23:07:29 -0500 Subject: [PATCH 230/293] Add package reference --- src/Mathematics.NET/Mathematics.NET.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Mathematics.NET/Mathematics.NET.csproj b/src/Mathematics.NET/Mathematics.NET.csproj index ac72bf03..9b686890 100644 --- a/src/Mathematics.NET/Mathematics.NET.csproj +++ b/src/Mathematics.NET/Mathematics.NET.csproj @@ -34,6 +34,10 @@ + + + + From 427d4ef837fd6dc65a16664c999f4514047d70bf Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 6 Oct 2023 23:25:07 -0500 Subject: [PATCH 231/293] Update Mathematics.NET.Benchmarks.csproj --- .../Mathematics.NET.Benchmarks.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj index 7f898c95..4f080b22 100644 --- a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj +++ b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj @@ -9,7 +9,7 @@ - + From 18bfd819012ece7d62b8aa0149987e50b3f53d32 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 7 Oct 2023 09:33:20 -0500 Subject: [PATCH 232/293] Allow unsafe --- src/Mathematics.NET/Mathematics.NET.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mathematics.NET/Mathematics.NET.csproj b/src/Mathematics.NET/Mathematics.NET.csproj index 9b686890..df134626 100644 --- a/src/Mathematics.NET/Mathematics.NET.csproj +++ b/src/Mathematics.NET/Mathematics.NET.csproj @@ -2,6 +2,7 @@ net7.0 + true enable enable x64 From c7aa2bbc829b60ec0c54f29cf5a8bc28ffbcec8a Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 7 Oct 2023 14:04:07 -0500 Subject: [PATCH 233/293] Remove type parameter requirement for numbers - Rename Complex to ComplexNumber to avoid name clash - Update documentation - Rename Math class to Mathematics - Update tests to account for the changes - Remove Two from IComplex - Fix Real.Root method --- docs/articles/fundamentals/numeric-types.md | 38 +- src/Mathematics.NET/Core/Complex.cs | 674 ------------------ src/Mathematics.NET/Core/ComplexNumber.cs | 664 +++++++++++++++++ src/Mathematics.NET/Core/Extensions.cs | 7 +- src/Mathematics.NET/Core/IComplex.cs | 85 ++- src/Mathematics.NET/Core/IConstants.cs | 8 +- .../Core/IDifferentiableFunctions.cs | 8 +- src/Mathematics.NET/Core/IRational.cs | 6 +- src/Mathematics.NET/Core/IReal.cs | 10 +- src/Mathematics.NET/Core/Rational.cs | 190 +++-- src/Mathematics.NET/Core/Real.cs | 287 ++++---- .../{Math.cs => Mathematics.cs} | 40 +- .../ComplexDivisionBenchmarks.cs | 14 +- .../ComplexTrigonometryBenchmarks.cs | 26 +- .../SystemComplexAbsVsComplexAbsBenchmarks.cs | 14 +- .../RealvsDouble.cs | 8 +- .../Mathematics.NET.Benchmarks.csproj | 1 + tests/Mathematics.NET.Benchmarks/Program.cs | 2 +- .../Core/ComplexTests.cs | 76 +- .../Core/RationalTests.cs | 32 +- 20 files changed, 1067 insertions(+), 1123 deletions(-) delete mode 100644 src/Mathematics.NET/Core/Complex.cs create mode 100644 src/Mathematics.NET/Core/ComplexNumber.cs rename src/Mathematics.NET/{Math.cs => Mathematics.cs} (66%) rename tests/Mathematics.NET.Benchmarks/Core/{Complex => ComplexNumberBenchmarks}/ComplexDivisionBenchmarks.cs (82%) rename tests/Mathematics.NET.Benchmarks/Core/{Complex => ComplexNumberBenchmarks}/ComplexTrigonometryBenchmarks.cs (69%) rename tests/Mathematics.NET.Benchmarks/Core/{Complex => ComplexNumberBenchmarks}/SystemComplexAbsVsComplexAbsBenchmarks.cs (83%) rename tests/Mathematics.NET.Benchmarks/Core/{Real => RealNumberBenchmarks}/RealvsDouble.cs (91%) diff --git a/docs/articles/fundamentals/numeric-types.md b/docs/articles/fundamentals/numeric-types.md index e36e8ac6..a6d0293b 100644 --- a/docs/articles/fundamentals/numeric-types.md +++ b/docs/articles/fundamentals/numeric-types.md @@ -2,21 +2,21 @@ There are three numeric types that can be used to represent complex, real, and rational numbers in Mathematics.NET. -All Mathematics.NET numbers implement the [IComplex](https://mathematics.hamlettanyavong.com/api/Mathematics.NET.Core.IComplex-2.html) interface. Particularly useful is the fact that, unlike .NET runtime's [INumberBase\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs), `IComplex` defines the `Conjugate` method; this is incredibly helpful in avoiding code duplication for calculations involving complex and real numbers. +All Mathematics.NET numbers implement the [IComplex\](https://mathematics.hamlettanyavong.com/api/Mathematics.NET.Core.IComplex-1.html) interface. Particularly useful is the fact that, unlike .NET runtime's [INumberBase\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs), `IComplex` defines the `Conjugate` method; this is helpful in avoiding code duplication for calculations involving complex and real numbers. ## Floating-Point Types -Floating-point Mathematics.NET numbers may be backed any number that implements [IFloatingPointIee754\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs) and [IMinMaxValue\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IMinMaxValue.cs), or more specifically, [float](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Single.cs), [double](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Double.cs), and [decimal](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Decimal.cs). +Floating-point Mathematics.NET numbers are backed by the [double](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Double.cs) numeric type. ### Complex Numbers -To create a complex number, we choose a backing type, in this case `double`, and write +To create a complex number, we can write ```csharp -Complex z = new(3, 4); +ComplexNumber z = new(3, 4); ``` This represents the number $ z = 3+i4 $. We can also specify only one number to create a complex number with no imaginary part ```csharp -Complex z = 3; +ComplexNumber z = 3; ``` which represents $ z = 3 $. @@ -24,15 +24,12 @@ which represents $ z = 3 $. Likewise, to create a real number, write ```csharp -Real z = 1; +Real x = 1.23; ``` -With real numbers, we can also get maximum and minimum values which will depend on the backing type. +To get is backing value, write ```csharp -Console.WriteLine("Max value with float backing type: {0}", Real.MaxValue); -Console.WriteLine("Max value with double backing type: {0}", Real.MaxValue); +double backingValue = x.Value; ``` -This will output `Max value with float backing type: 3.4028235E+38` -and `Max value with double backing type: 1.7976931348623157E+308`. ## Binary Types @@ -40,29 +37,22 @@ Rational numbers are the only Mathematics.NET type in this category. ### Rational Numbers -Rational numbers require two backing types, one that implements [IBinaryInteger\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs) and one that implements both [IFloatingPointIee754\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs) and [IMinMaxValue\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IMinMaxValue.cs). +Rational numbers require a type parameter that implements [IBinaryInteger\](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs). The type specified here is used to represent the numerator and denominator of the rational number. With this information, we can create the following rational numbers: ```csharp -Rational a = 2; -Rational b = new(2, 3); -Rational c = new(3, 4); +Rational a = 2; +Rational b = new(2, 3); +Rational c = new(3, 4); ``` which represent $ a = 2 $, $ b = 2/3 $, and $ c = 3/4 $. -The first type parameter indicates that the constructor only accepts values of that type. In these cases, `a` must be an int, `b` must be a byte, and `c` must be a BigInteger. The second parameter indicates the desired floating-point type with which we want to represent the rational number. We can get this value in two ways, e.g. -```csharp -Console.WriteLine(b.Value); -Console.WriteLine((float)b); -``` -which will both output `0.6666667`. - > [!CAUTION] > The floating-point representation of rational numbers may not be accurate in all cases. -We can also convert a floating-point number into a rational number with an explicit cast +We can also convert a double into a rational number with an explicit cast ```csharp -Console.WriteLine((Rational)3.14); +Console.WriteLine((Rational)3.14); ``` > [!NOTE] > The conversion conversion is not guaranteed to create the "best" fraction; for instance, the value $ 0.3333333333333333 $ will not produce $ 1/3 $ but instead produce $ 8333333333333331 / 25000000000000000 $. diff --git a/src/Mathematics.NET/Core/Complex.cs b/src/Mathematics.NET/Core/Complex.cs deleted file mode 100644 index f7474e9d..00000000 --- a/src/Mathematics.NET/Core/Complex.cs +++ /dev/null @@ -1,674 +0,0 @@ -// -// Mathematics.NET -// https://github.com/HamletTanyavong/Mathematics.NET -// -// MIT License -// -// Copyright (c) 2023 Hamlet Tanyavong -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace Mathematics.NET.Core; - -/// Represents a complex number -/// A type that implements and -[Serializable] -[StructLayout(LayoutKind.Sequential)] -public readonly struct Complex - : IComplex, T>, - IDifferentiableFunctions, T> - where T : IFloatingPointIeee754, IMinMaxValue -{ - private static readonly Complex s_im = new(Real.Zero, Real.One); - private static readonly Complex s_imOverTwo = new(Real.Zero, Real.One / Real.Two); - - private static readonly Complex s_oneOverTwo = T.CreateTruncating(0.5); - private static readonly Complex s_three = T.CreateTruncating(3.0); - private static readonly Real s_four = T.CreateTruncating(4.0); - - // For computing Asin and Acos - private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / Real.Two; - private static readonly Real s_threeOverFour = T.CreateTruncating(0.75); - private static readonly Real s_threeOverTwo = T.CreateTruncating(1.5); - - public static readonly Complex Zero = Real.Zero; - public static readonly Complex One = Real.One; - public static readonly Complex Two = Real.Two; - - public static readonly Complex NaN = new(Real.NaN, Real.NaN); - public static readonly Complex Infinity = new(Real.PositiveInfinity, Real.PositiveInfinity); - - private readonly Real _real; - private readonly Real _imaginary; - - public Complex(Real real) - { - _real = real; - _imaginary = T.Zero; - } - - public Complex(Real real, Real imaginary) - { - _real = real; - _imaginary = imaginary; - } - - // - // Complex number properties - // - - public Real Re => _real; - public Real Im => _imaginary; - - public Real Magnitude => Hypot(_real.Value, _imaginary.Value); - public Real Phase => T.Atan2(_imaginary.Value, _real.Value); - - // - // Constants - // - - static Complex IComplex, T>.Zero => Zero; - static Complex IComplex, T>.One => One; - static Complex IComplex, T>.Two => Two; - static Complex IComplex, T>.NaN => NaN; - - // - // Operators - // - - public static Complex operator -(Complex z) => new(-z._real, -z._imaginary); - - public static Complex operator +(Complex z, Complex w) => new(z._real + w._real, z._imaginary + w._imaginary); - - public static Complex operator -(Complex z, Complex w) => new(z._real - w._real, z._imaginary - w._imaginary); - - public static Complex operator *(Complex z, Complex w) - => new(z._real * w._real - z._imaginary * w._imaginary, z._real * w._imaginary + w._real * z._imaginary); - - // From Michael Baudin and Robert L. Smith - public static Complex operator /(Complex z, Complex w) - { - var zRe = z._real.Value; - var zIm = z._imaginary.Value; - var wRe = w._real.Value; - var wIm = w._imaginary.Value; - - T reResult; - T imResult; - if (T.Abs(wIm) <= T.Abs(wRe)) - { - DivisionHelper(zRe, zIm, wRe, wIm, out reResult, out imResult); - } - else - { - DivisionHelper(zIm, zRe, wIm, wRe, out reResult, out imResult); - imResult = -imResult; - } - - return new(reResult, imResult); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void DivisionHelper(T x, T y, T maxW, T minW, out T real, out T imaginary) - { - var ratio = minW / maxW; - var scale = T.One / (maxW + minW * ratio); - if (ratio != T.Zero) - { - real = (x + y * ratio) * scale; - imaginary = (y - x * ratio) * scale; - } - else - { - real = (x + minW * (y / maxW)) * scale; - imaginary = (y - minW * (x / maxW)) * scale; - } - } - - // - // Equality - // - - public static bool operator ==(Complex left, Complex right) => left.Re == right.Re && left.Im == right.Im; - - public static bool operator !=(Complex left, Complex right) => left.Re != right.Re || left.Im != right.Im; - - public override bool Equals([NotNullWhen(true)] object? obj) => obj is Complex other && Equals(other); - - public bool Equals(Complex value) => _real.Equals(value.Re) && _imaginary.Equals(value.Im); - - public override int GetHashCode() => HashCode.Combine(_real, _imaginary); - - // - // Formatting - // - - public override string ToString() => ToString(null, null); - - public string ToString(string? format, IFormatProvider? provider) - { - format = string.IsNullOrEmpty(format) ? "ALL" : format.ToUpperInvariant(); - provider ??= NumberFormatInfo.InvariantInfo; - - if (format is "ALL") - { - return string.Format(provider, "({0}, {1})", _real.ToString(null, provider), _imaginary.ToString(null, provider)); - } - else if (format is "RE") - { - return string.Format(provider, "{0}", _real.ToString(null, provider)); - } - else if (format is "IM") - { - return string.Format(provider, "{0}", _imaginary.ToString(null, provider)); - } - else - { - throw new FormatException($"The \"{format}\" format is not supported."); - } - } - - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) - { - format = format.IsEmpty ? "ALL" : format.ToString().ToUpperInvariant(); - provider ??= NumberFormatInfo.InvariantInfo; - - if (format is "ALL") - { - // There are a minimum of 6 characters for "(0, 0)". - int charsCurrentlyWritten = 0; - if (destination.Length < 6) - { - charsWritten = charsCurrentlyWritten; - return false; - } - - destination[charsCurrentlyWritten++] = '('; - - bool tryFormatSucceeded = _real.TryFormat(destination[charsCurrentlyWritten..], out int tryFormatCharsWritten, null, provider); - charsCurrentlyWritten += tryFormatCharsWritten; - if (!tryFormatSucceeded || destination.Length < charsCurrentlyWritten + 1) - { - charsWritten = charsCurrentlyWritten; - return false; - } - - destination[charsCurrentlyWritten++] = ','; - if (destination.Length < charsCurrentlyWritten + 1) - { - charsWritten = charsCurrentlyWritten; - return false; - } - destination[charsCurrentlyWritten++] = ' '; - if (destination.Length < charsCurrentlyWritten + 1) - { - charsWritten = charsCurrentlyWritten; - return false; - } - - tryFormatSucceeded = _imaginary.TryFormat(destination[charsCurrentlyWritten..], out tryFormatCharsWritten, null, provider); - charsCurrentlyWritten += tryFormatCharsWritten; - if (!tryFormatSucceeded || destination.Length < charsCurrentlyWritten + 1) - { - charsWritten = charsCurrentlyWritten; - return false; - } - - destination[charsCurrentlyWritten++] = ')'; - - charsWritten = charsCurrentlyWritten; - return true; - } - else if (format is "RE") - { - return _real.TryFormat(destination, out charsWritten, null, provider); - } - else if (format is "IM") - { - return _imaginary.TryFormat(destination, out charsWritten, null, provider); - } - else - { - throw new FormatException($"The \"{format}\" format is not supported."); - } - } - - // - // Parsing - // - - public static Complex Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); - - public static Complex Parse(ReadOnlySpan s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); - - public static Complex Parse(string s, NumberStyles style, IFormatProvider? provider) - { - ArgumentNullException.ThrowIfNull(s); - return Parse((ReadOnlySpan)s, style, provider); - } - - public static Complex Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) - { - if (!TryParse(s, style, provider, out Complex result)) - { - return Infinity; - } - return result; - } - - public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out Complex result) - => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); - - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out Complex result) - => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); - - public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Complex result) - => TryParse((ReadOnlySpan)s, style, provider, out result); - - public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out Complex result) - { - s = s.Trim(); - int openParenthesis = s.IndexOf('('); - int split = s.IndexOf(','); - int closeParenthesis = s.IndexOf(')'); - - // There a minimum of 5 characters for "(0,0)". - if (s.Length < 5 || openParenthesis == -1 || split == -1 || closeParenthesis == -1 || openParenthesis > split || openParenthesis > closeParenthesis || split > closeParenthesis) - { - result = Zero; - return false; - } - - if (!Real.TryParse(s.Slice(openParenthesis + 1, split - 1), style, provider, out Real real)) - { - result = Zero; - return false; - } - - if (!Real.TryParse(s.Slice(split + 1, closeParenthesis - split - 1), style, provider, out Real imaginary)) - { - result = Zero; - return false; - } - - result = new(real, imaginary); - return true; - } - - // - // Methods - // - - public static Complex Abs(Complex z) => Hypot(z._real.Value, z._imaginary.Value); - - public static Complex Conjugate(Complex z) => new(z._real, -z._imaginary); - - public static Complex FromPolarForm(Real magnitude, Real phase) - => new(magnitude * T.Cos(phase.Value), magnitude * T.Sin(phase.Value)); - - private static T Hypot(T x, T y) - { - // Factor out the larger value to avoid possible overflow - x = T.Abs(x); - y = T.Abs(y); - - T small, large; - if (x < y) - { - small = x; - large = y; - } - else - { - small = y; - large = x; - } - - if (small == T.Zero) - { - return large; - } - else if (T.IsPositiveInfinity(large) && !T.IsNaN(small)) - { - return T.PositiveInfinity; - } - else - { - T ratio = small / large; - return large * T.Sqrt(T.One + ratio * ratio); - } - } - - public static bool IsFinite(Complex z) => Real.IsFinite(z._real) && Real.IsFinite(z._imaginary); - - public static bool IsInfinity(Complex z) => Real.IsInfinity(z._real) || Real.IsInfinity(z._imaginary); - - public static bool IsNaN(Complex z) => !IsInfinity(z) && !IsFinite(z); - - public static bool IsZero(Complex z) => Real.IsZero(z._real) && Real.IsZero(z._imaginary); - - public static Complex Reciprocate(Complex z) - { - if (z._real == T.Zero && z._imaginary == T.Zero) - { - return Infinity; - } - - var re = z._real.Value; - var im = z._imaginary.Value; - - T reResult; - T imResult; - if (T.Abs(im) <= T.Abs(re)) - { - DivisionHelper(T.One, T.Zero, re, im, out reResult, out imResult); - } - else - { - DivisionHelper(T.Zero, T.One, im, re, out reResult, out imResult); - imResult = -imResult; - } - - return new(reResult, imResult); - } - - // We will only consider the real part of complex numbers for these conversions. - - public static bool TryConvertFromChecked(V value, out Complex result) - where V : INumberBase - { - result = T.CreateChecked(value); - return true; - } - - public static bool TryConvertFromSaturating(V value, out Complex result) - where V : INumberBase - { - result = T.CreateSaturating(value); - return true; - } - - public static bool TryConvertFromTruncating(V value, out Complex result) - where V : INumberBase - { - result = T.CreateTruncating(value); - return true; - } - - public static bool TryConvertToChecked(Complex value, [MaybeNullWhen(false)] out V result) - where V : INumberBase - { - if (value._imaginary == Real.Zero) - { - throw new OverflowException(); - } - - result = V.CreateChecked(value._real.Value); - return true; - } - - public static bool TryConvertToSaturating(Complex value, [MaybeNullWhen(false)] out V result) - where V : INumberBase - { - result = V.CreateSaturating(value._real.Value); - return true; - } - - public static bool TryConvertToTruncating(Complex value, [MaybeNullWhen(false)] out V result) - where V : INumberBase - { - result = V.CreateTruncating(value._real.Value); - return true; - } - - // - // IDifferentiableFunctions interface - // - - // Exponential functions - - public static Complex Exp(Complex z) - { - Real expReal = Real.Exp(z._real); - return new(expReal * Real.Cos(z._imaginary), expReal * Real.Sin(z._imaginary)); - } - - public static Complex Exp2(Complex z) => Exp(Real.Ln2 * z); - - public static Complex Exp10(Complex z) => Exp(Real.Ln10 * z); - - // Hyperbolic functions - - public static Complex Acosh(Complex z) => Ln(z + Sqrt(z * z - One)); - - public static Complex Asinh(Complex z) => Ln(z + Sqrt(z * z + One)); - - public static Complex Atanh(Complex z) => s_oneOverTwo * Ln((One + z) / (One - z)); - - public static Complex Cosh(Complex z) - => new(Real.Cosh(z._real) * Real.Cos(z._imaginary), Real.Sinh(z._real) * Real.Sin(z._imaginary)); - - public static Complex Sinh(Complex z) - => new(Real.Sinh(z._real) * Real.Cos(z._imaginary), Real.Cosh(z._real) * Real.Sin(z._imaginary)); - - public static Complex Tanh(Complex z) => Sinh(z) / Cosh(z); - - // Logarithmic functions - - public static Complex Ln(Complex z) => new(Real.Ln(Hypot(z._real.Value, z._imaginary.Value)), Real.Atan2(z._imaginary, z._real)); - - public static Complex Log(Complex z, Complex b) => Ln(z) / Ln(b); - - public static Complex Log2(Complex z) => Ln(z) / Ln(Real.Ln2); - - public static Complex Log10(Complex z) => Ln(z) / Ln(Real.Ln10); - - // Power functions - - public static Complex Pow(Complex z, Complex w) => Exp(w * Ln(z)); - - // Root functions - - public static Complex Cbrt(Complex z) => Exp(Ln(z) / s_three); - - public static Complex Root(Complex z, Complex w) => Exp(Ln(z) / w); - - public static Complex Sqrt(Complex z) => Exp(s_oneOverTwo * Ln(z)); - - // Trigonometric functions - - public static Complex Acos(Complex z) - { - AsinInternal(Real.Abs(z._real), Real.Abs(z._imaginary), out Real b, out Real bPrime, out Real v); - - Real u; - if (bPrime < Real.Zero) - { - u = Real.Acos(b); - } - else - { - u = Real.Atan(Real.One / bPrime); - } - - if (z._real < Real.Zero) - { - u = Real.Pi - u; - } - if (z._imaginary > Real.Zero) - { - v = -v; - } - - return new(u, v); - } - - public static Complex Asin(Complex z) - { - AsinInternal(Real.Abs(z._real), Real.Abs(z._imaginary), out Real b, out Real bPrime, out Real v); - - Real u; - if (bPrime < Real.Zero) - { - u = Real.Asin(b); - } - else - { - u = Real.Atan(bPrime); - } - - if (z._real < Real.Zero) - { - u = -u; - } - if (z._imaginary < Real.Zero) - { - v = -v; - } - - return new(u, v); - } - - private static void AsinInternal(Real x, Real y, out Real b, out Real bPrime, out Real v) - { - // This is the same method described by Hull, Fairgrieve, and Tang in "Implementing the Complex - // ArcSine and Arccosine Functions Using Exception Handling" that is used in System.Numerics.Complex. - if (x > s_asinOverflowThreshold || y > s_asinOverflowThreshold) - { - b = -Real.One; - bPrime = x / y; - - Real small, big; - if (x < y) - { - small = x; - big = y; - } - else - { - small = y; - big = x; - } - Real ratio = small / big; - v = Real.Ln2 + Real.Ln(big) + Real.Ln(ratio * ratio + Real.One) / Real.Two; - } - else - { - Real r = Hypot((x + Real.One).Value, y.Value); - Real s = Hypot((x - Real.One).Value, y.Value); - - Real a = (r + s) / Real.Two; - b = x / a; - - if (b > s_threeOverFour) - { - if (x <= Real.One) - { - Real amx = (y * y / (r + (x + Real.One)) + (s + (Real.One - x))) / Real.Two; - bPrime = x / Real.Sqrt((a + x) * amx); - } - else - { - Real t = (Real.One / (r + (x + Real.One)) + Real.One / (s + (x - Real.One))) / Real.Two; - bPrime = x / y / Real.Sqrt((a + x) * t); - } - } - else - { - bPrime = -Real.One; - } - - if (a < s_threeOverTwo) - { - if (x < Real.One) - { - Real t = (Real.One / (r + (x + Real.One)) + Real.One / (s + (Real.One - x))) / Real.Two; - Real am1 = y * y * t; - v = Real.Ln(am1 + y * Real.Sqrt(t * (a + Real.One)) + Real.One); - } - else - { - Real am1 = (y * y / (r + (x + Real.One)) + (s + (x - Real.One))) / Real.Two; - v = Real.Ln(am1 + Real.Sqrt(am1 * (a + Real.One)) + Real.One); - } - } - else - { - v = Real.Ln(a + Real.Sqrt((a - Real.One) * (a + Real.One))); - } - } - } - - public static Complex Atan(Complex z) => s_imOverTwo * Ln((s_im + z) / (s_im - z)); - - public static Complex Cos(Complex z) - { - Real p = Real.Exp(z._imaginary); - Real q = Real.One / p; - Real sinh = (p - q) / Real.Two; - Real cosh = (p + q) / Real.Two; - return new(Real.Cos(z._real) * cosh, -Real.Sin(z._real) * sinh); - } - - public static Complex Sin(Complex z) - { - Real p = Real.Exp(z._imaginary); - Real q = Real.One / p; - Real sinh = (p - q) / Real.Two; - Real cosh = (p + q) / Real.Two; - return new(Real.Sin(z._real) * cosh, Real.Cos(z._real) * sinh); - } - - public static Complex Tan(Complex z) - { - Real x2 = Real.Two * z._real; - Real y2 = Real.Two * z._imaginary; - Real p = Real.Exp(y2); - Real q = Real.One / p; - Real cosh = (p + q) / Real.Two; - if (Real.Abs(z._imaginary) <= s_four) - { - Real sinh = (p - q) / Real.Two; - Real D = Real.Cos(x2) + cosh; - return new(Real.Sin(x2) / D, sinh / D); - } - else - { - Real D = Real.One + Real.Cos(x2) / cosh; - return new(Real.Sin(x2) / cosh / D, Real.Tanh(y2) / D); - } - } - - // - // Implicit Operators - // - - public static implicit operator Complex(T x) => new(x); - - /// Convert a value of type to one of type - /// The value to convert - public static implicit operator Complex(Real x) => new(x); -} diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/ComplexNumber.cs new file mode 100644 index 00000000..35f91d82 --- /dev/null +++ b/src/Mathematics.NET/Core/ComplexNumber.cs @@ -0,0 +1,664 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Mathematics.NET.Core; + +/// Represents a complex number +[Serializable] +[StructLayout(LayoutKind.Sequential)] +public readonly struct ComplexNumber + : IComplex, + IDifferentiableFunctions +{ + private static readonly ComplexNumber s_im = new(Real.Zero, Real.One); + private static readonly ComplexNumber s_imOverTwo = new(Real.Zero, Real.One / 2.0); + + // For computing Asin and Acos + private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / 2.0; + + public static readonly ComplexNumber Zero = Real.Zero; + public static readonly ComplexNumber One = Real.One; + + public static readonly ComplexNumber NaN = new(Real.NaN, Real.NaN); + public static readonly ComplexNumber Infinity = new(Real.PositiveInfinity, Real.PositiveInfinity); + + private readonly Real _real; + private readonly Real _imaginary; + + public ComplexNumber(Real real) + { + _real = real; + _imaginary = 0.0; + } + + public ComplexNumber(Real real, Real imaginary) + { + _real = real; + _imaginary = imaginary; + } + + // + // Complex number properties + // + + public Real Re => _real; + public Real Im => _imaginary; + + public Real Magnitude => Hypot(_real.Value, _imaginary.Value); + public Real Phase => Math.Atan2(_imaginary.Value, _real.Value); + + // + // Constants + // + + static ComplexNumber IComplex.Zero => Zero; + static ComplexNumber IComplex.One => One; + static ComplexNumber IComplex.NaN => NaN; + + // + // Operators + // + + public static ComplexNumber operator -(ComplexNumber z) => new(-z._real, -z._imaginary); + + public static ComplexNumber operator +(ComplexNumber z, ComplexNumber w) => new(z._real + w._real, z._imaginary + w._imaginary); + + public static ComplexNumber operator -(ComplexNumber z, ComplexNumber w) => new(z._real - w._real, z._imaginary - w._imaginary); + + public static ComplexNumber operator *(ComplexNumber z, ComplexNumber w) + => new(z._real * w._real - z._imaginary * w._imaginary, z._real * w._imaginary + w._real * z._imaginary); + + // From Michael Baudin and Robert L. Smith + public static ComplexNumber operator /(ComplexNumber z, ComplexNumber w) + { + var zRe = z._real.Value; + var zIm = z._imaginary.Value; + var wRe = w._real.Value; + var wIm = w._imaginary.Value; + + double reResult; + double imResult; + if (Math.Abs(wIm) <= Math.Abs(wRe)) + { + DivisionHelper(zRe, zIm, wRe, wIm, out reResult, out imResult); + } + else + { + DivisionHelper(zIm, zRe, wIm, wRe, out reResult, out imResult); + imResult = -imResult; + } + + return new(reResult, imResult); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void DivisionHelper(double x, double y, double maxW, double minW, out double real, out double imaginary) + { + var ratio = minW / maxW; + var scale = 1.0 / (maxW + minW * ratio); + if (ratio != 0.0) + { + real = (x + y * ratio) * scale; + imaginary = (y - x * ratio) * scale; + } + else + { + real = (x + minW * (y / maxW)) * scale; + imaginary = (y - minW * (x / maxW)) * scale; + } + } + + // + // Equality + // + + public static bool operator ==(ComplexNumber left, ComplexNumber right) => left.Re == right.Re && left.Im == right.Im; + + public static bool operator !=(ComplexNumber left, ComplexNumber right) => left.Re != right.Re || left.Im != right.Im; + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is ComplexNumber other && Equals(other); + + public bool Equals(ComplexNumber value) => _real.Equals(value.Re) && _imaginary.Equals(value.Im); + + public override int GetHashCode() => HashCode.Combine(_real, _imaginary); + + // + // Formatting + // + + public override string ToString() => ToString(null, null); + + public string ToString(string? format, IFormatProvider? provider) + { + format = string.IsNullOrEmpty(format) ? "ALL" : format.ToUpperInvariant(); + provider ??= NumberFormatInfo.InvariantInfo; + + if (format is "ALL") + { + return string.Format(provider, "({0}, {1})", _real.ToString(null, provider), _imaginary.ToString(null, provider)); + } + else if (format is "RE") + { + return string.Format(provider, "{0}", _real.ToString(null, provider)); + } + else if (format is "IM") + { + return string.Format(provider, "{0}", _imaginary.ToString(null, provider)); + } + else + { + throw new FormatException($"The \"{format}\" format is not supported."); + } + } + + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + format = format.IsEmpty ? "ALL" : format.ToString().ToUpperInvariant(); + provider ??= NumberFormatInfo.InvariantInfo; + + if (format is "ALL") + { + // There are a minimum of 6 characters for "(0, 0)". + int charsCurrentlyWritten = 0; + if (destination.Length < 6) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + destination[charsCurrentlyWritten++] = '('; + + bool tryFormatSucceeded = _real.TryFormat(destination[charsCurrentlyWritten..], out int tryFormatCharsWritten, null, provider); + charsCurrentlyWritten += tryFormatCharsWritten; + if (!tryFormatSucceeded || destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + destination[charsCurrentlyWritten++] = ','; + if (destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + destination[charsCurrentlyWritten++] = ' '; + if (destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + tryFormatSucceeded = _imaginary.TryFormat(destination[charsCurrentlyWritten..], out tryFormatCharsWritten, null, provider); + charsCurrentlyWritten += tryFormatCharsWritten; + if (!tryFormatSucceeded || destination.Length < charsCurrentlyWritten + 1) + { + charsWritten = charsCurrentlyWritten; + return false; + } + + destination[charsCurrentlyWritten++] = ')'; + + charsWritten = charsCurrentlyWritten; + return true; + } + else if (format is "RE") + { + return _real.TryFormat(destination, out charsWritten, null, provider); + } + else if (format is "IM") + { + return _imaginary.TryFormat(destination, out charsWritten, null, provider); + } + else + { + throw new FormatException($"The \"{format}\" format is not supported."); + } + } + + // + // Parsing + // + + public static ComplexNumber Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); + + public static ComplexNumber Parse(ReadOnlySpan s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); + + public static ComplexNumber Parse(string s, NumberStyles style, IFormatProvider? provider) + { + ArgumentNullException.ThrowIfNull(s); + return Parse((ReadOnlySpan)s, style, provider); + } + + public static ComplexNumber Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) + { + if (!TryParse(s, style, provider, out ComplexNumber result)) + { + return Infinity; + } + return result; + } + + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out ComplexNumber result) + => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); + + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out ComplexNumber result) + => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); + + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out ComplexNumber result) + => TryParse((ReadOnlySpan)s, style, provider, out result); + + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out ComplexNumber result) + { + s = s.Trim(); + int openParenthesis = s.IndexOf('('); + int split = s.IndexOf(','); + int closeParenthesis = s.IndexOf(')'); + + // There a minimum of 5 characters for "(0,0)". + if (s.Length < 5 || openParenthesis == -1 || split == -1 || closeParenthesis == -1 || openParenthesis > split || openParenthesis > closeParenthesis || split > closeParenthesis) + { + result = Zero; + return false; + } + + if (!Real.TryParse(s.Slice(openParenthesis + 1, split - 1), style, provider, out Real real)) + { + result = Zero; + return false; + } + + if (!Real.TryParse(s.Slice(split + 1, closeParenthesis - split - 1), style, provider, out Real imaginary)) + { + result = Zero; + return false; + } + + result = new(real, imaginary); + return true; + } + + // + // Methods + // + + public static ComplexNumber Abs(ComplexNumber z) => Hypot(z._real.Value, z._imaginary.Value); + + public static ComplexNumber Conjugate(ComplexNumber z) => new(z._real, -z._imaginary); + + public static ComplexNumber FromPolarForm(Real magnitude, Real phase) + => new(magnitude * Math.Cos(phase.Value), magnitude * Math.Sin(phase.Value)); + + private static double Hypot(double x, double y) + { + // Factor out the larger value to avoid possible overflow + x = Math.Abs(x); + y = Math.Abs(y); + + double small, large; + if (x < y) + { + small = x; + large = y; + } + else + { + small = y; + large = x; + } + + if (small == 0.0) + { + return large; + } + else if (double.IsPositiveInfinity(large) && !double.IsNaN(small)) + { + return double.PositiveInfinity; + } + else + { + double ratio = small / large; + return large * Math.Sqrt(1.0 + ratio * ratio); + } + } + + public static bool IsFinite(ComplexNumber z) => Real.IsFinite(z._real) && Real.IsFinite(z._imaginary); + + public static bool IsInfinity(ComplexNumber z) => Real.IsInfinity(z._real) || Real.IsInfinity(z._imaginary); + + public static bool IsNaN(ComplexNumber z) => !IsInfinity(z) && !IsFinite(z); + + public static bool IsZero(ComplexNumber z) => Real.IsZero(z._real) && Real.IsZero(z._imaginary); + + public static ComplexNumber Reciprocate(ComplexNumber z) + { + if (z._real == 0.0 && z._imaginary == 0.0) + { + return Infinity; + } + + var re = z._real.Value; + var im = z._imaginary.Value; + + double reResult; + double imResult; + if (Math.Abs(im) <= Math.Abs(re)) + { + DivisionHelper(1.0, 0.0, re, im, out reResult, out imResult); + } + else + { + DivisionHelper(0.0, 1.0, im, re, out reResult, out imResult); + imResult = -imResult; + } + + return new(reResult, imResult); + } + + // We will only consider the real part of complex numbers for these conversions. + + public static bool TryConvertFromChecked(V value, out ComplexNumber result) + where V : INumberBase + { + result = double.CreateChecked(value); + return true; + } + + public static bool TryConvertFromSaturating(V value, out ComplexNumber result) + where V : INumberBase + { + result = double.CreateSaturating(value); + return true; + } + + public static bool TryConvertFromTruncating(V value, out ComplexNumber result) + where V : INumberBase + { + result = double.CreateTruncating(value); + return true; + } + + public static bool TryConvertToChecked(ComplexNumber value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + if (value._imaginary == Real.Zero) + { + throw new OverflowException(); + } + + result = V.CreateChecked(value._real.Value); + return true; + } + + public static bool TryConvertToSaturating(ComplexNumber value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + result = V.CreateSaturating(value._real.Value); + return true; + } + + public static bool TryConvertToTruncating(ComplexNumber value, [MaybeNullWhen(false)] out V result) + where V : INumberBase + { + result = V.CreateTruncating(value._real.Value); + return true; + } + + // + // IDifferentiableFunctions interface + // + + // Exponential functions + + public static ComplexNumber Exp(ComplexNumber z) + { + Real expReal = Real.Exp(z._real); + return new(expReal * Real.Cos(z._imaginary), expReal * Real.Sin(z._imaginary)); + } + + public static ComplexNumber Exp2(ComplexNumber z) => Exp(Real.Ln2 * z); + + public static ComplexNumber Exp10(ComplexNumber z) => Exp(Real.Ln10 * z); + + // Hyperbolic functions + + public static ComplexNumber Acosh(ComplexNumber z) => Ln(z + Sqrt(z * z - One)); + + public static ComplexNumber Asinh(ComplexNumber z) => Ln(z + Sqrt(z * z + One)); + + public static ComplexNumber Atanh(ComplexNumber z) => 0.5 * Ln((One + z) / (One - z)); + + public static ComplexNumber Cosh(ComplexNumber z) + => new(Real.Cosh(z._real) * Real.Cos(z._imaginary), Real.Sinh(z._real) * Real.Sin(z._imaginary)); + + public static ComplexNumber Sinh(ComplexNumber z) + => new(Real.Sinh(z._real) * Real.Cos(z._imaginary), Real.Cosh(z._real) * Real.Sin(z._imaginary)); + + public static ComplexNumber Tanh(ComplexNumber z) => Sinh(z) / Cosh(z); + + // Logarithmic functions + + public static ComplexNumber Ln(ComplexNumber z) => new(Real.Ln(Hypot(z._real.Value, z._imaginary.Value)), Real.Atan2(z._imaginary, z._real)); + + public static ComplexNumber Log(ComplexNumber z, ComplexNumber b) => Ln(z) / Ln(b); + + public static ComplexNumber Log2(ComplexNumber z) => Ln(z) / Ln(Real.Ln2); + + public static ComplexNumber Log10(ComplexNumber z) => Ln(z) / Ln(Real.Ln10); + + // Power functions + + public static ComplexNumber Pow(ComplexNumber z, ComplexNumber w) => Exp(w * Ln(z)); + + // Root functions + + public static ComplexNumber Cbrt(ComplexNumber z) => Exp(Ln(z) / 3.0); + + public static ComplexNumber Root(ComplexNumber z, ComplexNumber w) => Exp(Ln(z) / w); + + public static ComplexNumber Sqrt(ComplexNumber z) => Exp(0.5 * Ln(z)); + + // Trigonometric functions + + public static ComplexNumber Acos(ComplexNumber z) + { + AsinInternal(Real.Abs(z._real), Real.Abs(z._imaginary), out Real b, out Real bPrime, out Real v); + + Real u; + if (bPrime < Real.Zero) + { + u = Real.Acos(b); + } + else + { + u = Real.Atan(Real.One / bPrime); + } + + if (z._real < Real.Zero) + { + u = Real.Pi - u; + } + if (z._imaginary > Real.Zero) + { + v = -v; + } + + return new(u, v); + } + + public static ComplexNumber Asin(ComplexNumber z) + { + AsinInternal(Real.Abs(z._real), Real.Abs(z._imaginary), out Real b, out Real bPrime, out Real v); + + Real u; + if (bPrime < Real.Zero) + { + u = Real.Asin(b); + } + else + { + u = Real.Atan(bPrime); + } + + if (z._real < Real.Zero) + { + u = -u; + } + if (z._imaginary < Real.Zero) + { + v = -v; + } + + return new(u, v); + } + + private static void AsinInternal(Real x, Real y, out Real b, out Real bPrime, out Real v) + { + // This is the same method described by Hull, Fairgrieve, and Tang in "Implementing the Complex + // ArcSine and Arccosine Functions Using Exception Handling" that is used in System.Numerics.Complex. + if (x > s_asinOverflowThreshold || y > s_asinOverflowThreshold) + { + b = -Real.One; + bPrime = x / y; + + Real small, big; + if (x < y) + { + small = x; + big = y; + } + else + { + small = y; + big = x; + } + Real ratio = small / big; + v = Real.Ln2 + Real.Ln(big) + Real.Ln(ratio * ratio + Real.One) / 2.0; + } + else + { + Real r = Hypot((x + Real.One).Value, y.Value); + Real s = Hypot((x - Real.One).Value, y.Value); + + Real a = (r + s) / 2.0; + b = x / a; + + if (b > 0.75) + { + if (x <= Real.One) + { + Real amx = (y * y / (r + (x + Real.One)) + (s + (Real.One - x))) / 2.0; + bPrime = x / Real.Sqrt((a + x) * amx); + } + else + { + Real t = (Real.One / (r + (x + Real.One)) + Real.One / (s + (x - Real.One))) / 2.0; + bPrime = x / y / Real.Sqrt((a + x) * t); + } + } + else + { + bPrime = -Real.One; + } + + if (a < 1.5) + { + if (x < Real.One) + { + Real t = (Real.One / (r + (x + Real.One)) + Real.One / (s + (Real.One - x))) / 2.0; + Real am1 = y * y * t; + v = Real.Ln(am1 + y * Real.Sqrt(t * (a + Real.One)) + Real.One); + } + else + { + Real am1 = (y * y / (r + (x + Real.One)) + (s + (x - Real.One))) / 2.0; + v = Real.Ln(am1 + Real.Sqrt(am1 * (a + Real.One)) + Real.One); + } + } + else + { + v = Real.Ln(a + Real.Sqrt((a - Real.One) * (a + Real.One))); + } + } + } + + public static ComplexNumber Atan(ComplexNumber z) => s_imOverTwo * Ln((s_im + z) / (s_im - z)); + + public static ComplexNumber Cos(ComplexNumber z) + { + Real p = Real.Exp(z._imaginary); + Real q = Real.One / p; + Real sinh = (p - q) / 2.0; + Real cosh = (p + q) / 2.0; + return new(Real.Cos(z._real) * cosh, -Real.Sin(z._real) * sinh); + } + + public static ComplexNumber Sin(ComplexNumber z) + { + Real p = Real.Exp(z._imaginary); + Real q = Real.One / p; + Real sinh = (p - q) / 2.0; + Real cosh = (p + q) / 2.0; + return new(Real.Sin(z._real) * cosh, Real.Cos(z._real) * sinh); + } + + public static ComplexNumber Tan(ComplexNumber z) + { + Real x2 = 2.0 * z._real; + Real y2 = 2.0 * z._imaginary; + Real p = Real.Exp(y2); + Real q = Real.One / p; + Real cosh = (p + q) / 2.0; + if (Real.Abs(z._imaginary) <= 4.0) + { + Real sinh = (p - q) / 2.0; + Real D = Real.Cos(x2) + cosh; + return new(Real.Sin(x2) / D, sinh / D); + } + else + { + Real D = Real.One + Real.Cos(x2) / cosh; + return new(Real.Sin(x2) / cosh / D, Real.Tanh(y2) / D); + } + } + + // + // Implicit Operators + // + + public static implicit operator ComplexNumber(double x) => new(x); + + /// Convert a value of type to one of type + /// The value to convert + public static implicit operator ComplexNumber(Real x) => new(x); +} diff --git a/src/Mathematics.NET/Core/Extensions.cs b/src/Mathematics.NET/Core/Extensions.cs index 8ccd7740..fdff5455 100644 --- a/src/Mathematics.NET/Core/Extensions.cs +++ b/src/Mathematics.NET/Core/Extensions.cs @@ -29,10 +29,11 @@ namespace Mathematics.NET.Core; +/// Extension methods for Mathematics.NET public static class Extensions { - public static Rational Reduce(this Rational r) + /// + public static Rational Reduce(this Rational r) where T : IBinaryInteger - where U : IFloatingPointIeee754, IMinMaxValue - => Rational.Reduce(r); + => Rational.Reduce(r); } diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 0c0f4d18..40607a11 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -36,8 +36,7 @@ namespace Mathematics.NET.Core; /// Defines support for complex numbers /// The type that implements the interface -/// A type that implements and -public interface IComplex +public interface IComplex : IAdditionOperation, IDivisionOperation, IMultiplicationOperation, @@ -47,20 +46,19 @@ public interface IComplex IEquatable, ISpanFormattable, ISpanParsable - where T : IComplex - where U : IFloatingPointIeee754, IMinMaxValue + where T : IComplex { /// The real part of the complex number - public Real Re { get; } + public Real Re { get; } /// The imaginary part of the complex number - public virtual Real Im => Real.Zero; + public virtual Real Im => Real.Zero; /// The magnitude of the complex number in polar coordinates - public virtual Real Magnitude => U.Hypot(Re.Value, Im.Value); + public virtual Real Magnitude => Real.Hypot(Re, Im); /// The phase of the complex number in polar coordinates - public virtual Real Phase => U.Atan2(Im.Value, Re.Value); + public virtual Real Phase => Real.Atan2(Im, Re); /// Reprsents zero for the type static abstract T Zero { get; } @@ -68,9 +66,6 @@ public interface IComplex /// Represents one for the type static abstract T One { get; } - /// Represents two for the type - static abstract T Two { get; } - /// Represents NaN for the type static abstract T NaN { get; } @@ -85,17 +80,17 @@ public interface IComplex static abstract T Conjugate(T z); /// Convert a value to one of the current type, and throw and overflow exception if the value falls outside the representable range. - /// The type from which to convert + /// The type from which to convert /// The value to convert /// The result of the conversion - /// Conversions from the type are not supported. + /// Conversions from the type are not supported. [MethodImpl(MethodImplOptions.AggressiveInlining)] - static virtual T CreateChecked(V value) - where V : INumberBase + static virtual T CreateChecked(U value) + where U : INumberBase { T? result; - if (typeof(V) == typeof(T)) + if (typeof(U) == typeof(T)) { result = (T)(object)value; } @@ -108,17 +103,17 @@ static virtual T CreateChecked(V value) } /// Convert a value to one of the current type, and saturate values that fall outside the representable range. - /// The type from which to convert + /// The type from which to convert /// The value to convert /// The result of the conversion - /// Conversions from the type are not supported. + /// Conversions from the type are not supported. [MethodImpl(MethodImplOptions.AggressiveInlining)] - static virtual T CreateSaturating(V value) - where V : INumberBase + static virtual T CreateSaturating(U value) + where U : INumberBase { T? result; - if (typeof(V) == typeof(T)) + if (typeof(U) == typeof(T)) { result = (T)(object)value; } @@ -131,17 +126,17 @@ static virtual T CreateSaturating(V value) } /// Convert a value to one of another type, and truncate values that fall outside of the representable range. - /// The type from which to convert + /// The type from which to convert /// The value to convert /// The result of the conversion - /// Conversions from the type are not supported. + /// Conversions from the type are not supported. [MethodImpl(MethodImplOptions.AggressiveInlining)] - static virtual T CreateTruncating(V value) - where V : INumberBase + static virtual T CreateTruncating(U value) + where U : INumberBase { T? result; - if (typeof(V) == typeof(T)) + if (typeof(U) == typeof(T)) { result = (T)(object)value; } @@ -197,54 +192,54 @@ static virtual T CreateTruncating(V value) static abstract T Reciprocate(T z); /// Try to convert a value to one of the current type, and throw and overflow exception if the value falls outside the representable range. - /// The type from which to convert + /// The type from which to convert /// The value to convert /// The result of the conversion /// true if the conversion was successful; otherwise, false /// The value is not representable by the type . - protected static abstract bool TryConvertFromChecked(V value, [MaybeNullWhen(false)] out T result) - where V : INumberBase; + protected static abstract bool TryConvertFromChecked(U value, [MaybeNullWhen(false)] out T result) + where U : INumberBase; /// Try to convert a value to one of the current type, and saturate values that fall outside the representable range. - /// The type from which to convert + /// The type from which to convert /// The value to convert /// The result of the conversion /// true if the conversion was successful; otherwise, false - protected static abstract bool TryConvertFromSaturating(V value, [MaybeNullWhen(false)] out T result) - where V : INumberBase; + protected static abstract bool TryConvertFromSaturating(U value, [MaybeNullWhen(false)] out T result) + where U : INumberBase; /// Try to convert a value to one of the current type, and truncate values that fall outside the representable range. - /// The type from which to convert + /// The type from which to convert /// The value to convert /// The result of the conversion /// true if the conversion was successful; otherwise, false - protected static abstract bool TryConvertFromTruncating(V value, [MaybeNullWhen(false)] out T result) - where V : INumberBase; + protected static abstract bool TryConvertFromTruncating(U value, [MaybeNullWhen(false)] out T result) + where U : INumberBase; /// Try to convert a value to one of another type, and throw and overflow exception if the value falls outside the representable range. - /// The target type + /// The target type /// The value to convert /// The result of the conversion /// true if the conversion was successful; otherwise, false /// The value is not representable by the target type. - protected static abstract bool TryConvertToChecked(T value, [MaybeNullWhen(false)] out V result) - where V : INumberBase; + protected static abstract bool TryConvertToChecked(T value, [MaybeNullWhen(false)] out U result) + where U : INumberBase; /// Try to convert a value to one of another type, and saturate values that fall outside of the representable range. - /// The target type + /// The target type /// The value to convert /// The result of the conversion /// true if the conversion was successful; otherwise, false - protected static abstract bool TryConvertToSaturating(T value, [MaybeNullWhen(false)] out V result) - where V : INumberBase; + protected static abstract bool TryConvertToSaturating(T value, [MaybeNullWhen(false)] out U result) + where U : INumberBase; /// Try to convert a value to one of another type, and truncate values that fall outside of the representable range. - /// The target type + /// The target type /// The value to convert /// The result of the conversion /// true if the conversion was successful; otherwise, false - protected static abstract bool TryConvertToTruncating(T value, [MaybeNullWhen(false)] out V result) - where V : INumberBase; + protected static abstract bool TryConvertToTruncating(T value, [MaybeNullWhen(false)] out U result) + where U : INumberBase; /// Try to parse a string into a value /// The string to parse @@ -266,5 +261,5 @@ protected static abstract bool TryConvertToTruncating(T value, [MaybeNullWhen /// Convert a value of type to one of type /// The value to convert - static virtual implicit operator T(U x) => T.CreateTruncating(x); + static virtual implicit operator T(double x) => T.CreateSaturating(x); } diff --git a/src/Mathematics.NET/Core/IConstants.cs b/src/Mathematics.NET/Core/IConstants.cs index b9cbd048..b7af8e79 100644 --- a/src/Mathematics.NET/Core/IConstants.cs +++ b/src/Mathematics.NET/Core/IConstants.cs @@ -25,16 +25,12 @@ // SOFTWARE. // -using System.Numerics; - namespace Mathematics.NET.Core; /// Defines support for common mathematical constants /// The type that implements the interface -/// A type that implements and -public interface IConstants : IComplex - where T : IConstants - where U : IFloatingPointIeee754, IMinMaxValue +public interface IConstants : IComplex + where T : IConstants { /// static abstract T E { get; } diff --git a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs index 60011e7e..a57d4e92 100644 --- a/src/Mathematics.NET/Core/IDifferentiableFunctions.cs +++ b/src/Mathematics.NET/Core/IDifferentiableFunctions.cs @@ -25,16 +25,12 @@ // SOFTWARE. // -using System.Numerics; - namespace Mathematics.NET.Core; /// Defines support for common differentiable functions /// The type that implements the interface -/// A type that implements and -public interface IDifferentiableFunctions : IComplex - where T : IDifferentiableFunctions - where U : IFloatingPointIeee754, IMinMaxValue +public interface IDifferentiableFunctions : IComplex + where T : IDifferentiableFunctions { // // Exponential functions diff --git a/src/Mathematics.NET/Core/IRational.cs b/src/Mathematics.NET/Core/IRational.cs index afabffbf..5341fed2 100644 --- a/src/Mathematics.NET/Core/IRational.cs +++ b/src/Mathematics.NET/Core/IRational.cs @@ -32,11 +32,9 @@ namespace Mathematics.NET.Core; /// Defines support for rational numbers /// A type that implements the interface /// A type that implements -/// A type that implements and -public interface IRational : IReal - where T : IRational +public interface IRational : IReal + where T : IRational where U : IBinaryInteger - where V : IFloatingPointIeee754, IMinMaxValue { /// Get the numerator of the rational number U Num { get; } diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 21698570..8169c6bb 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -33,20 +33,18 @@ namespace Mathematics.NET.Core; /// Defines support for real numbers /// A type that implements the interface -/// A type that implements and -public interface IReal - : IComplex, +public interface IReal + : IComplex, IInequalityRelations, IDecrementOperation, IIncrementOperation, IComparable, IComparable, IMinMaxValue - where T : IReal - where U : IFloatingPointIeee754, IMinMaxValue + where T : IReal { /// The backing value of the type - U Value { get; } + double Value { get; } /// Check if a value is negative infinity /// The value to check diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs index 84896777..ea97283d 100644 --- a/src/Mathematics.NET/Core/Rational.cs +++ b/src/Mathematics.NET/Core/Rational.cs @@ -35,25 +35,20 @@ namespace Mathematics.NET.Core; /// Represents a rational number /// A type that implements -/// A type that implements and [Serializable] [StructLayout(LayoutKind.Sequential)] -public readonly struct Rational : IRational, T, U> +public readonly struct Rational : IRational, T> where T : IBinaryInteger - where U : IFloatingPointIeee754, IMinMaxValue { - private static U s_ten = U.Exp10(U.One); + public static readonly Rational Zero = T.Zero; + public static readonly Rational One = T.One; - public static readonly Rational Zero = T.Zero; - public static readonly Rational One = T.One; - public static readonly Rational Two = T.One + T.One; + public static readonly Rational MaxValue = T.CreateSaturating(double.MaxValue); + public static readonly Rational MinValue = T.CreateSaturating(double.MinValue); - public static readonly Rational MaxValue = T.CreateSaturating(U.MaxValue); - public static readonly Rational MinValue = T.CreateSaturating(U.MinValue); - - public static readonly Rational NaN = new(T.Zero, T.Zero); - public static readonly Rational NegativeInfinity = new(-T.One, T.Zero); - public static readonly Rational PositiveInfinity = new(T.One, T.Zero); + public static readonly Rational NaN = new(T.Zero, T.Zero); + public static readonly Rational NegativeInfinity = new(-T.One, T.Zero); + public static readonly Rational PositiveInfinity = new(T.One, T.Zero); private readonly T _numerator; private readonly T _denominator; @@ -96,31 +91,30 @@ public Rational(T p, T q) public T Num => _numerator; public T Den => _denominator; - public Real Re => (U)this; - public U Value => (U)this; + public Real Re => (Real)this; + public double Value => (double)this; // // Constants // - static Rational IComplex, U>.Zero => Zero; - static Rational IComplex, U>.One => One; - static Rational IComplex, U>.Two => Zero; - static Rational IComplex, U>.NaN => NaN; - static Rational IMinMaxValue>.MaxValue => MaxValue; - static Rational IMinMaxValue>.MinValue => MinValue; + static Rational IComplex>.Zero => Zero; + static Rational IComplex>.One => One; + static Rational IComplex>.NaN => NaN; + static Rational IMinMaxValue>.MaxValue => MaxValue; + static Rational IMinMaxValue>.MinValue => MinValue; // // Operators // - public static Rational operator -(Rational x) => x + One; + public static Rational operator -(Rational x) => x + One; - public static Rational operator --(Rational x) => new(x._numerator, x._denominator); + public static Rational operator --(Rational x) => new(x._numerator, x._denominator); - public static Rational operator ++(Rational x) => new(x._numerator, x._denominator); + public static Rational operator ++(Rational x) => new(x._numerator, x._denominator); - public static Rational operator +(Rational x, Rational y) + public static Rational operator +(Rational x, Rational y) { var lcm = LCM(x._denominator, y._denominator); var num = lcm / x._denominator * x._numerator + lcm / y._denominator * y._numerator; @@ -128,7 +122,7 @@ public Rational(T p, T q) return new(num / gcd, lcm / gcd); } - public static Rational operator -(Rational x, Rational y) + public static Rational operator -(Rational x, Rational y) { var lcm = LCM(x._denominator, y._denominator); var num = lcm / x._denominator * x._numerator - lcm / y._denominator * y._numerator; @@ -136,7 +130,7 @@ public Rational(T p, T q) return new(num / gcd, lcm / gcd); } - public static Rational operator *(Rational x, Rational y) + public static Rational operator *(Rational x, Rational y) { var num = x._numerator * y._numerator; var den = x._denominator * y._denominator; @@ -144,7 +138,7 @@ public Rational(T p, T q) return new(num / gcd, den / gcd); } - public static Rational operator /(Rational x, Rational y) + public static Rational operator /(Rational x, Rational y) { if (y._denominator == T.Zero) { @@ -161,19 +155,19 @@ public Rational(T p, T q) // Equality // - public static bool operator ==(Rational left, Rational right) + public static bool operator ==(Rational left, Rational right) { return left._numerator == right._numerator && left._denominator == right._denominator; } - public static bool operator !=(Rational left, Rational right) + public static bool operator !=(Rational left, Rational right) { return left._numerator != right._numerator || left._denominator != right._denominator; } - public override bool Equals([NotNullWhen(true)] object? obj) => obj is Rational other && Equals(other); + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Rational other && Equals(other); - public bool Equals(Rational value) + public bool Equals(Rational value) { return _numerator.Equals(value._numerator) && _denominator.Equals(value._denominator); } @@ -184,22 +178,22 @@ public bool Equals(Rational value) // Comparison // - public static bool operator <(Rational x, Rational y) + public static bool operator <(Rational x, Rational y) { return x._numerator * y._denominator < y._numerator * x._denominator; } - public static bool operator >(Rational x, Rational y) + public static bool operator >(Rational x, Rational y) { return x._numerator * y._denominator > y._numerator * x._denominator; } - public static bool operator <=(Rational x, Rational y) + public static bool operator <=(Rational x, Rational y) { return x._numerator * y._denominator <= y._numerator * x._denominator; } - public static bool operator >=(Rational x, Rational y) + public static bool operator >=(Rational x, Rational y) { return x._numerator * y._denominator >= y._numerator * x._denominator; } @@ -211,7 +205,7 @@ public int CompareTo(object? obj) return 1; } - if (obj is Rational other) + if (obj is Rational other) { return CompareTo(other); } @@ -219,7 +213,7 @@ public int CompareTo(object? obj) throw new ArgumentException("Argument is not a rational number"); } - public int CompareTo(Rational value) + public int CompareTo(Rational value) { if (this < value) { @@ -378,35 +372,35 @@ static bool TryFormatAllInternal(T num, T den, Span destination, out int c // Parsing // - public static Rational Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); + public static Rational Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); - public static Rational Parse(ReadOnlySpan s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); + public static Rational Parse(ReadOnlySpan s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); - public static Rational Parse(string s, NumberStyles style, IFormatProvider? provider) + public static Rational Parse(string s, NumberStyles style, IFormatProvider? provider) { ArgumentNullException.ThrowIfNull(s); return Parse((ReadOnlySpan)s, style, provider); } - public static Rational Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) + public static Rational Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) { - if (!TryParse(s, style, provider, out Rational result)) + if (!TryParse(s, style, provider, out Rational result)) { return NaN; } return result; } - public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out Rational result) + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out Rational result) => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out Rational result) + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out Rational result) => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); - public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Rational result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Rational result) => TryParse((ReadOnlySpan)s, style, provider, out result); - public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out Rational result) + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out Rational result) { s = s.Trim(); int openParenthesis = s.IndexOf('('); @@ -440,9 +434,9 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // Methods // - public static Rational Abs(Rational x) => new(T.Abs(x._numerator), T.Abs(x._denominator)); + public static Rational Abs(Rational x) => new(T.Abs(x._numerator), T.Abs(x._denominator)); - public static Rational Conjugate(Rational x) => x; + public static Rational Conjugate(Rational x) => x; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static T GCD(T p, T q) @@ -463,17 +457,17 @@ private static T GCD(T p, T q) return p | q; } - public static bool IsFinite(Rational x) => !T.IsZero(x._denominator); + public static bool IsFinite(Rational x) => !T.IsZero(x._denominator); - public static bool IsInfinity(Rational x) => T.IsZero(x._denominator); + public static bool IsInfinity(Rational x) => T.IsZero(x._denominator); - public static bool IsNaN(Rational x) => T.IsZero(x._numerator) && T.IsZero(x._denominator); + public static bool IsNaN(Rational x) => T.IsZero(x._numerator) && T.IsZero(x._denominator); - public static bool IsZero(Rational x) => T.IsZero(x._numerator); + public static bool IsZero(Rational x) => T.IsZero(x._numerator); - public static bool IsNegativeInfinity(Rational x) => x._numerator == -T.One && T.IsZero(x._denominator); + public static bool IsNegativeInfinity(Rational x) => x._numerator == -T.One && T.IsZero(x._denominator); - public static bool IsPositiveInfinity(Rational x) => x._numerator == T.One && T.IsZero(x._denominator); + public static bool IsPositiveInfinity(Rational x) => x._numerator == T.One && T.IsZero(x._denominator); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static T LCM(T p, T q) @@ -496,7 +490,7 @@ private static T LCM(T p, T q) return holdP / (p | q) * holdQ; } - public static Rational Reciprocate(Rational x) + public static Rational Reciprocate(Rational x) { if (x._numerator == T.Zero) { @@ -505,7 +499,7 @@ public static Rational Reciprocate(Rational x) return new(x._denominator, x._numerator); } - public static Rational Reduce(Rational x) + public static Rational Reduce(Rational x) { var gcd = GCD(x._numerator, x._denominator); if (gcd == T.One) @@ -515,17 +509,12 @@ public static Rational Reduce(Rational x) return new(x._numerator / gcd, x._denominator / gcd); } - public static bool TryConvertFromChecked(V value, out Rational result) - where V : INumberBase + public static bool TryConvertFromChecked(U value, out Rational result) + where U : INumberBase { - if (V.IsInteger(value)) - { - result = T.CreateChecked(value); - return true; - } - else if (value is IFloatingPointIeee754 floatingPointNumber) + if (Real.TryConvertFromChecked(value, out var intermediateResult)) { - result = (Rational)(U)floatingPointNumber; + result = (Rational)intermediateResult; return true; } else @@ -535,17 +524,12 @@ public static bool TryConvertFromChecked(V value, out Rational result) } } - public static bool TryConvertFromSaturating(V value, out Rational result) - where V : INumberBase + public static bool TryConvertFromSaturating(U value, out Rational result) + where U : INumberBase { - if (V.IsInteger(value)) - { - result = T.CreateSaturating(value); - return true; - } - else if (value is IFloatingPointIeee754 floatingPointNumber) + if (Real.TryConvertFromSaturating(value, out var intermediateResult)) { - result = (Rational)(U)floatingPointNumber; + result = (Rational)intermediateResult; return true; } else @@ -555,17 +539,12 @@ public static bool TryConvertFromSaturating(V value, out Rational resul } } - public static bool TryConvertFromTruncating(V value, out Rational result) - where V : INumberBase + public static bool TryConvertFromTruncating(U value, out Rational result) + where U : INumberBase { - if (V.IsInteger(value)) - { - result = T.CreateTruncating(value); - return true; - } - else if (value is IFloatingPointIeee754 floatingPointNumber) + if (Real.TryConvertFromTruncating(value, out var intermediateResult)) { - result = (Rational)(U)floatingPointNumber; + result = (Rational)intermediateResult; return true; } else @@ -575,24 +554,24 @@ public static bool TryConvertFromTruncating(V value, out Rational resul } } - public static bool TryConvertToChecked(Rational value, [MaybeNullWhen(false)] out V result) - where V : INumberBase + public static bool TryConvertToChecked(Rational value, [MaybeNullWhen(false)] out U result) + where U : INumberBase { - result = V.CreateChecked(checked((U)value)); + result = U.CreateChecked(checked(double.CreateChecked(value._numerator) / double.CreateChecked(value._denominator))); return true; } - public static bool TryConvertToSaturating(Rational value, [MaybeNullWhen(false)] out V result) - where V : INumberBase + public static bool TryConvertToSaturating(Rational value, [MaybeNullWhen(false)] out U result) + where U : INumberBase { - result = V.CreateSaturating(U.CreateSaturating(value._numerator) / U.CreateSaturating(value._denominator)); + result = U.CreateSaturating(double.CreateSaturating(value._numerator) / double.CreateSaturating(value._denominator)); return true; } - public static bool TryConvertToTruncating(Rational value, [MaybeNullWhen(false)] out V result) - where V : INumberBase + public static bool TryConvertToTruncating(Rational value, [MaybeNullWhen(false)] out U result) + where U : INumberBase { - result = V.CreateTruncating(U.CreateTruncating(value._numerator) / U.CreateTruncating(value._denominator)); + result = U.CreateTruncating(double.CreateTruncating(value._numerator) / double.CreateTruncating(value._denominator)); return true; } @@ -600,35 +579,40 @@ public static bool TryConvertToTruncating(Rational value, [MaybeNullWhe // Implicit operators // - public static implicit operator Rational(T p) => new(p); + public static implicit operator Rational(T p) => new(p); // // Explicit operators // // TODO: Find a better implementation - public static explicit operator Rational(U x) + public static explicit operator Rational(Real x) { - if (U.IsNaN(x) || U.IsInfinity(x)) + var value = x.Value; + if (double.IsNaN(value) || double.IsInfinity(value)) { return NaN; } - var n = U.Zero; - while (x != U.Floor(x)) + var n = 0.0; + while (x != double.Floor(value)) { - x *= s_ten; + x *= 10.0; n++; } - T num = T.CreateChecked(x); - T den = T.CreateChecked(U.Pow(s_ten, n)); + T num = T.CreateChecked(value); + T den = T.CreateChecked(Math.Pow(10.0, n)); var gcd = GCD(num, den); return new(num / gcd, den / gcd); } - public static explicit operator checked U(Rational x) => checked(U.CreateChecked(x._numerator) / U.CreateChecked(x._denominator)); + public static explicit operator checked Real(Rational x) => checked(double.CreateChecked(x._numerator) / double.CreateChecked(x._denominator)); + + public static explicit operator Real(Rational x) => double.CreateSaturating(x._numerator) / double.CreateSaturating(x._denominator); + + public static explicit operator checked double(Rational x) => double.CreateChecked(x._numerator) / double.CreateChecked(x._denominator); - public static explicit operator U(Rational x) => U.CreateChecked(x._numerator) / U.CreateChecked(x._denominator); + public static explicit operator double(Rational x) => double.CreateSaturating(x._numerator) / double.CreateSaturating(x._denominator); } diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 49f033b0..b935a07c 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -36,71 +36,69 @@ namespace Mathematics.NET.Core; /// A type that implements and [Serializable] [StructLayout(LayoutKind.Sequential)] -public readonly struct Real - : IReal, T>, - IConstants, T>, - IDifferentiableFunctions, T> - where T : IFloatingPointIeee754, IMinMaxValue +public readonly struct Real + : IReal, + IConstants, + IDifferentiableFunctions { - public static readonly Real Zero = T.Zero; - public static readonly Real One = T.One; - public static readonly Real Two = T.One + T.One; + public static readonly Real Zero = 0.0; + public static readonly Real One = 1.0; - public static readonly Real MaxValue = T.MaxValue; - public static readonly Real MinValue = T.MinValue; + public static readonly Real MaxValue = double.MaxValue; + public static readonly Real MinValue = double.MinValue; - public static readonly Real NaN = T.NaN; - public static readonly Real NegativeInfinity = T.NegativeInfinity; - public static readonly Real PositiveInfinity = T.PositiveInfinity; + public static readonly Real NaN = double.NaN; + public static readonly Real NegativeInfinity = double.NegativeInfinity; + public static readonly Real PositiveInfinity = double.PositiveInfinity; /// - public static readonly Real E = T.CreateTruncating(Constants.E); + public static readonly Real E = Constants.E; /// - public static readonly Real Pi = T.CreateTruncating(Constants.Pi); + public static readonly Real Pi = Constants.Pi; /// - public static readonly Real PiOverTwo = T.CreateTruncating(Constants.PiOverTwo); + public static readonly Real PiOverTwo = Constants.PiOverTwo; /// - public static readonly Real PiSquared = T.CreateTruncating(Constants.PiSquared); + public static readonly Real PiSquared = Constants.PiSquared; /// - public static readonly Real Tau = T.CreateTruncating(Constants.Tau); + public static readonly Real Tau = Constants.Tau; /// - public static readonly Real EulerMascheroni = T.CreateTruncating(Constants.EulerMascheroni); + public static readonly Real EulerMascheroni = Constants.EulerMascheroni; /// - public static readonly Real GoldenRatio = T.CreateTruncating(Constants.GoldenRatio); + public static readonly Real GoldenRatio = Constants.GoldenRatio; /// - public static readonly Real Ln2 = T.CreateTruncating(Constants.Ln2); + public static readonly Real Ln2 = Constants.Ln2; /// - public static readonly Real Ln10 = T.CreateTruncating(Constants.Ln10); + public static readonly Real Ln10 = Constants.Ln10; /// - public static readonly Real Sqrt2 = T.CreateTruncating(Constants.Sqrt2); + public static readonly Real Sqrt2 = Constants.Sqrt2; /// - public static readonly Real Sqrt3 = T.CreateTruncating(Constants.Sqrt3); + public static readonly Real Sqrt3 = Constants.Sqrt3; /// - public static readonly Real Sqrt5 = T.CreateTruncating(Constants.Sqrt5); + public static readonly Real Sqrt5 = Constants.Sqrt5; /// - public static readonly Real ZetaOf2 = T.CreateTruncating(Constants.ZetaOf2); + public static readonly Real ZetaOf2 = Constants.ZetaOf2; /// - public static readonly Real ZetaOf3 = T.CreateTruncating(Constants.ZetaOf3); + public static readonly Real ZetaOf3 = Constants.ZetaOf3; /// - public static readonly Real ZetaOf4 = T.CreateTruncating(Constants.ZetaOf4); + public static readonly Real ZetaOf4 = Constants.ZetaOf4; - private readonly T _value; + private readonly double _value; - public Real(T real) + public Real(double real) { _value = real; } @@ -109,61 +107,60 @@ public Real(T real) // Real number properties // - public Real Re => _value; - public T Value => _value; + public Real Re => _value; + public double Value => _value; // // Constants // - static Real IComplex, T>.Zero => Zero; - static Real IComplex, T>.One => One; - static Real IComplex, T>.Two => Two; - static Real IComplex, T>.NaN => NaN; - static Real IMinMaxValue>.MaxValue => MaxValue; - static Real IMinMaxValue>.MinValue => MinValue; + static Real IComplex.Zero => Zero; + static Real IComplex.One => One; + static Real IComplex.NaN => NaN; + static Real IMinMaxValue.MaxValue => MaxValue; + static Real IMinMaxValue.MinValue => MinValue; // IConstants interface - static Real IConstants, T>.E => E; - static Real IConstants, T>.Pi => Pi; - static Real IConstants, T>.PiOverTwo => PiOverTwo; - static Real IConstants, T>.PiSquared => PiSquared; - static Real IConstants, T>.Tau => Tau; - static Real IConstants, T>.EulerMascheroni => EulerMascheroni; - static Real IConstants, T>.GoldenRatio => GoldenRatio; - static Real IConstants, T>.Ln2 => Ln2; - static Real IConstants, T>.Ln10 => Ln10; - static Real IConstants, T>.Sqrt2 => Sqrt2; - static Real IConstants, T>.Sqrt3 => Sqrt3; - static Real IConstants, T>.Sqrt5 => Sqrt5; - static Real IConstants, T>.ZetaOf2 => ZetaOf2; - static Real IConstants, T>.ZetaOf3 => ZetaOf3; - static Real IConstants, T>.ZetaOf4 => ZetaOf4; + static Real IConstants.E => E; + static Real IConstants.Pi => Pi; + static Real IConstants.PiOverTwo => PiOverTwo; + static Real IConstants.PiSquared => PiSquared; + static Real IConstants.Tau => Tau; + static Real IConstants.EulerMascheroni => EulerMascheroni; + static Real IConstants.GoldenRatio => GoldenRatio; + static Real IConstants.Ln2 => Ln2; + static Real IConstants.Ln10 => Ln10; + static Real IConstants.Sqrt2 => Sqrt2; + static Real IConstants.Sqrt3 => Sqrt3; + static Real IConstants.Sqrt5 => Sqrt5; + static Real IConstants.ZetaOf2 => ZetaOf2; + static Real IConstants.ZetaOf3 => ZetaOf3; + static Real IConstants.ZetaOf4 => ZetaOf4; // // Operators // - public static Real operator -(Real value) => -value._value; - public static Real operator --(Real value) => value._value - One; - public static Real operator ++(Real value) => value._value + One; - public static Real operator +(Real left, Real right) => left._value + right._value; - public static Real operator -(Real left, Real right) => left._value - right._value; - public static Real operator *(Real left, Real right) => left._value * right._value; - public static Real operator /(Real left, Real right) => left._value / right._value; + public static Real operator -(Real value) => -value._value; + public static Real operator --(Real value) => value._value - One; + public static Real operator ++(Real value) => value._value + One; + public static Real operator +(Real left, Real right) => left._value + right._value; + public static Real operator -(Real left, Real right) => left._value - right._value; + public static Real operator *(Real left, Real right) => left._value * right._value; + public static Real operator /(Real left, Real right) => left._value / right._value; // // Equality // - public static bool operator ==(Real left, Real right) => left._value == right._value; + public static bool operator ==(Real left, Real right) => left._value == right._value; - public static bool operator !=(Real left, Real right) => left._value != right._value; + public static bool operator !=(Real left, Real right) => left._value != right._value; - public override bool Equals([NotNullWhen(true)] object? obj) => obj is Real other && Equals(other); + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Real other && Equals(other); - public bool Equals(Real value) => _value.Equals(value._value); + public bool Equals(Real value) => _value.Equals(value._value); public override int GetHashCode() => HashCode.Combine(_value); @@ -171,10 +168,10 @@ public Real(T real) // Comparison // - public static bool operator <(Real left, Real right) => left._value < right._value; - public static bool operator >(Real left, Real right) => left._value > right._value; - public static bool operator <=(Real left, Real right) => left._value <= right._value; - public static bool operator >=(Real left, Real right) => left._value >= right._value; + public static bool operator <(Real left, Real right) => left._value < right._value; + public static bool operator >(Real left, Real right) => left._value > right._value; + public static bool operator <=(Real left, Real right) => left._value <= right._value; + public static bool operator >=(Real left, Real right) => left._value >= right._value; public int CompareTo(object? obj) { @@ -183,7 +180,7 @@ public int CompareTo(object? obj) return 1; } - if (obj is Real value) + if (obj is Real value) { return _value.CompareTo(value._value); } @@ -191,7 +188,7 @@ public int CompareTo(object? obj) throw new ArgumentException("Argument is not a real number"); } - public int CompareTo(Real value) => _value.CompareTo(value._value); + public int CompareTo(Real value) => _value.CompareTo(value._value); // // Formatting @@ -208,53 +205,53 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan // Parsing // - public static Real Parse(string s, IFormatProvider? provider) => T.Parse(s, provider); + public static Real Parse(string s, IFormatProvider? provider) => double.Parse(s, provider); - public static Real Parse(ReadOnlySpan s, IFormatProvider? provider) => T.Parse(s, provider); + public static Real Parse(ReadOnlySpan s, IFormatProvider? provider) => double.Parse(s, provider); - public static Real Parse(string s, NumberStyles style, IFormatProvider? provider) - => T.Parse(s, style, provider); + public static Real Parse(string s, NumberStyles style, IFormatProvider? provider) + => double.Parse(s, style, provider); - public static Real Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) - => T.Parse(s, style, provider); + public static Real Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) + => double.Parse(s, style, provider); - public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out Real result) + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out Real result) { - var succeeded = T.TryParse(s, provider, out T? number); - result = number!; + var succeeded = double.TryParse(s, provider, out double number); + result = number; return succeeded; } - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out Real result) + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out Real result) { - var succeeded = T.TryParse(s, provider, out T? number); - result = number!; + var succeeded = double.TryParse(s, provider, out double number); + result = number; return succeeded; } - public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Real result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Real result) { if (s is null) { - result = T.Zero; + result = 0.0; return false; } - var succeeded = T.TryParse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider), out T? number); - result = number!; + var succeeded = double.TryParse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider), out double number); + result = number; return succeeded; } - public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out Real result) + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out Real result) { if (s.IsEmpty) { - result = T.Zero; + result = 0.0; return false; } - var succeeded = T.TryParse(s, style, NumberFormatInfo.GetInstance(provider), out T? number); - result = number!; + var succeeded = double.TryParse(s, style, NumberFormatInfo.GetInstance(provider), out double number); + result = number; return succeeded; } @@ -262,72 +259,72 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // Methods // - public static Real Abs(Real x) => T.Abs(x._value); + public static Real Abs(Real x) => Math.Abs(x._value); - public static Real Conjugate(Real x) => x; + public static Real Conjugate(Real x) => x; - public static Real Hypot(Real x, Real y) => T.Hypot(x._value, y._value); + public static Real Hypot(Real x, Real y) => double.Hypot(x._value, y._value); - public static bool IsFinite(Real x) => T.IsFinite(x._value); + public static bool IsFinite(Real x) => double.IsFinite(x._value); - public static bool IsInfinity(Real x) => T.IsInfinity(x._value); + public static bool IsInfinity(Real x) => double.IsInfinity(x._value); - public static bool IsNaN(Real x) => T.IsNaN(x._value); + public static bool IsNaN(Real x) => double.IsNaN(x._value); - public static bool IsZero(Real x) => T.IsZero(x._value); + public static bool IsZero(Real x) => x._value == 0.0; - public static bool IsNegativeInfinity(Real x) => T.IsNegativeInfinity(x._value); + public static bool IsNegativeInfinity(Real x) => double.IsNegativeInfinity(x._value); - public static bool IsPositiveInfinity(Real x) => T.IsPositiveInfinity(x._value); + public static bool IsPositiveInfinity(Real x) => double.IsPositiveInfinity(x._value); - public static Real Reciprocate(Real x) + public static Real Reciprocate(Real x) { - if (x._value == T.Zero) + if (x._value == 0.0) { return PositiveInfinity; } - return T.One / x; + return 1.0 / x; } - public static bool TryConvertFromChecked(V value, out Real result) - where V : INumberBase + public static bool TryConvertFromChecked(U value, out Real result) + where U : INumberBase { - result = T.CreateChecked(value); + result = double.CreateChecked(value); return true; } - public static bool TryConvertFromSaturating(V value, out Real result) - where V : INumberBase + public static bool TryConvertFromSaturating(U value, out Real result) + where U : INumberBase { - result = T.CreateSaturating(value); + result = double.CreateSaturating(value); return true; } - public static bool TryConvertFromTruncating(V value, out Real result) - where V : INumberBase + public static bool TryConvertFromTruncating(U value, out Real result) + where U : INumberBase { - result = T.CreateTruncating(value); + result = double.CreateTruncating(value); return true; } - public static bool TryConvertToChecked(Real value, [MaybeNullWhen(false)] out V result) - where V : INumberBase + public static bool TryConvertToChecked(Real value, [MaybeNullWhen(false)] out U result) + where U : INumberBase { - result = V.CreateChecked(value._value); + result = U.CreateChecked(value._value); return true; } - public static bool TryConvertToSaturating(Real value, [MaybeNullWhen(false)] out V result) - where V : INumberBase + public static bool TryConvertToSaturating(Real value, [MaybeNullWhen(false)] out U result) + where U : INumberBase { - result = V.CreateSaturating(value._value); + result = U.CreateSaturating(value._value); return true; } - public static bool TryConvertToTruncating(Real value, [MaybeNullWhen(false)] out V result) - where V : INumberBase + public static bool TryConvertToTruncating(Real value, [MaybeNullWhen(false)] out U result) + where U : INumberBase { - result = V.CreateTruncating(value._value); + result = U.CreateTruncating(value._value); return true; } @@ -337,67 +334,67 @@ public static bool TryConvertToTruncating(Real value, [MaybeNullWhen(false // Exponential functions - public static Real Exp(Real x) => T.Exp(x._value); + public static Real Exp(Real x) => Math.Exp(x._value); - public static Real Exp2(Real x) => T.Exp2(x._value); + public static Real Exp2(Real x) => double.Exp2(x._value); - public static Real Exp10(Real x) => T.Exp10(x._value); + public static Real Exp10(Real x) => double.Exp10(x._value); // Hyperbolic functions - public static Real Acosh(Real x) => T.Acosh(x._value); + public static Real Acosh(Real x) => Math.Acosh(x._value); - public static Real Asinh(Real x) => T.Asinh(x._value); + public static Real Asinh(Real x) => Math.Asinh(x._value); - public static Real Atanh(Real x) => T.Atanh(x._value); + public static Real Atanh(Real x) => Math.Atanh(x._value); - public static Real Cosh(Real x) => T.Cosh(x._value); + public static Real Cosh(Real x) => Math.Cosh(x._value); - public static Real Sinh(Real x) => T.Sinh(x._value); + public static Real Sinh(Real x) => Math.Sinh(x._value); - public static Real Tanh(Real x) => T.Tanh(x._value); + public static Real Tanh(Real x) => Math.Tanh(x._value); // Logarithmic functions - public static Real Ln(Real x) => T.Log(x._value); + public static Real Ln(Real x) => Math.Log(x._value); - public static Real Log(Real x, Real b) => T.Log(x._value, b._value); + public static Real Log(Real x, Real b) => Math.Log(x._value, b._value); - public static Real Log2(Real x) => T.Log2(x._value); + public static Real Log2(Real x) => Math.Log2(x._value); - public static Real Log10(Real x) => T.Log10(x._value); + public static Real Log10(Real x) => Math.Log10(x._value); // Power functions - public static Real Pow(Real x, Real y) => T.Pow(x._value, y._value); + public static Real Pow(Real x, Real y) => Math.Pow(x._value, y._value); // Root functions - public static Real Cbrt(Real x) => T.Cbrt(x._value); + public static Real Cbrt(Real x) => Math.Cbrt(x._value); - public static Real Root(Real x, Real y) => T.Exp(y._value * T.Log(x._value)); + public static Real Root(Real x, Real y) => Math.Exp(Math.Log(x._value) / y._value); - public static Real Sqrt(Real x) => T.Sqrt(x._value); + public static Real Sqrt(Real x) => Math.Sqrt(x._value); // Trigonometric functions - public static Real Acos(Real x) => T.Acos(x._value); + public static Real Acos(Real x) => Math.Acos(x._value); - public static Real Asin(Real x) => T.Asin(x._value); + public static Real Asin(Real x) => Math.Asin(x._value); - public static Real Atan(Real x) => T.Atan(x._value); + public static Real Atan(Real x) => Math.Atan(x._value); - public static Real Atan2(Real y, Real x) => T.Atan2(y._value, x._value); + public static Real Atan2(Real y, Real x) => Math.Atan2(y._value, x._value); - public static Real Cos(Real x) => T.Cos(x._value); + public static Real Cos(Real x) => Math.Cos(x._value); - public static Real Sin(Real x) => T.Sin(x._value); + public static Real Sin(Real x) => Math.Sin(x._value); - public static Real Tan(Real x) => T.Tan(x._value); + public static Real Tan(Real x) => Math.Tan(x._value); // // Implicit operators // - public static implicit operator Real(T x) => new(x); + public static implicit operator Real(double x) => new(x); } diff --git a/src/Mathematics.NET/Math.cs b/src/Mathematics.NET/Mathematics.cs similarity index 66% rename from src/Mathematics.NET/Math.cs rename to src/Mathematics.NET/Mathematics.cs index 10d5187f..11f90f32 100644 --- a/src/Mathematics.NET/Math.cs +++ b/src/Mathematics.NET/Mathematics.cs @@ -1,4 +1,4 @@ -// +// // Mathematics.NET // https://github.com/HamletTanyavong/Mathematics.NET // @@ -25,74 +25,72 @@ // SOFTWARE. // -using System.Numerics; using Mathematics.NET.Core; namespace Mathematics.NET; /// Provides Mathematics.NET functionality -/// A type that implements and /// /// This class contains constants and static methods for general mathematical purposes. Complicated mathematical operations may be found in their respective classes, and a list of all available operations can be found in the documentation. /// -public static class Math where T : IFloatingPointIeee754, IMinMaxValue +public static class Mathematics { // // Constants // /// Represents the imaginary unit, $ i $ - public static Complex Im => new(Real.Zero, Real.One); + public static ComplexNumber Im => new(Real.Zero, Real.One); /// - public static Real E => Real.E; + public static Real E => Real.E; /// - public static Real Pi => Real.Pi; + public static Real Pi => Real.Pi; /// - public static Real PiOverTwo => Real.PiOverTwo; + public static Real PiOverTwo => Real.PiOverTwo; /// - public static Real PiSquared => Real.PiSquared; + public static Real PiSquared => Real.PiSquared; /// - public static Real Tau => Real.Tau; + public static Real Tau => Real.Tau; /// - public static Real EulerMascheroni => Real.EulerMascheroni; + public static Real EulerMascheroni => Real.EulerMascheroni; /// - public static Real GoldenRatio => Real.GoldenRatio; + public static Real GoldenRatio => Real.GoldenRatio; /// - public static Real Ln2 => Real.Ln2; + public static Real Ln2 => Real.Ln2; /// - public static Real Ln10 => Real.Ln10; + public static Real Ln10 => Real.Ln10; /// - public static Real Sqrt2 => Real.Sqrt2; + public static Real Sqrt2 => Real.Sqrt2; /// - public static Real Sqrt3 => Real.Sqrt3; + public static Real Sqrt3 => Real.Sqrt3; /// - public static Real Sqrt5 => Real.Sqrt5; + public static Real Sqrt5 => Real.Sqrt5; /// - public static Real ZetaOf2 => Real.ZetaOf2; + public static Real ZetaOf2 => Real.ZetaOf2; /// - public static Real ZetaOf3 => Real.ZetaOf3; + public static Real ZetaOf3 => Real.ZetaOf3; /// - public static Real ZetaOf4 => Real.ZetaOf4; + public static Real ZetaOf4 => Real.ZetaOf4; // // Methods // // TODO: Account for fractional derivatives - public static Real Dif(Func, Real> function, (Real X, int N) args) => throw new NotImplementedException(); + public static Real Dif(Func function, (Real X, int N) args) => throw new NotImplementedException(); } diff --git a/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs b/tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/ComplexDivisionBenchmarks.cs similarity index 82% rename from tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs rename to tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/ComplexDivisionBenchmarks.cs index c2e32c77..c8a783c4 100644 --- a/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexDivisionBenchmarks.cs +++ b/tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/ComplexDivisionBenchmarks.cs @@ -25,16 +25,16 @@ // SOFTWARE. // -namespace Mathematics.NET.Benchmarks.Core.Complex; +namespace Mathematics.NET.Benchmarks.Core.ComplexNumberBenchmarks; [MemoryDiagnoser] public class ComplexDivisionBenchmarks { - public Complex Z { get; set; } - public Complex W { get; set; } + public ComplexNumber Z { get; set; } + public ComplexNumber W { get; set; } - public System.Numerics.Complex X { get; set; } - public System.Numerics.Complex Y { get; set; } + public Complex X { get; set; } + public Complex Y { get; set; } [GlobalSetup] public void GlobalSetup() @@ -47,13 +47,13 @@ public void GlobalSetup() } [Benchmark(Baseline = true)] - public System.Numerics.Complex SystemDivision() + public Complex SystemDivision() { return X / Y; } [Benchmark] - public Complex ComplexDivision_WithAggressiveInlining() + public ComplexNumber ComplexDivision_WithAggressiveInlining() { return Z / W; } diff --git a/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexTrigonometryBenchmarks.cs b/tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/ComplexTrigonometryBenchmarks.cs similarity index 69% rename from tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexTrigonometryBenchmarks.cs rename to tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/ComplexTrigonometryBenchmarks.cs index 8474df8a..07097a38 100644 --- a/tests/Mathematics.NET.Benchmarks/Core/Complex/ComplexTrigonometryBenchmarks.cs +++ b/tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/ComplexTrigonometryBenchmarks.cs @@ -25,48 +25,48 @@ // SOFTWARE. // -namespace Mathematics.NET.Benchmarks.Core.Complex; +namespace Mathematics.NET.Benchmarks.Core.ComplexNumberBenchmarks; [MemoryDiagnoser] [RankColumn] [Orderer(SummaryOrderPolicy.FastestToSlowest)] public class ComplexTrigonometryBenchmarks { - public Complex Z { get; set; } - public Complex ImOverTwo { get; set; } + public ComplexNumber Z { get; set; } + public ComplexNumber ImOverTwo { get; set; } - public System.Numerics.Complex W { get; set; } + public Complex W { get; set; } [GlobalSetup] public void GlobalSetup() { Z = new(1.23, 2.34); - ImOverTwo = Math.Im / Complex.Two; + ImOverTwo = Mathematics.Im / ComplexNumber.Two; W = new(1.23, 2.34); } [Benchmark(Baseline = true)] - public System.Numerics.Complex Atan_System() + public Complex Atan_System() { - return System.Numerics.Complex.Atan(W); + return Complex.Atan(W); } [Benchmark] - public Complex Atan_MathNET() + public ComplexNumber Atan_MathNET() { - return Complex.Atan(Z); + return ComplexNumber.Atan(Z); } //[Benchmark] - public Complex Atan_WithoutConstImOverTwo() + public ComplexNumber Atan_WithoutConstImOverTwo() { - return Math.Im / Complex.Two * Complex.Ln((Math.Im + Z) / (Math.Im - Z)); + return Mathematics.Im / ComplexNumber.Two * ComplexNumber.Ln((Mathematics.Im + Z) / (Mathematics.Im - Z)); } //[Benchmark] - public Complex Atan_WithConstImOverTwo() + public ComplexNumber Atan_WithConstImOverTwo() { - return ImOverTwo * Complex.Ln((Math.Im + Z) / (Math.Im - Z)); + return ImOverTwo * ComplexNumber.Ln((Mathematics.Im + Z) / (Mathematics.Im - Z)); } } diff --git a/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbsBenchmarks.cs b/tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/SystemComplexAbsVsComplexAbsBenchmarks.cs similarity index 83% rename from tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbsBenchmarks.cs rename to tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/SystemComplexAbsVsComplexAbsBenchmarks.cs index c31b0bd0..54b2bcfa 100644 --- a/tests/Mathematics.NET.Benchmarks/Core/Complex/SystemComplexAbsVsComplexAbsBenchmarks.cs +++ b/tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/SystemComplexAbsVsComplexAbsBenchmarks.cs @@ -25,15 +25,15 @@ // SOFTWARE. // -namespace Mathematics.NET.Benchmarks.Core.Complex; +namespace Mathematics.NET.Benchmarks.Core.ComplexNumberBenchmarks; [MemoryDiagnoser] [RankColumn] [Orderer(SummaryOrderPolicy.FastestToSlowest)] public class SystemComplexAbsVsComplexAbsBenchmarks { - public System.Numerics.Complex Z { get; set; } - public Complex W { get; set; } + public Complex Z { get; set; } + public ComplexNumber W { get; set; } [GlobalSetup] public void GlobalSetup() @@ -43,14 +43,14 @@ public void GlobalSetup() } [Benchmark(Baseline = true)] - public Real SystemComplexAbs() + public Real SystemComplexAbs() { - return System.Numerics.Complex.Abs(Z); + return Complex.Abs(Z); } [Benchmark] - public Complex ComplexAbs() + public ComplexNumber ComplexAbs() { - return Complex.Abs(W); + return ComplexNumber.Abs(W); } } diff --git a/tests/Mathematics.NET.Benchmarks/Core/Real/RealvsDouble.cs b/tests/Mathematics.NET.Benchmarks/Core/RealNumberBenchmarks/RealvsDouble.cs similarity index 91% rename from tests/Mathematics.NET.Benchmarks/Core/Real/RealvsDouble.cs rename to tests/Mathematics.NET.Benchmarks/Core/RealNumberBenchmarks/RealvsDouble.cs index 4dacfc77..19309799 100644 --- a/tests/Mathematics.NET.Benchmarks/Core/Real/RealvsDouble.cs +++ b/tests/Mathematics.NET.Benchmarks/Core/RealNumberBenchmarks/RealvsDouble.cs @@ -25,14 +25,14 @@ // SOFTWARE. // -namespace Mathematics.NET.Benchmarks.Core.Real; +namespace Mathematics.NET.Benchmarks.Core.RealNumberBenchmarks; [MemoryDiagnoser] [RankColumn] [Orderer(SummaryOrderPolicy.FastestToSlowest)] public class RealvsDouble { - public Real XReal { get; set; } + public Real XReal { get; set; } public double XDouble { get; set; } [GlobalSetup] @@ -54,9 +54,9 @@ public double AdditionsWithDouble() } [Benchmark] - public Real AdditionsWithReal() + public Real AdditionsWithReal() { - Real result = 0.0; + Real result = 0.0; for (int i = 0; i < 100_000; i++) { result += XReal; diff --git a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj index 4f080b22..da1b10e2 100644 --- a/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj +++ b/tests/Mathematics.NET.Benchmarks/Mathematics.NET.Benchmarks.csproj @@ -20,6 +20,7 @@ + diff --git a/tests/Mathematics.NET.Benchmarks/Program.cs b/tests/Mathematics.NET.Benchmarks/Program.cs index caf4c3b9..b151bf15 100644 --- a/tests/Mathematics.NET.Benchmarks/Program.cs +++ b/tests/Mathematics.NET.Benchmarks/Program.cs @@ -28,7 +28,7 @@ #if RELEASE using BenchmarkDotNet.Configs; using BenchmarkDotNet.Running; -using Mathematics.NET.Benchmarks.Core.Complex; +using Mathematics.NET.Benchmarks.Core.ComplexNumberBenchmarks; using Mathematics.NET.Benchmarks.Core.Real; var benchmarkSwitcher = new BenchmarkSwitcher(new[] diff --git a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs index 00398916..877b958d 100644 --- a/tests/Mathematics.NET.Tests/Core/ComplexTests.cs +++ b/tests/Mathematics.NET.Tests/Core/ComplexTests.cs @@ -33,11 +33,11 @@ public sealed class ComplexTests { [TestMethod] [DataRow(1.23, 2.34, 1.114564084931578, -1.686112230652994)] - public void Acos_ComplexOfDouble_ReturnsComplexOfDouble(double inReal, double inImaginary, double expectedRe, double expectedIm) + public void Acos_Complex_ReturnsComplex(double inReal, double inImaginary, double expectedRe, double expectedIm) { - Complex input = new(inReal, inImaginary); + ComplexNumber input = new(inReal, inImaginary); - var actualResult = Complex.Acos(input); + var actualResult = ComplexNumber.Acos(input); var actualRe = actualResult.Re.Value; var actualIm = actualResult.Im.Value; @@ -47,11 +47,11 @@ public void Acos_ComplexOfDouble_ReturnsComplexOfDouble(double inReal, double in [TestMethod] [DataRow(1.23, 2.34, 4.562322418633185e-1, 1.686112230652994)] - public void Asin_ComplexOfDouble_ReturnsComplexOfDouble(double inReal, double inImaginary, double expectedRe, double expectedIm) + public void Asin_Complex_ReturnsComplex(double inReal, double inImaginary, double expectedRe, double expectedIm) { - Complex input = new(inReal, inImaginary); + ComplexNumber input = new(inReal, inImaginary); - var actualResult = Complex.Asin(input); + var actualResult = ComplexNumber.Asin(input); var actualRe = actualResult.Re.Value; var actualIm = actualResult.Im.Value; @@ -61,11 +61,11 @@ public void Asin_ComplexOfDouble_ReturnsComplexOfDouble(double inReal, double in [TestMethod] [DataRow(1.23, 2.34, 1.37591078602063, 3.356559207392595e-1)] - public void Atan_ComplexOfDouble_ReturnsComplexOfDouble(double inReal, double inImaginary, double expectedRe, double expectedIm) + public void Atan_Complex_ReturnsComplex(double inReal, double inImaginary, double expectedRe, double expectedIm) { - Complex input = new(inReal, inImaginary); + ComplexNumber input = new(inReal, inImaginary); - var actualResult = Complex.Atan(input); + var actualResult = ComplexNumber.Atan(input); var actualRe = actualResult.Re.Value; var actualIm = actualResult.Im.Value; @@ -75,12 +75,12 @@ public void Atan_ComplexOfDouble_ReturnsComplexOfDouble(double inReal, double in [TestMethod] [DataRow(1.2, 2.3, 1.2, -2.3)] - public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inImaginary, double outReal, double outImaginary) + public void Conjugate_Complex_ReturnsConjugate(double inReal, double inImaginary, double outReal, double outImaginary) { - Complex input = new(inReal, inImaginary); - Complex expected = new(outReal, outImaginary); + ComplexNumber input = new(inReal, inImaginary); + ComplexNumber expected = new(outReal, outImaginary); - var actual = Complex.Conjugate(input); + var actual = ComplexNumber.Conjugate(input); Assert.AreEqual(expected, actual); } @@ -90,10 +90,10 @@ public void Conjugate_ComplexOfDouble_ReturnsConjugate(double inReal, double inI [DataRow(1, 2, 3, 4, 0.44, 0.08)] [DataRow(2, 1.5, 5, 3, 0.4264705882352942, 0.04411764705882351)] [DataRow(5, 3.5, 7, 0, 0.7142857142857142, 0.5)] - public void Division_ComplexOfDoubles_ReturnsComplexOfDouble(double dividendRe, double dividendIm, double divisorRe, double divisorIm, double expectedRe, double expectedIm) + public void Division_Complexs_ReturnsComplex(double dividendRe, double dividendIm, double divisorRe, double divisorIm, double expectedRe, double expectedIm) { - Complex dividend = new(dividendRe, dividendIm); - Complex divisor = new(divisorRe, divisorIm); + ComplexNumber dividend = new(dividendRe, dividendIm); + ComplexNumber divisor = new(divisorRe, divisorIm); var actualResult = dividend / divisor; var actualRe = actualResult.Re.Value; @@ -105,9 +105,9 @@ public void Division_ComplexOfDoubles_ReturnsComplexOfDouble(double dividendRe, [TestMethod] [DataRow(3, 4, 5)] - public void Magnitude_ComplexOfDouble_ReturnsMagnitude(double inReal, double inImaginary, double expected) + public void Magnitude_Complex_ReturnsMagnitude(double inReal, double inImaginary, double expected) { - Complex z = new(inReal, inImaginary); + ComplexNumber z = new(inReal, inImaginary); var actual = z.Magnitude.Value; @@ -119,9 +119,9 @@ public void Magnitude_ComplexOfDouble_ReturnsMagnitude(double inReal, double inI [DataRow(1, -1, -Math.PI / 2, 0)] [DataRow(-1, 1, Math.PI / 2, Math.PI)] [DataRow(-1, -1, -Math.PI, -Math.PI / 2)] - public void Phase_ComplexOfDouble_ReturnsAngleInCorrectQuadrant(double inReal, double inImaginary, double expectedMin, double expectedMax) + public void Phase_Complex_ReturnsAngleInCorrectQuadrant(double inReal, double inImaginary, double expectedMin, double expectedMax) { - Complex z = new(inReal, inImaginary); + ComplexNumber z = new(inReal, inImaginary); var actual = z.Phase.Value; @@ -131,12 +131,12 @@ public void Phase_ComplexOfDouble_ReturnsAngleInCorrectQuadrant(double inReal, d [TestMethod] [DataRow(2, 0, 0.5, 0)] [DataRow(1.5, 2.5, 1.76470588235294117e-1, -2.94117647058823529e-1)] - public void Reciprocate_ComplexOfDouble_ReturnsReciprocal(double inReal, double inImaginary, double expectedRe, double expectedIm) + public void Reciprocate_Complex_ReturnsReciprocal(double inReal, double inImaginary, double expectedRe, double expectedIm) { - Complex z = new(inReal, inImaginary); - Complex expected = new(expectedRe, expectedIm); + ComplexNumber z = new(inReal, inImaginary); + ComplexNumber expected = new(expectedRe, expectedIm); - var actual = Complex.Reciprocate(z); + var actual = ComplexNumber.Reciprocate(z); Assert.AreEqual(expected, actual); } @@ -146,9 +146,9 @@ public void Reciprocate_ComplexOfDouble_ReturnsReciprocal(double inReal, double [DataRow(24.56, 9.23, "ALL", "(24.56, 9.23)")] [DataRow(62.151, 27, "RE", "62.151")] [DataRow(7.345, 124.841, "IM", "124.841")] - public void ToString_ComplexOfDouble_ReturnsString(double inReal, double inImaginary, string? format, string expected) + public void ToString_Complex_ReturnsString(double inReal, double inImaginary, string? format, string expected) { - Complex z = new(inReal, inImaginary); + ComplexNumber z = new(inReal, inImaginary); var actual = z.ToString(format, null); @@ -158,9 +158,9 @@ public void ToString_ComplexOfDouble_ReturnsString(double inReal, double inImagi [TestMethod] [DataRow(0, 0, 6)] [DataRow(1.23, 2.34, 12)] - public void TryFormat_ComplexOfDoubleWithAdequateDestinationLength_ReturnsTrue(double inReal, double inImaginary, int length) + public void TryFormat_ComplexWithAdequateDestinationLength_ReturnsTrue(double inReal, double inImaginary, int length) { - Complex z = new(inReal, inImaginary); + ComplexNumber z = new(inReal, inImaginary); Span span = new char[length]; var actual = z.TryFormat(span, out int _, null, null); @@ -171,9 +171,9 @@ public void TryFormat_ComplexOfDoubleWithAdequateDestinationLength_ReturnsTrue(d [TestMethod] [DataRow(0, 0, 5)] [DataRow(1.23, 2.34, 11)] - public void TryFormat_ComplexOfDoubleWithInadequateDestinationLength_ReturnsFalse(double inReal, double inImaginary, int length) + public void TryFormat_ComplexWithInadequateDestinationLength_ReturnsFalse(double inReal, double inImaginary, int length) { - Complex z = new(inReal, inImaginary); + ComplexNumber z = new(inReal, inImaginary); Span span = new char[length]; var actual = z.TryFormat(span, out int _, null, null); @@ -186,11 +186,11 @@ public void TryFormat_ComplexOfDoubleWithInadequateDestinationLength_ReturnsFals [DataRow(" (0, 0) ", 0, 0)] [DataRow("(1.23, 3.456)", 1.23, 3.456)] [DataRow("( 1.23 , 3.45 )", 1.23, 3.45)] - public void TryParse_SpanOfChar_ReturnsComplexOfDouble(string s, double expectedRe, double expectedIm) + public void TryParse_SpanOfChar_ReturnsComplex(string s, double expectedRe, double expectedIm) { - Complex expected = new(expectedRe, expectedIm); + ComplexNumber expected = new(expectedRe, expectedIm); - _ = Complex.TryParse(s.AsSpan(), null, out Complex actual); + _ = ComplexNumber.TryParse(s.AsSpan(), null, out ComplexNumber actual); Assert.AreEqual(expected, actual); } @@ -202,7 +202,7 @@ public void TryParse_SpanOfChar_ReturnsComplexOfDouble(string s, double expected [DataRow("(0,0")] public void TryParse_SpanOfChar_ReturnsFalse(string s) { - var actual = Complex.TryParse(s.AsSpan(), null, out _); + var actual = ComplexNumber.TryParse(s.AsSpan(), null, out _); Assert.IsFalse(actual); } @@ -219,9 +219,9 @@ public void TryParse_SpanOfChar_ReturnsFalse(string s) [DataRow(1.2345, 0, 6, 1)] [DataRow(1.2345, 0, 7, 7)] [DataRow(1.2345, 0, 8, 8)] - public void TryFormat_ComplexOfDoubleWithInadequateDestinationLength_ReturnsCorrectNumberOfCharsWritten(double inReal, double inImaginary, int length, int expected) + public void TryFormat_ComplexWithInadequateDestinationLength_ReturnsCorrectNumberOfCharsWritten(double inReal, double inImaginary, int length, int expected) { - Complex z = new(inReal, inImaginary); + ComplexNumber z = new(inReal, inImaginary); Span span = new char[length]; _ = z.TryFormat(span, out int actual, null, null); @@ -234,9 +234,9 @@ public void TryFormat_ComplexOfDoubleWithInadequateDestinationLength_ReturnsCorr [DataRow(1.23, 3.4567, 14, "ALL", "(1.23, 3.4567)")] [DataRow(4.537, 2.3, 5, "RE", "4.537")] [DataRow(1.2, 7, 1, "IM", "7")] - public void TryFormat_ComplexOfDouble_ReturnsSpanOfCharacters(double inReal, double inImaginary, int length, string? format, string expected) + public void TryFormat_Complex_ReturnsSpanOfCharacters(double inReal, double inImaginary, int length, string? format, string expected) { - Complex z = new(inReal, inImaginary); + ComplexNumber z = new(inReal, inImaginary); Span actual = new char[length]; _ = z.TryFormat(actual, out int _, format, null); diff --git a/tests/Mathematics.NET.Tests/Core/RationalTests.cs b/tests/Mathematics.NET.Tests/Core/RationalTests.cs index 83a127e1..3e2ee94e 100644 --- a/tests/Mathematics.NET.Tests/Core/RationalTests.cs +++ b/tests/Mathematics.NET.Tests/Core/RationalTests.cs @@ -33,11 +33,11 @@ public sealed class RationalTests { [TestMethod] [DataRow(2, 4, 5, 3, 13, 6)] - public void Add_TwoRationalsOfIntAndDouble_ReturnsReducedSum(int inANum, int inADen, int inBNum, int inBDen, int expectedNum, int expectedDen) + public void Add_TwoRationalsOfInt_ReturnsReducedSum(int inANum, int inADen, int inBNum, int inBDen, int expectedNum, int expectedDen) { - Rational x = new(inANum, inADen); - Rational y = new(inBNum, inBDen); - Rational expected = new(expectedNum, expectedDen); + Rational x = new(inANum, inADen); + Rational y = new(inBNum, inBDen); + Rational expected = new(expectedNum, expectedDen); var actual = x + y; @@ -45,20 +45,20 @@ public void Add_TwoRationalsOfIntAndDouble_ReturnsReducedSum(int inANum, int inA } [TestMethod] - public void Divide_RationalOfIntAndDoubleByZero_ReturnsNaN() + public void Divide_RationalOfIntByZero_ReturnsNaN() { - var actual = Rational.One / Rational.Zero; + var actual = Rational.One / Rational.Zero; - Assert.AreEqual(Rational.NaN, actual); + Assert.AreEqual(Rational.NaN, actual); } [TestMethod] [DataRow(2, 3, 4, 8, 1, 3)] - public void Multiply_TwoRationalsOfIntAndDouble_ReturnsReducedProduct(int inANum, int inADen, int inBNum, int inBDen, int expectedNum, int expectedDen) + public void Multiply_TwoRationalsOfInt_ReturnsReducedProduct(int inANum, int inADen, int inBNum, int inBDen, int expectedNum, int expectedDen) { - Rational x = new(inANum, inADen); - Rational y = new(inBNum, inBDen); - Rational expected = new(expectedNum, expectedDen); + Rational x = new(inANum, inADen); + Rational y = new(inBNum, inBDen); + Rational expected = new(expectedNum, expectedDen); var actual = x * y; @@ -67,10 +67,10 @@ public void Multiply_TwoRationalsOfIntAndDouble_ReturnsReducedProduct(int inANum [TestMethod] [DataRow(6, 8, 3, 4)] - public void Reduce_RationalOfIntAndDouble_ReturnsReducedFraction(int inNum, int inDen, int expectedNum, int expectedDen) + public void Reduce_RationalOfInt_ReturnsReducedFraction(int inNum, int inDen, int expectedNum, int expectedDen) { - Rational p = new(inNum, inDen); - Rational expected = new(expectedNum, expectedDen); + Rational p = new(inNum, inDen); + Rational expected = new(expectedNum, expectedDen); var actual = p.Reduce(); @@ -79,9 +79,9 @@ public void Reduce_RationalOfIntAndDouble_ReturnsReducedFraction(int inNum, int [TestMethod] [DataRow(3, 4, 7)] - public void TryFormat_RationalOfIntAndDoubleWithAdequateDestinationLength_ReturnsTrue(int inNum, int inDen, int length) + public void TryFormat_RationalOfIntWithAdequateDestinationLength_ReturnsTrue(int inNum, int inDen, int length) { - Rational p = new(inNum, inDen); + Rational p = new(inNum, inDen); Span span = new char[length]; var actual = p.TryFormat(span, out int _, null, null); From bf01b3f859cc45c0af45858a5b11f7befafa79ca Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sat, 7 Oct 2023 23:40:33 -0500 Subject: [PATCH 234/293] Update DerivativesBuilder.cs - Put generated code under Generated namespace --- .../SourceBuilders/DerivativesBuilder.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET.SourceGenerators/SourceBuilders/DerivativesBuilder.cs b/src/Mathematics.NET.SourceGenerators/SourceBuilders/DerivativesBuilder.cs index 7b320346..4ee72477 100644 --- a/src/Mathematics.NET.SourceGenerators/SourceBuilders/DerivativesBuilder.cs +++ b/src/Mathematics.NET.SourceGenerators/SourceBuilders/DerivativesBuilder.cs @@ -71,7 +71,9 @@ private CompilationUnitSyntax CreateCompilationUnit(MemberDeclarationSyntax[] me SingletonList( FileScopedNamespaceDeclaration( QualifiedName( - IdentifierName(_assemblyName), + QualifiedName( + IdentifierName(_assemblyName), + IdentifierName("Generated")), IdentifierName("Mathematics"))) .WithMembers( SingletonList( From e3d5e9fb6c7c67d2749a1a63d96e0c2818820a30 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 8 Oct 2023 00:32:21 -0500 Subject: [PATCH 235/293] Update ComplexNumber.cs - Rename type parameters --- src/Mathematics.NET/Core/ComplexNumber.cs | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/ComplexNumber.cs index 35f91d82..f467ac5a 100644 --- a/src/Mathematics.NET/Core/ComplexNumber.cs +++ b/src/Mathematics.NET/Core/ComplexNumber.cs @@ -387,50 +387,50 @@ public static ComplexNumber Reciprocate(ComplexNumber z) // We will only consider the real part of complex numbers for these conversions. - public static bool TryConvertFromChecked(V value, out ComplexNumber result) - where V : INumberBase + public static bool TryConvertFromChecked(U value, out ComplexNumber result) + where U : INumberBase { result = double.CreateChecked(value); return true; } - public static bool TryConvertFromSaturating(V value, out ComplexNumber result) - where V : INumberBase + public static bool TryConvertFromSaturating(U value, out ComplexNumber result) + where U : INumberBase { result = double.CreateSaturating(value); return true; } - public static bool TryConvertFromTruncating(V value, out ComplexNumber result) - where V : INumberBase + public static bool TryConvertFromTruncating(U value, out ComplexNumber result) + where U : INumberBase { result = double.CreateTruncating(value); return true; } - public static bool TryConvertToChecked(ComplexNumber value, [MaybeNullWhen(false)] out V result) - where V : INumberBase + public static bool TryConvertToChecked(ComplexNumber value, [MaybeNullWhen(false)] out U result) + where U : INumberBase { if (value._imaginary == Real.Zero) { throw new OverflowException(); } - result = V.CreateChecked(value._real.Value); + result = U.CreateChecked(value._real.Value); return true; } - public static bool TryConvertToSaturating(ComplexNumber value, [MaybeNullWhen(false)] out V result) - where V : INumberBase + public static bool TryConvertToSaturating(ComplexNumber value, [MaybeNullWhen(false)] out U result) + where U : INumberBase { - result = V.CreateSaturating(value._real.Value); + result = U.CreateSaturating(value._real.Value); return true; } - public static bool TryConvertToTruncating(ComplexNumber value, [MaybeNullWhen(false)] out V result) - where V : INumberBase + public static bool TryConvertToTruncating(ComplexNumber value, [MaybeNullWhen(false)] out U result) + where U : INumberBase { - result = V.CreateTruncating(value._real.Value); + result = U.CreateTruncating(value._real.Value); return true; } From c070e7dc8c438f06d2776135b7490583d9ff4250 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 8 Oct 2023 17:08:40 -0500 Subject: [PATCH 236/293] Update Precision.cs - Add minimum positive values for float and double --- src/Mathematics.NET/Core/Precision.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Mathematics.NET/Core/Precision.cs b/src/Mathematics.NET/Core/Precision.cs index 7089d3b7..67c1df85 100644 --- a/src/Mathematics.NET/Core/Precision.cs +++ b/src/Mathematics.NET/Core/Precision.cs @@ -44,6 +44,16 @@ public static class Precision /// Machine epsilon for double-precision floating-point numbers according to the variant definition public const double DblEpsilonVariant = 2.22044604925031308e-16; + // This is the value given by 2^-149 + /// The minimum positive value that single-precision numbers can represent + /// This is equivalent to + public const double FltMinPositive = 1.40129846432481707e-45; + + // This is the value given by 2^-1074 + /// The minimum positive value that double-precision numbers can represent + /// This is equivalent to + public const double DblMinPositive = 4.94065645841246544e-324; + public static bool AreApproximatelyEqual(T left, T right, T epsilon) where T : IBinaryFloatingPointIeee754 => T.Abs(left - right) <= epsilon * T.Max(T.Abs(left), T.Abs(right)); From 433cad79bcdb58f4428bb30fee7c3018178b1163 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 8 Oct 2023 18:36:58 -0500 Subject: [PATCH 237/293] Update copyright header --- src/Mathematics.NET/Core/ComplexNumber.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/ComplexNumber.cs index f467ac5a..d4795ba5 100644 --- a/src/Mathematics.NET/Core/ComplexNumber.cs +++ b/src/Mathematics.NET/Core/ComplexNumber.cs @@ -1,4 +1,4 @@ -// +// // Mathematics.NET // https://github.com/HamletTanyavong/Mathematics.NET // From 95ee113f76828249ac64303c54ca18a821a6671f Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 8 Oct 2023 18:55:14 -0500 Subject: [PATCH 238/293] Use improved division algorithm --- src/Mathematics.NET/Core/ComplexNumber.cs | 139 ++++++++++++++++++---- 1 file changed, 114 insertions(+), 25 deletions(-) diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/ComplexNumber.cs index d4795ba5..972c1a07 100644 --- a/src/Mathematics.NET/Core/ComplexNumber.cs +++ b/src/Mathematics.NET/Core/ComplexNumber.cs @@ -43,6 +43,15 @@ public readonly struct ComplexNumber private static readonly ComplexNumber s_im = new(Real.Zero, Real.One); private static readonly ComplexNumber s_imOverTwo = new(Real.Zero, Real.One / 2.0); + // For division and reciprocal + + // double.MaxValue / 2.0; + private const double s_upper = 8.98846567431157854e307; + // 2.0 * Precision.DblMinPositive / (Precision.DblEpsilonVariant * Precision.DblEpsilonVariant) + private const double s_lower = 2.00416836000897277e-292; + // 2.0 / (Precision.DblEpsilonVariant * Precision.DblEpsilonVariant) + private const double s_scale = 4.05648192073033408e31; + // For computing Asin and Acos private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / 2.0; @@ -101,40 +110,103 @@ public ComplexNumber(Real real, Real imaginary) // From Michael Baudin and Robert L. Smith public static ComplexNumber operator /(ComplexNumber z, ComplexNumber w) { - var zRe = z._real.Value; - var zIm = z._imaginary.Value; - var wRe = w._real.Value; - var wIm = w._imaginary.Value; + var a = z._real.Value; + var b = z._imaginary.Value; + var c = w._real.Value; + var d = w._imaginary.Value; + + Max(Math.Abs(a), Math.Abs(b), out var maxAB); + Max(Math.Abs(c), Math.Abs(d), out var maxCD); + var scale = 1.0; - double reResult; - double imResult; - if (Math.Abs(wIm) <= Math.Abs(wRe)) + if (maxAB > s_upper) { - DivisionHelper(zRe, zIm, wRe, wIm, out reResult, out imResult); + a /= 2.0; + b /= 2.0; + scale *= 2.0; + } + if (maxCD > s_upper) + { + c /= 2.0; + d /= 2.0; + scale /= 2.0; + } + + if (maxAB < s_lower) + { + a *= s_scale; + b *= s_scale; + scale /= s_scale; + } + if (maxCD < s_lower) + { + c *= s_scale; + d *= s_scale; + scale *= s_scale; + } + + double re, im; + if (Math.Abs(d) <= Math.Abs(c)) + { + DivisionInternal(a, b, c, d, out re, out im); } else { - DivisionHelper(zIm, zRe, wIm, wRe, out reResult, out imResult); - imResult = -imResult; + DivisionInternal(b, a, d, c, out re, out im); + im = -im; } - return new(reResult, imResult); + return new(scale * re, scale * im); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void DivisionHelper(double x, double y, double maxW, double minW, out double real, out double imaginary) + private static void Max(double a, double b, out double max) => max = a < b ? b : a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void MinMax(double a, double b, out double minab, out double maxab) { - var ratio = minW / maxW; - var scale = 1.0 / (maxW + minW * ratio); - if (ratio != 0.0) + if (a < b) { - real = (x + y * ratio) * scale; - imaginary = (y - x * ratio) * scale; + minab = a; + maxab = b; } else { - real = (x + minW * (y / maxW)) * scale; - imaginary = (y - minW * (x / maxW)) * scale; + minab = b; + maxab = a; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void DivisionInternal(double a, double b, double c, double d, out double re, out double im) + { + double u, v; + u = d / c; + v = 1.0 / (c + d * u); + ComputeComponent(a, b, c, d, u, v, out re); + a = -a; + ComputeComponent(b, a, c, d, u, v, out im); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ComputeComponent(double a, double b, double c, double d, double u, double v, out double component) + { + double bu; + if (u != 0.0) + { + bu = b * u; + if (bu != 0.0) + { + component = (a + bu) * v; + } + else + { + component = a * v + b * v * u; + } + } + else + { + component = (a + d * (b / c)) * v; } } @@ -367,22 +439,39 @@ public static ComplexNumber Reciprocate(ComplexNumber z) return Infinity; } + var scale = 1.0; + var re = z._real.Value; var im = z._imaginary.Value; - double reResult; - double imResult; + Max(Math.Abs(re), Math.Abs(im), out var max); + + if (max > s_upper) + { + re /= 2.0; + im /= 2.0; + scale /= 2.0; + } + + if (max < s_lower) + { + re *= s_scale; + im *= s_scale; + scale *= s_scale; + } + + double outRe, outIm; if (Math.Abs(im) <= Math.Abs(re)) { - DivisionHelper(1.0, 0.0, re, im, out reResult, out imResult); + DivisionInternal(1.0, 0.0, re, im, out outRe, out outIm); } else { - DivisionHelper(0.0, 1.0, im, re, out reResult, out imResult); - imResult = -imResult; + DivisionInternal(0.0, 1.0, im, re, out outRe, out outIm); + outIm = -outIm; } - return new(reResult, imResult); + return new(scale * outRe, scale * outIm); } // We will only consider the real part of complex numbers for these conversions. From 56d81d7584bd5e5861d34ceb865028703dded536 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 9 Oct 2023 09:56:44 -0500 Subject: [PATCH 239/293] Update Program.cs - Fix incorrect using directive --- tests/Mathematics.NET.Benchmarks/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Mathematics.NET.Benchmarks/Program.cs b/tests/Mathematics.NET.Benchmarks/Program.cs index b151bf15..f133b2c6 100644 --- a/tests/Mathematics.NET.Benchmarks/Program.cs +++ b/tests/Mathematics.NET.Benchmarks/Program.cs @@ -29,7 +29,7 @@ using BenchmarkDotNet.Configs; using BenchmarkDotNet.Running; using Mathematics.NET.Benchmarks.Core.ComplexNumberBenchmarks; -using Mathematics.NET.Benchmarks.Core.Real; +using Mathematics.NET.Benchmarks.Core.RealNumberBenchmarks; var benchmarkSwitcher = new BenchmarkSwitcher(new[] { From ec6b90db062cb1e20d56bd82338a149ab725e51a Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 9 Oct 2023 10:26:49 -0500 Subject: [PATCH 240/293] Update IComplex.cs - Update documentation comments --- src/Mathematics.NET/Core/IComplex.cs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 40607a11..74e47d3e 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -150,22 +150,22 @@ static virtual T CreateTruncating(U value) /// Check if a value is finite /// The value to check - /// true if the value is finite; otherwise, false + /// if the value is finite; otherwise, static abstract bool IsFinite(T z); /// Check if a value is infinity /// The value to check - /// true if the value is infinity; otherwise, false + /// if the value is infinity; otherwise, static abstract bool IsInfinity(T z); /// Checks if a value is not a number /// The value to check - /// true if the value is not a number; otherwise, false + /// if the value is not a number; otherwise, static abstract bool IsNaN(T z); /// Check if a value is zero /// The value to check - /// true if the value is zero; otherwise, false + /// if the value is zero; otherwise, static abstract bool IsZero(T z); /// Parse a string into a value @@ -195,7 +195,7 @@ static virtual T CreateTruncating(U value) /// The type from which to convert /// The value to convert /// The result of the conversion - /// true if the conversion was successful; otherwise, false + /// if the conversion was successful; otherwise, /// The value is not representable by the type . protected static abstract bool TryConvertFromChecked(U value, [MaybeNullWhen(false)] out T result) where U : INumberBase; @@ -204,7 +204,7 @@ protected static abstract bool TryConvertFromChecked(U value, [MaybeNullWhen( /// The type from which to convert /// The value to convert /// The result of the conversion - /// true if the conversion was successful; otherwise, false + /// if the conversion was successful; otherwise, protected static abstract bool TryConvertFromSaturating(U value, [MaybeNullWhen(false)] out T result) where U : INumberBase; @@ -212,7 +212,7 @@ protected static abstract bool TryConvertFromSaturating(U value, [MaybeNullWh /// The type from which to convert /// The value to convert /// The result of the conversion - /// true if the conversion was successful; otherwise, false + /// if the conversion was successful; otherwise, protected static abstract bool TryConvertFromTruncating(U value, [MaybeNullWhen(false)] out T result) where U : INumberBase; @@ -220,7 +220,7 @@ protected static abstract bool TryConvertFromTruncating(U value, [MaybeNullWh /// The target type /// The value to convert /// The result of the conversion - /// true if the conversion was successful; otherwise, false + /// if the conversion was successful; otherwise, /// The value is not representable by the target type. protected static abstract bool TryConvertToChecked(T value, [MaybeNullWhen(false)] out U result) where U : INumberBase; @@ -229,7 +229,7 @@ protected static abstract bool TryConvertToChecked(T value, [MaybeNullWhen(fa /// The target type /// The value to convert /// The result of the conversion - /// true if the conversion was successful; otherwise, false + /// if the conversion was successful; otherwise, protected static abstract bool TryConvertToSaturating(T value, [MaybeNullWhen(false)] out U result) where U : INumberBase; @@ -237,7 +237,7 @@ protected static abstract bool TryConvertToSaturating(T value, [MaybeNullWhen /// The target type /// The value to convert /// The result of the conversion - /// true if the conversion was successful; otherwise, false + /// if the conversion was successful; otherwise, protected static abstract bool TryConvertToTruncating(T value, [MaybeNullWhen(false)] out U result) where U : INumberBase; @@ -246,7 +246,7 @@ protected static abstract bool TryConvertToTruncating(T value, [MaybeNullWhen /// The number style /// The culture-specific formatting information about the string /// The result of the parse or a default value if the parse was unsuccessful - /// True if the parse was successful; otherwise, false + /// if the parse was successful; otherwise, /// is not a supported static abstract bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out T result); @@ -255,7 +255,7 @@ protected static abstract bool TryConvertToTruncating(T value, [MaybeNullWhen /// The number style /// The culture-specific formatting information about the span of characters /// The result of the parse or a default value if the parse was unsuccessful - /// True if the parse was successful; otherwise, false + /// if the parse was successful; otherwise, /// is not a supported static abstract bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out T result); From 36e4a0f5769631b16763b221d0889e545ae55f7e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 9 Oct 2023 10:51:31 -0500 Subject: [PATCH 241/293] Update ComplexTrigonometryBenchmarks.cs - Fix benchmark; ComplexNumber.Two no longer exists --- .../ComplexNumberBenchmarks/ComplexTrigonometryBenchmarks.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/ComplexTrigonometryBenchmarks.cs b/tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/ComplexTrigonometryBenchmarks.cs index 07097a38..68bdae3e 100644 --- a/tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/ComplexTrigonometryBenchmarks.cs +++ b/tests/Mathematics.NET.Benchmarks/Core/ComplexNumberBenchmarks/ComplexTrigonometryBenchmarks.cs @@ -41,7 +41,7 @@ public class ComplexTrigonometryBenchmarks public void GlobalSetup() { Z = new(1.23, 2.34); - ImOverTwo = Mathematics.Im / ComplexNumber.Two; + ImOverTwo = Mathematics.Im / 2.0; W = new(1.23, 2.34); } @@ -61,7 +61,7 @@ public ComplexNumber Atan_MathNET() //[Benchmark] public ComplexNumber Atan_WithoutConstImOverTwo() { - return Mathematics.Im / ComplexNumber.Two * ComplexNumber.Ln((Mathematics.Im + Z) / (Mathematics.Im - Z)); + return Mathematics.Im / 2.0 * ComplexNumber.Ln((Mathematics.Im + Z) / (Mathematics.Im - Z)); } //[Benchmark] From 4565e212191f7ac27a7510c61d72d1b86710d359 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 9 Oct 2023 15:13:16 -0500 Subject: [PATCH 242/293] Update ComplexNumber.cs - Update AsinInternal method --- src/Mathematics.NET/Core/ComplexNumber.cs | 99 ++++++++++++++--------- 1 file changed, 59 insertions(+), 40 deletions(-) diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/ComplexNumber.cs index 972c1a07..e2641d92 100644 --- a/src/Mathematics.NET/Core/ComplexNumber.cs +++ b/src/Mathematics.NET/Core/ComplexNumber.cs @@ -52,9 +52,6 @@ public readonly struct ComplexNumber // 2.0 / (Precision.DblEpsilonVariant * Precision.DblEpsilonVariant) private const double s_scale = 4.05648192073033408e31; - // For computing Asin and Acos - private static readonly Real s_asinOverflowThreshold = Real.Sqrt(Real.MaxValue) / 2.0; - public static readonly ComplexNumber Zero = Real.Zero; public static readonly ComplexNumber One = Real.One; @@ -581,23 +578,23 @@ public static ComplexNumber Sinh(ComplexNumber z) public static ComplexNumber Acos(ComplexNumber z) { - AsinInternal(Real.Abs(z._real), Real.Abs(z._imaginary), out Real b, out Real bPrime, out Real v); + AsinInternal(Math.Abs(z._real.Value), Math.Abs(z._imaginary.Value), out double b, out double bPrime, out double v); - Real u; - if (bPrime < Real.Zero) + double u; + if (bPrime < 0.0) { - u = Real.Acos(b); + u = Math.Acos(b); } else { - u = Real.Atan(Real.One / bPrime); + u = Math.Atan(1.0 / bPrime); } - if (z._real < Real.Zero) + if (z._real < 0.0) { - u = Real.Pi - u; + u = Constants.Pi - u; } - if (z._imaginary > Real.Zero) + if (z._imaginary > 0.0) { v = -v; } @@ -607,23 +604,23 @@ public static ComplexNumber Acos(ComplexNumber z) public static ComplexNumber Asin(ComplexNumber z) { - AsinInternal(Real.Abs(z._real), Real.Abs(z._imaginary), out Real b, out Real bPrime, out Real v); + AsinInternal(Math.Abs(z._real.Value), Math.Abs(z._imaginary.Value), out double b, out double bPrime, out double v); - Real u; - if (bPrime < Real.Zero) + double u; + if (bPrime < 0.0) { - u = Real.Asin(b); + u = Math.Asin(b); } else { - u = Real.Atan(bPrime); + u = Math.Atan(bPrime); } - if (z._real < Real.Zero) + if (z._real < 0.0) { u = -u; } - if (z._imaginary < Real.Zero) + if (z._imaginary < 0.0) { v = -v; } @@ -631,16 +628,21 @@ public static ComplexNumber Asin(ComplexNumber z) return new(u, v); } - private static void AsinInternal(Real x, Real y, out Real b, out Real bPrime, out Real v) + private static void AsinInternal(double x, double y, out double b, out double bPrime, out double v) { // This is the same method described by Hull, Fairgrieve, and Tang in "Implementing the Complex // ArcSine and Arccosine Functions Using Exception Handling" that is used in System.Numerics.Complex. - if (x > s_asinOverflowThreshold || y > s_asinOverflowThreshold) + // + // https://www.researchgate.net/profile/Ping_Tang3/publication/220493330_Implementing_the_Complex_Arcsine_and_Arccosine_Functions_Using_Exception_Handling/links/55b244b208ae9289a085245d.pdf + + const double overflowThreshold = 6.70390396497129854e153; + + if (x > overflowThreshold || y > overflowThreshold) { - b = -Real.One; + b = -1.0; bPrime = x / y; - Real small, big; + double small, big; if (x < y) { small = x; @@ -651,56 +653,73 @@ private static void AsinInternal(Real x, Real y, out Real b, out Real bPrime, ou small = y; big = x; } - Real ratio = small / big; - v = Real.Ln2 + Real.Ln(big) + Real.Ln(ratio * ratio + Real.One) / 2.0; + double ratio = small / big; + v = Constants.Ln2 + Math.Log(big) + 0.5 * Log1P(ratio * ratio); } else { - Real r = Hypot((x + Real.One).Value, y.Value); - Real s = Hypot((x - Real.One).Value, y.Value); + double r = Hypot(x + 1.0, y); + double s = Hypot(x - 1.0, y); - Real a = (r + s) / 2.0; + double a = (r + s) * 0.5; b = x / a; if (b > 0.75) { - if (x <= Real.One) + if (x <= 1.0) { - Real amx = (y * y / (r + (x + Real.One)) + (s + (Real.One - x))) / 2.0; - bPrime = x / Real.Sqrt((a + x) * amx); + double amx = (y * y / (r + (x + 1.0)) + (s + (1.0 - x))) * 0.5; + bPrime = x / Math.Sqrt((a + x) * amx); } else { - Real t = (Real.One / (r + (x + Real.One)) + Real.One / (s + (x - Real.One))) / 2.0; - bPrime = x / y / Real.Sqrt((a + x) * t); + double t = (1.0 / (r + (x + 1.0)) + 1.0 / (s + (x - 1.0))) * 0.5; + bPrime = x / y / Math.Sqrt((a + x) * t); } } else { - bPrime = -Real.One; + bPrime = -1.0; } if (a < 1.5) { - if (x < Real.One) + if (x < 1.0) { - Real t = (Real.One / (r + (x + Real.One)) + Real.One / (s + (Real.One - x))) / 2.0; - Real am1 = y * y * t; - v = Real.Ln(am1 + y * Real.Sqrt(t * (a + Real.One)) + Real.One); + double t = (1.0 / (r + (x + 1.0)) + 1.0 / (s + (1.0 - x))) * 0.5; + double am1 = y * y * t; + v = Log1P(am1 + y * Math.Sqrt(t * (a + 1.0))); } else { - Real am1 = (y * y / (r + (x + Real.One)) + (s + (x - Real.One))) / 2.0; - v = Real.Ln(am1 + Real.Sqrt(am1 * (a + Real.One)) + Real.One); + double am1 = (y * y / (r + (x + 1.0)) + (s + (x - 1.0))) * 0.5; + v = Log1P(am1 + Math.Sqrt(am1 * (a + 1.0))); } } else { - v = Real.Ln(a + Real.Sqrt((a - Real.One) * (a + Real.One))); + v = Math.Log(a + Math.Sqrt((a - 1.0) * (a + 1.0))); } } } + private static double Log1P(double x) + { + double xp1 = 1.0 + x; + if (xp1 == 1.0) + { + return x; + } + else if (x < 0.75) + { + return x * Math.Log(xp1) / (xp1 - 1.0); + } + else + { + return Math.Log(xp1); + } + } + public static ComplexNumber Atan(ComplexNumber z) => s_imOverTwo * Ln((s_im + z) / (s_im - z)); public static ComplexNumber Cos(ComplexNumber z) From 2ad7c7f2dc66213186726d5c67502f22bc515334 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:58:12 -0500 Subject: [PATCH 243/293] Update Real.cs - Remove documentation comment --- src/Mathematics.NET/Core/Real.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index b935a07c..9fa0ad88 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -33,7 +33,6 @@ namespace Mathematics.NET.Core; /// Represents a real number -/// A type that implements and [Serializable] [StructLayout(LayoutKind.Sequential)] public readonly struct Real From a822031f4c6ff014e04f06fdf0e764f52b50019c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 10 Oct 2023 15:00:08 -0500 Subject: [PATCH 244/293] Update ComplexNumber.cs --- src/Mathematics.NET/Core/ComplexNumber.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/ComplexNumber.cs index e2641d92..7110fb13 100644 --- a/src/Mathematics.NET/Core/ComplexNumber.cs +++ b/src/Mathematics.NET/Core/ComplexNumber.cs @@ -188,10 +188,9 @@ private static void DivisionInternal(double a, double b, double c, double d, out [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ComputeComponent(double a, double b, double c, double d, double u, double v, out double component) { - double bu; if (u != 0.0) { - bu = b * u; + var bu = b * u; if (bu != 0.0) { component = (a + bu) * v; From 1e20ba10cbfdf3fc44764484938c995cec2f0fd9 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:54:53 -0500 Subject: [PATCH 245/293] Update ComplexNumber.cs --- src/Mathematics.NET/Core/ComplexNumber.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/ComplexNumber.cs index 7110fb13..63242402 100644 --- a/src/Mathematics.NET/Core/ComplexNumber.cs +++ b/src/Mathematics.NET/Core/ComplexNumber.cs @@ -177,9 +177,8 @@ private static void MinMax(double a, double b, out double minab, out double maxa [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void DivisionInternal(double a, double b, double c, double d, out double re, out double im) { - double u, v; - u = d / c; - v = 1.0 / (c + d * u); + var u = d / c; + var v = 1.0 / (c + d * u); ComputeComponent(a, b, c, d, u, v, out re); a = -a; ComputeComponent(b, a, c, d, u, v, out im); From 44640bfe509f6058ed17ea4c78b713dccefd0343 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 12 Oct 2023 02:11:42 -0500 Subject: [PATCH 246/293] Add basic support for vectors - Add Vector4 - Add interfaces that define mathematical objects that can be represented by arrays - Add operations for Hadamard and inner products --- .../Operations/IHadamardProductOperation.cs | 38 ++++ .../Core/Operations/IInnerProductOperation.cs | 44 ++++ .../Abstractions/IArrayRepresentable.cs | 38 ++++ .../IOneDimensionalArrayRepresentable.cs | 55 +++++ src/Mathematics.NET/LinearAlgebra/Vector4.cs | 198 ++++++++++++++++++ 5 files changed, 373 insertions(+) create mode 100644 src/Mathematics.NET/Core/Operations/IHadamardProductOperation.cs create mode 100644 src/Mathematics.NET/Core/Operations/IInnerProductOperation.cs create mode 100644 src/Mathematics.NET/LinearAlgebra/Abstractions/IArrayRepresentable.cs create mode 100644 src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs create mode 100644 src/Mathematics.NET/LinearAlgebra/Vector4.cs diff --git a/src/Mathematics.NET/Core/Operations/IHadamardProductOperation.cs b/src/Mathematics.NET/Core/Operations/IHadamardProductOperation.cs new file mode 100644 index 00000000..4d4654c0 --- /dev/null +++ b/src/Mathematics.NET/Core/Operations/IHadamardProductOperation.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +namespace Mathematics.NET.Core.Operations; + +/// Defines a mechanism for performing element-wise multiplication on two array-backed objects +/// The input type +/// The output type +public interface IHadamardProductOperation + where TInput : IHadamardProductOperation +{ + static abstract TOutput operator *(TInput left, TInput right); + static virtual TOutput operator checked *(TInput left, TInput right) => left * right; +} diff --git a/src/Mathematics.NET/Core/Operations/IInnerProductOperation.cs b/src/Mathematics.NET/Core/Operations/IInnerProductOperation.cs new file mode 100644 index 00000000..1712bc3a --- /dev/null +++ b/src/Mathematics.NET/Core/Operations/IInnerProductOperation.cs @@ -0,0 +1,44 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using Mathematics.NET.LinearAlgebra.Abstractions; + +namespace Mathematics.NET.Core.Operations; + +/// Defines a mechanism for computing inner products of vectors +/// A type that implements +/// A type that implements +public interface IInnerProductOperation + where T : IOneDimensionalArrayRepresentable + where U : IComplex +{ + /// Compute the inner product of two vectors + /// A vector of type + /// A vector of type + /// A scalar + static abstract U InnerProduct(T left, T right); +} diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/IArrayRepresentable.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/IArrayRepresentable.cs new file mode 100644 index 00000000..0d620805 --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/IArrayRepresentable.cs @@ -0,0 +1,38 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using Mathematics.NET.Core; + +namespace Mathematics.NET.LinearAlgebra.Abstractions; + +/// Defines support for mathematical objects that can be represented by arrays +public interface IArrayRepresentable + where T : IComplex +{ + /// The total number of components in the array + static abstract int Components { get; } +} diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs new file mode 100644 index 00000000..5f1fe05b --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs @@ -0,0 +1,55 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using Mathematics.NET.Core; +using Mathematics.NET.Core.Operations; +using Mathematics.NET.Core.Relations; + +namespace Mathematics.NET.LinearAlgebra.Abstractions; + +/// Defines support for mathematical objects that can be represented by one-dimensional arrays +/// The type that implements the interface +/// A type that implements +public interface IOneDimensionalArrayRepresentable + : IArrayRepresentable, + IAdditionOperation, + ISubtractionOperation, + IHadamardProductOperation, + IInnerProductOperation, + IEqualityRelation, + IFormattable + where T : IOneDimensionalArrayRepresentable + where U : IComplex +{ + /// The number of components in the one-dimensional array + static abstract int E1Components { get; } + + /// Get the element at the specified index + /// An index + /// The element at the index + U this[int index] { get; set; } +} diff --git a/src/Mathematics.NET/LinearAlgebra/Vector4.cs b/src/Mathematics.NET/LinearAlgebra/Vector4.cs new file mode 100644 index 00000000..b741ddc8 --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Vector4.cs @@ -0,0 +1,198 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Mathematics.NET.Core; +using Mathematics.NET.DifferentialGeometry; +using Mathematics.NET.LinearAlgebra.Abstractions; + +namespace Mathematics.NET.LinearAlgebra; + +/// Represents a vector with four components +/// A type that implements +[StructLayout(LayoutKind.Sequential)] +public struct Vector4 + : IOneDimensionalArrayRepresentable, T>, + IFormattable + where T : IComplex +{ + /// The first element of the vector + public T X1; + + /// The second element of the vector + public T X2; + + /// The third element of the vector + public T X3; + + /// The fourth element of the vector + public T X4; + + public Vector4(T x1, T x2, T x3, T x4) + { + X1 = x1; + X2 = x2; + X3 = x3; + X4 = x4; + } + + // + // IArrayRepresentable & relevant interfaces + // + + public static int Components => 4; + + public static int E1Components => 4; + + // + // Indexer + // + + public T this[int index] + { + get => GetElement(this, index); + set => this = WithElement(this, index, value); + } + + // Get + + internal static T GetElement(Vector4 vector, int index) + { + if ((uint)index >= 4) + { + throw new ArgumentOutOfRangeException(); + } + + return GetElementUnsafe(ref vector, index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static T GetElementUnsafe(ref Vector4 vector, int index) + { + Debug.Assert(index is >= 0 and < 4); + return Unsafe.Add(ref Unsafe.As, T>(ref vector), index); + } + + // Set + + internal static Vector4 WithElement(Vector4 vector, int index, T value) + { + if ((uint)index >= 4) + { + throw new ArgumentOutOfRangeException(); + } + + Vector4 result = vector; + SetElementUnsafe(ref result, index, value); + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void SetElementUnsafe(ref Vector4 vector, int index, T value) + { + Debug.Assert(index is >= 0 and < 4); + Unsafe.Add(ref Unsafe.As, T>(ref vector), index) = value; + } + + // + // Operators + // + + public static Vector4 operator +(Vector4 left, Vector4 right) + { + return new( + left.X1 + right.X1, + left.X2 + right.X2, + left.X3 + right.X3, + left.X4 + right.X4); + } + + public static Vector4 operator -(Vector4 left, Vector4 right) + { + return new( + left.X1 - right.X1, + left.X2 - right.X2, + left.X3 - right.X3, + left.X4 - right.X4); + } + + public static Vector4 operator *(Vector4 left, Vector4 right) + { + return new( + left.X1 * right.X1, + left.X2 * right.X2, + left.X3 * right.X3, + left.X4 * right.X4); + } + + // + // Equality + // + + public static bool operator ==(Vector4 left, Vector4 right) + => left.X1 == right.X1 + && left.X2 == right.X2 + && left.X3 == right.X3 + && left.X4 == right.X4; + + public static bool operator !=(Vector4 left, Vector4 right) + => left.X1 != right.X1 + || left.X2 != right.X2 + || left.X3 != right.X3 + || left.X4 != right.X4; + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Vector4 other && Equals(other); + + public bool Equals(Vector4 value) + => X1.Equals(value.X1) + && X2.Equals(value.X2) + && X3.Equals(value.X3) + && X4.Equals(value.X4); + + public override int GetHashCode() => HashCode.Combine(X1, X2, X3, X4); + + // + // Formatting + // + + public string ToString(string? format, IFormatProvider? provider) + => string.Format(provider, "({0}, {1}, {2}, {3})", + X1.ToString(format, provider), + X2.ToString(format, provider), + X3.ToString(format, provider), + X4.ToString(format, provider)); + + // + // Methods + // + + public static T InnerProduct(Vector4 left, Vector4 right) + => T.Conjugate(left.X1) * right.X1 + T.Conjugate(left.X2) * right.X2 + T.Conjugate(left.X3) * right.X3 + T.Conjugate(left.X4) * right.X4; +} From aa763d0d98736b6ea6ac183d58ae8e4606ff0ba4 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 12 Oct 2023 13:08:10 -0500 Subject: [PATCH 247/293] Update Vector4.cs - Remove using directive --- src/Mathematics.NET/LinearAlgebra/Vector4.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Vector4.cs b/src/Mathematics.NET/LinearAlgebra/Vector4.cs index b741ddc8..4a9e80a3 100644 --- a/src/Mathematics.NET/LinearAlgebra/Vector4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Vector4.cs @@ -30,7 +30,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Mathematics.NET.Core; -using Mathematics.NET.DifferentialGeometry; using Mathematics.NET.LinearAlgebra.Abstractions; namespace Mathematics.NET.LinearAlgebra; From 52d120f6544dc2928fae7ec32dca253c8ff1187e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 12 Oct 2023 13:17:17 -0500 Subject: [PATCH 248/293] Update Vector4.cs - Remove IFormattable constraint --- src/Mathematics.NET/LinearAlgebra/Vector4.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Vector4.cs b/src/Mathematics.NET/LinearAlgebra/Vector4.cs index 4a9e80a3..7948086f 100644 --- a/src/Mathematics.NET/LinearAlgebra/Vector4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Vector4.cs @@ -37,9 +37,7 @@ namespace Mathematics.NET.LinearAlgebra; /// Represents a vector with four components /// A type that implements [StructLayout(LayoutKind.Sequential)] -public struct Vector4 - : IOneDimensionalArrayRepresentable, T>, - IFormattable +public struct Vector4 : IOneDimensionalArrayRepresentable, T> where T : IComplex { /// The first element of the vector From bea3e464512e5e408c0025aad7594eb6a8c6f5e8 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 12 Oct 2023 13:40:21 -0500 Subject: [PATCH 249/293] Update IReal.cs - Define Max and Min --- src/Mathematics.NET/Core/IReal.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 8169c6bb..8fd95e9b 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -55,4 +55,18 @@ public interface IReal /// The value to check /// true if the value is positive infinity; otherwise, false static abstract bool IsPositiveInfinity(T x); + + /// Find which of two numbers is greater than the other + /// If any of the values are NaN, then NaN is returned + /// The first value + /// The second value + /// The greater of the two values + static abstract T Max(T x, T y); + + /// Find which of two numbers is less than the other + /// If any of the values are NaN, then NaN is returned + /// The first value + /// The second value + /// The lesser of the two values + static abstract T Min(T x, T y); } From da9b0b5297d6921694d7191dc71e52190dafac72 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 12 Oct 2023 15:00:53 -0500 Subject: [PATCH 250/293] Implement Max and Min --- src/Mathematics.NET/Core/Rational.cs | 17 +++++++++++++++++ src/Mathematics.NET/Core/Real.cs | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs index ea97283d..0e0d4af2 100644 --- a/src/Mathematics.NET/Core/Rational.cs +++ b/src/Mathematics.NET/Core/Rational.cs @@ -490,6 +490,23 @@ private static T LCM(T p, T q) return holdP / (p | q) * holdQ; } + // TODO: Find a better implementation for Max and Min + public static Rational Max(Rational x, Rational y) + { + var u = x.Reduce(); + var v = y.Reduce(); + + return u._numerator * v._denominator >= v._numerator * u._denominator ? x : y; + } + + public static Rational Min(Rational x, Rational y) + { + var u = x.Reduce(); + var v = y.Reduce(); + + return u._numerator * v._denominator <= v._numerator * u._denominator ? x : y; + } + public static Rational Reciprocate(Rational x) { if (x._numerator == T.Zero) diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 9fa0ad88..ba611a84 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -276,6 +276,10 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static bool IsPositiveInfinity(Real x) => double.IsPositiveInfinity(x._value); + public static Real Max(Real x, Real y) => Math.Max(x._value, y._value); + + public static Real Min(Real x, Real y) => Math.Min(x._value, y._value); + public static Real Reciprocate(Real x) { if (x._value == 0.0) From 93ffd149335c40a873376ff450aea90e63bbd692 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Thu, 12 Oct 2023 22:58:13 -0500 Subject: [PATCH 251/293] Add Norm - Add a method for computing the norm of a vector - Define Norm in interface - Add benchmark --- .../IOneDimensionalArrayRepresentable.cs | 4 + src/Mathematics.NET/LinearAlgebra/Vector4.cs | 28 +++++ .../LinearAlgebra/NormBenchmarks.cs | 102 ++++++++++++++++++ tests/Mathematics.NET.Benchmarks/Program.cs | 2 + 4 files changed, 136 insertions(+) create mode 100644 tests/Mathematics.NET.Benchmarks/LinearAlgebra/NormBenchmarks.cs diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs index 5f1fe05b..847ec9b7 100644 --- a/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs @@ -52,4 +52,8 @@ public interface IOneDimensionalArrayRepresentable /// An index /// The element at the index U this[int index] { get; set; } + + /// Compute the $ L^2 $-norm of the vector + /// The norm + Real Norm(); } diff --git a/src/Mathematics.NET/LinearAlgebra/Vector4.cs b/src/Mathematics.NET/LinearAlgebra/Vector4.cs index 7948086f..070cfb53 100644 --- a/src/Mathematics.NET/LinearAlgebra/Vector4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Vector4.cs @@ -192,4 +192,32 @@ public string ToString(string? format, IFormatProvider? provider) public static T InnerProduct(Vector4 left, Vector4 right) => T.Conjugate(left.X1) * right.X1 + T.Conjugate(left.X2) * right.X2 + T.Conjugate(left.X3) * right.X3 + T.Conjugate(left.X4) * right.X4; + + public Real Norm() + { + Span components = stackalloc Real[4]; + + components[0] = (T.Conjugate(X1) * X1).Re; + components[1] = (T.Conjugate(X2) * X2).Re; + components[2] = (T.Conjugate(X3) * X3).Re; + components[3] = (T.Conjugate(X4) * X4).Re; + + Real max = components[0]; + for (int i = 1; i < 4; i++) + { + if (components[i] > max) + { + max = components[i]; + } + } + + Real partialSum = Real.Zero; + var maxSquared = max * max; + partialSum += components[0] / maxSquared; + partialSum += components[1] / maxSquared; + partialSum += components[2] / maxSquared; + partialSum += components[3] / maxSquared; + + return max * Real.Sqrt(partialSum); + } } diff --git a/tests/Mathematics.NET.Benchmarks/LinearAlgebra/NormBenchmarks.cs b/tests/Mathematics.NET.Benchmarks/LinearAlgebra/NormBenchmarks.cs new file mode 100644 index 00000000..32d97363 --- /dev/null +++ b/tests/Mathematics.NET.Benchmarks/LinearAlgebra/NormBenchmarks.cs @@ -0,0 +1,102 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using Mathematics.NET.LinearAlgebra; + +namespace Mathematics.NET.Benchmarks.LinearAlgebra; + +[MemoryDiagnoser] +[RankColumn] +[Orderer(SummaryOrderPolicy.FastestToSlowest)] +public class NormBenchmarks +{ + public Vector4 Vector { get; set; } + + [GlobalSetup] + public void GlobalSetup() + { + Vector = new(1.23, 2.34, 3.45, 4.56); + } + + [Benchmark(Baseline = true)] + public Real NormWithoutLoop() + { + Span components = stackalloc Real[4]; + + components[0] = (Real.Conjugate(Vector.X1) * Vector.X1).Re; + components[1] = (Real.Conjugate(Vector.X2) * Vector.X2).Re; + components[2] = (Real.Conjugate(Vector.X3) * Vector.X3).Re; + components[3] = (Real.Conjugate(Vector.X4) * Vector.X4).Re; + + Real max = components[0]; + for (int i = 1; i < 4; i++) + { + if (components[i] > max) + { + max = components[i]; + } + } + + Real partialSum = Real.Zero; + var maxSquared = max * max; + partialSum += components[0] / maxSquared; + partialSum += components[1] / maxSquared; + partialSum += components[2] / maxSquared; + partialSum += components[3] / maxSquared; + + return max * Real.Sqrt(partialSum); + } + + [Benchmark] + public Real NormWithLoop() + { + Span components = stackalloc Real[4]; + + components[0] = (Real.Conjugate(Vector.X1) * Vector.X1).Re; + components[1] = (Real.Conjugate(Vector.X2) * Vector.X2).Re; + components[2] = (Real.Conjugate(Vector.X3) * Vector.X3).Re; + components[3] = (Real.Conjugate(Vector.X4) * Vector.X4).Re; + + Real max = components[0]; + for (int i = 1; i < 4; i++) + { + if (components[i] > max) + { + max = components[i]; + } + } + + Real partialSum = Real.Zero; + var maxSquared = max * max; + for (int i = 0; i < 4; i++) + { + partialSum += components[i] / maxSquared; + } + + return max * Real.Sqrt(partialSum); + } +} diff --git a/tests/Mathematics.NET.Benchmarks/Program.cs b/tests/Mathematics.NET.Benchmarks/Program.cs index f133b2c6..81b4b18e 100644 --- a/tests/Mathematics.NET.Benchmarks/Program.cs +++ b/tests/Mathematics.NET.Benchmarks/Program.cs @@ -30,11 +30,13 @@ using BenchmarkDotNet.Running; using Mathematics.NET.Benchmarks.Core.ComplexNumberBenchmarks; using Mathematics.NET.Benchmarks.Core.RealNumberBenchmarks; +using Mathematics.NET.Benchmarks.LinearAlgebra; var benchmarkSwitcher = new BenchmarkSwitcher(new[] { typeof(ComplexDivisionBenchmarks), typeof(ComplexTrigonometryBenchmarks), + typeof(NormBenchmarks), typeof(RealvsDouble), typeof(SystemComplexAbsVsComplexAbsBenchmarks) }); From 4881e846e94fb75882bff5814fcba0034c5ff3c8 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 13 Oct 2023 00:36:19 -0500 Subject: [PATCH 252/293] Use IndexOutOfRangeException --- src/Mathematics.NET/LinearAlgebra/Vector4.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Vector4.cs b/src/Mathematics.NET/LinearAlgebra/Vector4.cs index 070cfb53..174cb6d1 100644 --- a/src/Mathematics.NET/LinearAlgebra/Vector4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Vector4.cs @@ -84,7 +84,7 @@ internal static T GetElement(Vector4 vector, int index) { if ((uint)index >= 4) { - throw new ArgumentOutOfRangeException(); + throw new IndexOutOfRangeException(); } return GetElementUnsafe(ref vector, index); @@ -103,7 +103,7 @@ internal static Vector4 WithElement(Vector4 vector, int index, T value) { if ((uint)index >= 4) { - throw new ArgumentOutOfRangeException(); + throw new IndexOutOfRangeException(); } Vector4 result = vector; From 35296c3bef6ef1910ac426596db40dc13651d311 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 13 Oct 2023 01:28:35 -0500 Subject: [PATCH 253/293] Add method for normalizing vectors --- .../Abstractions/IOneDimensionalArrayRepresentable.cs | 5 +++++ src/Mathematics.NET/LinearAlgebra/Vector4.cs | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs index 847ec9b7..0bb08a0c 100644 --- a/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs @@ -56,4 +56,9 @@ public interface IOneDimensionalArrayRepresentable /// Compute the $ L^2 $-norm of the vector /// The norm Real Norm(); + + /// Normalize a given vector + /// The vector to normalize + /// The normalized vector + T Normalize(); } diff --git a/src/Mathematics.NET/LinearAlgebra/Vector4.cs b/src/Mathematics.NET/LinearAlgebra/Vector4.cs index 174cb6d1..34082f3b 100644 --- a/src/Mathematics.NET/LinearAlgebra/Vector4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Vector4.cs @@ -220,4 +220,10 @@ public Real Norm() return max * Real.Sqrt(partialSum); } + + public Vector4 Normalize() + { + var norm = Norm().Value; + return new(X1 / norm, X2 / norm, X3 / norm, X4 / norm); + } } From 8ce6cf9bffdc429cfe4e55baac7241a24d814ab2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 13 Oct 2023 02:13:31 -0500 Subject: [PATCH 254/293] Update IOneDimensionalArrayRepresentable.cs - Fix documentation comment --- .../Abstractions/IOneDimensionalArrayRepresentable.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs index 0bb08a0c..bfbb78ee 100644 --- a/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs @@ -57,8 +57,7 @@ public interface IOneDimensionalArrayRepresentable /// The norm Real Norm(); - /// Normalize a given vector - /// The vector to normalize + /// Normalize the vector /// The normalized vector T Normalize(); } From 914df89b3192d53457a53280595b4c5c11f2a795 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 13 Oct 2023 19:40:29 -0500 Subject: [PATCH 255/293] Update Vector4.cs - Add readonly keyword --- src/Mathematics.NET/LinearAlgebra/Vector4.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Vector4.cs b/src/Mathematics.NET/LinearAlgebra/Vector4.cs index 34082f3b..265f05de 100644 --- a/src/Mathematics.NET/LinearAlgebra/Vector4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Vector4.cs @@ -173,7 +173,7 @@ public bool Equals(Vector4 value) && X3.Equals(value.X3) && X4.Equals(value.X4); - public override int GetHashCode() => HashCode.Combine(X1, X2, X3, X4); + public override readonly int GetHashCode() => HashCode.Combine(X1, X2, X3, X4); // // Formatting From 93b8d5e6610eb926713ec085534bbc866e2a91ea Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 13 Oct 2023 20:12:31 -0500 Subject: [PATCH 256/293] Create ISquareMatrix.cs --- .../Abstractions/ISquareMatrix.cs | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs new file mode 100644 index 00000000..4d8aa3f4 --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs @@ -0,0 +1,54 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using Mathematics.NET.Core; + +namespace Mathematics.NET.LinearAlgebra.Abstractions; + +/// Defines support for square matrices +/// A type that implements +/// A type that implements +public interface ISquareMatrix + where T : ITwoDimensionalArrayRepresentable + where U : IComplex +{ + /// Represents a value that is not a matrix + /// This result will be returned when trying to invert a singular matrix + static abstract T NaM { get; } + + /// Compute the determinant of the matrix + /// The determinant + U Determinant(); + + /// Compute the inverse of the matrix + /// The inverse if the matrix is invertible; otherwise, + T Inverse(); + + /// Compute the trace of the matrix + /// The trace + U Trace(); +} From 90515df153fc11d80ace1264f68c76fcef34d87c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 13 Oct 2023 23:22:43 -0500 Subject: [PATCH 257/293] Create ITwoDimensionalArrayRepresentable.cs --- .../ITwoDimensionalArrayRepresentable.cs | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/Mathematics.NET/LinearAlgebra/Abstractions/ITwoDimensionalArrayRepresentable.cs diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/ITwoDimensionalArrayRepresentable.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/ITwoDimensionalArrayRepresentable.cs new file mode 100644 index 00000000..98da5e96 --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/ITwoDimensionalArrayRepresentable.cs @@ -0,0 +1,58 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using Mathematics.NET.Core; +using Mathematics.NET.Core.Operations; +using Mathematics.NET.Core.Relations; + +namespace Mathematics.NET.LinearAlgebra.Abstractions; + +/// Defines support for mathematical objects that can be represented by two-dimensional arrays +/// The type that implements the interface +/// A type that implements +public interface ITwoDimensionalArrayRepresentable + : IArrayRepresentable, + IAdditionOperation, + ISubtractionOperation, + IMultiplicationOperation, + IEqualityRelation, + IFormattable + where T : ITwoDimensionalArrayRepresentable + where U : IComplex +{ + /// The number of rows in the array + static abstract int E1Components { get; } + + /// The number of columns in the array + static abstract int E2Components { get; } + + /// Get the element at the specified row and column + /// The row + /// The column + /// The element at the specified row and column + U this[int row, int column] { get; set; } +} From 4992633f87e5fd9164b9a38fdad3075b1522df9e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Fri, 13 Oct 2023 23:30:24 -0500 Subject: [PATCH 258/293] Update ISquareMatrix.cs - Define method for checking if a value is not a matrix --- .../LinearAlgebra/Abstractions/ISquareMatrix.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs index 4d8aa3f4..a12f9daf 100644 --- a/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs @@ -48,6 +48,11 @@ public interface ISquareMatrix /// The inverse if the matrix is invertible; otherwise, T Inverse(); + /// Check if a value is not a matrix + /// The value to check + /// if the value is not a matrix; otherwise, + static abstract bool IsNaM(T matrix); + /// Compute the trace of the matrix /// The trace U Trace(); From 0a80c47e34b3ab0b97e6e64a1a9574481e04cd19 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 15 Oct 2023 02:40:14 -0500 Subject: [PATCH 259/293] Create Extensions.cs --- .../LinearAlgebra/Extensions.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/Mathematics.NET/LinearAlgebra/Extensions.cs diff --git a/src/Mathematics.NET/LinearAlgebra/Extensions.cs b/src/Mathematics.NET/LinearAlgebra/Extensions.cs new file mode 100644 index 00000000..4cfe6116 --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Extensions.cs @@ -0,0 +1,46 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Runtime.CompilerServices; +using CommunityToolkit.HighPerformance; +using Mathematics.NET.Core; + +namespace Mathematics.NET.LinearAlgebra; + +public static class Extensions +{ + /// Create a new over a 4x4 matrix of numbers + /// A type that implements + /// The input matrix + /// A with elements from the input matrix + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Span2D AsSpan2D(this Matrix4x4 matrix) + where T : IComplex + { + return new Span2D(Unsafe.AsPointer(ref matrix.E11), Matrix4x4.E1Components, Matrix4x4.E2Components, 0); + } +} From 1ca7a8f4377b8629b9f471e2fa319ecb5853e5d0 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 15 Oct 2023 02:45:11 -0500 Subject: [PATCH 260/293] Update Vector4.cs - Reorder when conjugate is taken; this does not affect the calculation - Use var keyword --- src/Mathematics.NET/LinearAlgebra/Vector4.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Vector4.cs b/src/Mathematics.NET/LinearAlgebra/Vector4.cs index 265f05de..1832f860 100644 --- a/src/Mathematics.NET/LinearAlgebra/Vector4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Vector4.cs @@ -197,10 +197,10 @@ public Real Norm() { Span components = stackalloc Real[4]; - components[0] = (T.Conjugate(X1) * X1).Re; - components[1] = (T.Conjugate(X2) * X2).Re; - components[2] = (T.Conjugate(X3) * X3).Re; - components[3] = (T.Conjugate(X4) * X4).Re; + components[0] = (X1 * T.Conjugate(X1)).Re; + components[1] = (X2 * T.Conjugate(X2)).Re; + components[2] = (X3 * T.Conjugate(X3)).Re; + components[3] = (X4 * T.Conjugate(X4)).Re; Real max = components[0]; for (int i = 1; i < 4; i++) @@ -211,7 +211,7 @@ public Real Norm() } } - Real partialSum = Real.Zero; + var partialSum = Real.Zero; var maxSquared = max * max; partialSum += components[0] / maxSquared; partialSum += components[1] / maxSquared; From 1172bca6e5167ec924c8c3736206b5d58dc1546b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Sun, 15 Oct 2023 02:45:45 -0500 Subject: [PATCH 261/293] Create Matrix4x4.cs --- .../LinearAlgebra/Matrix4x4.cs | 328 ++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs new file mode 100644 index 00000000..2e80b904 --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -0,0 +1,328 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using CommunityToolkit.HighPerformance; +using Mathematics.NET.Core; +using Mathematics.NET.LinearAlgebra.Abstractions; + +namespace Mathematics.NET.LinearAlgebra; + +[StructLayout(LayoutKind.Sequential)] +public struct Matrix4x4 + : ITwoDimensionalArrayRepresentable, T>, + ISquareMatrix, T> + where T : IComplex +{ + public static readonly Matrix4x4 NaM = CreateDiagonal(T.NaN, T.NaN, T.NaN, T.NaN); + + public T E11; + public T E12; + public T E13; + public T E14; + + public T E21; + public T E22; + public T E23; + public T E24; + + public T E31; + public T E32; + public T E33; + public T E34; + + public T E41; + public T E42; + public T E43; + public T E44; + + public Matrix4x4( + T e11, T e12, T e13, T e14, + T e21, T e22, T e23, T e24, + T e31, T e32, T e33, T e34, + T e41, T e42, T e43, T e44) + { + E11 = e11; + E12 = e12; + E13 = e13; + E14 = e14; + + E21 = e21; + E22 = e22; + E23 = e23; + E24 = e24; + + E31 = e31; + E32 = e32; + E33 = e33; + E34 = e34; + + E41 = e41; + E42 = e42; + E43 = e43; + E44 = e44; + } + + public static int Components => 16; + + public static int E1Components => 4; + + public static int E2Components => 4; + + // + // Indexer + // + + public T this[int row, int column] + { + get + { + if ((uint)row >= 4) + { + throw new ArgumentOutOfRangeException(); + } + + ref Vector4 vrow = ref Unsafe.Add(ref Unsafe.As>(ref E11), row); + return vrow[column]; + } + set + { + if ((uint)row >= 4) + { + throw new IndexOutOfRangeException(); + } + + ref Vector4 vrow = ref Unsafe.Add(ref Unsafe.As>(ref E11), row); + var temp = Vector4.WithElement(vrow, column, value); + vrow = temp; + } + } + + // + // Constants + // + + static Matrix4x4 ISquareMatrix, T>.NaM => NaM; + + // + // Operators + // + + public static Matrix4x4 operator +(Matrix4x4 a, Matrix4x4 b) + { + return new( + a.E11 + b.E11, a.E12 + b.E12, a.E13 + b.E13, a.E14 + b.E14, + a.E21 + b.E21, a.E22 + b.E22, a.E23 + b.E23, a.E24 + b.E24, + a.E31 + b.E31, a.E32 + b.E32, a.E33 + b.E33, a.E34 + b.E34, + a.E41 + b.E41, a.E42 + b.E42, a.E43 + b.E43, a.E44 + b.E44); + } + + public static Matrix4x4 operator -(Matrix4x4 a, Matrix4x4 b) + { + return new( + a.E11 - b.E11, a.E12 - b.E12, a.E13 - b.E13, a.E14 - b.E14, + a.E21 - b.E21, a.E22 - b.E22, a.E23 - b.E23, a.E24 - b.E24, + a.E31 - b.E31, a.E32 - b.E32, a.E33 - b.E33, a.E34 - b.E34, + a.E41 - b.E41, a.E42 - b.E42, a.E43 - b.E43, a.E44 - b.E44); + } + + public static Matrix4x4 operator *(Matrix4x4 a, Matrix4x4 b) + { + Unsafe.SkipInit(out Matrix4x4 result); + + result.E11 = a.E11 * b.E11 + a.E12 * b.E21 + a.E13 * b.E31 + a.E14 * b.E41; + result.E12 = a.E11 * b.E12 + a.E12 * b.E22 + a.E13 * b.E32 + a.E14 * b.E42; + result.E13 = a.E11 * b.E13 + a.E12 * b.E23 + a.E13 * b.E33 + a.E14 * b.E43; + result.E14 = a.E11 * b.E14 + a.E12 * b.E24 + a.E13 * b.E34 + a.E14 * b.E44; + + result.E21 = a.E21 * b.E11 + a.E22 * b.E21 + a.E23 * b.E31 + a.E24 * b.E41; + result.E22 = a.E21 * b.E12 + a.E22 * b.E22 + a.E23 * b.E32 + a.E24 * b.E42; + result.E23 = a.E21 * b.E13 + a.E22 * b.E23 + a.E23 * b.E33 + a.E24 * b.E43; + result.E24 = a.E21 * b.E14 + a.E22 * b.E24 + a.E23 * b.E34 + a.E24 * b.E44; + + result.E31 = a.E31 * b.E11 + a.E32 * b.E21 + a.E33 * b.E31 + a.E34 * b.E41; + result.E32 = a.E31 * b.E12 + a.E32 * b.E22 + a.E33 * b.E32 + a.E34 * b.E42; + result.E33 = a.E31 * b.E13 + a.E32 * b.E23 + a.E33 * b.E33 + a.E34 * b.E43; + result.E34 = a.E31 * b.E14 + a.E32 * b.E24 + a.E33 * b.E34 + a.E34 * b.E44; + + result.E41 = a.E41 * b.E11 + a.E42 * b.E21 + a.E43 * b.E31 + a.E44 * b.E41; + result.E42 = a.E41 * b.E12 + a.E42 * b.E22 + a.E43 * b.E32 + a.E44 * b.E42; + result.E43 = a.E41 * b.E13 + a.E42 * b.E23 + a.E43 * b.E33 + a.E44 * b.E43; + result.E44 = a.E41 * b.E14 + a.E42 * b.E24 + a.E43 * b.E34 + a.E44 * b.E44; + + return result; + } + + // + // Equality + // + + public static bool operator ==(Matrix4x4 a, Matrix4x4 b) + { + return a.E11 == b.E11 && a.E22 == b.E22 && a.E33 == b.E33 && a.E44 == b.E44 // Check diagonal first + && a.E12 == b.E12 && a.E13 == b.E13 && a.E14 == b.E14 + && a.E21 == b.E21 && a.E23 == b.E23 && a.E24 == b.E24 + && a.E31 == b.E31 && a.E32 == b.E32 && a.E34 == b.E34 + && a.E41 == b.E41 && a.E42 == b.E42 && a.E43 == b.E43; + } + + public static bool operator !=(Matrix4x4 a, Matrix4x4 b) + { + return a.E11 != b.E11 || a.E22 != b.E22 || a.E33 != b.E33 || a.E44 == b.E44 // Check diagonal first + || a.E12 != b.E12 || a.E13 != b.E13 || a.E14 != b.E14 + || a.E21 != b.E21 || a.E23 != b.E23 || a.E24 != b.E24 + || a.E31 != b.E31 || a.E32 != b.E32 || a.E34 != b.E34 + || a.E41 != b.E41 || a.E42 != b.E42 || a.E43 != b.E43; + } + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Matrix4x4 other && Equals(other); + + public bool Equals(Matrix4x4 value) + { + return E11.Equals(value.E11) && E22.Equals(value.E22) && E33.Equals(value.E33) && E44.Equals(value.E44) // Check diagonal first + && E12.Equals(value.E12) && E13.Equals(value.E13) && E14.Equals(value.E14) + && E21.Equals(value.E21) && E23.Equals(value.E23) && E24.Equals(value.E24) + && E31.Equals(value.E31) && E32.Equals(value.E32) && E34.Equals(value.E34) + && E41.Equals(value.E41) && E42.Equals(value.E42) && E43.Equals(value.E43); + } + + public override readonly int GetHashCode() + { + HashCode hash = default; + + hash.Add(E11); + hash.Add(E12); + hash.Add(E13); + hash.Add(E14); + + hash.Add(E21); + hash.Add(E22); + hash.Add(E23); + hash.Add(E24); + + hash.Add(E31); + hash.Add(E32); + hash.Add(E33); + hash.Add(E34); + + hash.Add(E41); + hash.Add(E42); + hash.Add(E43); + hash.Add(E44); + + return hash.ToHashCode(); + } + + // + // Formatting + // + + public string ToString(string? format, IFormatProvider? provider) + { + Span2D strings = new string[4, 4]; + var maxElementLength = 0; + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + var s = this[i, j].ToString(format, provider); + strings[i, j] = s; + var length = s.Length + 2; + if (maxElementLength < length) + { + maxElementLength = length; + } + } + } + + var trimLength = Environment.NewLine.Length; + StringBuilder builder = new(); + builder.Append('['); + for (int i = 0; i < 4; i++) + { + builder.Append(i != 0 ? " [" : "["); + for (int j = 0; j < 4; j++) + { + string value = j != 3 ? $"{strings[i, j]}, " : strings[i, j]; + builder.Append(value.PadRight(maxElementLength)); + } + builder.Remove(builder.Length - trimLength, trimLength); + builder.Append($"],{Environment.NewLine}"); + } + builder.Remove(builder.Length - trimLength - 1, trimLength + 1); // Trim last comma + builder.Append(']'); + return string.Format(provider, builder.ToString()); + } + + // + // Methods + // + + public static Matrix4x4 CreateDiagonal(T e11, T e22, T e33, T e44) + { + return new( + e11, T.Zero, T.Zero, T.Zero, + T.Zero, e22, T.Zero, T.Zero, + T.Zero, T.Zero, e33, T.Zero, + T.Zero, T.Zero, T.Zero, e44); + } + + public T Determinant() + { + throw new NotImplementedException(); + } + + public Matrix4x4 Inverse() + { + var det = Determinant(); + if (det == T.Zero) + { + return NaM; + } + throw new NotImplementedException(); + } + + public static bool IsNaM(Matrix4x4 matrix) + => matrix.E11 == T.NaN && matrix.E22 == T.NaN && matrix.E33 == T.NaN && matrix.E44 == T.NaN; + + public T Trace() => E11 + E22 + E33 + E44; + + public Matrix4x4 Transpose() + { + Unsafe.SkipInit(out Matrix4x4 result); + + result.E11 = E11; result.E12 = E21; result.E13 = E31; result.E14 = E41; + result.E21 = E12; result.E22 = E22; result.E23 = E32; result.E24 = E42; + result.E31 = E13; result.E32 = E23; result.E33 = E33; result.E34 = E43; + result.E41 = E14; result.E42 = E24; result.E43 = E34; result.E44 = E44; + + return result; + } +} From 7cb033237548fb8b79f7ae1b1135b46b506ed676 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 16 Oct 2023 01:21:14 -0500 Subject: [PATCH 262/293] Add implicit operator - Add an implicit operator for converting a value of type Real to one that implements IComplex. If the value to convert from is also of type Real, return itself - Define and implement FromReal method --- src/Mathematics.NET/Core/ComplexNumber.cs | 2 ++ src/Mathematics.NET/Core/IComplex.cs | 11 +++++++++++ src/Mathematics.NET/Core/Rational.cs | 2 ++ src/Mathematics.NET/Core/Real.cs | 2 ++ 4 files changed, 17 insertions(+) diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/ComplexNumber.cs index 63242402..90b2e235 100644 --- a/src/Mathematics.NET/Core/ComplexNumber.cs +++ b/src/Mathematics.NET/Core/ComplexNumber.cs @@ -386,6 +386,8 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static ComplexNumber FromPolarForm(Real magnitude, Real phase) => new(magnitude * Math.Cos(phase.Value), magnitude * Math.Sin(phase.Value)); + public static ComplexNumber FromReal(Real x) => new(x); + private static double Hypot(double x, double y) { // Factor out the larger value to avoid possible overflow diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index 74e47d3e..be520e04 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -148,6 +148,12 @@ static virtual T CreateTruncating(U value) return result; } + /// Create an instance of type from one of type + /// If the value to convert from is also of type , return itself + /// A value of type + /// An instance of type created from + static abstract T FromReal(Real x); + /// Check if a value is finite /// The value to check /// if the value is finite; otherwise, @@ -262,4 +268,9 @@ protected static abstract bool TryConvertToTruncating(T value, [MaybeNullWhen /// Convert a value of type to one of type /// The value to convert static virtual implicit operator T(double x) => T.CreateSaturating(x); + + /// Convert a value of type to one of type + /// If the type to convert from is also , return itself + /// The value to convert + static virtual implicit operator T(Real x) => T.FromReal(x); } diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs index 0e0d4af2..de7a7d16 100644 --- a/src/Mathematics.NET/Core/Rational.cs +++ b/src/Mathematics.NET/Core/Rational.cs @@ -438,6 +438,8 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static Rational Conjugate(Rational x) => x; + public static Rational FromReal(Real x) => (Rational)x; + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static T GCD(T p, T q) { diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index ba611a84..5ba3bf71 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -262,6 +262,8 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static Real Conjugate(Real x) => x; + public static Real FromReal(Real x) => x; + public static Real Hypot(Real x, Real y) => double.Hypot(x._value, y._value); public static bool IsFinite(Real x) => double.IsFinite(x._value); From 8469838eb2368a2f848361c83cde13982780dc53 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 16 Oct 2023 02:18:19 -0500 Subject: [PATCH 263/293] Define and implement FromDouble method - Update explicit operator in rational struct - Update implicit operator in IComplex --- src/Mathematics.NET/Core/ComplexNumber.cs | 2 ++ src/Mathematics.NET/Core/IComplex.cs | 7 ++++++- src/Mathematics.NET/Core/Rational.cs | 8 ++++++-- src/Mathematics.NET/Core/Real.cs | 2 ++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Mathematics.NET/Core/ComplexNumber.cs b/src/Mathematics.NET/Core/ComplexNumber.cs index 90b2e235..406e4bd7 100644 --- a/src/Mathematics.NET/Core/ComplexNumber.cs +++ b/src/Mathematics.NET/Core/ComplexNumber.cs @@ -383,6 +383,8 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static ComplexNumber Conjugate(ComplexNumber z) => new(z._real, -z._imaginary); + public static ComplexNumber FromDouble(double x) => new(x); + public static ComplexNumber FromPolarForm(Real magnitude, Real phase) => new(magnitude * Math.Cos(phase.Value), magnitude * Math.Sin(phase.Value)); diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index be520e04..eb13b8d9 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -148,6 +148,11 @@ static virtual T CreateTruncating(U value) return result; } + /// Create an instance of type from one of type + /// A value of type + /// An instance of type created from + static abstract T FromDouble(double x); + /// Create an instance of type from one of type /// If the value to convert from is also of type , return itself /// A value of type @@ -267,7 +272,7 @@ protected static abstract bool TryConvertToTruncating(T value, [MaybeNullWhen /// Convert a value of type to one of type /// The value to convert - static virtual implicit operator T(double x) => T.CreateSaturating(x); + static virtual implicit operator T(double x) => T.FromDouble(x); /// Convert a value of type to one of type /// If the type to convert from is also , return itself diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs index de7a7d16..ec703f5b 100644 --- a/src/Mathematics.NET/Core/Rational.cs +++ b/src/Mathematics.NET/Core/Rational.cs @@ -438,6 +438,8 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static Rational Conjugate(Rational x) => x; + public static Rational FromDouble(double x) => (Rational)x; + public static Rational FromReal(Real x) => (Rational)x; [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -605,9 +607,9 @@ public static bool TryConvertToTruncating(Rational value, [MaybeNullWhen(f // // TODO: Find a better implementation - public static explicit operator Rational(Real x) + public static explicit operator Rational(double x) { - var value = x.Value; + var value = x; if (double.IsNaN(value) || double.IsInfinity(value)) { return NaN; @@ -627,6 +629,8 @@ public static explicit operator Rational(Real x) return new(num / gcd, den / gcd); } + public static explicit operator Rational(Real x) => (Rational)x.Value; + public static explicit operator checked Real(Rational x) => checked(double.CreateChecked(x._numerator) / double.CreateChecked(x._denominator)); public static explicit operator Real(Rational x) => double.CreateSaturating(x._numerator) / double.CreateSaturating(x._denominator); diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 5ba3bf71..39d8624f 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -262,6 +262,8 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro public static Real Conjugate(Real x) => x; + public static Real FromDouble(double x) => new(x); + public static Real FromReal(Real x) => x; public static Real Hypot(Real x, Real y) => double.Hypot(x._value, y._value); From 52d8ace384c77e2a403d3ab7a8a8fb1d6dca5980 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 16 Oct 2023 02:19:29 -0500 Subject: [PATCH 264/293] Update Vector4.cs - No longer need .Value since implicit operator exists --- src/Mathematics.NET/LinearAlgebra/Vector4.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Vector4.cs b/src/Mathematics.NET/LinearAlgebra/Vector4.cs index 1832f860..bab8c03a 100644 --- a/src/Mathematics.NET/LinearAlgebra/Vector4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Vector4.cs @@ -223,7 +223,7 @@ public Real Norm() public Vector4 Normalize() { - var norm = Norm().Value; + var norm = Norm(); return new(X1 / norm, X2 / norm, X3 / norm, X4 / norm); } } From 21ffd90ee6470b4eb8d17318998f529fc24c9a4a Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 16 Oct 2023 04:33:38 -0500 Subject: [PATCH 265/293] Create LinAlg.cs --- src/Mathematics.NET/LinearAlgebra/LinAlg.cs | 178 ++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 src/Mathematics.NET/LinearAlgebra/LinAlg.cs diff --git a/src/Mathematics.NET/LinearAlgebra/LinAlg.cs b/src/Mathematics.NET/LinearAlgebra/LinAlg.cs new file mode 100644 index 00000000..c5fb204e --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/LinAlg.cs @@ -0,0 +1,178 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Runtime.CompilerServices; +using CommunityToolkit.HighPerformance; +using CommunityToolkit.HighPerformance.Enumerables; +using Mathematics.NET.Core; + +namespace Mathematics.NET.LinearAlgebra; + +/// A class containing linear algebra operations +public static class LinAlg +{ + /// Compute the eigenvalues of a matrix using a QR decomposition method + /// A type that implements + /// A matrix + /// A QR decomposition method + /// The eigenvalues of the given matrix + public static Span EigVals(Span2D matrix, QRDecompositionMethod method, int iterations = 10) + where T : IComplex + { + // TODO: Implement shifted QR algorithm for faster convergence and dynamically determine how many iterations should be run + // TODO: Check to make sure new arrays are not being created every iteration + Span2D rq = matrix; + for (int i = 0; i < iterations; i++) + { + method(rq, out Span2D Q, out Span2D R); + rq = MatMul(R, Q); + } + + Span result = new T[matrix.Height]; + for (int i = 0; i < matrix.Height; i++) + { + result[i] = rq[i, i]; + } + return result; + } + + /// Multiply two matrices + /// A type that implements + /// The left matrix + /// The right matrix + /// The result of the operation if the dimensions of the matrices are valid; otherwise, throw an exception + /// Cannot multiply matrices of incompatible dimensions + public static Span2D MatMul(Span2D left, Span2D right) + where T : IComplex + { + if (left.Width != right.Height) + { + throw new ArgumentException("Cannot multiply matrices of incompatible dimensions"); + } + + Span2D result = new T[left.Height, right.Width]; + for (int i = 0; i < left.Height; i++) + { + for (int j = 0; j < right.Width; j++) + { + for (int k = 0; k < left.Width; k++) + { + result[i, j] += left[i, k] * right[k, j]; + } + } + } + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Real Norm(RefEnumerable vector) + where T : IComplex + { + Span components = new Real[vector.Length]; + for (int i = 0; i < vector.Length; i++) + { + components[i] = (vector[i] * T.Conjugate(vector[i])).Re; + } + + Real max = components[0]; + for (int i = 1; i < vector.Length; i++) + { + if (components[i] > max) + { + max = components[i]; + } + } + + var partialSum = Real.Zero; + var scale = Real.One / (max * max); + foreach (ref var component in components) + { + partialSum += scale * component; + } + + return max * Real.Sqrt(partialSum); + } + + /// Encapsulates a QR decomposition method with one input and two out parameters + /// A type that implements + /// An input matrix + /// The resulting orthogonal matrix + /// The resulting upper triangular matrix + public delegate void QRDecompositionMethod(Span2D matrix, out Span2D Q, out Span2D R) + where T : IComplex; + + /// Perform QR decomposition on a matrix using the modified Gram-Schmidt process + /// A type that implements + /// An input matrix + /// The resulting orthogonal matrix + /// The resulting upper triangular matrix + /// One of the columns is not linearly independent from the others + public static void QRGramSchmidt(Span2D matrix, out Span2D Q, out Span2D R) + where T : IComplex + { + var height = matrix.Height; + var width = matrix.Width; + + Q = new T[height, width]; + R = new T[height, width]; + + for (int i = 0; i < width; i++) + { + var column = Q.GetColumn(i); + matrix.GetColumn(i).CopyTo(column); + for (int j = 0; j < i; j++) + { + var proj = T.Zero; + for (int k = 0; k < height; k++) + { + proj += T.Conjugate(Q[k, j]) * Q[k, i]; + } + R[j, i] = proj; + + for (int k = 0; k < height; k++) + { + Q[k, i] = Q[k, i] - proj * Q[k, j]; + } + } + + var norm = Norm(column); + if (norm != Real.Zero) + { + R[i, i] = norm; + foreach (ref var element in column) + { + element /= norm; + } + } + else + { + // TODO: Consider not throwing an exception + throw new DivideByZeroException(string.Format("Column {0} is not linearly independent from the others", i)); + } + } + } +} From d3bcfd780a1b4c609d3b78e5cbd91a4150d0c231 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 16 Oct 2023 20:32:32 -0500 Subject: [PATCH 266/293] Define and implement Sign function --- src/Mathematics.NET/Core/IReal.cs | 11 +++++++++++ src/Mathematics.NET/Core/Rational.cs | 9 +++++++++ src/Mathematics.NET/Core/Real.cs | 2 ++ 3 files changed, 22 insertions(+) diff --git a/src/Mathematics.NET/Core/IReal.cs b/src/Mathematics.NET/Core/IReal.cs index 8fd95e9b..5fff79b2 100644 --- a/src/Mathematics.NET/Core/IReal.cs +++ b/src/Mathematics.NET/Core/IReal.cs @@ -69,4 +69,15 @@ public interface IReal /// The second value /// The lesser of the two values static abstract T Min(T x, T y); + + /// Find the sign of a real number + /// The value to check + /// + /// A number indicating the sign of the value:

+ /// 1 if the value is greater than zero
+ /// 0 if the value is greater than zero
+ /// -1 if the value is less than zero + ///
+ /// An overflow or underflow has occurred + static abstract int Sign(T x); } diff --git a/src/Mathematics.NET/Core/Rational.cs b/src/Mathematics.NET/Core/Rational.cs index ec703f5b..c8a3a71f 100644 --- a/src/Mathematics.NET/Core/Rational.cs +++ b/src/Mathematics.NET/Core/Rational.cs @@ -530,6 +530,15 @@ public static Rational Reduce(Rational x) return new(x._numerator / gcd, x._denominator / gcd); } + public static int Sign(Rational x) + { + if (x == Rational.Zero) + { + return 0; + } + return x._numerator > T.Zero ? 1 : -1; + } + public static bool TryConvertFromChecked(U value, out Rational result) where U : INumberBase { diff --git a/src/Mathematics.NET/Core/Real.cs b/src/Mathematics.NET/Core/Real.cs index 39d8624f..3c58d124 100644 --- a/src/Mathematics.NET/Core/Real.cs +++ b/src/Mathematics.NET/Core/Real.cs @@ -293,6 +293,8 @@ public static Real Reciprocate(Real x) return 1.0 / x; } + public static int Sign(Real x) => Math.Sign(x._value); + public static bool TryConvertFromChecked(U value, out Real result) where U : INumberBase { From e516c7a88dfa90b72b88cb8c08ed938384a15dd0 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 16 Oct 2023 22:59:28 -0500 Subject: [PATCH 267/293] Implement Determinant --- .../LinearAlgebra/Matrix4x4.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index 2e80b904..b51c654a 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -294,9 +294,24 @@ public static Matrix4x4 CreateDiagonal(T e11, T e22, T e33, T e44) T.Zero, T.Zero, T.Zero, e44); } - public T Determinant() + public readonly T Determinant() { - throw new NotImplementedException(); + T a = E11, b = E12, c = E13, d = E14; + T e = E21, f = E22, g = E23, h = E24; + T i = E31, j = E32, k = E33, l = E34; + T m = E41, n = E42, o = E43, p = E44; + + T kp_lo = k * p - l * o; + T jp_ln = j * p - l * n; + T jo_kn = j * o - k * n; + T ip_lm = i * p - l * m; + T io_km = i * o - k * m; + T in_jm = i * n - j * m; + + return a * (f * kp_lo - g * jp_ln + h * jo_kn) - + b * (e * kp_lo - g * ip_lm + h * io_km) + + c * (e * jp_ln - f * ip_lm + h * in_jm) - + d * (e * jo_kn - f * io_km + g * in_jm); } public Matrix4x4 Inverse() From 9721871206352ec70225225403144665f17ba380 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 16 Oct 2023 23:21:44 -0500 Subject: [PATCH 268/293] Implement Inverse --- .../LinearAlgebra/Matrix4x4.cs | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index b51c654a..f08c3a32 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -314,14 +314,71 @@ public readonly T Determinant() d * (e * jo_kn - f * io_km + g * in_jm); } + // TODO: Optimize public Matrix4x4 Inverse() { - var det = Determinant(); + T a = E11, b = E12, c = E13, d = E14; + T e = E21, f = E22, g = E23, h = E24; + T i = E31, j = E32, k = E33, l = E34; + T m = E41, n = E42, o = E43, p = E44; + + T kp_lo = k * p - l * o; + T jp_ln = j * p - l * n; + T jo_kn = j * o - k * n; + T ip_lm = i * p - l * m; + T io_km = i * o - k * m; + T in_jm = i * n - j * m; + + T a11 = f * kp_lo - g * jp_ln + h * jo_kn; + T a12 = -(e * kp_lo - g * ip_lm + h * io_km); + T a13 = e * jp_ln - f * ip_lm + h * in_jm; + T a14 = -(e * jo_kn - f * io_km + g * in_jm); + + T det = a * a11 + b * a12 + c * a13 + d * a14; + if (det == T.Zero) { return NaM; } - throw new NotImplementedException(); + + T invDet = T.One / det; + Matrix4x4 result; + + result.E11 = a11 * invDet; + result.E21 = a12 * invDet; + result.E31 = a13 * invDet; + result.E41 = a14 * invDet; + + result.E12 = -(b * kp_lo - c * jp_ln + d * jo_kn) * invDet; + result.E22 = (a * kp_lo - c * ip_lm + d * io_km) * invDet; + result.E32 = -(a * jp_ln - b * ip_lm + d * in_jm) * invDet; + result.E42 = (a * jo_kn - b * io_km + c * in_jm) * invDet; + + T gp_ho = g * p - h * o; + T fp_hn = f * p - h * n; + T fo_gn = f * o - g * n; + T ep_hm = e * p - h * m; + T eo_gm = e * o - g * m; + T en_fm = e * n - f * m; + + result.E13 = (b * gp_ho - c * fp_hn + d * fo_gn) * invDet; + result.E23 = -(a * gp_ho - c * ep_hm + d * eo_gm) * invDet; + result.E33 = (a * fp_hn - b * ep_hm + d * en_fm) * invDet; + result.E43 = -(a * fo_gn - b * eo_gm + c * en_fm) * invDet; + + T gl_hk = g * l - h * k; + T fl_hj = f * l - h * j; + T fk_gj = f * k - g * j; + T el_hi = e * l - h * i; + T ek_gi = e * k - g * i; + T ej_fi = e * j - f * i; + + result.E14 = -(b * gl_hk - c * fl_hj + d * fk_gj) * invDet; + result.E24 = (a * gl_hk - c * el_hi + d * ek_gi) * invDet; + result.E34 = -(a * fl_hj - b * el_hi + d * ej_fi) * invDet; + result.E44 = (a * fk_gj - b * ek_gi + c * ej_fi) * invDet; + + return result; } public static bool IsNaM(Matrix4x4 matrix) From 2fb8a06620e1c11f64e1d32947a8c9d6a07e42a4 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 16 Oct 2023 23:25:53 -0500 Subject: [PATCH 269/293] Update Matrix4x4.cs - Add documentation comments --- src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index f08c3a32..984e34ce 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -35,6 +35,8 @@ namespace Mathematics.NET.LinearAlgebra; +/// Represents a 4x4 matrix +/// A type that implements [StructLayout(LayoutKind.Sequential)] public struct Matrix4x4 : ITwoDimensionalArrayRepresentable, T>, From 77736d0955c29fceef910451d3caecbac879016a Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Mon, 16 Oct 2023 23:33:12 -0500 Subject: [PATCH 270/293] Create Extensions.cs --- src/Mathematics.NET/Extensions.cs | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/Mathematics.NET/Extensions.cs diff --git a/src/Mathematics.NET/Extensions.cs b/src/Mathematics.NET/Extensions.cs new file mode 100644 index 00000000..61f0892a --- /dev/null +++ b/src/Mathematics.NET/Extensions.cs @@ -0,0 +1,61 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Text; + +namespace Mathematics.NET; + +public static class Extensions +{ + /// Remove specified characters from the end of a string being built by a string builder + /// A string builder instance + /// An array of characters to trim + /// The same string builder with characters removed + public static StringBuilder TrimEnd(this StringBuilder builder, params char[]? unwantedChars) + { + if (unwantedChars == null || builder.Length == 0 || unwantedChars.Length == 0) + { + return builder; + } + + int i = builder.Length - 1; + while (i >= 0) + { + if (!unwantedChars.Contains(builder[i])) + { + break; + } + i--; + } + if (i < builder.Length - 1) + { + builder.Length = ++i; + } + + return builder; + } +} From 15318c50d8641c03d2538232998cfc4ed42b9c2e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 00:46:35 -0500 Subject: [PATCH 271/293] Update Extensions.cs --- .../LinearAlgebra/Extensions.cs | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/Mathematics.NET/LinearAlgebra/Extensions.cs b/src/Mathematics.NET/LinearAlgebra/Extensions.cs index 4cfe6116..17c165e9 100644 --- a/src/Mathematics.NET/LinearAlgebra/Extensions.cs +++ b/src/Mathematics.NET/LinearAlgebra/Extensions.cs @@ -26,6 +26,7 @@ //
using System.Runtime.CompilerServices; +using System.Text; using CommunityToolkit.HighPerformance; using Mathematics.NET.Core; @@ -43,4 +44,97 @@ public static unsafe Span2D AsSpan2D(this Matrix4x4 matrix) { return new Span2D(Unsafe.AsPointer(ref matrix.E11), Matrix4x4.E1Components, Matrix4x4.E2Components, 0); } + + /// Get the string representation of this object + /// A type that implements + /// The span to format + /// The format to use + /// The provider to use to format the value + /// A string representation of this object + public static string ToDisplayString(this Span span, string? format = null, IFormatProvider? provider = null) + where T : IComplex + { + var count = span.Length; + + var maxElementLength = 0; + Span strings = new string[count]; + for (int i = 0; i < count; i++) + { + var s = span[i].ToString(format, provider); + strings[i] = s; + var length = s.Length + 2; + if (maxElementLength < length) + { + maxElementLength = length; + } + } + + StringBuilder builder = new(); + builder.Append('['); + for (int i = 0; i < count; i++) + { + string value = i != count - 1 ? $"{strings[i]}, " : strings[i]; + builder.Append(value.PadRight(maxElementLength)); + } + builder.Append(']'); + return string.Format(provider, builder.ToString()); + } + + /// Get the string representation of this object + /// A type that implements + /// The span to format + /// The format to use + /// The provider to use to format the value + /// A string representation of this object + public static string ToDisplayString(this Span2D span, string? format = null, IFormatProvider? provider = null) + where T : IComplex + { + var rows = span.Height; + var cols = span.Width; + + Span2D strings = new string[rows, cols]; + var maxElementLength = 0; + for (int i = 0; i < rows; i++) + { + for (int j = 0; j < cols; j++) + { + var s = span[i, j].ToString(format, provider); + strings[i, j] = s; + var length = s.Length + 2; + if (maxElementLength < length) + { + maxElementLength = length; + } + } + } + + StringBuilder builder = new(); + var newlineChars = Environment.NewLine.ToCharArray(); + builder.Append('['); + for (int i = 0; i < rows; i++) + { + builder.Append(i != 0 ? " [" : "["); + for (int j = 0; j < cols; j++) + { + var value = j != cols - 1 ? $"{strings[i, j]}, " : strings[i, j]; + builder.Append(value.PadRight(maxElementLength)); + } + CloseGroup(builder, newlineChars); + } + CloseGroup(builder, newlineChars, true); + return string.Format(provider, builder.ToString()); + } + + internal static void CloseGroup(StringBuilder builder, char[]? unwantedChars, bool isEnd = false) + { + builder.TrimEnd(unwantedChars); + if (!isEnd) + { + builder.AppendLine("]"); + } + else + { + builder.Append(']'); + } + } } From 299fac57e2d8f3f3ab408f8ea639d590f65b2711 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 00:55:59 -0500 Subject: [PATCH 272/293] Update Matrix4x4.cs - Update ToString method --- src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index 984e34ce..8a83c5a7 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -264,8 +264,8 @@ public string ToString(string? format, IFormatProvider? provider) } } - var trimLength = Environment.NewLine.Length; StringBuilder builder = new(); + var newlineChars = Environment.NewLine.ToCharArray(); builder.Append('['); for (int i = 0; i < 4; i++) { @@ -275,11 +275,9 @@ public string ToString(string? format, IFormatProvider? provider) string value = j != 3 ? $"{strings[i, j]}, " : strings[i, j]; builder.Append(value.PadRight(maxElementLength)); } - builder.Remove(builder.Length - trimLength, trimLength); - builder.Append($"],{Environment.NewLine}"); + Extensions.CloseGroup(builder, newlineChars); } - builder.Remove(builder.Length - trimLength - 1, trimLength + 1); // Trim last comma - builder.Append(']'); + Extensions.CloseGroup(builder, newlineChars, true); return string.Format(provider, builder.ToString()); } From 2de2225afc5c4e595de8323d12d3064672ef7bd6 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 00:56:44 -0500 Subject: [PATCH 273/293] Rename Extensions to LinAlgExtensions --- .../LinearAlgebra/{Extensions.cs => LinAlgExtensions.cs} | 5 +++-- src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) rename src/Mathematics.NET/LinearAlgebra/{Extensions.cs => LinAlgExtensions.cs} (96%) diff --git a/src/Mathematics.NET/LinearAlgebra/Extensions.cs b/src/Mathematics.NET/LinearAlgebra/LinAlgExtensions.cs similarity index 96% rename from src/Mathematics.NET/LinearAlgebra/Extensions.cs rename to src/Mathematics.NET/LinearAlgebra/LinAlgExtensions.cs index 17c165e9..3bbafc3c 100644 --- a/src/Mathematics.NET/LinearAlgebra/Extensions.cs +++ b/src/Mathematics.NET/LinearAlgebra/LinAlgExtensions.cs @@ -1,4 +1,4 @@ -// +// // Mathematics.NET // https://github.com/HamletTanyavong/Mathematics.NET // @@ -32,7 +32,8 @@ namespace Mathematics.NET.LinearAlgebra; -public static class Extensions +/// A class containing linear algebra extension methods +public static class LinAlgExtensions { /// Create a new over a 4x4 matrix of numbers /// A type that implements diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index 8a83c5a7..f2c35f91 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -275,9 +275,9 @@ public string ToString(string? format, IFormatProvider? provider) string value = j != 3 ? $"{strings[i, j]}, " : strings[i, j]; builder.Append(value.PadRight(maxElementLength)); } - Extensions.CloseGroup(builder, newlineChars); + LinAlgExtensions.CloseGroup(builder, newlineChars); } - Extensions.CloseGroup(builder, newlineChars, true); + LinAlgExtensions.CloseGroup(builder, newlineChars, true); return string.Format(provider, builder.ToString()); } From c37650a96143dd6d50b35021d2132ff67cdcd09d Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 00:58:50 -0500 Subject: [PATCH 274/293] Update Extensions.cs - Add documentation comment --- src/Mathematics.NET/Extensions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mathematics.NET/Extensions.cs b/src/Mathematics.NET/Extensions.cs index 61f0892a..5443839f 100644 --- a/src/Mathematics.NET/Extensions.cs +++ b/src/Mathematics.NET/Extensions.cs @@ -29,6 +29,7 @@ namespace Mathematics.NET; +/// A class containing Mathematics.NET extension methods public static class Extensions { /// Remove specified characters from the end of a string being built by a string builder From 530affacb9e919134bdee27d826942b577ee2ca3 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 01:02:46 -0500 Subject: [PATCH 275/293] Rename Extensions to ExternalExtensions --- .../{Extensions.cs => ExternalExtensions.cs} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename src/Mathematics.NET/{Extensions.cs => ExternalExtensions.cs} (91%) diff --git a/src/Mathematics.NET/Extensions.cs b/src/Mathematics.NET/ExternalExtensions.cs similarity index 91% rename from src/Mathematics.NET/Extensions.cs rename to src/Mathematics.NET/ExternalExtensions.cs index 5443839f..23d7bec7 100644 --- a/src/Mathematics.NET/Extensions.cs +++ b/src/Mathematics.NET/ExternalExtensions.cs @@ -1,4 +1,4 @@ -// +// // Mathematics.NET // https://github.com/HamletTanyavong/Mathematics.NET // @@ -29,8 +29,8 @@ namespace Mathematics.NET; -/// A class containing Mathematics.NET extension methods -public static class Extensions +/// A class containing extension methods for external .NET objects +public static class ExternalExtensions { /// Remove specified characters from the end of a string being built by a string builder /// A string builder instance From 36aa175e73827a0b51e1d5076b135f1e92d1b495 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 01:04:51 -0500 Subject: [PATCH 276/293] Add global using directives --- .../LinearAlgebra/Abstractions/IArrayRepresentable.cs | 2 -- .../Abstractions/IOneDimensionalArrayRepresentable.cs | 1 - .../LinearAlgebra/Abstractions/ISquareMatrix.cs | 2 -- .../Abstractions/ITwoDimensionalArrayRepresentable.cs | 1 - src/Mathematics.NET/LinearAlgebra/LinAlg.cs | 2 -- src/Mathematics.NET/LinearAlgebra/LinAlgExtensions.cs | 2 -- src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs | 2 -- src/Mathematics.NET/LinearAlgebra/Vector4.cs | 1 - src/Mathematics.NET/Mathematics.NET.csproj | 5 +++++ src/Mathematics.NET/Mathematics.cs | 2 -- 10 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/IArrayRepresentable.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/IArrayRepresentable.cs index 0d620805..85b4f92b 100644 --- a/src/Mathematics.NET/LinearAlgebra/Abstractions/IArrayRepresentable.cs +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/IArrayRepresentable.cs @@ -25,8 +25,6 @@ // SOFTWARE. // -using Mathematics.NET.Core; - namespace Mathematics.NET.LinearAlgebra.Abstractions; /// Defines support for mathematical objects that can be represented by arrays diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs index bfbb78ee..d066add1 100644 --- a/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/IOneDimensionalArrayRepresentable.cs @@ -25,7 +25,6 @@ // SOFTWARE. // -using Mathematics.NET.Core; using Mathematics.NET.Core.Operations; using Mathematics.NET.Core.Relations; diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs index a12f9daf..f9ee7dfd 100644 --- a/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/ISquareMatrix.cs @@ -25,8 +25,6 @@ // SOFTWARE. // -using Mathematics.NET.Core; - namespace Mathematics.NET.LinearAlgebra.Abstractions; /// Defines support for square matrices diff --git a/src/Mathematics.NET/LinearAlgebra/Abstractions/ITwoDimensionalArrayRepresentable.cs b/src/Mathematics.NET/LinearAlgebra/Abstractions/ITwoDimensionalArrayRepresentable.cs index 98da5e96..176f41bc 100644 --- a/src/Mathematics.NET/LinearAlgebra/Abstractions/ITwoDimensionalArrayRepresentable.cs +++ b/src/Mathematics.NET/LinearAlgebra/Abstractions/ITwoDimensionalArrayRepresentable.cs @@ -25,7 +25,6 @@ // SOFTWARE. // -using Mathematics.NET.Core; using Mathematics.NET.Core.Operations; using Mathematics.NET.Core.Relations; diff --git a/src/Mathematics.NET/LinearAlgebra/LinAlg.cs b/src/Mathematics.NET/LinearAlgebra/LinAlg.cs index c5fb204e..c204e17f 100644 --- a/src/Mathematics.NET/LinearAlgebra/LinAlg.cs +++ b/src/Mathematics.NET/LinearAlgebra/LinAlg.cs @@ -26,9 +26,7 @@ //
using System.Runtime.CompilerServices; -using CommunityToolkit.HighPerformance; using CommunityToolkit.HighPerformance.Enumerables; -using Mathematics.NET.Core; namespace Mathematics.NET.LinearAlgebra; diff --git a/src/Mathematics.NET/LinearAlgebra/LinAlgExtensions.cs b/src/Mathematics.NET/LinearAlgebra/LinAlgExtensions.cs index 3bbafc3c..a0efbe13 100644 --- a/src/Mathematics.NET/LinearAlgebra/LinAlgExtensions.cs +++ b/src/Mathematics.NET/LinearAlgebra/LinAlgExtensions.cs @@ -27,8 +27,6 @@ using System.Runtime.CompilerServices; using System.Text; -using CommunityToolkit.HighPerformance; -using Mathematics.NET.Core; namespace Mathematics.NET.LinearAlgebra; diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index f2c35f91..1d528656 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -29,8 +29,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using CommunityToolkit.HighPerformance; -using Mathematics.NET.Core; using Mathematics.NET.LinearAlgebra.Abstractions; namespace Mathematics.NET.LinearAlgebra; diff --git a/src/Mathematics.NET/LinearAlgebra/Vector4.cs b/src/Mathematics.NET/LinearAlgebra/Vector4.cs index bab8c03a..6ec56da9 100644 --- a/src/Mathematics.NET/LinearAlgebra/Vector4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Vector4.cs @@ -29,7 +29,6 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using Mathematics.NET.Core; using Mathematics.NET.LinearAlgebra.Abstractions; namespace Mathematics.NET.LinearAlgebra; diff --git a/src/Mathematics.NET/Mathematics.NET.csproj b/src/Mathematics.NET/Mathematics.NET.csproj index df134626..ae0fa918 100644 --- a/src/Mathematics.NET/Mathematics.NET.csproj +++ b/src/Mathematics.NET/Mathematics.NET.csproj @@ -43,4 +43,9 @@ + + + + + diff --git a/src/Mathematics.NET/Mathematics.cs b/src/Mathematics.NET/Mathematics.cs index 11f90f32..df98c747 100644 --- a/src/Mathematics.NET/Mathematics.cs +++ b/src/Mathematics.NET/Mathematics.cs @@ -25,8 +25,6 @@ // SOFTWARE. // -using Mathematics.NET.Core; - namespace Mathematics.NET; /// Provides Mathematics.NET functionality From 28139657279790127e5492e0ec5d741ffb5a284c Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 01:38:41 -0500 Subject: [PATCH 277/293] Update LinAlg.cs - Update documentation comments --- src/Mathematics.NET/LinearAlgebra/LinAlg.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Mathematics.NET/LinearAlgebra/LinAlg.cs b/src/Mathematics.NET/LinearAlgebra/LinAlg.cs index c204e17f..351021ba 100644 --- a/src/Mathematics.NET/LinearAlgebra/LinAlg.cs +++ b/src/Mathematics.NET/LinearAlgebra/LinAlg.cs @@ -38,6 +38,22 @@ public static class LinAlg /// A matrix /// A QR decomposition method /// The eigenvalues of the given matrix + /// + /// Suppose we want to find the eigenvalues of a 2x2 matrix. We can write the following to get them: + /// + /// Span2D<ComplexNumber> matrix = new ComplexNumber[2, 2] + /// { + /// { new(1, 2), new(2, 3) }, + /// { new(1, -2), new(3, 5) } + /// } + /// var eigvals = LinAlg.EigVals(matrix, LinAlg.QRGramSchmidt); + /// + /// This method returns a span of the eigenvalues which we can use for other computations. We can also specify the number of + /// iterations as well if the values do not converge quickly enough. To display the result in the console, write + /// + /// Console.WriteLine(eigvals.ToDisplayString()); + /// + /// public static Span EigVals(Span2D matrix, QRDecompositionMethod method, int iterations = 10) where T : IComplex { From 0750d28f3e152dbe1b9736e419587bc3593bdba5 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 02:07:25 -0500 Subject: [PATCH 278/293] Create Vector3.cs --- src/Mathematics.NET/LinearAlgebra/Vector3.cs | 215 +++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 src/Mathematics.NET/LinearAlgebra/Vector3.cs diff --git a/src/Mathematics.NET/LinearAlgebra/Vector3.cs b/src/Mathematics.NET/LinearAlgebra/Vector3.cs new file mode 100644 index 00000000..80693387 --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Vector3.cs @@ -0,0 +1,215 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Mathematics.NET.LinearAlgebra.Abstractions; + +namespace Mathematics.NET.LinearAlgebra; + +/// Represents a vector with three components +/// A type that implements +[StructLayout(LayoutKind.Sequential)] +public struct Vector3 : IOneDimensionalArrayRepresentable, T> + where T : IComplex +{ + /// The first element of the vector + public T X1; + + /// The second element of the vector + public T X2; + + /// The third element of the vector + public T X3; + + public Vector3(T x1, T x2, T x3) + { + X1 = x1; + X2 = x2; + X3 = x3; + } + + // + // IArrayRepresentable & relevant interfaces + // + + public static int Components => 3; + + public static int E1Components => 3; + + // + // Indexer + // + + public T this[int index] + { + get => GetElement(this, index); + set => this = WithElement(this, index, value); + } + + // Get + + internal static T GetElement(Vector3 vector, int index) + { + if ((uint)index >= 3) + { + throw new IndexOutOfRangeException(); + } + + return GetElementUnsafe(ref vector, index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static T GetElementUnsafe(ref Vector3 vector, int index) + { + Debug.Assert(index is >= 0 and < 3); + return Unsafe.Add(ref Unsafe.As, T>(ref vector), index); + } + + // Set + + internal static Vector3 WithElement(Vector3 vector, int index, T value) + { + if ((uint)index >= 3) + { + throw new IndexOutOfRangeException(); + } + + Vector3 result = vector; + SetElementUnsafe(ref result, index, value); + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void SetElementUnsafe(ref Vector3 vector, int index, T value) + { + Debug.Assert(index is >= 0 and < 3); + Unsafe.Add(ref Unsafe.As, T>(ref vector), index) = value; + } + + // + // Operators + // + + public static Vector3 operator +(Vector3 left, Vector3 right) + { + return new( + left.X1 + right.X1, + left.X2 + right.X2, + left.X3 + right.X3); + } + + public static Vector3 operator -(Vector3 left, Vector3 right) + { + return new( + left.X1 - right.X1, + left.X2 - right.X2, + left.X3 - right.X3); + } + + public static Vector3 operator *(Vector3 left, Vector3 right) + { + return new( + left.X1 * right.X1, + left.X2 * right.X2, + left.X3 * right.X3); + } + + // + // Equality + // + + public static bool operator ==(Vector3 left, Vector3 right) + => left.X1 == right.X1 + && left.X2 == right.X2 + && left.X3 == right.X3; + + public static bool operator !=(Vector3 left, Vector3 right) + => left.X1 != right.X1 + || left.X2 != right.X2 + || left.X3 != right.X3; + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Vector3 other && Equals(other); + + public bool Equals(Vector3 value) + => X1.Equals(value.X1) + && X2.Equals(value.X2) + && X3.Equals(value.X3); + + public override readonly int GetHashCode() => HashCode.Combine(X1, X2, X3); + + // + // Formatting + // + + public string ToString(string? format, IFormatProvider? provider) + => string.Format(provider, "({0}, {1}, {2})", + X1.ToString(format, provider), + X2.ToString(format, provider), + X3.ToString(format, provider)); + + // + // Methods + // + + public static T InnerProduct(Vector3 left, Vector3 right) + => T.Conjugate(left.X1) * right.X1 + T.Conjugate(left.X2) * right.X2 + T.Conjugate(left.X3) * right.X3; + + public Real Norm() + { + Span components = stackalloc Real[3]; + + components[0] = (X1 * T.Conjugate(X1)).Re; + components[1] = (X2 * T.Conjugate(X2)).Re; + components[2] = (X3 * T.Conjugate(X3)).Re; + + Real max = components[0]; + for (int i = 1; i < 3; i++) + { + if (components[i] > max) + { + max = components[i]; + } + } + + var partialSum = Real.Zero; + var maxSquared = max * max; + partialSum += components[0] / maxSquared; + partialSum += components[1] / maxSquared; + partialSum += components[2] / maxSquared; + + return max * Real.Sqrt(partialSum); + } + + public Vector3 Normalize() + { + var norm = Norm(); + return new(X1 / norm, X2 / norm, X3 / norm); + } +} From 1637facc49aa9f9b537a422f6dfe31f600ed939e Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 02:25:24 -0500 Subject: [PATCH 279/293] Create Vector2.cs --- src/Mathematics.NET/LinearAlgebra/Vector2.cs | 172 +++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 src/Mathematics.NET/LinearAlgebra/Vector2.cs diff --git a/src/Mathematics.NET/LinearAlgebra/Vector2.cs b/src/Mathematics.NET/LinearAlgebra/Vector2.cs new file mode 100644 index 00000000..5885f51e --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Vector2.cs @@ -0,0 +1,172 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Mathematics.NET.LinearAlgebra.Abstractions; + +namespace Mathematics.NET.LinearAlgebra; + +/// Represents a vector with two components +/// A type that implements +[StructLayout(LayoutKind.Sequential)] +public struct Vector2 : IOneDimensionalArrayRepresentable, T> + where T : IComplex +{ + /// The first element of the vector + public T X1; + + /// The second element of the vector + public T X2; + + public Vector2(T x1, T x2) + { + X1 = x1; + X2 = x2; + } + + // + // IArrayRepresentable & relevant interfaces + // + + public static int Components => 2; + + public static int E1Components => 2; + + // + // Indexer + // + + public T this[int index] + { + get => GetElement(this, index); + set => this = WithElement(this, index, value); + } + + // Get + + internal static T GetElement(Vector2 vector, int index) + { + if ((uint)index >= 2) + { + throw new IndexOutOfRangeException(); + } + + return GetElementUnsafe(ref vector, index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static T GetElementUnsafe(ref Vector2 vector, int index) + { + Debug.Assert(index is >= 0 and < 2); + return Unsafe.Add(ref Unsafe.As, T>(ref vector), index); + } + + // Set + + internal static Vector2 WithElement(Vector2 vector, int index, T value) + { + if ((uint)index >= 2) + { + throw new IndexOutOfRangeException(); + } + + Vector2 result = vector; + SetElementUnsafe(ref result, index, value); + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void SetElementUnsafe(ref Vector2 vector, int index, T value) + { + Debug.Assert(index is >= 0 and < 2); + Unsafe.Add(ref Unsafe.As, T>(ref vector), index) = value; + } + + // + // Operators + // + + public static Vector2 operator +(Vector2 left, Vector2 right) + => new(left.X1 + right.X1, left.X2 + right.X2); + + public static Vector2 operator -(Vector2 left, Vector2 right) + => new(left.X1 - right.X1, left.X2 - right.X2); + + public static Vector2 operator *(Vector2 left, Vector2 right) + => new(left.X1 * right.X1, left.X2 * right.X2); + + // + // Equality + // + + public static bool operator ==(Vector2 left, Vector2 right) + => left.X1 == right.X1 && left.X2 == right.X2; + + public static bool operator !=(Vector2 left, Vector2 right) + => left.X1 != right.X1 || left.X2 != right.X2; + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Vector2 other && Equals(other); + + public bool Equals(Vector2 value) + => X1.Equals(value.X1) && X2.Equals(value.X2); + + public override readonly int GetHashCode() => HashCode.Combine(X1, X2); + + // + // Formatting + // + + public string ToString(string? format, IFormatProvider? provider) + => string.Format(provider, "({0}, {1})", X1.ToString(format, provider), X2.ToString(format, provider)); + + // + // Methods + // + + public static T InnerProduct(Vector2 left, Vector2 right) + => T.Conjugate(left.X1) * right.X1 + T.Conjugate(left.X2) * right.X2; + + public Real Norm() + { + var x0 = (X1 * T.Conjugate(X1)).Re; + var x1 = (X2 * T.Conjugate(X2)).Re; + + Real max = Real.Max(x0, x1); + var maxSquared = max * max; + + return max * Real.Sqrt(x0 / maxSquared + x1 / maxSquared); + } + + public Vector2 Normalize() + { + var norm = Norm(); + return new(X1 / norm, X2 / norm); + } +} From f7134262b269843cc31593218a724646454130f2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 02:39:10 -0500 Subject: [PATCH 280/293] Update Matrix4x4.cs - Add constants --- .../LinearAlgebra/Matrix4x4.cs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index 1d528656..b10fe38d 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -41,6 +41,10 @@ public struct Matrix4x4 ISquareMatrix, T> where T : IComplex { + public const int Components = 16; + public const int E1Components = 4; + public const int E2Components = 4; + public static readonly Matrix4x4 NaM = CreateDiagonal(T.NaN, T.NaN, T.NaN, T.NaN); public T E11; @@ -90,11 +94,14 @@ public Matrix4x4( E44 = e44; } - public static int Components => 16; - - public static int E1Components => 4; + // + // Constants + // - public static int E2Components => 4; + static int IArrayRepresentable.Components => Components; + static int ITwoDimensionalArrayRepresentable, T>.E1Components => E1Components; + static int ITwoDimensionalArrayRepresentable, T>.E2Components => E2Components; + static Matrix4x4 ISquareMatrix, T>.NaM => NaM; // // Indexer @@ -125,12 +132,6 @@ public Matrix4x4( } } - // - // Constants - // - - static Matrix4x4 ISquareMatrix, T>.NaM => NaM; - // // Operators // From 4af980f2c479d87b5799fc062bd0544ed736e185 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 02:42:02 -0500 Subject: [PATCH 281/293] Update Matrix4x4.cs - Use IndexOutOfRangeException --- src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index b10fe38d..d3d1621d 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -113,7 +113,7 @@ public Matrix4x4( { if ((uint)row >= 4) { - throw new ArgumentOutOfRangeException(); + throw new IndexOutOfRangeException(); } ref Vector4 vrow = ref Unsafe.Add(ref Unsafe.As>(ref E11), row); From 719d181310496a9988a5dc82a814ec7da18c5854 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 02:56:05 -0500 Subject: [PATCH 282/293] Fix IsNaM --- src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index d3d1621d..6f15f9bd 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -381,7 +381,7 @@ public Matrix4x4 Inverse() } public static bool IsNaM(Matrix4x4 matrix) - => matrix.E11 == T.NaN && matrix.E22 == T.NaN && matrix.E33 == T.NaN && matrix.E44 == T.NaN; + => T.IsNaN(matrix.E11) && T.IsNaN(matrix.E22) && T.IsNaN(matrix.E33) && T.IsNaN(matrix.E44); public T Trace() => E11 + E22 + E33 + E44; From 7dbeebfb9476ca28eacede6e3f8bca03784abba9 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 04:04:32 -0500 Subject: [PATCH 283/293] Update Matrix4x4.cs - Add and remove new empty lines --- src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index 6f15f9bd..e77ac400 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -334,13 +334,12 @@ public Matrix4x4 Inverse() T a14 = -(e * jo_kn - f * io_km + g * in_jm); T det = a * a11 + b * a12 + c * a13 + d * a14; - if (det == T.Zero) { return NaM; } - T invDet = T.One / det; + Matrix4x4 result; result.E11 = a11 * invDet; From 42d026eb142d9a83a7f02c57681cc54f72011cf1 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 04:44:55 -0500 Subject: [PATCH 284/293] Create Matrix3x3.cs --- .../LinearAlgebra/Matrix3x3.cs | 325 ++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 src/Mathematics.NET/LinearAlgebra/Matrix3x3.cs diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix3x3.cs b/src/Mathematics.NET/LinearAlgebra/Matrix3x3.cs new file mode 100644 index 00000000..58a4c455 --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Matrix3x3.cs @@ -0,0 +1,325 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text; +using Mathematics.NET.LinearAlgebra.Abstractions; + +namespace Mathematics.NET.LinearAlgebra; + +/// Represents a 3x3 matrix +/// A type that implements +public struct Matrix3x3 + : ITwoDimensionalArrayRepresentable, T>, + ISquareMatrix, T> + where T : IComplex +{ + public const int Components = 9; + public const int E1Components = 3; + public const int E2Components = 3; + + public static readonly Matrix3x3 NaM = CreateDiagonal(T.NaN, T.NaN, T.NaN); + + public T E11; + public T E12; + public T E13; + + public T E21; + public T E22; + public T E23; + + public T E31; + public T E32; + public T E33; + + public Matrix3x3( + T e11, T e12, T e13, + T e21, T e22, T e23, + T e31, T e32, T e33) + { + E11 = e11; + E12 = e12; + E13 = e13; + + E21 = e21; + E22 = e22; + E23 = e23; + + E31 = e31; + E32 = e32; + E33 = e33; + } + + // + // Constants + // + + static int IArrayRepresentable.Components => Components; + static int ITwoDimensionalArrayRepresentable, T>.E1Components => E1Components; + static int ITwoDimensionalArrayRepresentable, T>.E2Components => E2Components; + static Matrix3x3 ISquareMatrix, T>.NaM => NaM; + + // + // Indexer + // + + public T this[int row, int column] + { + get + { + if ((uint)row >= 3) + { + throw new IndexOutOfRangeException(); + } + + ref Vector3 vrow = ref Unsafe.Add(ref Unsafe.As>(ref E11), row); + return vrow[column]; + } + set + { + if ((uint)row >= 3) + { + throw new IndexOutOfRangeException(); + } + + ref Vector3 vrow = ref Unsafe.Add(ref Unsafe.As>(ref E11), row); + var temp = Vector3.WithElement(vrow, column, value); + vrow = temp; + } + } + + // + // Operators + // + + public static Matrix3x3 operator +(Matrix3x3 a, Matrix3x3 b) + { + return new( + a.E11 + b.E11, a.E12 + b.E12, a.E13 + b.E13, + a.E21 + b.E21, a.E22 + b.E22, a.E23 + b.E23, + a.E31 + b.E31, a.E32 + b.E32, a.E33 + b.E33); + } + + public static Matrix3x3 operator -(Matrix3x3 a, Matrix3x3 b) + { + return new( + a.E11 - b.E11, a.E12 - b.E12, a.E13 - b.E13, + a.E21 - b.E21, a.E22 - b.E22, a.E23 - b.E23, + a.E31 - b.E31, a.E32 - b.E32, a.E33 - b.E33); + } + + public static Matrix3x3 operator *(Matrix3x3 a, Matrix3x3 b) + { + Unsafe.SkipInit(out Matrix3x3 result); + + result.E11 = a.E11 * b.E11 + a.E12 * b.E21 + a.E13 * b.E31; + result.E12 = a.E11 * b.E12 + a.E12 * b.E22 + a.E13 * b.E32; + result.E13 = a.E11 * b.E13 + a.E12 * b.E23 + a.E13 * b.E33; + + result.E21 = a.E21 * b.E11 + a.E22 * b.E21 + a.E23 * b.E31; + result.E22 = a.E21 * b.E12 + a.E22 * b.E22 + a.E23 * b.E32; + result.E23 = a.E21 * b.E13 + a.E22 * b.E23 + a.E23 * b.E33; + + result.E31 = a.E31 * b.E11 + a.E32 * b.E21 + a.E33 * b.E31; + result.E32 = a.E31 * b.E12 + a.E32 * b.E22 + a.E33 * b.E32; + result.E33 = a.E31 * b.E13 + a.E32 * b.E23 + a.E33 * b.E33; + + return result; + } + + // + // Equality + // + + public static bool operator ==(Matrix3x3 a, Matrix3x3 b) + { + return a.E11 == b.E11 && a.E22 == b.E22 && a.E33 == b.E33 // Check diagonal first + && a.E12 == b.E12 && a.E13 == b.E13 + && a.E21 == b.E21 && a.E23 == b.E23 + && a.E31 == b.E31 && a.E32 == b.E32; + } + + public static bool operator !=(Matrix3x3 a, Matrix3x3 b) + { + return a.E11 != b.E11 || a.E22 != b.E22 || a.E33 != b.E33 // Check diagonal first + || a.E12 != b.E12 || a.E13 != b.E13 + || a.E21 != b.E21 || a.E23 != b.E23 + || a.E31 != b.E31 || a.E32 != b.E32; + } + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Matrix3x3 other && Equals(other); + + public bool Equals(Matrix3x3 value) + { + return E11.Equals(value.E11) && E22.Equals(value.E22) && E33.Equals(value.E33) // Check diagonal first + && E12.Equals(value.E12) && E13.Equals(value.E13) + && E21.Equals(value.E21) && E23.Equals(value.E23) + && E31.Equals(value.E31) && E32.Equals(value.E32); + } + + public override readonly int GetHashCode() + { + HashCode hash = default; + + hash.Add(E11); + hash.Add(E12); + hash.Add(E13); + + hash.Add(E21); + hash.Add(E22); + hash.Add(E23); + + hash.Add(E31); + hash.Add(E32); + hash.Add(E33); + + return hash.ToHashCode(); + } + + // + // Formatting + // + + public string ToString(string? format, IFormatProvider? provider) + { + Span2D strings = new string[3, 3]; + var maxElementLength = 0; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + var s = this[i, j].ToString(format, provider); + strings[i, j] = s; + var length = s.Length + 2; + if (maxElementLength < length) + { + maxElementLength = length; + } + } + } + + StringBuilder builder = new(); + var newlineChars = Environment.NewLine.ToCharArray(); + builder.Append('['); + for (int i = 0; i < 3; i++) + { + builder.Append(i != 0 ? " [" : "["); + for (int j = 0; j < 3; j++) + { + string value = j != 2 ? $"{strings[i, j]}, " : strings[i, j]; + builder.Append(value.PadRight(maxElementLength)); + } + LinAlgExtensions.CloseGroup(builder, newlineChars); + } + LinAlgExtensions.CloseGroup(builder, newlineChars, true); + return string.Format(provider, builder.ToString()); + } + + // + // Methods + // + + public static Matrix3x3 CreateDiagonal(T e11, T e22, T e33) + { + return new( + e11, T.Zero, T.Zero, + T.Zero, e22, T.Zero, + T.Zero, T.Zero, e33); + } + + public readonly T Determinant() + { + T a = E11, b = E12, c = E13; + T d = E21, e = E22, f = E23; + T g = E31, h = E32, i = E33; + + T ei_fh = e * i - f * h; + T di_fg = d * i - f * g; + T dh_eg = d * h - e * g; + + return a * ei_fh - b * di_fg + c * dh_eg; + } + + public Matrix3x3 Inverse() + { + T a = E11, b = E12, c = E13; + T d = E21, e = E22, f = E23; + T g = E31, h = E32, i = E33; + + T ei_fh = e * i - f * h; + T di_fg = d * i - f * g; + T dh_eg = d * h - e * g; + + T det = a * ei_fh - b * di_fg + c * dh_eg; + if (det == T.Zero) + { + return NaM; + } + var invDet = T.One / det; + + Matrix3x3 result; + + result.E11 = ei_fh * invDet; + result.E21 = -di_fg * invDet; + result.E31 = dh_eg * invDet; + + T bi_ch = b * i - c * h; + T ai_cg = a * i - c * g; + T ah_bg = a * h - b * g; + + result.E12 = -bi_ch * invDet; + result.E22 = ai_cg * invDet; + result.E32 = -ah_bg * invDet; + + T bf_ce = b * f - c * e; + T af_cd = a * f - c * d; + T ae_bd = a * e - b * d; + + result.E13 = bf_ce * invDet; + result.E23 = -af_cd * invDet; + result.E33 = ae_bd * invDet; + + return result; + } + + public static bool IsNaM(Matrix3x3 matrix) + => T.IsNaN(matrix.E11) && T.IsNaN(matrix.E22) && T.IsNaN(matrix.E33); + + public T Trace() => E11 + E22 + E33; + + public Matrix3x3 Transpose() + { + Unsafe.SkipInit(out Matrix3x3 result); + + result.E11 = E11; result.E12 = E21; result.E13 = E31; + result.E21 = E12; result.E22 = E22; result.E23 = E32; + result.E31 = E13; result.E32 = E23; result.E33 = E33; + + return result; + } +} From 4d6265c12c20a7e9d331f23d36d729688cead031 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 05:09:49 -0500 Subject: [PATCH 285/293] Create Matrix2x2.cs --- .../LinearAlgebra/Matrix2x2.cs | 218 ++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 src/Mathematics.NET/LinearAlgebra/Matrix2x2.cs diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix2x2.cs b/src/Mathematics.NET/LinearAlgebra/Matrix2x2.cs new file mode 100644 index 00000000..2e2b4af6 --- /dev/null +++ b/src/Mathematics.NET/LinearAlgebra/Matrix2x2.cs @@ -0,0 +1,218 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text; +using Mathematics.NET.LinearAlgebra.Abstractions; + +namespace Mathematics.NET.LinearAlgebra; + +/// Represents a 2x2 matrix +/// A type that implements +public struct Matrix2x2 + : ITwoDimensionalArrayRepresentable, T>, + ISquareMatrix, T> + where T : IComplex +{ + public const int Components = 4; + public const int E1Components = 2; + public const int E2Components = 2; + + public static readonly Matrix2x2 NaM = CreateDiagonal(T.NaN, T.NaN); + + public T E11; + public T E12; + + public T E21; + public T E22; + + public Matrix2x2(T e11, T e12, T e21, T e22) + { + E11 = e11; + E12 = e12; + + E21 = e21; + E22 = e22; + } + + // + // Constants + // + + static int IArrayRepresentable.Components => Components; + static int ITwoDimensionalArrayRepresentable, T>.E1Components => E1Components; + static int ITwoDimensionalArrayRepresentable, T>.E2Components => E2Components; + static Matrix2x2 ISquareMatrix, T>.NaM => NaM; + + // + // Indexer + // + + public T this[int row, int column] + { + get + { + if ((uint)row >= 2) + { + throw new IndexOutOfRangeException(); + } + + ref Vector2 vrow = ref Unsafe.Add(ref Unsafe.As>(ref E11), row); + return vrow[column]; + } + set + { + if ((uint)row >= 2) + { + throw new IndexOutOfRangeException(); + } + + ref Vector2 vrow = ref Unsafe.Add(ref Unsafe.As>(ref E11), row); + var temp = Vector2.WithElement(vrow, column, value); + vrow = temp; + } + } + + + // + // Operators + // + + public static Matrix2x2 operator +(Matrix2x2 a, Matrix2x2 b) + { + return new( + a.E11 + b.E11, a.E12 + b.E12, + a.E21 + b.E21, a.E22 + b.E22); + } + + public static Matrix2x2 operator -(Matrix2x2 a, Matrix2x2 b) + { + return new( + a.E11 - b.E11, a.E12 - b.E12, + a.E21 - b.E21, a.E22 - b.E22); + } + + public static Matrix2x2 operator *(Matrix2x2 a, Matrix2x2 b) + { + return new( + a.E11 * b.E11 + a.E12 * b.E21, a.E11 * b.E12 + a.E12 * b.E22, + a.E21 * b.E11 + a.E22 * b.E21, a.E21 * b.E12 + a.E22 * b.E22); + } + + // + // Equality + // + + public static bool operator ==(Matrix2x2 a, Matrix2x2 b) + { + return a.E11 == b.E11 && a.E22 == b.E22 // Check diagonal first + && a.E12 == b.E12 + && a.E21 == b.E21; + } + + public static bool operator !=(Matrix2x2 a, Matrix2x2 b) + { + return a.E11 != b.E11 || a.E22 != b.E22 // Check diagonal first + || a.E12 != b.E12 + || a.E21 != b.E21; + } + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Matrix2x2 other && Equals(other); + + public bool Equals(Matrix2x2 value) + { + return E11.Equals(value.E11) && E22.Equals(value.E22) // Check diagonal first + && E12.Equals(value.E12) + && E21.Equals(value.E21); + } + + public override readonly int GetHashCode() => HashCode.Combine(E11, E12, E21, E22); + + // + // Formatting + // + + public string ToString(string? format, IFormatProvider? provider) + { + Span2D strings = new string[2, 2]; + var maxElementLength = 0; + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + var s = this[i, j].ToString(format, provider); + strings[i, j] = s; + var length = s.Length + 2; + if (maxElementLength < length) + { + maxElementLength = length; + } + } + } + + StringBuilder builder = new(); + var newlineChars = Environment.NewLine.ToCharArray(); + builder.Append('['); + for (int i = 0; i < 2; i++) + { + builder.Append(i != 0 ? " [" : "["); + for (int j = 0; j < 2; j++) + { + string value = j != 1 ? $"{strings[i, j]}, " : strings[i, j]; + builder.Append(value.PadRight(maxElementLength)); + } + LinAlgExtensions.CloseGroup(builder, newlineChars); + } + LinAlgExtensions.CloseGroup(builder, newlineChars, true); + return string.Format(provider, builder.ToString()); + } + + public static Matrix2x2 CreateDiagonal(T e11, T e22) + => new(e11, T.Zero, T.Zero, e22); + + public readonly T Determinant() => E11 * E22 - E12 * E21; + + public Matrix2x2 Inverse() + { + var det = Determinant(); + if (det == T.Zero) + { + return NaM; + } + T invDet = T.One / det; + + return new(E22 * invDet, -E12 * invDet, -E21 * invDet, E11 * invDet); + } + + public static bool IsNaM(Matrix2x2 matrix) + => T.IsNaN(matrix.E11) && T.IsNaN(matrix.E22); + + public T Trace() => E11 + E22; + + public Matrix2x2 Transpose() => new(E11, E21, E12, E22); +} From 7ad9e721c9fd0a9ada886f1a17489109663c9a40 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 05:13:59 -0500 Subject: [PATCH 286/293] Update Matrix4x4.cs - Update Transpose method --- src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs index e77ac400..19ab2988 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix4x4.cs @@ -386,13 +386,10 @@ public static bool IsNaM(Matrix4x4 matrix) public Matrix4x4 Transpose() { - Unsafe.SkipInit(out Matrix4x4 result); - - result.E11 = E11; result.E12 = E21; result.E13 = E31; result.E14 = E41; - result.E21 = E12; result.E22 = E22; result.E23 = E32; result.E24 = E42; - result.E31 = E13; result.E32 = E23; result.E33 = E33; result.E34 = E43; - result.E41 = E14; result.E42 = E24; result.E43 = E34; result.E44 = E44; - - return result; + return new( + E11, E21, E31, E41, + E12, E22, E32, E42, + E13, E23, E33, E43, + E14, E24, E34, E44); } } From d7304f2dab07b4b41243453a0159d00994d013db Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 05:15:00 -0500 Subject: [PATCH 287/293] Update Matrix3x3.cs - Update Transpose method --- src/Mathematics.NET/LinearAlgebra/Matrix3x3.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Mathematics.NET/LinearAlgebra/Matrix3x3.cs b/src/Mathematics.NET/LinearAlgebra/Matrix3x3.cs index 58a4c455..d6ad369d 100644 --- a/src/Mathematics.NET/LinearAlgebra/Matrix3x3.cs +++ b/src/Mathematics.NET/LinearAlgebra/Matrix3x3.cs @@ -314,12 +314,9 @@ public static bool IsNaM(Matrix3x3 matrix) public Matrix3x3 Transpose() { - Unsafe.SkipInit(out Matrix3x3 result); - - result.E11 = E11; result.E12 = E21; result.E13 = E31; - result.E21 = E12; result.E22 = E22; result.E23 = E32; - result.E31 = E13; result.E32 = E23; result.E33 = E33; - - return result; + return new( + E11, E21, E31, + E12, E22, E32, + E13, E23, E33); } } From 383885bbc667e7b66fa4600f12a94b43e9e207d2 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 21:31:02 -0500 Subject: [PATCH 288/293] Update Abs method - Abs method will now return a real number - Define Abs method in IRational that hides the IComplex one --- src/Mathematics.NET/Core/IComplex.cs | 2 +- src/Mathematics.NET/Core/IRational.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/IComplex.cs b/src/Mathematics.NET/Core/IComplex.cs index eb13b8d9..1ac7c687 100644 --- a/src/Mathematics.NET/Core/IComplex.cs +++ b/src/Mathematics.NET/Core/IComplex.cs @@ -72,7 +72,7 @@ public interface IComplex /// Compute the absolute value of a number /// A complex number /// The absolute value - static abstract T Abs(T z); + static virtual Real Abs(T z) => Real.Hypot(z.Re, z.Im); /// Compute the complex conjugate of a number /// A complex number diff --git a/src/Mathematics.NET/Core/IRational.cs b/src/Mathematics.NET/Core/IRational.cs index 5341fed2..2a3ec991 100644 --- a/src/Mathematics.NET/Core/IRational.cs +++ b/src/Mathematics.NET/Core/IRational.cs @@ -42,6 +42,11 @@ public interface IRational : IReal /// Get the denominator of the rational number U Den { get; } + /// Compute the absolute value of a number + /// A rational number + /// The absolute value + static new abstract T Abs(T x); + /// Reduce a rational number /// The value to reduce /// A reduced fraction if the number was reducible; otherwise, itself From d40b35e9fb0a3147947771b53bd304ab8db1921b Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Tue, 17 Oct 2023 22:57:53 -0500 Subject: [PATCH 289/293] Update Precision.cs - Add comparison methods for numbers that implement IComplex - Add documentation comments --- src/Mathematics.NET/Core/Precision.cs | 62 ++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/src/Mathematics.NET/Core/Precision.cs b/src/Mathematics.NET/Core/Precision.cs index 67c1df85..f60b70e0 100644 --- a/src/Mathematics.NET/Core/Precision.cs +++ b/src/Mathematics.NET/Core/Precision.cs @@ -29,7 +29,11 @@ namespace Mathematics.NET.Core; -/// A class for working with floating-point numbers +/// +/// A class for working with floating-point numbers. +/// +/// The methods for computing equalities and inequalies come from The Art of Computer Programming: Seminumerical Algorithms, section 4.2.2, Accuracy of Floating Point Arithmetic by Donald Knuth. +/// public static class Precision { /// Machine epsilon for single-precision floating-point numbers according to the formal definition @@ -54,18 +58,74 @@ public static class Precision /// This is equivalent to public const double DblMinPositive = 4.94065645841246544e-324; + // + // Equalities and Inequalities + // + + /// Check if two values are approximately equal within a specified threshold + /// A type that implements + /// The left value + /// The right value + /// A threshold value + /// if the values are approximately equal; otherwise, public static bool AreApproximatelyEqual(T left, T right, T epsilon) where T : IBinaryFloatingPointIeee754 => T.Abs(left - right) <= epsilon * T.Max(T.Abs(left), T.Abs(right)); + /// + /// Check if two values are approximately equal within a specified threshold $ \epsilon $. + /// + /// If the values are complex, the threshold represents a disk of radius $ \epsilon $ in which the two values must reside. + /// + /// A type that implements + /// The left value + /// The right value + /// The radius of threshold disk + /// if the values are approximately equal; otherwise, + public static bool AreApproximatelyEqual(T left, T right, Real epsilon) + where T : IComplex + => T.Abs(left - right) <= epsilon * Real.Max(T.Abs(left), T.Abs(right)); + + /// Check if two values are essentially equal within a specified threshold + /// A type that implements + /// The left value + /// The right value + /// A threshold value + /// if the values are essentially equal; otherwise, public static bool AreEssentiallyEqual(T left, T right, T epsilon) where T : IBinaryFloatingPointIeee754 => T.Abs(left - right) <= epsilon * T.Min(T.Abs(left), T.Abs(right)); + /// + /// Check if two values are essentially equal within a specified threshold $ \epsilon $. + /// + /// If the values are complex, the threshold represents a disk of radius $ \epsilon $ in which the two values must reside. + /// + /// A type that implements + /// The left value + /// The right value + /// The radius of threshold disk + /// if the values are essentially equal; otherwise, + public static bool AreEssentiallyEqual(T left, T right, Real epsilon) + where T : IComplex + => T.Abs(left - right) <= epsilon * Real.Min(T.Abs(left), T.Abs(right)); + + /// Check if this value is definitely greater than a specified value + /// A type that implements + /// This number + /// A value to which to compare this number + /// A threshold value + /// if this number is definitely greater than the specified value; otherwise, public static bool IsDefinitelyGreaterThan(this T number, T value, T epsilon) where T : IBinaryFloatingPointIeee754 => number - value > epsilon * T.Max(T.Abs(number), T.Abs(value)); + /// Check if this value is definitely less than a specified value + /// A type that implements + /// This number + /// A value to which to compare this number + /// A threshold value + /// if this number is definitely less than the specified value; otherwise, public static bool IsDefinitelyLessThan(this T number, T value, T epsilon) where T : IBinaryFloatingPointIeee754 => value - number > epsilon * T.Max(T.Abs(number), T.Abs(value)); From 2932c8e0de200a7e7fd6003e1811997a4c804445 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 18 Oct 2023 00:13:43 -0500 Subject: [PATCH 290/293] Create Assert.cs - Create a class with custom asserts --- tests/Mathematics.NET.Tests/Assert.cs | 81 +++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 tests/Mathematics.NET.Tests/Assert.cs diff --git a/tests/Mathematics.NET.Tests/Assert.cs b/tests/Mathematics.NET.Tests/Assert.cs new file mode 100644 index 00000000..e81483eb --- /dev/null +++ b/tests/Mathematics.NET.Tests/Assert.cs @@ -0,0 +1,81 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using CommunityToolkit.HighPerformance; + +namespace Mathematics.NET.Tests; + +public sealed class Assert + where T : IComplex +{ + public static void AreApproximatelyEqual(T expected, T actual, Real delta) + { + if (T.IsNaN(expected) && T.IsNaN(actual) || T.IsInfinity(expected) && T.IsInfinity(actual)) + { + return; + } + + if (!Precision.AreApproximatelyEqual(expected, actual, delta)) + { + Assert.Fail($$""" + Actual value does not fall within the specifed margin of error, {{delta}}: + + Expected: {{expected}} + Actual: {{actual}} + """); + } + } + + public static void ElementsAreApproximatelyEqual(Span2D expected, Span2D actual, Real delta) + { + if (expected.Height != actual.Height || expected.Width != actual.Width) + { + Assert.Fail($"Dimensions of the actual matrix, [{actual.Height}, {actual.Width}], does not match the dimensions of the expected matrix, [{expected.Height}, {expected.Width}]"); + } + + for (int i = 0; i < expected.Height; i++) + { + for (int j = 0; j < expected.Width; j++) + { + if (T.IsNaN(expected[i, j]) && T.IsNaN(actual[i, j]) || T.IsInfinity(expected[i, j]) && T.IsInfinity(actual[i, j])) + { + continue; + } + + if (!Precision.AreApproximatelyEqual(expected[i, j], actual[i, j], delta)) + { + Assert.Fail($$""" + Actual value at row {{i}} and column {{j}} does not fall within the specifed margin of error, {{delta}}: + + Expected: {{expected[i, j]}} + Actual: {{actual[i, j]}} + """); + } + } + } + } +} From e6ce0e1b6902c64610f52fe4830f6a4b28102fab Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 18 Oct 2023 00:22:55 -0500 Subject: [PATCH 291/293] Create LinAlgTests.cs - Add test for QR decomposition --- .../LinearAlgebra/LinAlgTests.cs | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 tests/Mathematics.NET.Tests/LinearAlgebra/LinAlgTests.cs diff --git a/tests/Mathematics.NET.Tests/LinearAlgebra/LinAlgTests.cs b/tests/Mathematics.NET.Tests/LinearAlgebra/LinAlgTests.cs new file mode 100644 index 00000000..6cf7d452 --- /dev/null +++ b/tests/Mathematics.NET.Tests/LinearAlgebra/LinAlgTests.cs @@ -0,0 +1,86 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using CommunityToolkit.HighPerformance; +using Mathematics.NET.LinearAlgebra; + +namespace Mathematics.NET.Tests.LinearAlgebra; + +[TestClass] +[TestCategory("Linear Algebra")] +public sealed class LinAlgTests +{ + // Inputs + + public static IEnumerable GetComplexInputs() + { + yield return new[] + { + new ComplexNumber[2, 2] + { + { new(1, 2), new(2, 3) }, + { new(1, -2), new(3, 5) } + } + }; + } + + public static IEnumerable GetRealInputs() + { + yield return new[] + { + new Real[3, 3] + { + { -1, 2.424, 3 }, + { 4, 5, 6.74241 }, + { 7, 8, 9.3 } + } + }; + } + + // Tests + + [TestMethod] + [DynamicData(nameof(GetComplexInputs), DynamicDataSourceType.Method)] + public void QRGramSchmidt_MatrixOfComplex_ReturnsQRDecompositionOfMatrix(ComplexNumber[,] matrix) + => QRGramSchmidt_Helper_MatrixOfGeneric_ReturnsQRDecompositionOfMatrix(matrix); + + [TestMethod] + [DynamicData(nameof(GetRealInputs), DynamicDataSourceType.Method)] + public void QRGramSchmidt_MatrixOfReal_ReturnsQRDecompositionOfMatrix(Real[,] matrix) + => QRGramSchmidt_Helper_MatrixOfGeneric_ReturnsQRDecompositionOfMatrix(matrix); + + public void QRGramSchmidt_Helper_MatrixOfGeneric_ReturnsQRDecompositionOfMatrix(T[,] matrix) + where T : IComplex + { + var expected = matrix.AsSpan2D(); + LinAlg.QRGramSchmidt(expected, out var Q, out var R); + + var actual = LinAlg.MatMul(Q, R); + + Assert.ElementsAreApproximatelyEqual(expected, actual, 1e-15); + } +} From dd796c14de9f3c897137c81ec4637d93f5987202 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 18 Oct 2023 07:02:45 -0500 Subject: [PATCH 292/293] Add method for multiplying matrices by scalars - Add method for multiplying matrices by scalars in parallel --- .../ParallelActions/MultiplyByScalarAction.cs | 47 +++++++++++++++++++ src/Mathematics.NET/LinearAlgebra/LinAlg.cs | 11 +++++ 2 files changed, 58 insertions(+) create mode 100644 src/Mathematics.NET/Core/ParallelActions/MultiplyByScalarAction.cs diff --git a/src/Mathematics.NET/Core/ParallelActions/MultiplyByScalarAction.cs b/src/Mathematics.NET/Core/ParallelActions/MultiplyByScalarAction.cs new file mode 100644 index 00000000..b0c7b9c7 --- /dev/null +++ b/src/Mathematics.NET/Core/ParallelActions/MultiplyByScalarAction.cs @@ -0,0 +1,47 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using System.Runtime.CompilerServices; +using CommunityToolkit.HighPerformance.Helpers; + +namespace Mathematics.NET.Core.ParallelActions; + +/// An action for multiplying items by a scalar +/// A type that implements +public readonly struct MultiplyByScalarAction : IRefAction + where T : IComplex +{ + private readonly T _factor; + + public MultiplyByScalarAction(T factor) + { + _factor = factor; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Invoke(ref T item) => item *= _factor; +} diff --git a/src/Mathematics.NET/LinearAlgebra/LinAlg.cs b/src/Mathematics.NET/LinearAlgebra/LinAlg.cs index 351021ba..8a917d6b 100644 --- a/src/Mathematics.NET/LinearAlgebra/LinAlg.cs +++ b/src/Mathematics.NET/LinearAlgebra/LinAlg.cs @@ -27,6 +27,8 @@ using System.Runtime.CompilerServices; using CommunityToolkit.HighPerformance.Enumerables; +using CommunityToolkit.HighPerformance.Helpers; +using Mathematics.NET.Core.ParallelActions; namespace Mathematics.NET.LinearAlgebra; @@ -102,6 +104,15 @@ public static Span2D MatMul(Span2D left, Span2D right) return result; } + /// Multiply a matrix by a scalar in parallel + /// A type that implements + /// A scalar + /// A matrix + /// This process overwrites the original matrix. + public static void MatMulByScalarParallel(T scalar, Memory2D matrix) + where T : IComplex + => ParallelHelper.ForEach(matrix, new MultiplyByScalarAction(scalar)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Real Norm(RefEnumerable vector) where T : IComplex From 83033b92a228d28575b9df297e43872c59053a94 Mon Sep 17 00:00:00 2001 From: Hamlet Tanyavong <34531738+HamletTanyavong@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:56:57 -0500 Subject: [PATCH 293/293] Add benchmarks - Add benchmark for multiplying matrices by scalars in parallel - Update version --- src/Mathematics.NET/Mathematics.NET.csproj | 2 +- .../MatrixMultiplyByScalarBenchmarks.cs | 81 +++++++++++++++++++ tests/Mathematics.NET.Benchmarks/Program.cs | 1 + 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tests/Mathematics.NET.Benchmarks/LinearAlgebra/MatrixMultiplyByScalarBenchmarks.cs diff --git a/src/Mathematics.NET/Mathematics.NET.csproj b/src/Mathematics.NET/Mathematics.NET.csproj index ae0fa918..7dcc178b 100644 --- a/src/Mathematics.NET/Mathematics.NET.csproj +++ b/src/Mathematics.NET/Mathematics.NET.csproj @@ -7,7 +7,7 @@ enable x64 Mathematics.NET - 0.1.0-alpha.1 + 0.1.0-alpha.2 Hamlet Tanyavong Mathematics.NET is a C# class library that provides tools for solving mathematical problems. mathematics; math; maths diff --git a/tests/Mathematics.NET.Benchmarks/LinearAlgebra/MatrixMultiplyByScalarBenchmarks.cs b/tests/Mathematics.NET.Benchmarks/LinearAlgebra/MatrixMultiplyByScalarBenchmarks.cs new file mode 100644 index 00000000..f53bd4ad --- /dev/null +++ b/tests/Mathematics.NET.Benchmarks/LinearAlgebra/MatrixMultiplyByScalarBenchmarks.cs @@ -0,0 +1,81 @@ +// +// Mathematics.NET +// https://github.com/HamletTanyavong/Mathematics.NET +// +// MIT License +// +// Copyright (c) 2023 Hamlet Tanyavong +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +using CommunityToolkit.HighPerformance; +using CommunityToolkit.HighPerformance.Helpers; +using Mathematics.NET.Core.ParallelActions; + +namespace Mathematics.NET.Benchmarks.LinearAlgebra; + +[MemoryDiagnoser] +[RankColumn] +[Orderer(SummaryOrderPolicy.FastestToSlowest)] +public class MatrixMultiplyByScalarBenchmarks +{ + public int Rows { get; set; } + public int Cols { get; set; } + public required ComplexNumber[,] MatrixOne { get; set; } + public required ComplexNumber[,] MatrixTwo { get; set; } + + [GlobalSetup] + public void GlobalSetup() + { + Rows = 100; + Cols = 100; + + MatrixOne = new ComplexNumber[Rows, Cols]; + + for (int i = 0; i < Rows; i++) + { + for (int j = 0; j < Cols; j++) + { + MatrixOne[i, j] = new(Random.Shared.NextDouble(), Random.Shared.NextDouble()); + MatrixTwo[i, j] = new(Random.Shared.NextDouble(), Random.Shared.NextDouble()); + } + } + } + + [Benchmark(Baseline = true)] + public void MultiplyByScalarNaive() + { + var matrixAsSpan = MatrixOne.AsMemory2D().Span; + for (int i = 0; i < Rows; i++) + { + for (int j = 0; j < Cols; j++) + { + matrixAsSpan[i, j] *= Real.Pi; + } + } + } + + [Benchmark] + public void MultiplyByScalarParallel() + { + Memory2D matrixAsMemory = MatrixTwo; + ParallelHelper.ForEach(matrixAsMemory, new MultiplyByScalarAction(Real.Pi)); + } +} diff --git a/tests/Mathematics.NET.Benchmarks/Program.cs b/tests/Mathematics.NET.Benchmarks/Program.cs index 81b4b18e..eace8a1c 100644 --- a/tests/Mathematics.NET.Benchmarks/Program.cs +++ b/tests/Mathematics.NET.Benchmarks/Program.cs @@ -36,6 +36,7 @@ { typeof(ComplexDivisionBenchmarks), typeof(ComplexTrigonometryBenchmarks), + typeof(MatrixMultiplyByScalarBenchmarks), typeof(NormBenchmarks), typeof(RealvsDouble), typeof(SystemComplexAbsVsComplexAbsBenchmarks)