├── .github └── workflows │ ├── deploy.yml │ └── library unit test.yml ├── .gitignore ├── .idea ├── .gitignore ├── kotlinc.xml ├── misc.xml └── vcs.xml ├── LICENSE ├── README.md ├── build.gradle.kts ├── docs ├── images │ ├── logo.png │ └── telegram.svg └── languages │ └── README-en.md ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── build.gradle.kts └── src │ ├── androidMain │ └── kotlin │ │ └── more │ │ └── math │ │ ├── native │ │ └── model │ │ │ └── NativeProvider.android.kt │ │ └── platform │ │ └── model │ │ ├── BigFloat.android.kt │ │ └── BigInt.android.kt │ ├── androidTest │ └── java │ │ └── more │ │ └── math │ │ └── native │ │ └── model │ │ └── NativeLibTest.kt │ ├── androidUnitTest │ └── kotlin │ │ ├── more.math │ │ └── MoreMathTest.kt │ │ └── more │ │ └── math │ │ └── platform │ │ └── model │ │ └── Factorial_androidKtTest.kt │ ├── commonMain │ ├── cpp │ │ ├── CMakeLists.txt │ │ ├── hyperoperator.cpp │ │ ├── hyperoperator.h │ │ └── nativelib.cpp │ └── kotlin │ │ └── more │ │ └── math │ │ ├── Annotations.kt │ │ ├── Extensions.kt │ │ ├── MoreMath.kt │ │ ├── combinatorics │ │ └── CombinatoricsParent.kt │ │ ├── complex │ │ └── model │ │ │ └── Complex.kt │ │ ├── factorial │ │ └── FactorialParent.kt │ │ ├── graph │ │ ├── model │ │ │ ├── Connection.kt │ │ │ ├── Graph.kt │ │ │ ├── GraphPath.kt │ │ │ ├── Vertex.kt │ │ │ ├── exception │ │ │ │ ├── NegativeWeightException.kt │ │ │ │ └── VertexNotFoundException.kt │ │ │ └── mode │ │ │ │ ├── GraphMode.kt │ │ │ │ ├── RemoveVertexMode.kt │ │ │ │ └── SetVertexMode.kt │ │ └── parent │ │ │ └── GraphParent.kt │ │ ├── matrix │ │ ├── model │ │ │ ├── Matrix.kt │ │ │ ├── MatrixExtension.kt │ │ │ └── MatrixSize.kt │ │ └── parent │ │ │ └── MatrixParent.kt │ │ ├── native │ │ └── model │ │ │ └── NativeProvider.kt │ │ ├── platform │ │ └── model │ │ │ ├── BigFloat.kt │ │ │ └── BigInt.kt │ │ ├── tetraction │ │ └── TetractionParent.kt │ │ └── vector │ │ └── model │ │ ├── Vector2.kt │ │ └── Vector2Extensions.kt │ ├── commonTest │ └── kotlin │ │ └── more │ │ └── math │ │ ├── ExtensionsKtTest.kt │ │ ├── combinatorics │ │ └── CombinatoricsTest.kt │ │ ├── complex │ │ └── model │ │ │ └── ComplexTest.kt │ │ ├── factorial │ │ └── FactorialTest.kt │ │ ├── graph │ │ └── model │ │ │ └── GraphTest.kt │ │ ├── matrix │ │ └── model │ │ │ └── MatrixExtensionKtTest.kt │ │ ├── other │ │ └── OtherTest.kt │ │ ├── platform │ │ └── MoreMathPlatformSpecificTest.kt │ │ ├── tetraction │ │ └── TetractionTest.kt │ │ └── vector │ │ └── model │ │ └── Vector2Test.kt │ ├── iosMain │ └── kotlin │ │ └── more │ │ └── math │ │ ├── native │ │ └── model │ │ │ └── NativeProvider.ios.kt │ │ └── platform │ │ └── model │ │ ├── BigFloat.ios.kt │ │ └── BigInt.ios.kt │ ├── iosTest │ └── kotlin │ │ └── more │ │ └── math │ │ ├── MoreMathTest.kt │ │ └── platform │ │ └── model │ │ └── Factorial_iosKtTest.kt │ ├── jvmMain │ └── kotlin │ │ └── more │ │ └── math │ │ ├── native │ │ └── model │ │ │ └── NativeProvider.jvm.kt │ │ └── platform │ │ └── model │ │ ├── BigFloat.jvm.kt │ │ └── BigInt.jvm.kt │ ├── jvmTest │ └── kotlin │ │ └── more │ │ └── math │ │ ├── MoreMathTest.kt │ │ └── platform │ │ └── model │ │ └── Factorial_jvmKtTest.kt │ ├── linuxX64Main │ └── kotlin │ │ └── more │ │ └── math │ │ ├── native │ │ └── model │ │ │ └── NativeProvider.linuxX64.kt │ │ └── platform │ │ └── model │ │ ├── BigFloat.linuxX64.kt │ │ └── BigInt.linuxX64.kt │ └── linuxX64Test │ └── kotlin │ └── more │ └── math │ ├── MoreMathTest.kt │ └── platform │ └── model │ └── Factorial_linuxX64KtTest.kt └── settings.gradle.kts /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to Maven Central 2 | 3 | on: 4 | release: 5 | types: [released, prereleased] 6 | 7 | jobs: 8 | publish: 9 | name: Release build and publish 10 | runs-on: macOS-latest 11 | steps: 12 | - name: Check out code 13 | uses: actions/checkout@v4 14 | - name: Set up JDK 21 15 | uses: actions/setup-java@v4 16 | with: 17 | distribution: 'zulu' 18 | java-version: 21 19 | - name: Make gradlew executable 20 | run: chmod +x ./gradlew 21 | - name: Publish to MavenCentral 22 | run: ./gradlew publishToMavenCentral --no-configuration-cache 23 | env: 24 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 25 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 26 | ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }} 27 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }} 28 | ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY_CONTENTS }} -------------------------------------------------------------------------------- /.github/workflows/library unit test.yml: -------------------------------------------------------------------------------- 1 | name: Library unit test 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - 'library/**' 7 | 8 | jobs: 9 | test: 10 | runs-on: windows-latest 11 | steps: 12 | - uses: actions/checkout@v1 13 | - name: set up JDK 14 | uses: actions/setup-java@v1 15 | with: 16 | java-version: 21 17 | cache: gradle 18 | - name: Make gradlew executable 19 | run: chmod +x ./gradlew 20 | - name: Unit Test 21 | run: ./gradlew :library:JvmTest 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .kotlin/ 2 | local.properties 3 | .intellijPlatform/ 4 | 5 | # Created by https://www.toptal.com/developers/gitignore/api/swift,xcode,gradle,kotlin,intellij,cocoapods 6 | # Edit at https://www.toptal.com/developers/gitignore?templates=swift,xcode,gradle,kotlin,intellij,cocoapods 7 | 8 | ### CocoaPods ### 9 | ## CocoaPods GitIgnore Template 10 | 11 | # CocoaPods - Only use to conserve bandwidth / Save time on Pushing 12 | # - Also handy if you have a large number of dependant pods 13 | # - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE 14 | Pods/ 15 | 16 | ### Intellij ### 17 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 18 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 19 | 20 | # Cpp 21 | .cxx 22 | 23 | # User-specific stuff 24 | .idea/**/workspace.xml 25 | .idea/**/tasks.xml 26 | .idea/**/usage.statistics.xml 27 | .idea/**/dictionaries 28 | .idea/**/shelf 29 | 30 | # AWS User-specific 31 | .idea/**/aws.xml 32 | 33 | # Generated files 34 | .idea/**/contentModel.xml 35 | 36 | # Sensitive or high-churn files 37 | .idea/**/dataSources/ 38 | .idea/**/dataSources.ids 39 | .idea/**/dataSources.local.xml 40 | .idea/**/sqlDataSources.xml 41 | .idea/**/dynamic.xml 42 | .idea/**/uiDesigner.xml 43 | .idea/**/dbnavigator.xml 44 | 45 | # Gradle 46 | .idea/**/gradle.xml 47 | .idea/**/libraries 48 | 49 | # Gradle and Maven with auto-import 50 | # When using Gradle or Maven with auto-import, you should exclude module files, 51 | # since they will be recreated, and may cause churn. Uncomment if using 52 | # auto-import. 53 | .idea/artifacts 54 | .idea/compiler.xml 55 | .idea/jarRepositories.xml 56 | .idea/modules.xml 57 | .idea/*.iml 58 | .idea/modules 59 | *.iml 60 | *.ipr 61 | 62 | # CMake 63 | cmake-build-*/ 64 | 65 | # Mongo Explorer plugin 66 | .idea/**/mongoSettings.xml 67 | 68 | # File-based project format 69 | *.iws 70 | 71 | # IntelliJ 72 | out/ 73 | 74 | # mpeltonen/sbt-idea plugin 75 | .idea_modules/ 76 | 77 | # JIRA plugin 78 | atlassian-ide-plugin.xml 79 | 80 | # Cursive Clojure plugin 81 | .idea/replstate.xml 82 | 83 | # Crashlytics plugin (for Android Studio and IntelliJ) 84 | com_crashlytics_export_strings.xml 85 | crashlytics.properties 86 | crashlytics-build.properties 87 | fabric.properties 88 | 89 | # Editor-based Rest Client 90 | .idea/httpRequests 91 | 92 | # Android studio 3.1+ serialized cache file 93 | .idea/caches/build_file_checksums.ser 94 | 95 | ### Intellij Patch ### 96 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 97 | 98 | # *.iml 99 | # modules.xml 100 | # .idea/misc.xml 101 | # *.ipr 102 | 103 | # Sonarlint plugin 104 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 105 | .idea/**/sonarlint/ 106 | 107 | # SonarQube Plugin 108 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 109 | .idea/**/sonarIssues.xml 110 | 111 | # Markdown Navigator plugin 112 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 113 | .idea/**/markdown-navigator.xml 114 | .idea/**/markdown-navigator-enh.xml 115 | .idea/**/markdown-navigator/ 116 | 117 | # Cache file creation bug 118 | # See https://youtrack.jetbrains.com/issue/JBR-2257 119 | .idea/$CACHE_FILE$ 120 | 121 | # CodeStream plugin 122 | # https://plugins.jetbrains.com/plugin/12206-codestream 123 | .idea/codestream.xml 124 | 125 | ### Kotlin ### 126 | # Compiled class file 127 | *.class 128 | 129 | # Log file 130 | *.log 131 | 132 | # BlueJ files 133 | *.ctxt 134 | 135 | # Mobile Tools for Java (J2ME) 136 | .mtj.tmp/ 137 | 138 | # Package Files # 139 | *.jar 140 | *.war 141 | *.nar 142 | *.ear 143 | *.zip 144 | *.tar.gz 145 | *.rar 146 | 147 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 148 | hs_err_pid* 149 | 150 | ### Swift ### 151 | # Xcode 152 | # 153 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 154 | 155 | ## User settings 156 | xcuserdata/ 157 | 158 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 159 | *.xcscmblueprint 160 | *.xccheckout 161 | 162 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 163 | build/ 164 | DerivedData/ 165 | *.moved-aside 166 | *.pbxuser 167 | !default.pbxuser 168 | *.mode1v3 169 | !default.mode1v3 170 | *.mode2v3 171 | !default.mode2v3 172 | *.perspectivev3 173 | !default.perspectivev3 174 | 175 | ## Obj-C/Swift specific 176 | *.hmap 177 | 178 | ## App packaging 179 | *.ipa 180 | *.dSYM.zip 181 | *.dSYM 182 | 183 | ## Playgrounds 184 | timeline.xctimeline 185 | playground.xcworkspace 186 | 187 | # Swift Package Manager 188 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 189 | # Packages/ 190 | # Package.pins 191 | # Package.resolved 192 | # *.xcodeproj 193 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 194 | # hence it is not needed unless you have added a package configuration file to your project 195 | # .swiftpm 196 | 197 | .build/ 198 | 199 | # CocoaPods 200 | # We recommend against adding the Pods directory to your .gitignore. However 201 | # you should judge for yourself, the pros and cons are mentioned at: 202 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 203 | # Pods/ 204 | # Add this line if you want to avoid checking in source code from the Xcode workspace 205 | # *.xcworkspace 206 | 207 | # Carthage 208 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 209 | # Carthage/Checkouts 210 | 211 | Carthage/Build/ 212 | 213 | # Accio dependency management 214 | Dependencies/ 215 | .accio/ 216 | 217 | # fastlane 218 | # It is recommended to not store the screenshots in the git repo. 219 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 220 | # For more information about the recommended setup visit: 221 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 222 | 223 | fastlane/report.xml 224 | fastlane/Preview.html 225 | fastlane/screenshots/**/*.png 226 | fastlane/test_output 227 | 228 | # Code Injection 229 | # After new code Injection tools there's a generated folder /iOSInjectionProject 230 | # https://github.com/johnno1962/injectionforxcode 231 | 232 | iOSInjectionProject/ 233 | 234 | ### Xcode ### 235 | # Xcode 236 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 237 | 238 | 239 | 240 | 241 | ## Gcc Patch 242 | /*.gcno 243 | 244 | ### Xcode Patch ### 245 | *.xcodeproj/* 246 | !*.xcodeproj/project.pbxproj 247 | !*.xcodeproj/xcshareddata/ 248 | !*.xcworkspace/contents.xcworkspacedata 249 | **/xcshareddata/WorkspaceSettings.xcsettings 250 | 251 | ### Gradle ### 252 | .gradle 253 | 254 | # Ignore Gradle GUI config 255 | gradle-app.setting 256 | 257 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 258 | !gradle-wrapper.jar 259 | 260 | # Cache of project 261 | .gradletasknamecache 262 | 263 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 264 | # gradle/wrapper/gradle-wrapper.properties 265 | 266 | ### Gradle Patch ### 267 | **/build/ 268 | 269 | # End of https://www.toptal.com/developers/gitignore/api/swift,xcode,gradle,kotlin,intellij,cocoapods -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2023 JetBrains s.r.o. and and respective authors and developers. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Kotlin](https://img.shields.io/badge/kotlin-%237F52FF.svg?style=for-the-badge&logo=kotlin&logoColor=white) 2 | ![Gradle](https://img.shields.io/badge/Gradle-02303A.svg?style=for-the-badge&logo=Gradle&logoColor=white) 3 | ![Apache Maven](https://img.shields.io/badge/Apache%20Maven-C71A36?style=for-the-badge&logo=Apache%20Maven&logoColor=white) 4 | ![Maven Central Version](https://img.shields.io/maven-central/v/io.github.plumsoftware/more-math?style=for-the-badge&logo=kotlin&logoColor=white&logoSize=auto&label=more%20math&labelColor=orange&color=orange) 5 | 6 | ![More Math logo](https://github.com/plumsoftware/more-math/blob/master/docs/images/logo.png) 7 | 8 | ## More math 9 | 10 | Мультиплатформенная библиотека Kotlin, добавляющая математические операции с матрицами, векторами, комбинаторикой и многим другим. 11 | 12 | ![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white) 13 |
Эмоджи для телеграм доступны по ссылке https://t.me/addemoji/RkIQSnNfAAA 14 | 15 | ## Подключение 16 | 17 | Чтобы подключить библиотеку нужно добавить строчки ниже в файл ```build.gradle.kts``` вашего мультиплатформенного модуля 18 | ```kotlin 19 | dependencies { 20 | implementation("io.github.plumsoftware:more-math:") 21 | } 22 | ``` 23 | 24 | ## Документация на других языках (Documentation) 25 | 26 | + [English](https://github.com/plumsoftware/more-math/blob/develop-v0.0.1/docs/languages/README-en.md) 27 | 28 | ## Содержание 29 | 30 | Эта библиотека предоставляет функциональность для работы с вектором на плоскости, матрицей, комбинаторикой. 31 | 32 | * [Факториал](#Факториал) 33 | * [Тетрация](#Тетрация) 34 | * [Остальное](#Другое) 35 | * [Матрица](#Матрица) 36 | * [Граф](#Граф) 37 | * [Комплексные числа](#Комплексные-числа) 38 | * [Вектор на плоскости](#Вектор) 39 | * [Комбинаторика](#Комбинаторика) 40 | 41 | ## Возможности 42 | 43 | ### Факториал 44 | Вычисление факториала для числа до 21 45 | ```kotlin 46 | val res = MoreMath.factorial(3) 47 | ``` 48 | 49 | Вычислить факторил для числа более 20 50 | ```kotlin 51 | val res = MoreMath.bigFactorial(22L) 52 | ``` 53 | 54 | 55 | 56 | ### Тетрация 57 | Вычислить тетрацию 58 | ```kotlin 59 | val res = MoreMath.tetraction(2.0, 3) 60 | ``` 61 | 62 | Если, число в тетрации большое, то используйте 63 | ```kotlin 64 | val res = MoreMath.bigTetraction(2.0, 40) 65 | ``` 66 | 67 | 68 | ### Другое 69 | Чтобы вычислить **наименьшее общее кратное** двух чисел 70 | ```kotlin 71 | val res = MoreMath.gcd(13, 17) 72 | ``` 73 | 74 | Вычисление **стандартного отклонения** ряда чисел 75 | ```kotlin 76 | val res = MoreMath.standardDeviation(1.0, 2.0, 3.0) 77 | ``` 78 | 79 | **Среднее значение** 80 | ```kotlin 81 | val res = MoreMath.average(1, 2, 3) 82 | ``` 83 | 84 | Узнать, положительное или отрицательное число 85 | 86 | ```kotlin 87 | 4.isPositive 88 | (-4).isNegative 89 | ``` 90 | 91 | 92 | ### Матрица 93 | Создать матрицу можно тремя способами 94 | ```kotlin 95 | val matrix = matrixOf ( 96 | mutableListOf(1, 2), 97 | mutableListOf(3, 4) 98 | ) 99 | ``` 100 | или 101 | ```kotlin 102 | val matrix = Matrix ( 103 | mutableListOf(1, 2), 104 | mutableListOf(3, 4) 105 | ) 106 | ``` 107 | или 108 | ```kotlin 109 | val matrix = Matrix(size = MatrixSize(row = 3, column = 4)) 110 | ``` 111 | Последее создаст пустую матрицу. Также можно получить размер матрицы 112 | ```kotlin 113 | val size = matrix.size 114 | ``` 115 | 116 | Операторы, доступные для матриц ```+```, ```-```, ```*```, ```pow()```, ```>```, ```>=``` и подобные. Для сравнения контента матриц, используйте метод ```equals()```. 117 | ```kotlin 118 | val matrix1 = matrixOf ( 119 | mutableListOf(1, 2), 120 | mutableListOf(3, 4) 121 | ) 122 | val matrix2 = matrixOf ( 123 | mutableListOf(5, 6), 124 | mutableListOf(7, 8) 125 | ) 126 | val matrix3 = matrix1.pow(2) 127 | 128 | val plus = matrix1 + matrix2 129 | val times = matrix1 * matrix2 130 | val minus = matrix1 - matrix2 131 | ``` 132 | 133 | Вычислить определитель матрицы 134 | ```kotlin 135 | val det = matrix.determinant() 136 | ``` 137 | 138 | Транспонировать матрицу 139 | ```kotlin 140 | val transposedMatrix = matrix.transpose() 141 | ``` 142 | 143 | Умножить матрицу на число 144 | ```kotlin 145 | val res = matrix.times(2) 146 | ``` 147 | 148 | Найти минимальный или максимальный элемент в матрице. 149 | Если Ваша матрица состоит из ```Double```, ```Long```, ```Float``` или ```Int```, то воспользуйтесь кодом ниже 150 | ```kotlin 151 | val min = matrix.minInMatrix() 152 | val max = matrix.maxInMatrix() 153 | ``` 154 | или 155 | ```kotlin 156 | val min = matrix.minInMatrixBy { it } 157 | val max = matrix.maxInMatrixBy { it } 158 | ``` 159 | 160 | ### Граф 161 | Создать взвешенный граф 162 | ```kotlin 163 | val graph = Graph(mode = GraphMode.UNDIRECTED) 164 | ``` 165 | Где ```VertexType``` - это тип вершины. 166 | ```WeightType``` - это тип веса вершины: ```Int```, ```Double```, ```Long```, ```Float```. 167 | ```mode``` - это тип графа: ```UNDIRECTED```, ```DIRECTED```. 168 | 169 | Для создания связи нужно добавить вершины: 170 | ```kotlin 171 | val graph = Graph() 172 | 173 | val vertexA = Vertex(id = "A") 174 | val vertexB = Vertex(id = "B") 175 | val vertexC = Vertex(id = "C") 176 | val vertexD = Vertex(id = "D") 177 | 178 | graph.addVertex(vertexA) 179 | graph.addVertex(vertexB) 180 | graph.addVertex(vertexC) 181 | graph.addVertex(vertexD) 182 | ``` 183 | 184 | Затем создайте связь между вершинами 185 | ```kotlin 186 | graph.createConnection(from = vertexA, to = vertexB, weight = 2) 187 | ``` 188 | 189 | Получить минимальный путь в графе от и до вершины 190 | ```kotlin 191 | val minPath: GraphPath = graph.minPath(from = Vertex("A"), to = Vertex("B")) 192 | ``` 193 | В результате будет возвращен ```GraphPath```, который содержит пары - вершины и суммарный путь до следующей вершины. 194 | 195 | Получить все вершины 196 | ```kotlin 197 | val vertices = graph.vertices 198 | ``` 199 | 200 | Получить все связи 201 | ```kotlin 202 | val vertices = graph.connections 203 | ``` 204 | 205 | Узнать, есть ли вершина 206 | ```kotlin 207 | val vertex: Vertex? = graph[someVertex] 208 | ``` 209 | Это вернёт ```null```, если вершины в графе нет. 210 | 211 | Заменить вершину в графе 212 | ```kotlin 213 | val newVertex = Vertex("A") 214 | val oldVertex = Vertex("B") //Эта вершина уже есть в графе 215 | graph.set(oldVertex, newVertex, SetVertexMode.NEW_FROM_TO) 216 | ``` 217 | Это заменит все вершины во всех связях в графе и удалит старую вершину. 218 | Если вы хотите заменить только начальные вершины в связях или конечные, то используйте ```NEW_FROM``` или ```NEW_TO``` соответственно. 219 | 220 | Для удаления всех связей используйте: 221 | ```kotlin 222 | graph.removeConnectionsByVertex(someVertex, RemoveVertexMode.TO) 223 | ``` 224 | Это удалит все связи, где есть переданная конечная вершина. 225 | Если нужно удалить только начальные вершины или обе (начальную и конечную) из связей, то используйте ```FROM``` или ```BOTH``` соответственно. 226 | 227 | Для получения всех вершин без связей или наоборот всех вершин в связях 228 | ```kotlin 229 | val freeList = graph.getFreeVertices() 230 | val busyList = graph.getBusyVertices() 231 | ``` 232 | 233 | 234 | ### Комплексные числа 235 | Создать комплексное число 236 | ```kotlin 237 | val complex: Complex = complex(-4.0) 238 | ``` 239 | В результате будет ```0.0 - 2.0i``` 240 | 241 | Если Вам нужно указать реальную часть числа, то воспользуйтесь 242 | ```kotlin 243 | val complex: Complex = complex(3, -4.0) 244 | ``` 245 | В результате будет ```3.0 - 2.0i``` 246 | 247 | Получить алгебраическую или геометрическую форму можно таким образом 248 | ```kotlin 249 | val algebraic = complex.toAlgebraic() 250 | val geometric = complex.toGeometric() 251 | ``` 252 | 253 | С комплексными числами можно выполнять ```+```, ```-```, ```*```, ```/```. Также доступны ```equals()``` и ```hashCode()```. 254 | 255 | 256 | 257 | ### Вектор 258 | 259 | #### Вектор на плоскости 260 | Создание вектора аналогично созданию матрицы 261 | ```kotlin 262 | val vector2 = vector2Of(1 , 2) 263 | ``` 264 | или 265 | ```kotlin 266 | val vector2 = Vector2(1 , 2) 267 | ``` 268 | 269 | С векторами на плоскости доступны следующие операторы ```+```, ```-```, ```*```, ```/```. Также Вы можете использовать ```equals()``` и ```length()```. 270 | ```kotlin 271 | val vector1 = vector2Of(1, 2) 272 | val vector2 = vector2Of(3, 4) 273 | 274 | val plus = vector1 + vector2 275 | val minus = vector1 - vector2 276 | val times = vector1 * vector2 277 | val div = vector1 / vector2 278 | val length = vector1.length() 279 | ``` 280 | 281 | 282 | 283 | ### Комбинаторика 284 | 285 | Комбинации из 5 элементов по 2 элемента 286 | ```kotlin 287 | val res = MoreMath.combinations(5, 2) 288 | ``` 289 | 290 | Размещения 291 | ```kotlin 292 | val res = MoreMath.placements(5, 2) 293 | ``` 294 | 295 | Биноменальный коэффициент 296 | ```kotlin 297 | val res = MoreMath.binomialCoefficient(5, 2) 298 | ``` 299 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.androidLibrary).apply(false) 3 | alias(libs.plugins.kotlinMultiplatform).apply(false) 4 | alias(libs.plugins.vanniktech.mavenPublish).apply(false) 5 | alias(libs.plugins.kotlin.android) apply false 6 | } 7 | -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plumsoftware/more-math/9d8566fddb49dba72f069f6335654d93b8fb5b63/docs/images/logo.png -------------------------------------------------------------------------------- /docs/images/telegram.svg: -------------------------------------------------------------------------------- 1 | 2 | Telegram 3 | 5 | -------------------------------------------------------------------------------- /docs/languages/README-en.md: -------------------------------------------------------------------------------- 1 | ![Kotlin](https://img.shields.io/badge/kotlin-%237F52FF.svg?style=for-the-badge&logo=kotlin&logoColor=white) 2 | ![Gradle](https://img.shields.io/badge/Gradle-02303A.svg?style=for-the-badge&logo=Gradle&logoColor=white) 3 | ![Apache Maven](https://img.shields.io/badge/Apache%20Maven-C71A36?style=for-the-badge&logo=Apache%20Maven&logoColor=white) 4 | ![Maven Central Version](https://img.shields.io/maven-central/v/io.github.plumsoftware/more-math?style=for-the-badge&logo=kotlin&logoColor=white&logoSize=auto&label=more%20math&labelColor=orange&color=orange) 5 | 6 | ![More Math logo](https://github.com/plumsoftware/more-math/blob/develop-v0.0.1/docs/images/logo.png) 7 | 8 | # More math 9 | 10 | Kotlin multiplatform library adding mathematical operations with matrices, vectors, combinatorics and much more. 11 | ![Telegram](https://github.com/plumsoftware/more-math/blob/develop-v0.0.1/docs/images/telegram.svg) Telegram emoji are available below the link https://t.me/addemoji/RkIQSnNfAAA 12 | 13 | ![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white) 14 |
Telegram emoji are available below the link https://t.me/addemoji/RkIQSnNfAAA 15 | 16 | ## Add 17 | 18 | To connect the library, you need to add the lines below to the ```build.gradle.kts``` file of your multiplatform module 19 | ```kotlin 20 | dependencies { 21 | implementation("io.github.plumsoftware:more-math:") 22 | } 23 | ``` 24 | 25 | # Overview 26 | 27 | This library provides functionality to work with Vector on a plane, Matrix, Combinatorics. 28 | 29 | * [Factorial](#Factorial) 30 | * [Tetraction](#Tetraction) 31 | * [Other](#Other) 32 | * [Matrix](#Matrix) 33 | * [Graph](#Graph) 34 | * [Complex numbers](#Complex-numbers) 35 | * [Vector on plane](#Vector) 36 | * [Combinatorics](#Combinatorics) 37 | 38 | ## Usage 39 | 40 | ### Factorial 41 | Use factorial for input below 21 like this 42 | ```kotlin 43 | val res = MoreMath.factorial(3) 44 | ``` 45 | 46 | Use factorial for input more 20 like this 47 | ```kotlin 48 | val res = MoreMath.bigFactorial(22L) 49 | ``` 50 | 51 | 52 | ### Tetraction 53 | To get tetraction use this 54 | ```kotlin 55 | val res = MoreMath.tetraction(2.0, 3) 56 | ``` 57 | 58 | To work with big numbers 59 | ```kotlin 60 | val res = MoreMath.bigTetraction(2.0, 40) 61 | ``` 62 | 63 | 64 | ### Other 65 | To get **least common multiple** 66 | ```kotlin 67 | val res = MoreMath.gcd(13, 17) 68 | ``` 69 | 70 | Get a **standart deviation** 71 | ```kotlin 72 | val res = MoreMath.standardDeviation(1.0, 2.0, 3.0) 73 | ``` 74 | 75 | Get a **average** 76 | ```kotlin 77 | val res = MoreMath.average(1, 2, 3) 78 | ``` 79 | 80 | Positive or negative number 81 | 82 | ```kotlin 83 | 4.isPositive 84 | (-4).isNegative 85 | ``` 86 | 87 | 88 | ### Matrix 89 | To create matrix just write 90 | ```kotlin 91 | val matrix = matrixOf ( 92 | mutableListOf(1, 2), 93 | mutableListOf(3, 4) 94 | ) 95 | ``` 96 | or 97 | ```kotlin 98 | val matrix = Matrix ( 99 | mutableListOf(1, 2), 100 | mutableListOf(3, 4) 101 | ) 102 | ``` 103 | or with matrix size 104 | ```kotlin 105 | val matrix = Matrix(size = MatrixSize(row = 3, column = 4)) 106 | ``` 107 | It creates an empty matrix. Get a matrix size like this 108 | ```kotlin 109 | val size = matrix.size 110 | ``` 111 | 112 | You can ```+```, ```-```, ```*```, ```pow()```, ```>```, ```!=``` etc. To compare a matrix content use ```equals()```. 113 | ```kotlin 114 | val matrix1 = matrixOf ( 115 | mutableListOf(1, 2), 116 | mutableListOf(3, 4) 117 | ) 118 | val matrix2 = matrixOf ( 119 | mutableListOf(5, 6), 120 | mutableListOf(7, 8) 121 | ) 122 | val matrix3 = matrix1.pow(2) 123 | 124 | val plus = matrix1 + matrix2 125 | val times = matrix1 * matrix2 126 | val minus = matrix1 - matrix2 127 | ``` 128 | 129 | Get a determinant 130 | ```kotlin 131 | val det = matrix.determinant() 132 | ``` 133 | 134 | Transpose matrix 135 | ```kotlin 136 | val transposedMatrix = matrix.transpose() 137 | ``` 138 | 139 | Times matrix with number 140 | ```kotlin 141 | val res = matrix.times(2) 142 | ``` 143 | 144 | To find min or max item in matrix. 145 | If your matrix contains one of ```Double```, ```Long```, ```Float```, ```Int```, use the code below 146 | ```kotlin 147 | val min = matrix.minInMatrix() 148 | val max = matrix.maxInMatrix() 149 | ``` 150 | or 151 | ```kotlin 152 | val min = matrix.minInMatrixBy { it } 153 | val max = matrix.maxInMatrixBy { it } 154 | ``` 155 | 156 | ### Graph 157 | Create a weighted graph 158 | ```kotlin 159 | val graph = Graph(mode = GraphMode.UNDIRECTED) 160 | ``` 161 | 162 | Where VertexType is the type of the vertex. WeightType is the type of the vertex weight: Int, Double, Long, Float. mode is the type of the graph: UNDIRECTED, DIRECTED. 163 | 164 | To create a connection, you need to add vertices: 165 | ```kotlin 166 | val graph = Graph() 167 | 168 | val vertexA = Vertex(id = "A") 169 | val vertexB = Vertex(id = "B") 170 | val vertexC = Vertex(id = "C") 171 | val vertexD = Vertex(id = "D") 172 | 173 | graph.addVertex(vertexA) 174 | graph.addVertex(vertexB) 175 | graph.addVertex(vertexC) 176 | graph.addVertex(vertexD) 177 | ``` 178 | 179 | Then create a connection between the vertices 180 | ```kotlin 181 | graph.createConnection(from = vertexA, to = vertexB, weight = 2) 182 | ``` 183 | 184 | Get a min path in graph: 185 | ```kotlin 186 | val minPath: GraphPath = graph.minPath(from = Vertex("A"), to = Vertex("B")) 187 | ``` 188 | It returns a ```GraphPath``` which contains a list of pairs - vertex and sum weight to next vertex. 189 | 190 | Get all vertices 191 | ```kotlin 192 | val vertices = graph.vertices 193 | ``` 194 | 195 | Get all connections 196 | ```kotlin 197 | val vertices = graph.connections 198 | ``` 199 | Check if a vertex exists 200 | ```kotlin 201 | val vertex: Vertex? = graph[someVertex] 202 | ``` 203 | This will return null if the vertex does not exist in the graph. 204 | 205 | Replace a vertex in a graph 206 | 207 | ```kotlin 208 | val newVertex = Vertex("A") 209 | val oldVertex = Vertex("B") //This vertex is already in the graph 210 | graph.set(oldVertex, newVertex, SetVertexMode.NEW_FROM_TO) 211 | ``` 212 | This will replace all nodes in all links in the graph and remove the old node. If you want to replace only the start nodes in links or the end nodes, use NEW_FROM or NEW_TO respectively. 213 | 214 | To remove all connections use: 215 | ```kotlin 216 | graph.removeConnectionsByVertex(someVertex, RemoveVertexMode.TO) 217 | ``` 218 | 219 | This will remove all links where the given end node is present. If you want to remove only the start nodes or both (start and end) from links, use FROM or BOTH respectively. 220 | 221 | To get all nodes without links or vice versa all nodes in links 222 | ```kotlin 223 | val freeList = graph.getFreeVertices() 224 | val busyList = graph.getBusyVertices() 225 | ``` 226 | 227 | 228 | ### Complex numbers 229 | Create a complex number 230 | ```kotlin 231 | val complex: Complex = complex(-4.0) 232 | ``` 233 | This will be ```0.0 - 2.0i``` 234 | 235 | If you need to specify the real part of the number, use 236 | ```kotlin 237 | val complex: Complex = MoreMath.complex(3, -4.0) 238 | ``` 239 | This will be ```3.0 - 2.0i``` 240 | 241 | T0 find algebraic or geometric form 242 | ```kotlin 243 | val algebraic = complex.toAlgebraic() 244 | val geometric = complex.toGeometric() 245 | ``` 246 | 247 | With complex numbers, you can perform ```+```, ```-```, ```*```, ```/```. ```equals()``` and ```hashCode()``` are also available. 248 | 249 | 250 | 251 | ### Vector 252 | 253 | #### On plane 254 | To create vector 255 | ```kotlin 256 | val vector2 = vector2Of(1 , 2) 257 | ``` 258 | or 259 | ```kotlin 260 | val vector2 = Vector2(1 , 2) 261 | ``` 262 | 263 | You can ```+```, ```-```, ```*```, ```/``` vector2. Also ```equals()``` and ```length()``` are available. 264 | ```kotlin 265 | val vector1 = vector2Of(1, 2) 266 | val vector2 = vector2Of(3, 4) 267 | 268 | val plus = vector1 + vector2 269 | val minus = vector1 - vector2 270 | val times = vector1 * vector2 271 | val div = vector1 / vector2 272 | val length = vector1.length() 273 | ``` 274 | 275 | 276 | 277 | ### Combinatorics 278 | 279 | Combinations of 5 elements by 2 elements 280 | ```kotlin 281 | val res = MoreMath.combinations(5, 2) 282 | ``` 283 | 284 | Placements 285 | ```kotlin 286 | val res = MoreMath.placements(5, 2) 287 | ``` 288 | 289 | Binomial coefficient 290 | ```kotlin 291 | val res = MoreMath.binomialCoefficient(5, 2) 292 | ``` 293 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | #Gradle 2 | org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M" 3 | org.gradle.caching=true 4 | org.gradle.configuration-cache=true 5 | #Kotlin 6 | kotlin.code.style=official 7 | kotlin.js.compiler=ir 8 | #MPP 9 | kotlin.mpp.enableCInteropCommonization=true 10 | #Android 11 | android.useAndroidX=true 12 | android.nonTransitiveRClass=true 13 | #KMP 14 | kotlin.native.ignoreDisabledTargets=true 15 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | agp = "8.3.0" 3 | kotlin = "2.0.0" 4 | nexus-publish = "2.0.0" 5 | android-minSdk = "21" 6 | android-compileSdk = "35" 7 | mavenPublish = "0.29.0" 8 | 9 | #Coroutines 10 | kotlin-coroutines = "1.9.0" 11 | kotlinVersion = "1.9.0" 12 | coreKtx = "1.15.0" 13 | junit = "4.13.2" 14 | junitVersion = "1.2.1" 15 | espressoCore = "3.6.1" 16 | appcompat = "1.7.0" 17 | material = "1.12.0" 18 | 19 | [libraries] 20 | kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } 21 | 22 | #Coroutines 23 | kotlin-coroutines = {module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines"} 24 | kotlin-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlin-coroutines" } 25 | core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } 26 | junit = { group = "junit", name = "junit", version.ref = "junit" } 27 | ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } 28 | espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } 29 | appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } 30 | material = { group = "com.google.android.material", name = "material", version.ref = "material" } 31 | 32 | [plugins] 33 | androidLibrary = { id = "com.android.library", version.ref = "agp" } 34 | kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } 35 | vanniktech-mavenPublish = {id = "com.vanniktech.maven.publish", version.ref = "mavenPublish"} 36 | kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plumsoftware/more-math/9d8566fddb49dba72f069f6335654d93b8fb5b63/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Collect all arguments for the java command; 201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 202 | # shell script including quotes and variable substitutions, so put them in 203 | # double quotes to make sure that they get re-expanded; and 204 | # * put everything else in single quotes, so that it's not re-expanded. 205 | 206 | set -- \ 207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 208 | -classpath "$CLASSPATH" \ 209 | org.gradle.wrapper.GradleWrapperMain \ 210 | "$@" 211 | 212 | # Stop when "xargs" is not available. 213 | if ! command -v xargs >/dev/null 2>&1 214 | then 215 | die "xargs is not available" 216 | fi 217 | 218 | # Use "xargs" to parse quoted args. 219 | # 220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 221 | # 222 | # In Bash we could simply go: 223 | # 224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 225 | # set -- "${ARGS[@]}" "$@" 226 | # 227 | # but POSIX shell has neither arrays nor command substitution, so instead we 228 | # post-process each arg (as a line of input to sed) to backslash-escape any 229 | # character that might be a shell metacharacter, then use eval to reverse 230 | # that process (while maintaining the separation between arguments), and wrap 231 | # the whole thing up as a single "set" statement. 232 | # 233 | # This will of course break if any of these variables contains a newline or 234 | # an unmatched quote. 235 | # 236 | 237 | eval "set -- $( 238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 239 | xargs -n1 | 240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 241 | tr '\n' ' ' 242 | )" '"$@"' 243 | 244 | exec "$JAVACMD" "$@" 245 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /library/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.vanniktech.maven.publish.SonatypeHost 2 | import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi 3 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 4 | 5 | plugins { 6 | alias(libs.plugins.kotlinMultiplatform) 7 | alias(libs.plugins.androidLibrary) 8 | alias(libs.plugins.vanniktech.mavenPublish) 9 | } 10 | 11 | kotlin { 12 | jvm { 13 | compilations.all { 14 | kotlinOptions.jvmTarget = "1.8" 15 | } 16 | testRuns["test"].executionTask.configure { 17 | useJUnitPlatform() 18 | } 19 | } 20 | 21 | androidTarget { 22 | publishLibraryVariants("release") 23 | @OptIn(ExperimentalKotlinGradlePluginApi::class) 24 | compilerOptions { 25 | jvmTarget.set(JvmTarget.JVM_1_8) 26 | } 27 | } 28 | 29 | iosX64() 30 | iosArm64() 31 | iosSimulatorArm64() 32 | 33 | linuxX64() 34 | 35 | applyDefaultHierarchyTemplate() 36 | 37 | sourceSets { 38 | val commonMain by getting { 39 | dependencies {} 40 | } 41 | val commonTest by getting { 42 | dependencies { 43 | implementation(libs.kotlin.test) 44 | } 45 | } 46 | } 47 | } 48 | 49 | android { 50 | namespace = "more.math" 51 | compileSdk = libs.versions.android.compileSdk.get().toInt() 52 | defaultConfig { 53 | minSdk = libs.versions.android.minSdk.get().toInt() 54 | 55 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 56 | } 57 | 58 | externalNativeBuild { 59 | cmake { 60 | path("src/commonMain/cpp/CMakeLists.txt") 61 | version = "3.22.1" 62 | } 63 | } 64 | 65 | dependencies { 66 | testImplementation(libs.junit) 67 | androidTestImplementation(libs.ext.junit) 68 | androidTestImplementation(libs.espresso.core) 69 | } 70 | } 71 | 72 | mavenPublishing { 73 | 74 | group = "io.github.plumsoftware" 75 | version = "1.1.1" 76 | 77 | publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) 78 | 79 | signAllPublications() 80 | 81 | coordinates(group.toString(), "more-math", version.toString()) 82 | 83 | pom { 84 | name.set("More math") 85 | description.set("Это KMP библиотека для работы с математикой.") 86 | url.set("https://github.com/plumsoftware/more-math") 87 | 88 | licenses { 89 | license { 90 | name.set("MIT") 91 | url.set("https://opensource.org/licenses/MIT") 92 | } 93 | } 94 | developers { 95 | developer { 96 | id.set("https://t.me/Sl1vka") 97 | name.set("Vyacheslav Deych") 98 | organization.set("Plumsoftware") 99 | organizationUrl.set("https://github.com/plumsoftware") 100 | } 101 | } 102 | scm { 103 | url.set("https://github.com/plumsoftware/more-math") 104 | connection.set("scm:git:git://github.com/plumsoftware/more-math") 105 | developerConnection = "scm:git:ssh://git@github.com:plumsoftware/more-math.git" 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /library/src/androidMain/kotlin/more/math/native/model/NativeProvider.android.kt: -------------------------------------------------------------------------------- 1 | package more.math.native.model 2 | 3 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 4 | internal actual class NativeProvider actual constructor() { 5 | 6 | companion object { 7 | init { 8 | System.loadLibrary("nativelib") 9 | } 10 | } 11 | 12 | private external fun cppFactorial(number: Int) : Long 13 | 14 | private external fun cppLongFactorial(number: Long) : Long 15 | 16 | private external fun cppAverage(vararg number: Int) : Double 17 | 18 | private external fun cppStandardDeviation(vararg numbers: Double) : Double 19 | 20 | private external fun cppTetraction(number: Double, other: Int) : Double 21 | 22 | private external fun cppGcd(a: Int, b: Int) : Int 23 | 24 | actual fun nativeFactorial(number: Int): Long { 25 | return cppFactorial(number = number) 26 | } 27 | 28 | actual fun nativeFactorial(number: Long): Long { 29 | return cppLongFactorial(number = number) 30 | } 31 | 32 | actual fun nativeAverage(vararg numbers: Int) : Double { 33 | return cppAverage(*numbers) 34 | } 35 | 36 | actual fun standardDeviation(vararg numbers: Double) : Double { 37 | return cppStandardDeviation(*numbers) 38 | } 39 | 40 | actual fun tetraction(number: Double, other: Int) : Double { 41 | return cppTetraction(number = number, other = other) 42 | } 43 | 44 | actual fun gcd(a: Int, b: Int): Int { 45 | return cppGcd(a, b) 46 | } 47 | } -------------------------------------------------------------------------------- /library/src/androidMain/kotlin/more/math/platform/model/BigFloat.android.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | import java.math.BigDecimal 4 | 5 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 6 | actual class BigFloat actual constructor(value: String) { 7 | actual companion object { 8 | actual val ZERO: BigFloat get() = BigFloat(BigDecimal.ZERO.toString()) 9 | actual val ONE: BigFloat get() = BigFloat(BigDecimal.ONE.toString()) 10 | } 11 | 12 | private val bigFloat = BigDecimal(value) 13 | 14 | actual fun add(other: BigFloat): BigFloat { 15 | return BigFloat(this.bigFloat.add(other.bigFloat).toString()) 16 | } 17 | 18 | actual fun multiply(other: BigFloat): BigFloat { 19 | return BigFloat(this.bigFloat.multiply(other.bigFloat).toString()) 20 | } 21 | 22 | actual override fun toString(): String { 23 | return this.bigFloat.toString() 24 | } 25 | } -------------------------------------------------------------------------------- /library/src/androidMain/kotlin/more/math/platform/model/BigInt.android.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | import java.math.BigInteger 4 | 5 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 6 | actual class BigInt actual constructor(value: String) { 7 | 8 | actual companion object { 9 | actual val ZERO: BigInt 10 | get() = BigInt("0") 11 | actual val ONE: BigInt 12 | get() = BigInt("1") 13 | } 14 | 15 | private val bigInt = BigInteger(value) 16 | 17 | actual fun add(other: BigInt): BigInt { 18 | return BigInt(this.bigInt.add(other.bigInt).toString()) 19 | } 20 | 21 | actual fun multiply(other: BigInt): BigInt { 22 | return BigInt(this.bigInt.multiply(other.bigInt).toString()) 23 | } 24 | 25 | actual override fun toString(): String { 26 | return this.bigInt.toString() 27 | } 28 | } -------------------------------------------------------------------------------- /library/src/androidTest/java/more/math/native/model/NativeLibTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.native.model 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import more.math.MoreMath 5 | import org.junit.Test 6 | import org.junit.runner.RunWith 7 | import org.junit.Assert.* 8 | 9 | @RunWith(AndroidJUnit4::class) 10 | class NativeLibTest { 11 | 12 | @Test 13 | fun nativeFactorial() { 14 | val actual = MoreMath.factorial(n = 3) 15 | val expected = 6L 16 | assertEquals(expected, actual) 17 | 18 | val actual1 = MoreMath.factorial(n = 3L) 19 | val expected1 = 6L 20 | assertEquals(expected1, actual1) 21 | } 22 | 23 | @Test 24 | fun average() { 25 | val exp: Double = 2.0 26 | val act: Double = MoreMath.average(1, 2, 3) 27 | assertEquals(exp.toString(), act.toString()) 28 | } 29 | 30 | @Test 31 | fun tetraction() { 32 | val result = MoreMath.tetraction(number = 2.0, other = 3) 33 | assertEquals(16.0.toString(), result.toString()) 34 | } 35 | 36 | @Test 37 | fun stdDev() { 38 | val exp: Double = 1.0 39 | val act: Double = MoreMath.standardDeviation(1.0, 2.0, 3.0) 40 | assertEquals(exp.toString(), act.toString()) 41 | } 42 | 43 | @Test 44 | fun gcd() { 45 | val exp: Int = 5 46 | val act: Int = MoreMath.gcd(10, 15) 47 | assertEquals(exp, act) 48 | } 49 | } -------------------------------------------------------------------------------- /library/src/androidUnitTest/kotlin/more.math/MoreMathTest.kt: -------------------------------------------------------------------------------- 1 | package more.math 2 | 3 | import more.math.matrix.model.Matrix 4 | import more.math.matrix.model.determinant 5 | import more.math.matrix.model.transpose 6 | import more.math.vector.model.Vector2 7 | import kotlin.test.Test 8 | import kotlin.test.assertEquals 9 | 10 | class MoreMathTest { 11 | 12 | @Test 13 | fun test() { 14 | val matrix = matrixOf( 15 | mutableListOf(1,2), 16 | mutableListOf(3,4), 17 | ) 18 | val vector1 = vector2Of(1, 2) 19 | val vector2 = vector2Of(3, 4) 20 | 21 | assertEquals(expected = -2.0, actual = matrix.determinant()) 22 | assertEquals(expected = 6, MoreMath.factorial(3)) 23 | assertEquals(expected = 2.0, MoreMath.average(1, 2, 3)) 24 | assertEquals(expected = Matrix(mutableListOf(1, 3), mutableListOf(2, 4)), matrix.transpose()) 25 | assertEquals(expected = 16.0, MoreMath.tetraction(2.0, 3)) 26 | assertEquals(expected = Vector2(x = 4, y = 6), actual = (vector1 + vector2)) 27 | } 28 | } -------------------------------------------------------------------------------- /library/src/androidUnitTest/kotlin/more/math/platform/model/Factorial_androidKtTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | import more.math.MoreMath 4 | 5 | import org.junit.Test 6 | import java.math.BigInteger 7 | 8 | class Factorial_androidKtTest { 9 | 10 | @Test 11 | fun bigFactorial() { 12 | val n = 22L 13 | val result = MoreMath.bigFactorial(n) 14 | kotlin.test.assertEquals( 15 | expected = BigInteger("1124000727777607680000").toString(), 16 | actual = result.toString() 17 | ) 18 | } 19 | } -------------------------------------------------------------------------------- /library/src/commonMain/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html. 3 | # For more examples on how to use CMake, see https://github.com/android/ndk-samples. 4 | 5 | # Sets the minimum CMake version required for this project. 6 | cmake_minimum_required(VERSION 3.22.1) 7 | 8 | # Declares the project name. The project name can be accessed via ${ PROJECT_NAME}, 9 | # Since this is the top level CMakeLists.txt, the project name is also accessible 10 | # with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level 11 | # build script scope). 12 | project("nativelib") 13 | 14 | # Creates and names a library, sets it as either STATIC 15 | # or SHARED, and provides the relative paths to its source code. 16 | # You can define multiple libraries, and CMake builds them for you. 17 | # Gradle automatically packages shared libraries with your APK. 18 | # 19 | # In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define 20 | # the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME} 21 | # is preferred for the same purpose. 22 | # 23 | # In order to load a library into your app from Java/Kotlin, you must call 24 | # System.loadLibrary() and pass the name of the library defined here; 25 | # for GameActivity/NativeActivity derived applications, the same library name must be 26 | # used in the AndroidManifest.xml file. 27 | add_library(${CMAKE_PROJECT_NAME} SHARED 28 | # List C/C++ source files with relative paths to this CMakeLists.txt. 29 | hyperoperator.cpp 30 | nativelib.cpp) 31 | 32 | # Specifies libraries CMake should link to your target library. You 33 | # can link libraries from various origins, such as libraries defined in this 34 | # build script, prebuilt third-party libraries, or Android system libraries. 35 | target_link_libraries(${CMAKE_PROJECT_NAME} 36 | # List libraries link to the target library 37 | android 38 | log) -------------------------------------------------------------------------------- /library/src/commonMain/cpp/hyperoperator.cpp: -------------------------------------------------------------------------------- 1 | #include "hyperoperator.h" 2 | #include 3 | 4 | double tetraction(double number, int other) { 5 | if (other == 0) { 6 | return 1.0; 7 | } else { 8 | return pow(number, tetraction(number, other - 1)); 9 | } 10 | } 11 | 12 | unsigned long factorial(int number) { 13 | unsigned long long result = 1; 14 | 15 | for (int i = 2; i <= number; ++i) { 16 | result *= i; 17 | 18 | if (result > 9223372036854775807ULL) { 19 | return -1; 20 | } 21 | } 22 | 23 | return result; 24 | } 25 | 26 | unsigned long factorial_(long number) { 27 | unsigned long long result = 1; 28 | 29 | for (int i = 2; i <= number; ++i) { 30 | result *= i; 31 | 32 | if (result > 9223372036854775807ULL) { 33 | return -1; 34 | } 35 | } 36 | 37 | return result; 38 | } 39 | 40 | double average(const int* numbers, size_t length) { 41 | if (length == 0) { 42 | return 0.0; 43 | } 44 | 45 | int sum = 0; 46 | for (size_t i = 0; i < length; i++) { 47 | sum += numbers[i]; 48 | } 49 | return static_cast(sum) / length; 50 | } 51 | 52 | double standardDeviation(const double* numbers, size_t length) { 53 | if (length < 2) { 54 | return 0.0; 55 | } 56 | 57 | double sum = 0.0; 58 | for (size_t i = 0; i < length; i++) { 59 | sum += numbers[i]; 60 | } 61 | 62 | double avg = sum / length; 63 | double sumOfSquares = 0.0; 64 | for (size_t i = 0; i < length; i++) { 65 | sumOfSquares += (numbers[i] - avg) * (numbers[i] - avg); 66 | } 67 | 68 | return sqrt(sumOfSquares / (length - 1)); 69 | } 70 | 71 | int gcd(int a, int b) { 72 | return (b == 0) ? a : gcd(b, a % b); 73 | } -------------------------------------------------------------------------------- /library/src/commonMain/cpp/hyperoperator.h: -------------------------------------------------------------------------------- 1 | #ifndef MORE_MATH_HYPEROPERATOR_H 2 | #define MORE_MATH_HYPEROPERATOR_H 3 | 4 | #include 5 | 6 | double tetraction(double number, int other); 7 | unsigned long factorial(int number); 8 | unsigned long factorial_(long number); 9 | double average(const int* number, size_t length); 10 | double standardDeviation(const double* numbers, size_t length); 11 | int gcd(int a, int b); 12 | 13 | #endif //MORE_MATH_HYPEROPERATOR_H 14 | -------------------------------------------------------------------------------- /library/src/commonMain/cpp/nativelib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "hyperoperator.h" 5 | 6 | extern "C" { 7 | JNIEXPORT jlong JNICALL 8 | Java_more_math_native_model_NativeProvider_cppFactorial(JNIEnv *env, jobject thiz, jint number) { 9 | return static_cast(factorial(number)); 10 | } 11 | JNIEXPORT jlong JNICALL 12 | Java_more_math_native_model_NativeProvider_cppLongFactorial(JNIEnv *env, jobject thiz, jlong number) { 13 | return static_cast(factorial_(static_cast(number))); 14 | } 15 | 16 | JNIEXPORT jdouble JNICALL 17 | Java_more_math_native_model_NativeProvider_cppAverage(JNIEnv *env, jobject thiz,jintArray numbers) { 18 | 19 | jsize length = env->GetArrayLength(numbers); 20 | jint* elements = env->GetIntArrayElements(numbers, nullptr); 21 | if (elements == nullptr) { 22 | return 0.0; 23 | } 24 | 25 | double avg = average(elements, length); 26 | 27 | env->ReleaseIntArrayElements(numbers, elements, 0); 28 | 29 | return avg; 30 | } 31 | 32 | JNIEXPORT jdouble JNICALL 33 | Java_more_math_native_model_NativeProvider_cppStandardDeviation(JNIEnv *env, jobject thiz, 34 | jdoubleArray numbers) { 35 | jsize length = env->GetArrayLength(numbers); 36 | 37 | jdouble *elements = env->GetDoubleArrayElements(numbers, nullptr); 38 | if (elements == nullptr) { 39 | return 0.0; 40 | } 41 | 42 | double stddev = standardDeviation(elements, length); 43 | 44 | env->ReleaseDoubleArrayElements(numbers, elements, 0); 45 | 46 | return stddev; 47 | } 48 | 49 | JNIEXPORT jdouble JNICALL 50 | Java_more_math_native_model_NativeProvider_cppTetraction(JNIEnv *env, jobject thiz, jdouble number, 51 | jint other) { 52 | return tetraction(static_cast(number), static_cast(other)); 53 | } 54 | 55 | JNIEXPORT jint JNICALL 56 | Java_more_math_native_model_NativeProvider_cppGcd(JNIEnv *env, jobject thiz, jint a, jint b) { 57 | return gcd(a, b); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/Annotations.kt: -------------------------------------------------------------------------------- 1 | package more.math 2 | 3 | @Target( 4 | AnnotationTarget.FUNCTION, 5 | AnnotationTarget.CLASS, 6 | AnnotationTarget.LOCAL_VARIABLE, 7 | AnnotationTarget.FIELD 8 | ) 9 | @Retention(AnnotationRetention.RUNTIME) 10 | public annotation class ExperimentalApi public constructor(val reason: String = "Experimental API") 11 | 12 | @Target( 13 | AnnotationTarget.LOCAL_VARIABLE, 14 | AnnotationTarget.VALUE_PARAMETER 15 | ) 16 | @Retention(AnnotationRetention.RUNTIME) 17 | public annotation class InProgress public constructor(val reason: String = "In progress") 18 | -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/Extensions.kt: -------------------------------------------------------------------------------- 1 | package more.math 2 | 3 | import more.math.complex.model.Complex 4 | import more.math.matrix.model.Matrix 5 | import more.math.vector.model.Vector2 6 | 7 | public inline fun matrixOf(vararg row: MutableList): Matrix { 8 | return Matrix(*row.map { it.toMutableList() }.toTypedArray()) 9 | } 10 | 11 | //region::Vector 12 | public inline fun vector2Of(x: T, y: T): Vector2 { 13 | return Vector2(x, y) 14 | } 15 | //endregion 16 | 17 | //region::Complex 18 | public inline fun complex( 19 | realPart: R, 20 | imaginaryPart: Double 21 | ): Complex { 22 | return Complex( 23 | realPart = realPart, 24 | imaginaryPart = (if (imaginaryPart < 0) -1 else 1) * kotlin.math.sqrt( 25 | kotlin.math.abs( 26 | imaginaryPart 27 | ) 28 | ) 29 | ) 30 | } 31 | 32 | public inline fun complex( 33 | imaginaryPart: Double 34 | ): Complex { 35 | return Complex( 36 | realPart = 0, 37 | imaginaryPart = (if (imaginaryPart < 0) -1 else 1) * kotlin.math.sqrt( 38 | kotlin.math.abs( 39 | imaginaryPart 40 | ) 41 | ) 42 | ) 43 | } 44 | //endregion 45 | 46 | //region::Number 47 | public val Number.isPositive: Boolean 48 | get() = when (this) { 49 | is Int -> this.toInt() > 0 50 | is Double -> this.toDouble() > 0 51 | is Long -> this.toLong() > 0 52 | is Float -> this.toFloat() > 0 53 | else -> { 54 | throw IllegalArgumentException("Unknown type.") 55 | } 56 | } 57 | 58 | public val Number.isNegative: Boolean 59 | get() = when (this) { 60 | is Int -> this.toInt() < 0 61 | is Double -> this.toDouble() < 0 62 | is Long -> this.toLong() < 0 63 | is Float -> this.toFloat() < 0 64 | else -> { 65 | throw IllegalArgumentException("Unknown type.") 66 | } 67 | } 68 | //endregion -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/MoreMath.kt: -------------------------------------------------------------------------------- 1 | package more.math 2 | 3 | import more.math.combinatorics.CombinatoricsParent 4 | import more.math.factorial.FactorialParent 5 | import more.math.platform.model.BigFloat 6 | import more.math.platform.model.BigInt 7 | import more.math.native.model.NativeProvider 8 | import more.math.tetraction.TetractionParent 9 | import kotlin.math.pow 10 | 11 | public object MoreMath { 12 | 13 | private val factorialParent = FactorialParent() 14 | private val tetractionParent = TetractionParent() 15 | private val combinatoricsParent = CombinatoricsParent() 16 | private val nativeProvider = NativeProvider() 17 | 18 | //region::Algebra 19 | public fun factorial(n: Int): Long { 20 | factorialParent.verifyFactorial(n) 21 | return nativeProvider.nativeFactorial(number = n) 22 | } 23 | 24 | public fun factorial(n: Long): Long { 25 | factorialParent.verifyFactorial(n) 26 | return nativeProvider.nativeFactorial(number = n) 27 | } 28 | 29 | public fun bigFactorial(n: Long): BigInt { 30 | factorialParent.verifyPositive(n) 31 | if (n == 0L || n == 1L) { 32 | return BigInt(BigInt.ONE.toString()) 33 | } 34 | 35 | val number = BigInt(n.toString()) 36 | val result = number.multiply(bigFactorial(n - 1L)) 37 | 38 | return BigInt(result.toString()) 39 | } 40 | 41 | public fun tetraction(number: Double, other: Int): Double { 42 | tetractionParent.verify(number, other) 43 | return nativeProvider.tetraction(number, other) 44 | } 45 | 46 | public fun bigTetraction(number: Double, other: Int): BigFloat { 47 | tetractionParent.verify(number, other) 48 | return if (other == 0) { 49 | BigFloat(1.0.toString()) 50 | } else { 51 | BigFloat(number.pow(tetraction(number, other - 1)).toString()) 52 | } 53 | } 54 | 55 | public fun average(vararg numbers: Int): Double { 56 | return nativeProvider.nativeAverage(*numbers) 57 | } 58 | 59 | public fun standardDeviation(vararg numbers: Double): Double { 60 | return nativeProvider.standardDeviation(*numbers) 61 | } 62 | 63 | //Нок 64 | public fun gcd(a: Int, b: Int): Int { 65 | require(a >= 0 && b >= 0) { "Both numbers must be non-negative" } 66 | return nativeProvider.gcd(a = a, b = b) 67 | } 68 | //endregion 69 | 70 | //region::Combinatorics 71 | public fun combinations(n: Int, k: Int): Long { 72 | combinatoricsParent.verify(n, k) 73 | return factorial(n) / (factorial(k) * factorial(n - k)) 74 | } 75 | 76 | public fun placements(n: Int, k: Int): Long { 77 | combinatoricsParent.verify(n, k) 78 | return factorial(n) / factorial(n - k) 79 | } 80 | 81 | public fun binomialCoefficient(n: Int, k: Int) : Long { 82 | combinatoricsParent.verify(n, k) 83 | return factorial(n) / (factorial(k) * factorial(n - k)) 84 | } 85 | //endregion 86 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/combinatorics/CombinatoricsParent.kt: -------------------------------------------------------------------------------- 1 | package more.math.combinatorics 2 | 3 | class CombinatoricsParent { 4 | fun verify(n: Int, k: Int) { 5 | require(n >= 0 && k >= 0 && k <= n) { "Number n must be >= 0, k must be >= 0 and k must be <= n." } 6 | } 7 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/complex/model/Complex.kt: -------------------------------------------------------------------------------- 1 | package more.math.complex.model 2 | 3 | public data class Complex(val realPart: Number, val imaginaryPart: Double) { 4 | 5 | val modulus: Double 6 | get() = kotlin.math.hypot(realPart.toDouble(), imaginaryPart) 7 | 8 | val argument: Double 9 | get() = kotlin.math.atan2(imaginaryPart, realPart.toDouble()) 10 | 11 | override fun toString(): String { 12 | return "Algebraic form is ${toAlgebraic()}, geometric form is ${toGeometric()}" 13 | } 14 | 15 | fun toGeometric(): String { 16 | return if (imaginaryPart >= 0) { 17 | "$modulus * (cos(${argument}) + i * sin(${argument}))" 18 | } else { 19 | "$modulus * (cos(${argument}) - i * sin(${argument}))" 20 | } 21 | } 22 | 23 | fun toAlgebraic(): String { 24 | return if (imaginaryPart >= 0) { 25 | "$realPart + ${imaginaryPart}i" 26 | } else { 27 | "$realPart - ${-imaginaryPart}i" 28 | } 29 | } 30 | 31 | operator fun plus(other: Complex): Complex { 32 | val realPartSum = when (this.realPart) { 33 | is Int -> this.realPart.toInt() + other.realPart.toInt() 34 | is Double -> this.realPart.toDouble() + other.realPart.toDouble() 35 | else -> throw IllegalArgumentException("Unknown realPart type") 36 | } 37 | 38 | return Complex(realPartSum, this.imaginaryPart + other.imaginaryPart) 39 | } 40 | 41 | operator fun minus(other: Complex): Complex { 42 | val realPartMinus = when (this.realPart) { 43 | is Int -> this.realPart.toInt() - other.realPart.toInt() 44 | is Double -> this.realPart.toDouble() - other.realPart.toDouble() 45 | else -> throw IllegalArgumentException("Unknown realPart type") 46 | } 47 | 48 | return Complex(realPartMinus, this.imaginaryPart - other.imaginaryPart) 49 | } 50 | 51 | operator fun times(other: Complex): Complex { 52 | val realPartMul = when (this.realPart) { 53 | is Int -> this.realPart.toInt() * other.realPart.toInt() 54 | is Double -> this.realPart.toDouble() * other.realPart.toDouble() 55 | else -> throw IllegalArgumentException("Unknown realPart type") 56 | } 57 | 58 | val realPartRes = when (realPartMul) { 59 | is Int -> realPartMul.toInt() - this.imaginaryPart * other.imaginaryPart 60 | is Double -> realPartMul.toDouble() - this.imaginaryPart * other.imaginaryPart 61 | else -> throw IllegalArgumentException("Unknown realPart type") 62 | } 63 | 64 | val imaginaryPartRes = 65 | this.realPart.toDouble() * other.imaginaryPart + this.imaginaryPart * other.realPart.toDouble() 66 | 67 | return Complex(realPartRes, imaginaryPartRes) 68 | } 69 | 70 | operator fun div(other: Complex): Complex { 71 | val thisReal = this.realPart.toDouble() 72 | val otherReal = other.realPart.toDouble() 73 | 74 | val denominator = 75 | otherReal * otherReal + other.imaginaryPart * other.imaginaryPart 76 | val realPart = 77 | (thisReal * otherReal + this.imaginaryPart * other.imaginaryPart) / denominator 78 | val imaginaryPart = 79 | (this.imaginaryPart * otherReal - thisReal * other.imaginaryPart) / denominator 80 | 81 | return Complex(realPart, imaginaryPart) 82 | } 83 | 84 | override fun equals(other: Any?): Boolean { 85 | if (this === other) return true 86 | if (other !is Complex) return false 87 | 88 | return this.realPart == other.realPart && this.imaginaryPart == other.imaginaryPart 89 | } 90 | 91 | override fun hashCode(): Int { 92 | var result = realPart.hashCode() 93 | result = 31 * result + imaginaryPart.hashCode() 94 | return result 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/factorial/FactorialParent.kt: -------------------------------------------------------------------------------- 1 | package more.math.factorial 2 | 3 | class FactorialParent { 4 | fun verifyFactorial(n: Int) { 5 | require(n in 0..20) { 6 | "Factorial must be in range 0..20." 7 | } 8 | } 9 | 10 | fun verifyFactorial(n: Long) { 11 | require(n in 0..20) { 12 | "Factorial must be in range 0..20." 13 | } 14 | } 15 | 16 | fun verifyPositive(n: Long) { 17 | require(n >= 0) { 18 | "Factorial must positive." 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/graph/model/Connection.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.model 2 | 3 | data class Connection( 4 | val from: Vertex, 5 | val to: Vertex, 6 | val weight: W 7 | ) { 8 | fun hasVertex(vertex: Vertex): Boolean { 9 | return from.id == vertex.id || to.id == vertex.id 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/graph/model/Graph.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.model 2 | 3 | import more.math.ExperimentalApi 4 | import more.math.graph.model.exception.NegativeWeightException 5 | import more.math.graph.model.exception.VertexNotFoundException 6 | import more.math.graph.model.mode.GraphMode 7 | import more.math.graph.model.mode.RemoveVertexMode 8 | import more.math.graph.model.mode.SetVertexMode 9 | import more.math.graph.parent.GraphParent 10 | 11 | @ExperimentalApi 12 | public class Graph 13 | public constructor(val mode: GraphMode = GraphMode.UNDIRECTED) : GraphParent() { 14 | val vertices: MutableList> = mutableListOf() 15 | val connections: MutableList> = mutableListOf() 16 | private var hasNegativeWeight: Boolean = false 17 | 18 | public fun addVertex(vertex: Vertex) { 19 | vertices.add(vertex) 20 | } 21 | 22 | public operator fun get(vertex: Vertex): Vertex? { 23 | return vertices.find { it.id == vertex.id } 24 | } 25 | 26 | public operator fun set( 27 | oldVertex: Vertex, 28 | newVertex: Vertex, 29 | setVertexMode: SetVertexMode 30 | ) { 31 | when (setVertexMode) { 32 | SetVertexMode.NEW_FROM -> { 33 | this.addVertex(vertex = newVertex) 34 | connections.forEachIndexed { index, item -> 35 | if (item.from.id == oldVertex.id) { 36 | connections[index] = connections[index].copy(from = newVertex) 37 | } 38 | } 39 | } 40 | 41 | SetVertexMode.NEW_TO -> { 42 | this.addVertex(vertex = newVertex) 43 | connections.forEachIndexed { index, item -> 44 | if (item.to.id == oldVertex.id) { 45 | connections[index] = connections[index].copy(to = newVertex) 46 | } 47 | } 48 | } 49 | 50 | SetVertexMode.NEW_FROM_TO -> { 51 | this.addVertex(vertex = newVertex) 52 | connections.forEachIndexed { index, item -> 53 | if (item.to.id == oldVertex.id) { 54 | connections[index] = connections[index].copy(to = newVertex) 55 | } else if (item.from.id == oldVertex.id) { 56 | connections[index] = connections[index].copy(from = newVertex) 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | public fun clearAllConnection() { 64 | connections.clear() 65 | } 66 | 67 | public fun clearAllVertices() { 68 | vertices.clear() 69 | } 70 | 71 | public fun removeConnectionsByVertex(vertex: Vertex, removeVertexMode: RemoveVertexMode) { 72 | when (removeVertexMode) { 73 | RemoveVertexMode.TO -> { 74 | connections.removeAll { it.to.id == vertex.id } 75 | } 76 | 77 | RemoveVertexMode.FROM -> { 78 | connections.removeAll { it.from.id == vertex.id } 79 | } 80 | 81 | RemoveVertexMode.BOTH -> { 82 | connections.removeAll { it.from.id == vertex.id || it.to.id == vertex.id } 83 | } 84 | } 85 | } 86 | 87 | public fun getFreeVertices(): List> { 88 | val free = mutableListOf>() 89 | vertices.forEach { vertex -> 90 | connections.forEach { connection -> 91 | if (!connection.hasVertex(vertex)) 92 | free.add(vertex) 93 | } 94 | } 95 | return free.toList() 96 | } 97 | 98 | public fun getBusyVertices(): List> { 99 | val free = mutableListOf>() 100 | vertices.forEach { vertex -> 101 | connections.forEach { connection -> 102 | if (connection.hasVertex(vertex)) 103 | free.add(vertex) 104 | } 105 | } 106 | return free.toList() 107 | } 108 | 109 | public fun createConnection(from: Vertex, to: Vertex, weight: W): Connection { 110 | val fromVertex = vertices.find { it.id == from.id } 111 | val toVertex = vertices.find { it.id == to.id } 112 | verify(vertices, from, to) 113 | 114 | hasNegativeWeight = when (weight) { 115 | is Int -> weight < 0 116 | is Long -> weight < 0 117 | is Double -> weight < 0 118 | is Float -> weight < 0 119 | else -> false 120 | } 121 | 122 | fromVertex!! 123 | toVertex!! 124 | 125 | val connection = Connection(from = fromVertex, to = toVertex, weight = weight) 126 | connections.add(connection) 127 | return connection 128 | } 129 | 130 | public fun minPath(from: Vertex, to: Vertex) : GraphPath { 131 | if (from !in vertices || to !in vertices) { 132 | throw VertexNotFoundException() 133 | } 134 | 135 | if (hasNegativeWeight) throw NegativeWeightException() 136 | 137 | val distances = mutableMapOf, Double>() 138 | val previousVertices = mutableMapOf, Vertex?>() 139 | val queue = vertices.toMutableList() 140 | 141 | vertices.forEach { vertex -> 142 | distances[vertex] = Double.MAX_VALUE 143 | previousVertices[vertex] = null 144 | } 145 | distances[from] = 0.0 146 | 147 | while (queue.isNotEmpty()) { 148 | val currentVertex = queue.minByOrNull { distances[it] ?: Double.MAX_VALUE }!! 149 | queue.remove(currentVertex) 150 | 151 | if (currentVertex == to) break 152 | 153 | connections.filter { it.from == currentVertex || (mode == GraphMode.UNDIRECTED && it.to == currentVertex) }.forEach { connection -> 154 | val neighbor = if (connection.from == currentVertex) connection.to else connection.from 155 | val newDist = distances[currentVertex]!! + connection.weight.toDouble() 156 | 157 | if (newDist < distances[neighbor]!!) { 158 | distances[neighbor] = newDist 159 | previousVertices[neighbor] = currentVertex 160 | } 161 | } 162 | } 163 | 164 | val path = mutableListOf, Double>>() 165 | var current: Vertex? = to 166 | while (current != null) { 167 | val weight = distances[current] 168 | path.add(Pair(current, weight!!)) 169 | current = previousVertices[current] 170 | } 171 | 172 | return GraphPath(*path.reversed().toTypedArray()) 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/graph/model/GraphPath.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.model 2 | 3 | class GraphPath constructor( 4 | vararg val path: Pair, W> 5 | ) -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/graph/model/Vertex.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.model 2 | 3 | data class Vertex ( 4 | val id: V 5 | ) -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/graph/model/exception/NegativeWeightException.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.model.exception 2 | 3 | class NegativeWeightException : Exception() { 4 | override val message: String 5 | get() = "Negative weights in graph." 6 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/graph/model/exception/VertexNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.model.exception 2 | 3 | class VertexNotFoundException : Exception() { 4 | override val message: String 5 | get() = "Vertex not found in graph." 6 | override val cause: Throwable? 7 | get() = super.cause 8 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/graph/model/mode/GraphMode.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.model.mode 2 | 3 | enum class GraphMode { 4 | DIRECTED, 5 | UNDIRECTED 6 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/graph/model/mode/RemoveVertexMode.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.model.mode 2 | 3 | enum class RemoveVertexMode { 4 | TO, 5 | FROM, 6 | BOTH 7 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/graph/model/mode/SetVertexMode.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.model.mode 2 | 3 | enum class SetVertexMode { 4 | NEW_FROM, 5 | NEW_TO, 6 | NEW_FROM_TO, 7 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/graph/parent/GraphParent.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.parent 2 | 3 | import more.math.graph.model.Vertex 4 | 5 | abstract class GraphParent { 6 | fun verify(list: List>, from: Vertex, to: Vertex) { 7 | val from_ = list.find { it.id == from.id } 8 | val to_ = list.find { it.id == to.id } 9 | 10 | require(from_ != null && to_ != null) { 11 | "Source or Destination Vertex not found" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/matrix/model/Matrix.kt: -------------------------------------------------------------------------------- 1 | package more.math.matrix.model 2 | 3 | import more.math.matrix.parent.MatrixParent 4 | 5 | public class Matrix(vararg var rows: MutableList) : MatrixParent() { 6 | 7 | @Suppress("UNCHECKED_CAST") 8 | constructor(size: MatrixSize) : this(*Array(size.row) { MutableList(size.column) { null as R } }) { 9 | this.verifyMatrixSize(size = size) 10 | } 11 | 12 | init { 13 | this.verifyContent(*rows) 14 | } 15 | 16 | val size: MatrixSize = MatrixSize(row = rows.size, column = rows[0].size) 17 | 18 | fun column(columnIndex: Int): List { 19 | verifyColumn(this, columnIndex) 20 | val column: List = rows.map { it[columnIndex] } 21 | return column 22 | } 23 | 24 | operator fun get(rowIndex: Int, columnIndex: Int): R { 25 | verify(rows = rows, rowIndex = rowIndex, columnIndex = columnIndex) 26 | return rows[rowIndex][columnIndex] 27 | } 28 | 29 | operator fun set(rowIndex: Int, columnIndex: Int, item: R) { 30 | verify(rows = rows, rowIndex = rowIndex, columnIndex = columnIndex) 31 | rows[rowIndex][columnIndex] = item 32 | } 33 | 34 | @Suppress("UNCHECKED_CAST") 35 | operator fun plus(other: Matrix): Matrix { 36 | verifySize(rows = rows, other = other) 37 | val resultRows = Array(rows.size) { rowIndex -> 38 | List(rows[rowIndex].size) { columnIndex -> 39 | 40 | val unknownValueThis = this.rows[rowIndex][columnIndex] 41 | val thisValue = if (unknownValueThis is Int) { 42 | unknownValueThis 43 | } else { 44 | unknownValueThis as Double 45 | } 46 | 47 | val unknownValueOther = other.rows[rowIndex][columnIndex] 48 | val otherValue = if (unknownValueOther is Int) { 49 | unknownValueOther 50 | } else { 51 | unknownValueOther as Double 52 | } 53 | 54 | if (thisValue is Int && otherValue is Int) { 55 | (thisValue + otherValue) as R 56 | } else if (thisValue is Double && otherValue is Int) { 57 | (thisValue + otherValue) as R 58 | } else if (thisValue is Int && otherValue is Double) { 59 | (thisValue + otherValue) as R 60 | } else { 61 | thisValue as Double 62 | otherValue as Double 63 | (thisValue + otherValue) as R 64 | } 65 | } 66 | } 67 | 68 | return Matrix(*resultRows.map { it.toMutableList() }.toTypedArray()) 69 | } 70 | 71 | @Suppress("UNCHECKED_CAST") 72 | operator fun minus(other: Matrix): Matrix { 73 | verifySize(rows = rows, other = other) 74 | val resultRows = Array(rows.size) { rowIndex -> 75 | List(rows[rowIndex].size) { columnIndex -> 76 | 77 | val unknownValueThis = this.rows[rowIndex][columnIndex] 78 | val thisValue = if (unknownValueThis is Int) { 79 | unknownValueThis 80 | } else { 81 | unknownValueThis as Double 82 | } 83 | 84 | val unknownValueOther = other.rows[rowIndex][columnIndex] 85 | val otherValue = if (unknownValueOther is Int) { 86 | unknownValueOther 87 | } else { 88 | unknownValueOther as Double 89 | } 90 | 91 | if (thisValue is Int && otherValue is Int) { 92 | (thisValue - otherValue) as R 93 | } else if (thisValue is Double && otherValue is Int) { 94 | (thisValue - otherValue) as R 95 | } else if (thisValue is Int && otherValue is Double) { 96 | (thisValue - otherValue) as R 97 | } else { 98 | thisValue as Double 99 | otherValue as Double 100 | (thisValue - otherValue) as R 101 | } 102 | } 103 | } 104 | 105 | return Matrix(*resultRows.map { it.toMutableList() }.toTypedArray()) 106 | } 107 | 108 | operator fun compareTo(other: Matrix): Int { 109 | return this.size.compareTo(other.size) 110 | } 111 | 112 | @Suppress("UNCHECKED_CAST") 113 | operator fun times(other: Matrix): Matrix { 114 | verifyRows(rows = this.rows, other = other) 115 | 116 | val resultRows = Array(rows.size) { rowIndex -> 117 | List(other.rows[0].size) { columnIndex -> 118 | var sum = 0.0 119 | for (k in 0 until rows[0].size) { 120 | 121 | val unknownValueThis = this.rows[rowIndex][k] 122 | val thisValue = if (unknownValueThis is Int) { 123 | unknownValueThis 124 | } else { 125 | unknownValueThis as Double 126 | } 127 | 128 | val unknownValueOther = other.rows[k][columnIndex] 129 | val otherValue = if (unknownValueOther is Int) { 130 | unknownValueOther 131 | } else { 132 | unknownValueOther as Double 133 | } 134 | 135 | if (thisValue is Int && otherValue is Int) { 136 | sum += thisValue * otherValue 137 | } else if (thisValue is Double && otherValue is Int) { 138 | sum += thisValue * otherValue 139 | } else if (thisValue is Int && otherValue is Double) { 140 | sum += thisValue * otherValue 141 | } else { 142 | thisValue as Double 143 | otherValue as Double 144 | sum += thisValue * otherValue 145 | } 146 | } 147 | sum as R 148 | } 149 | } 150 | return Matrix(*resultRows.map { it.toMutableList() }.toTypedArray()) 151 | } 152 | 153 | override fun toString(): String { 154 | return rows.joinToString("\n") { it.joinToString(" ") } 155 | } 156 | 157 | override fun equals(other: Any?): Boolean { 158 | if (this === other) return true 159 | if (other !is Matrix<*>) return false 160 | 161 | if (rows.size != other.rows.size || rows[0].size != other.rows[0].size) return false 162 | 163 | for (i in rows.indices) { 164 | if (rows[i] != other.rows[i]) return false 165 | } 166 | return true 167 | } 168 | 169 | override fun hashCode(): Int { 170 | var result = 1 171 | for (row in rows) { 172 | result = 31 * result + row.hashCode() 173 | } 174 | return result 175 | } 176 | 177 | fun find(predicate: (R) -> Boolean): R? { 178 | for (row in rows.indices) { 179 | for (column in rows[row].indices) { 180 | val el = rows[row][column] 181 | if (predicate(el)){ 182 | return el 183 | } 184 | } 185 | } 186 | return null 187 | } 188 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/matrix/model/MatrixExtension.kt: -------------------------------------------------------------------------------- 1 | package more.math.matrix.model 2 | 3 | import kotlin.math.pow 4 | 5 | //region::Other 6 | public fun Matrix.determinant(): Double { 7 | isSquare(matrix = this) 8 | 9 | if (rows.size == 1) { 10 | return this[0, 0].toDouble() 11 | } 12 | if (rows.size == 2) { 13 | return (this[0, 0].toDouble() * this[1, 1].toDouble() - this[0, 1].toDouble() * this[1, 0].toDouble()) 14 | } 15 | 16 | var det = 0.0 17 | for (j in 0 until rows[0].size) { 18 | val minor = Matrix(*rows.indices.filter { it != 0 }.map { rowIndex -> 19 | rows[rowIndex].indices.filter { it != j }.map { colIndex -> 20 | this[rowIndex, colIndex] 21 | }.toMutableList() 22 | }.toTypedArray()) 23 | 24 | det += (-1.0).pow(j) * this[0, j].toDouble() * minor.determinant() 25 | } 26 | return det 27 | } 28 | 29 | public fun Matrix.transpose(): Matrix { 30 | val transposedRows = Array(rows[0].size) { rowIndex -> 31 | List(rows.size) { colIndex -> 32 | this[colIndex, rowIndex] 33 | } 34 | } 35 | return Matrix(*transposedRows.map { it.toMutableList() }.toTypedArray()) 36 | } 37 | 38 | public fun Matrix.pow(value: Int): Matrix { 39 | this.verifyMatrixPower(value) 40 | var resMatrix = this 41 | var power = value 42 | while (power > 1) { 43 | resMatrix *= resMatrix 44 | power -= 1 45 | } 46 | return resMatrix 47 | } 48 | //endregion 49 | 50 | //region::Times 51 | public fun Matrix.times(value: Int): Matrix { 52 | val map: List> = this.rows.map { rs -> 53 | val newRow = rs.map { item -> 54 | item.toInt() * value 55 | } 56 | newRow 57 | } 58 | return Matrix(*map.map { it.toMutableList() }.toTypedArray()) 59 | } 60 | 61 | public fun Matrix.times(value: Double): Matrix { 62 | val map: List> = this.rows.map { rs -> 63 | val newRow = rs.map { item -> 64 | item.toDouble() * value 65 | } 66 | newRow 67 | } 68 | return Matrix(*map.map { it.toMutableList() }.toTypedArray()) 69 | } 70 | 71 | public fun Matrix.times(value: Float): Matrix { 72 | val map: List> = this.rows.map { rs -> 73 | val newRow = rs.map { item -> 74 | item.toFloat() * value 75 | } 76 | newRow 77 | } 78 | return Matrix(*map.map { it.toMutableList() }.toTypedArray()) 79 | } 80 | 81 | public fun Matrix.times(value: Long): Matrix { 82 | val map: List> = this.rows.map { rs -> 83 | val newRow = rs.map { item -> 84 | item.toLong() * value 85 | } 86 | newRow 87 | } 88 | return Matrix(*map.map { it.toMutableList() }.toTypedArray()) 89 | } 90 | //endregion 91 | 92 | //region::Min in matrix 93 | public inline fun Matrix.minInMatrix(): Int { 94 | var globalMin: Int = Int.MAX_VALUE 95 | var min = 0 96 | this.rows.forEachIndexed { _, rs -> 97 | min = rs.minBy { it } 98 | if (min < globalMin) { 99 | globalMin = min 100 | } 101 | } 102 | return globalMin 103 | } 104 | 105 | public inline fun Matrix.minInMatrix(): Double { 106 | var globalMin: Double = Double.MAX_VALUE 107 | var min = 0.0 108 | this.rows.forEachIndexed { _, rs -> 109 | min = rs.minBy { it } 110 | if (min < globalMin) { 111 | globalMin = min 112 | } 113 | } 114 | return globalMin 115 | } 116 | 117 | public inline fun Matrix.minInMatrix(): Float { 118 | var globalMin: Float = Float.MAX_VALUE 119 | var min = 0.0f 120 | this.rows.forEachIndexed { _, rs -> 121 | min = rs.minBy { it } 122 | if (min < globalMin) { 123 | globalMin = min 124 | } 125 | } 126 | return globalMin 127 | } 128 | 129 | public inline fun Matrix.minInMatrix(): Long { 130 | var globalMin: Long = Long.MAX_VALUE 131 | var min = 0L 132 | this.rows.forEachIndexed { _, rs -> 133 | min = rs.minBy { it } 134 | if (min < globalMin) { 135 | globalMin = min 136 | } 137 | } 138 | return globalMin 139 | } 140 | 141 | public inline fun > Matrix.minInMatrixBy(block: (R) -> T): T { 142 | this.isEmpty(this) 143 | 144 | var minValue: T? = null 145 | 146 | for (row in rows) { 147 | for (element in row) { 148 | val transformedValue = block(element) 149 | 150 | if (minValue == null || transformedValue < minValue) { 151 | minValue = transformedValue 152 | } 153 | } 154 | } 155 | 156 | return minValue ?: throw IllegalStateException("Unable to find minimum value in the matrix.") 157 | } 158 | //endregion 159 | 160 | //region::Max in matrix 161 | public inline fun Matrix.maxInMatrix(): Int { 162 | var globalMax: Int = Int.MIN_VALUE 163 | var max = 0 164 | this.rows.forEachIndexed { _, rs -> 165 | max = rs.maxBy { it } 166 | if (max > globalMax) { 167 | globalMax = max 168 | } 169 | } 170 | return globalMax 171 | } 172 | 173 | public inline fun Matrix.maxInMatrix(): Double { 174 | var globalMax: Double = Double.MIN_VALUE 175 | var max = 0.0 176 | this.rows.forEachIndexed { _, rs -> 177 | max = rs.maxBy { it } 178 | if (max > globalMax) { 179 | globalMax = max 180 | } 181 | } 182 | return globalMax 183 | } 184 | 185 | public inline fun Matrix.maxInMatrix(): Float { 186 | var globalMax: Float = Float.MIN_VALUE 187 | var max = 0.0f 188 | this.rows.forEachIndexed { _, rs -> 189 | max = rs.maxBy { it } 190 | if (max > globalMax) { 191 | globalMax = max 192 | } 193 | } 194 | return globalMax 195 | } 196 | 197 | public inline fun Matrix.maxInMatrix(): Long { 198 | var globalMax: Long = Long.MIN_VALUE 199 | var max = 0L 200 | this.rows.forEachIndexed { _, rs -> 201 | max = rs.maxBy { it } 202 | if (max > globalMax) { 203 | globalMax = max 204 | } 205 | } 206 | return globalMax 207 | } 208 | 209 | public inline fun > Matrix.maxInMatrixBy(block: (R) -> T): T { 210 | this.isEmpty(this) 211 | 212 | var maxValue: T? = null 213 | 214 | for (row in rows) { 215 | for (element in row) { 216 | val transformedValue = block(element) 217 | 218 | if (maxValue == null || transformedValue > maxValue) { 219 | maxValue = transformedValue 220 | } 221 | } 222 | } 223 | 224 | return maxValue ?: throw IllegalStateException("Unable to find maximum value in the matrix.") 225 | } 226 | //endregion -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/matrix/model/MatrixSize.kt: -------------------------------------------------------------------------------- 1 | package more.math.matrix.model 2 | 3 | data class MatrixSize( 4 | val row: Int, 5 | val column: Int 6 | ) { 7 | operator fun compareTo(other: MatrixSize): Int { 8 | return (this.row * this.column).compareTo(other.row * other.column) 9 | } 10 | 11 | operator fun plus(other: MatrixSize): MatrixSize { 12 | return MatrixSize(row = this.row + other.row, column = this.column + other.column) 13 | } 14 | 15 | operator fun minus(other: MatrixSize): MatrixSize { 16 | return MatrixSize(row = this.row - other.row, column = this.column - other.column) 17 | } 18 | 19 | operator fun times(other: MatrixSize): MatrixSize { 20 | return MatrixSize(row = this.row * other.row, column = this.column * other.column) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/matrix/parent/MatrixParent.kt: -------------------------------------------------------------------------------- 1 | package more.math.matrix.parent 2 | 3 | import more.math.matrix.model.Matrix 4 | import more.math.matrix.model.MatrixSize 5 | 6 | abstract class MatrixParent { 7 | fun verify(rows: Array>, rowIndex: Int, columnIndex: Int) { 8 | require(rowIndex in rows.indices) { "Row index out of bounds." } 9 | require(columnIndex in rows[rowIndex].indices) { "Column index out of bounds." } 10 | } 11 | 12 | fun verifySize(rows: Array>, other: Matrix) { 13 | require(rows.size == other.rows.size && rows[0].size == other.rows[0].size) { 14 | "Matrices must have the same dimensions for addition." 15 | } 16 | } 17 | 18 | fun verifyRows(rows: Array>, other: Matrix) { 19 | require(rows.size == other.rows[0].size) { 20 | "Number of columns of the first matrix must be equal to the number of rows of the second matrix." 21 | } 22 | } 23 | 24 | fun isSquare(matrix: Matrix) { 25 | require(matrix.rows.size == matrix.rows[0].size) { 26 | "Number of rows must be equals number of columns." 27 | } 28 | } 29 | 30 | fun verifyColumn(matrix: Matrix, columnIndex: Int) { 31 | require(columnIndex in matrix.rows.indices) { 32 | "Column index is out of matrix size." 33 | } 34 | } 35 | 36 | fun verifyMatrixPower(power: Int) { 37 | require(power > 1) { 38 | "Power must be more than 1." 39 | } 40 | } 41 | 42 | fun isEmpty(matrix: Matrix) { 43 | require(matrix.rows.isNotEmpty() && matrix.rows[0].isNotEmpty()) { "Matrix cannot be empty." } 44 | } 45 | 46 | fun verifyContent(vararg rows: MutableList) { 47 | val rowSize = rows[0].size 48 | rows.forEachIndexed { _, rs -> 49 | require(rs.size == rowSize) { 50 | "Items in each row must be equals." 51 | } 52 | } 53 | } 54 | 55 | fun verifyMatrixSize(size: MatrixSize) { 56 | require(size.column > 0 && size.row > 0) { 57 | "Matrix size must be positive." 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/native/model/NativeProvider.kt: -------------------------------------------------------------------------------- 1 | package more.math.native.model 2 | 3 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 4 | internal expect class NativeProvider constructor() { 5 | 6 | //region::hyper operators 7 | fun nativeFactorial(number: Int): Long 8 | 9 | fun nativeFactorial(number: Long): Long 10 | 11 | fun nativeAverage(vararg numbers: Int) : Double 12 | 13 | fun standardDeviation(vararg numbers: Double) : Double 14 | 15 | fun tetraction(number: Double, other: Int) : Double 16 | 17 | fun gcd(a: Int, b: Int): Int 18 | //endregion 19 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/platform/model/BigFloat.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 4 | expect class BigFloat(value: String) { 5 | companion object { 6 | val ZERO: BigFloat 7 | val ONE: BigFloat 8 | } 9 | fun add(other: BigFloat): BigFloat 10 | fun multiply(other: BigFloat): BigFloat 11 | override fun toString(): String 12 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/platform/model/BigInt.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 4 | expect class BigInt(value: String) { 5 | companion object { 6 | val ZERO: BigInt 7 | val ONE: BigInt 8 | } 9 | fun add(other: BigInt): BigInt 10 | fun multiply(other: BigInt): BigInt 11 | override fun toString(): String 12 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/tetraction/TetractionParent.kt: -------------------------------------------------------------------------------- 1 | package more.math.tetraction 2 | 3 | class TetractionParent { 4 | fun verify(number: Double, other: Int) { 5 | require(number >= 0 && other >= 0) { 6 | "Both arguments must be more than zero" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/vector/model/Vector2.kt: -------------------------------------------------------------------------------- 1 | package more.math.vector.model 2 | 3 | @Suppress("UNCHECKED_CAST") 4 | public data class Vector2(val x: T, val y: T) { 5 | 6 | operator fun plus(other: Vector2): Vector2 { 7 | return Vector2( 8 | x = when (x) { 9 | is Double -> (x.toDouble() + other.x.toDouble()) as T 10 | is Float -> (x.toFloat() + other.x.toFloat()) as T 11 | is Int -> (x.toInt() + other.x.toInt()) as T 12 | is Long -> (x.toLong() + other.x.toLong()) as T 13 | else -> throw IllegalArgumentException("Unsupported type") 14 | }, 15 | y = when (y) { 16 | is Double -> (y.toDouble() + other.y.toDouble()) as T 17 | is Float -> (y.toFloat() + other.y.toFloat()) as T 18 | is Int -> (y.toInt() + other.y.toInt()) as T 19 | is Long -> (y.toLong() + other.y.toLong()) as T 20 | else -> throw IllegalArgumentException("Unsupported type") 21 | } 22 | ) 23 | } 24 | 25 | operator fun minus(other: Vector2): Vector2 { 26 | return Vector2( 27 | x = when (x) { 28 | is Double -> (x.toDouble() - other.x.toDouble()) as T 29 | is Float -> (x.toFloat() - other.x.toFloat()) as T 30 | is Int -> (x.toInt() - other.x.toInt()) as T 31 | is Long -> (x.toLong() - other.x.toLong()) as T 32 | else -> throw IllegalArgumentException("Unsupported type") 33 | }, 34 | y = when (y) { 35 | is Double -> (y.toDouble() - other.y.toDouble()) as T 36 | is Float -> (y.toFloat() - other.y.toFloat()) as T 37 | is Int -> (y.toInt() - other.y.toInt()) as T 38 | is Long -> (y.toLong() - other.y.toLong()) as T 39 | else -> throw IllegalArgumentException("Unsupported type") 40 | } 41 | ) 42 | } 43 | 44 | operator fun times(other: Vector2): Vector2 { 45 | return Vector2( 46 | x = when (x) { 47 | is Double -> (x.toDouble() * other.x.toDouble()) as T 48 | is Float -> (x.toFloat() * other.x.toFloat()) as T 49 | is Int -> (x.toInt() * other.x.toInt()) as T 50 | is Long -> (x.toLong() * other.x.toLong()) as T 51 | else -> throw IllegalArgumentException("Unsupported type") 52 | }, 53 | y = when (y) { 54 | is Double -> (y.toDouble() * other.y.toDouble()) as T 55 | is Float -> (y.toFloat() * other.y.toFloat()) as T 56 | is Int -> (y.toInt() * other.y.toInt()) as T 57 | is Long -> (y.toLong() * other.y.toLong()) as T 58 | else -> throw IllegalArgumentException("Unsupported type") 59 | } 60 | ) 61 | } 62 | 63 | operator fun div(other: Vector2): Vector2 { 64 | return Vector2( 65 | x = when (x) { 66 | is Double -> (x.toDouble() / other.x.toDouble()) as T 67 | is Float -> (x.toFloat() / other.x.toFloat()) as T 68 | is Int -> (x.toInt() / other.x.toInt()) as T 69 | is Long -> (x.toLong() / other.x.toLong()) as T 70 | else -> throw IllegalArgumentException("Unsupported type") 71 | }, 72 | y = when (y) { 73 | is Double -> (y.toDouble() / other.y.toDouble()) as T 74 | is Float -> (y.toFloat() / other.y.toFloat()) as T 75 | is Int -> (y.toInt() / other.y.toInt()) as T 76 | is Long -> (y.toLong() / other.y.toLong()) as T 77 | else -> throw IllegalArgumentException("Unsupported type") 78 | } 79 | ) 80 | } 81 | 82 | override fun toString(): String { 83 | return "[x: $x; y: $y]" 84 | } 85 | 86 | override fun equals(other: Any?): Boolean { 87 | if (this === other) return true 88 | if (other !is Vector2<*>) return false 89 | return (x.toDouble() == other.x.toDouble() && y.toDouble() == other.y.toDouble()) 90 | } 91 | 92 | // Переопределение hashCode 93 | override fun hashCode(): Int { 94 | var result = x.hashCode() 95 | result = 31 * result + y.hashCode() 96 | return result 97 | } 98 | } -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/more/math/vector/model/Vector2Extensions.kt: -------------------------------------------------------------------------------- 1 | package more.math.vector.model 2 | 3 | public fun Vector2.length(): Double { 4 | return kotlin.math.sqrt(this.x * this.x + this.y * this.y) 5 | } -------------------------------------------------------------------------------- /library/src/commonTest/kotlin/more/math/ExtensionsKtTest.kt: -------------------------------------------------------------------------------- 1 | package more.math 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertTrue 5 | 6 | class ExtensionsKtTest { 7 | 8 | @Test 9 | fun isPositiveOrNegative() { 10 | assertTrue(2.isPositive) 11 | assertTrue(2.0.isPositive) 12 | assertTrue(2.0f.isPositive) 13 | assertTrue(2L.isPositive) 14 | 15 | assertTrue((-2).isNegative) 16 | assertTrue((-2.0).isNegative) 17 | assertTrue((-2.0f).isNegative) 18 | assertTrue((-2L).isNegative) 19 | } 20 | } -------------------------------------------------------------------------------- /library/src/commonTest/kotlin/more/math/combinatorics/CombinatoricsTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.combinatorics 2 | 3 | import more.math.MoreMath 4 | import kotlin.test.Test 5 | import kotlin.test.assertEquals 6 | import kotlin.test.assertFails 7 | 8 | class CombinatoricsTest { 9 | 10 | @Test 11 | fun testCombinations() { 12 | assertEquals(1, MoreMath.combinations(0, 0)) 13 | assertEquals(1, MoreMath.combinations(5, 0)) 14 | assertEquals(10, MoreMath.combinations(5, 2)) 15 | assertEquals(1, MoreMath.combinations(5, 5)) 16 | assertEquals(1, MoreMath.combinations(5, 5)) 17 | } 18 | 19 | @Test 20 | fun testPermutations() { 21 | assertEquals(1, MoreMath.placements(0, 0)) 22 | assertEquals(5, MoreMath.placements(5, 1)) 23 | assertEquals(20, MoreMath.placements(5, 2)) 24 | assertEquals(120, MoreMath.placements(5, 5)) 25 | } 26 | 27 | @Test 28 | fun testBinomialCoefficient() { 29 | assertEquals(1, MoreMath.binomialCoefficient(0, 0)) 30 | assertEquals(1, MoreMath.binomialCoefficient(5, 0)) 31 | assertEquals(10, MoreMath.binomialCoefficient(5, 2)) 32 | assertEquals(1, MoreMath.binomialCoefficient(5, 5)) 33 | } 34 | 35 | @Test 36 | fun testInvalidInputs() { 37 | assertFails { 38 | MoreMath.combinations(5, 6) 39 | } 40 | assertFails { 41 | MoreMath.placements(5, 6) 42 | } 43 | assertFails { 44 | MoreMath.binomialCoefficient(5, 6) 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /library/src/commonTest/kotlin/more/math/complex/model/ComplexTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.complex.model 2 | 3 | import more.math.complex 4 | import kotlin.test.Test 5 | import kotlin.test.assertEquals 6 | import kotlin.test.assertTrue 7 | 8 | class ComplexTest { 9 | 10 | @Test 11 | fun creationOfComplexNumber() { 12 | val complex: Complex = complex(3, -4.0) 13 | assertEquals(3.0, complex.realPart.toDouble()) 14 | assertEquals(-2.0, complex.imaginaryPart) 15 | 16 | val complex2 = complex( -4.0) 17 | assertEquals(-2.0, complex2.imaginaryPart) 18 | } 19 | 20 | @Test 21 | fun sumOfComplexNumbers() { 22 | val complex1 = complex(2, 9.0) 23 | val complex2 = complex(1, 16.0) 24 | val result = complex1 + complex2 25 | assertEquals(3.0, result.realPart.toDouble()) 26 | assertEquals(7.0, result.imaginaryPart) 27 | } 28 | 29 | @Test 30 | fun minusOfComplexNumbers() { 31 | val complex1 = complex(5, 9.0) 32 | val complex2 = complex(2, 1.0) 33 | val result = complex1 - complex2 34 | assertEquals(3.0, result.realPart.toDouble()) 35 | assertEquals(2.0, result.imaginaryPart) 36 | } 37 | 38 | @Test 39 | fun timeOfComplexNumbers() { 40 | val complex1 = complex(1, 4.0) 41 | val complex2 = complex(3, 16.0) 42 | val result = complex1 * complex2 43 | assertEquals(-5.0, result.realPart.toDouble()) 44 | assertEquals(10.0, result.imaginaryPart) 45 | } 46 | 47 | @Test 48 | fun divisionOfComplexNumbers() { 49 | val complex1 = complex(1, 4.0) 50 | val complex2 = complex(3, 16.0) 51 | val result = complex1 / complex2 52 | assertEquals(0.44, result.realPart.toDouble(), 0.01) 53 | assertEquals(0.08, result.imaginaryPart, 0.01) 54 | } 55 | 56 | @Test 57 | fun testEquals() { 58 | val complex1 = complex(2, -4.0) 59 | val complex2 = complex(2, -4.0) 60 | assertTrue { 61 | complex1 == complex2 62 | } 63 | } 64 | 65 | @Test 66 | fun testAlgebraicForm() { 67 | assertEquals("2 - 3.0i", complex(2, -9.0).toAlgebraic()) 68 | assertEquals("2 + 3.0i", complex(2, 9.0).toAlgebraic()) 69 | } 70 | 71 | @Test 72 | fun testGeometricForm() { 73 | val complex = complex(3, 16.0) 74 | assertEquals("5.0 * (cos(0.9272952180016122) + i * sin(0.9272952180016122))", complex.toGeometric()) 75 | } 76 | } -------------------------------------------------------------------------------- /library/src/commonTest/kotlin/more/math/factorial/FactorialTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.factorial 2 | 3 | import more.math.MoreMath 4 | import kotlin.test.Test 5 | import kotlin.test.assertEquals 6 | import kotlin.test.assertFails 7 | 8 | class FactorialTest { 9 | 10 | @Test 11 | fun testFactorial() { 12 | assertEquals(expected = 6L, actual = MoreMath.factorial(n = 3)) 13 | assertEquals(expected = 1L, actual = MoreMath.factorial(n = 0)) 14 | assertEquals(expected = 1L, actual = MoreMath.factorial(n = 1)) 15 | assertEquals(expected = 6L, actual = MoreMath.factorial(n = 3L)) 16 | } 17 | 18 | @Test 19 | fun testFactorialFails() { 20 | assertFails { 21 | MoreMath.factorial(n = -3) 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /library/src/commonTest/kotlin/more/math/graph/model/GraphTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.graph.model 2 | 3 | import more.math.graph.model.mode.GraphMode 4 | import more.math.graph.model.mode.SetVertexMode 5 | import more.math.matrix.model.Matrix 6 | import more.math.matrixOf 7 | import kotlin.test.Test 8 | import kotlin.test.assertEquals 9 | import kotlin.test.assertFails 10 | import kotlin.test.assertNull 11 | 12 | class GraphTest { 13 | 14 | @Test 15 | fun testGraphFakeVertex() { 16 | val graph = Graph, Int>() 17 | 18 | val m1 = matrixOf( 19 | mutableListOf(1, 2), 20 | mutableListOf(3, 4) 21 | ) 22 | val m2 = matrixOf( 23 | mutableListOf(5, 6), 24 | mutableListOf(7, 8) 25 | ) 26 | val m3 = matrixOf(mutableListOf(0), mutableListOf(0)) 27 | 28 | graph.addVertex( 29 | Vertex( 30 | id = m1 31 | ) 32 | ) 33 | graph.addVertex( 34 | Vertex( 35 | id = m2 36 | ) 37 | ) 38 | 39 | graph.createConnection(from = Vertex(id = m1), to = Vertex(id = m2), weight = 2) 40 | assertFails { 41 | graph.createConnection(Vertex(id = m1), Vertex(id = m3), weight = 3) 42 | } 43 | 44 | val vertex = graph[Vertex(id = m1)] 45 | assertEquals( 46 | expected = Vertex(id = m1), 47 | actual = vertex 48 | ) 49 | assertEquals(expected = 2, actual = graph.vertices.size) 50 | } 51 | 52 | @Test 53 | fun get() { 54 | val graph = Graph() 55 | 56 | graph.addVertex(Vertex(id = "A")) 57 | graph.addVertex(Vertex(id = "B")) 58 | 59 | graph.createConnection(from = Vertex(id = "A"), to = Vertex(id = "B"), weight = 2) 60 | 61 | val vertex = graph[Vertex(id = "A")] 62 | assertEquals( 63 | expected = Vertex(id = "A"), 64 | actual = vertex 65 | ) 66 | assertNull(graph[Vertex(id = "C")]) 67 | } 68 | 69 | @Test 70 | fun sizes() { 71 | val graph = Graph() 72 | 73 | graph.addVertex(Vertex(id = "A")) 74 | graph.addVertex(Vertex(id = "B")) 75 | 76 | graph.createConnection(from = Vertex(id = "A"), to = Vertex(id = "B"), weight = 2) 77 | 78 | assertEquals(expected = 2, actual = graph.vertices.size) 79 | assertEquals(expected = 1, actual = graph.connections.size) 80 | } 81 | 82 | @Test 83 | fun testConnections() { 84 | val graph = Graph() 85 | 86 | graph.addVertex(Vertex(id = "A")) 87 | graph.addVertex(Vertex(id = "B")) 88 | 89 | graph.createConnection(from = Vertex(id = "A"), to = Vertex(id = "B"), weight = 2) 90 | 91 | assertEquals(expected = 1, actual = graph.connections.size) 92 | } 93 | 94 | @Test 95 | fun testSetVertexMode() { 96 | val graph = Graph() 97 | 98 | val vertexA = Vertex(id = "A") 99 | val vertexB = Vertex(id = "B") 100 | val vertexC = Vertex(id = "C") 101 | val vertexD = Vertex(id = "D") 102 | 103 | graph.addVertex(vertexA) 104 | graph.addVertex(vertexB) 105 | graph.addVertex(vertexD) 106 | 107 | graph.createConnection(from = vertexA, to = vertexB, weight = 2) 108 | graph.createConnection(from = vertexA, to = vertexD, weight = 5) 109 | 110 | graph.set(oldVertex = vertexA, newVertex = vertexC, setVertexMode = SetVertexMode.NEW_FROM) 111 | 112 | assertEquals(expected = vertexC, actual = graph[vertexC]) 113 | assertEquals(expected = 2, actual = graph.connections.size) 114 | 115 | graph.set(oldVertex = vertexC, newVertex = vertexA, setVertexMode = SetVertexMode.NEW_TO) 116 | 117 | assertEquals(expected = vertexA, actual = graph[vertexA]) 118 | assertEquals(expected = 2, actual = graph.connections.size) 119 | 120 | graph.createConnection(from = vertexD, to = vertexA, weight = 5) 121 | graph.createConnection(from = vertexA, to = vertexD, weight = 10) 122 | 123 | graph.set( 124 | oldVertex = vertexA, 125 | newVertex = vertexC, 126 | setVertexMode = SetVertexMode.NEW_FROM_TO 127 | ) 128 | 129 | assertEquals(expected = vertexC, actual = graph[vertexC]) 130 | assertEquals(expected = 4, actual = graph.connections.size) 131 | } 132 | 133 | @Test 134 | fun freeVertices() { 135 | val graph = Graph() 136 | 137 | val vertexA = Vertex(id = "A") 138 | val vertexB = Vertex(id = "B") 139 | val vertexC = Vertex(id = "C") 140 | val vertexD = Vertex(id = "D") 141 | 142 | graph.addVertex(vertexA) 143 | graph.addVertex(vertexB) 144 | graph.addVertex(vertexC) 145 | graph.addVertex(vertexD) 146 | 147 | graph.createConnection(from = vertexA, to = vertexB, weight = 2) 148 | assertEquals(expected = 2, graph.getFreeVertices().size) 149 | assertEquals(expected = 2, graph.getBusyVertices().size) 150 | } 151 | 152 | @Test 153 | fun testMinPathFunUndirectedGraph() { 154 | val graph = Graph(mode = GraphMode.UNDIRECTED) 155 | 156 | val vertexA = Vertex(id = "A") 157 | val vertexB = Vertex(id = "B") 158 | val vertexC = Vertex(id = "C") 159 | val vertexD = Vertex(id = "D") 160 | val vertexE = Vertex(id = "E") 161 | 162 | graph.addVertex(vertexA) 163 | graph.addVertex(vertexB) 164 | graph.addVertex(vertexC) 165 | graph.addVertex(vertexD) 166 | graph.addVertex(vertexE) 167 | 168 | graph.createConnection(from = vertexA, to = vertexB, weight = 2) 169 | graph.createConnection(from = vertexB, to = vertexC, weight = 5) 170 | graph.createConnection(from = vertexC, to = vertexD, weight = 6) 171 | graph.createConnection(from = vertexA, to = vertexD, weight = 17) 172 | 173 | val minPath1: GraphPath = graph.minPath(from = vertexA, to = vertexD) 174 | val expected1 = GraphPath( 175 | Pair(vertexA, 0.0), 176 | Pair(vertexB, 2.0), 177 | Pair(vertexC, 7.0), 178 | Pair(vertexD, 13.0), 179 | ) 180 | assertEquals(expected = expected1.path[2], actual = minPath1.path[2]) 181 | 182 | graph.createConnection(from = vertexB, to = vertexE, weight = 1) 183 | graph.createConnection(from = vertexE, to = vertexD, weight = 3) 184 | 185 | val minPath2: GraphPath = graph.minPath(from = vertexA, to = vertexD) 186 | val expected2 = GraphPath( 187 | Pair(vertexA, 0.0), 188 | Pair(vertexB, 2.0), 189 | Pair(vertexE, 3.0), 190 | Pair(vertexD, 6.0), 191 | ) 192 | assertEquals(expected = expected2.path[2].second, actual = minPath2.path[2].second) 193 | 194 | graph.createConnection(from = vertexE, to = vertexA, weight = -3) 195 | assertFails { 196 | graph.minPath(from = vertexA, to = vertexD) 197 | } 198 | } 199 | } -------------------------------------------------------------------------------- /library/src/commonTest/kotlin/more/math/matrix/model/MatrixExtensionKtTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.matrix.model 2 | 3 | import more.math.complex 4 | import more.math.complex.model.Complex 5 | import more.math.matrixOf 6 | import kotlin.test.BeforeTest 7 | import kotlin.test.Test 8 | import kotlin.test.assertEquals 9 | import kotlin.test.assertFails 10 | import kotlin.test.assertNull 11 | import kotlin.test.assertTrue 12 | import kotlin.test.assertTrue 13 | 14 | class MatrixExtensionKtTest { 15 | 16 | private lateinit var matrix: Matrix 17 | 18 | @BeforeTest 19 | fun setUp() { 20 | matrix = matrixOf( 21 | mutableListOf(1, 2.5, 3), 22 | mutableListOf(4.0, 5, 6) 23 | ) 24 | } 25 | 26 | @Test 27 | fun testMatrixFunctions() { 28 | val number: Number = matrix[0, 0] 29 | assertEquals(expected = 1, actual = number) 30 | } 31 | 32 | @Test 33 | fun sumMatrix() { 34 | val matrix1 = matrixOf( 35 | mutableListOf(1, 2, 3), 36 | mutableListOf(4, 5, 6) 37 | ) 38 | 39 | val matrix2 = Matrix( 40 | mutableListOf(7, 8, 9), 41 | mutableListOf(10, 11, 12) 42 | ) 43 | 44 | val sumMatrix = matrix1 + matrix2 45 | 46 | val expectedMatrix = matrixOf( 47 | mutableListOf(8, 10, 12), 48 | mutableListOf(14, 16, 18) 49 | ) 50 | 51 | assertEquals(expected = expectedMatrix, actual = sumMatrix) 52 | } 53 | 54 | @Test 55 | fun minusTest() { 56 | val matrix1 = matrixOf( 57 | mutableListOf(1, 2, 3), 58 | mutableListOf(4, 5, 6) 59 | ) 60 | 61 | val matrix2 = Matrix( 62 | mutableListOf(7, 8, 9), 63 | mutableListOf(10, 11, 12) 64 | ) 65 | 66 | val minusMatrix = matrix1 - matrix2 67 | 68 | val expectedMatrix = matrixOf( 69 | mutableListOf(-6, -6, -6), 70 | mutableListOf(-6, -6, -6) 71 | ) 72 | 73 | assertEquals(expected = expectedMatrix, actual = minusMatrix) 74 | } 75 | 76 | @Test 77 | fun timesTest() { 78 | val matrix1 = matrixOf( 79 | mutableListOf(1.0, 2.0, 3.0), 80 | mutableListOf(4.0, 5.0, 6.0) 81 | ) 82 | 83 | val matrix2 = Matrix( 84 | mutableListOf(7.0, 8.0), 85 | mutableListOf(9.0, 10.0), 86 | mutableListOf(11.0, 12.0) 87 | ) 88 | 89 | val timesMatrix = matrix1 * matrix2 90 | 91 | val expectedMatrix = matrixOf( 92 | mutableListOf(58.0, 64.0), 93 | mutableListOf(139.0, 154.0) 94 | ) 95 | 96 | assertEquals(expected = expectedMatrix, actual = timesMatrix) 97 | } 98 | 99 | @Test 100 | fun squareDeterminant() { 101 | val matrix = matrixOf( 102 | mutableListOf(1.0, 2.0), 103 | mutableListOf(3.0, 4.0) 104 | ) 105 | 106 | val determinant = matrix.determinant() 107 | 108 | assertEquals(expected = -2.0, actual = determinant) 109 | } 110 | 111 | @Test 112 | fun squareBigDeterminant() { 113 | val matrix = matrixOf( 114 | mutableListOf(1.0, 2.0, 3.0, 4.0), 115 | mutableListOf(5.0, 6.0, 7.0, 8.0), 116 | mutableListOf(9.0, 10.0, 11.0, 12.0), 117 | mutableListOf(13.0, 14.0, 15.0, 16.0), 118 | ) 119 | 120 | val determinant = matrix.determinant() 121 | 122 | assertEquals(expected = 0.0, actual = determinant) 123 | } 124 | 125 | @Test 126 | fun transposeTest() { 127 | val matrix1 = matrixOf( 128 | mutableListOf(1, 2, 3), 129 | mutableListOf(4, 5, 6) 130 | ).transpose() 131 | 132 | val expected = matrixOf( 133 | mutableListOf(1, 4), 134 | mutableListOf(2, 5), 135 | mutableListOf(3, 6) 136 | ) 137 | 138 | assertEquals(expected = expected, actual = matrix1) 139 | } 140 | 141 | @Test 142 | fun testFails() { 143 | assertFails { 144 | matrix[99, 1] 145 | } 146 | assertFails { 147 | matrix[1, 99] 148 | } 149 | assertFails { 150 | val matrix1 = matrixOf( 151 | mutableListOf(1, 2, 3), 152 | mutableListOf(4, 5, 6) 153 | ) 154 | val matrix2 = matrixOf( 155 | mutableListOf(1, 4), 156 | mutableListOf(2, 5), 157 | mutableListOf(3, 6) 158 | ) 159 | matrix1 + matrix2 160 | } 161 | assertFails { 162 | val matrix1 = matrixOf( 163 | mutableListOf(1, 2, 3), 164 | mutableListOf(4, 5, 6) 165 | ) 166 | val matrix2 = matrixOf( 167 | mutableListOf(1, 4), 168 | mutableListOf(2, 5), 169 | mutableListOf(3, 6) 170 | ) 171 | matrix1 - matrix2 172 | } 173 | 174 | assertFails { 175 | val matrix1 = matrixOf( 176 | mutableListOf(1, 2), 177 | mutableListOf(3, 4), 178 | mutableListOf(5, 6), 179 | mutableListOf(7, 8) 180 | ) 181 | val matrix2 = matrixOf( 182 | mutableListOf(1, 4), 183 | mutableListOf(2, 5), 184 | mutableListOf(3, 6) 185 | ) 186 | matrix1 * matrix2 187 | } 188 | assertFails { 189 | matrix.determinant() 190 | } 191 | } 192 | 193 | @Test 194 | fun timesByNumber() { 195 | val matrixInt = Matrix( 196 | mutableListOf(1, 2), 197 | mutableListOf(3, 4) 198 | ) 199 | val matrixDouble = Matrix( 200 | mutableListOf(1.0, 2.0), 201 | mutableListOf(3.0, 4.0) 202 | ) 203 | 204 | val resMatrix1 = Matrix( 205 | mutableListOf(2, 4), 206 | mutableListOf(6, 8) 207 | ) 208 | val resMatrix2 = Matrix( 209 | mutableListOf(2.0, 4.0), 210 | mutableListOf(6.0, 8.0) 211 | ) 212 | 213 | assertEquals(expected = matrixInt.times(2), actual = resMatrix1) 214 | assertEquals(expected = matrixDouble.times(2.0), actual = resMatrix2) 215 | } 216 | 217 | @Test 218 | fun columnTest() { 219 | val matrixInt = Matrix( 220 | mutableListOf(1, 2, 3), 221 | mutableListOf(4, 5, 6), 222 | mutableListOf(7, 8, 9) 223 | ) 224 | assertEquals(mutableListOf(1, 4, 7), matrixInt.column(0)) 225 | assertEquals(mutableListOf(2, 5, 8), matrixInt.column(1)) 226 | assertEquals(mutableListOf(3, 6, 9), matrixInt.column(2)) 227 | assertFails { 228 | matrixInt.column(4) 229 | matrixInt.column(-4) 230 | } 231 | } 232 | 233 | @Test 234 | fun testPowMatrix() { 235 | val matrixDouble = Matrix( 236 | mutableListOf(1.0, 2.0), 237 | mutableListOf(3.0, 4.0) 238 | ) 239 | val matrixDoubleRes = Matrix( 240 | mutableListOf(7.0, 10.0), 241 | mutableListOf(15.0, 22.0) 242 | ) 243 | 244 | assertEquals(expected = matrixDoubleRes, actual = matrixDouble.pow(2)) 245 | } 246 | 247 | @Test 248 | fun minItemInMatrix() { 249 | val matrix1 = matrixOf( 250 | mutableListOf(1, 2), 251 | mutableListOf(3, 4), 252 | mutableListOf(-1, -2), 253 | ) 254 | 255 | val min1 = matrix1.minInMatrix() 256 | assertEquals(expected = -2, actual = min1) 257 | 258 | val matrix2 = matrixOf( 259 | mutableListOf(1f, 2f), 260 | mutableListOf(3f, 4f), 261 | mutableListOf(-1f, -2f), 262 | ) 263 | 264 | val min2 = matrix2.minInMatrix() 265 | assertEquals(expected = -2f, actual = min2) 266 | 267 | val matrix3 = matrixOf( 268 | mutableListOf(1L, 2L), 269 | mutableListOf(3L, 4L), 270 | mutableListOf(-1L, -2L), 271 | ) 272 | 273 | val min3 = matrix3.minInMatrix() 274 | assertEquals(expected = -2L, actual = min3) 275 | 276 | val matrix4 = matrixOf( 277 | mutableListOf(1.0, 2.0), 278 | mutableListOf(3.0, 4.0), 279 | mutableListOf(-1.0, -2.0), 280 | ) 281 | 282 | val min4 = matrix4.minInMatrix() 283 | assertEquals(expected = -2.0, actual = min4) 284 | 285 | val matrix5 = matrixOf( 286 | mutableListOf(complex(3, -16.0), complex(3, -4.0)), 287 | mutableListOf(complex(3, 25.0), complex(3, -36.0)), 288 | mutableListOf(complex(3, -49.0), complex(3, 36.0)), 289 | ) 290 | 291 | assertEquals(expected = -7.0, actual = matrix5.minInMatrixBy { it.imaginaryPart }) 292 | } 293 | 294 | @Test 295 | fun maxItemInMatrix() { 296 | val matrix5 = matrixOf( 297 | mutableListOf(complex(3, -16.0), complex(3, -4.0)), 298 | mutableListOf(complex(3, 25.0), complex(3, -36.0)), 299 | mutableListOf(complex(3, -49.0), complex(3, 36.0)), 300 | ) 301 | assertEquals(expected = 6.0, actual = matrix5.maxInMatrixBy { it.imaginaryPart }) 302 | } 303 | 304 | @Test 305 | fun strMatrix() { 306 | val matrix = matrixOf( 307 | mutableListOf("a", "b"), 308 | mutableListOf("c", "d") 309 | ) 310 | assertEquals(expected = "a", actual = matrix[0, 0]) 311 | 312 | val matrix2 = matrixOf( 313 | mutableListOf( 314 | Complex(realPart = 1, imaginaryPart = -16.0), 315 | Complex(realPart = 2, imaginaryPart = -16.0) 316 | ), 317 | mutableListOf( 318 | Complex(realPart = 3, imaginaryPart = -16.0), 319 | Complex(realPart = 4, imaginaryPart = -16.0) 320 | ) 321 | ) 322 | assertEquals( 323 | expected = Complex(realPart = 1, imaginaryPart = -16.0), 324 | actual = matrix2[0, 0] 325 | ) 326 | 327 | assertFails { 328 | val sum = matrix + matrix 329 | val sum2 = matrix2 + matrix2 330 | } 331 | } 332 | 333 | @Test 334 | fun set() { 335 | val matrix1 = matrixOf( 336 | mutableListOf(1, 2, 3), 337 | mutableListOf(4, 5, 6) 338 | ) 339 | val matrix2 = matrixOf( 340 | mutableListOf(1, 2, 3), 341 | mutableListOf(4, -1, 6) 342 | ) 343 | matrix1[1, 1] = -1 344 | assertEquals(matrix1, matrix2) 345 | } 346 | 347 | @Test 348 | fun matrixSize() { 349 | val matrix = matrixOf( 350 | mutableListOf(1, 2, 3), 351 | mutableListOf(4, 5, 6) 352 | ) 353 | 354 | val size = matrix.size 355 | 356 | assertEquals(MatrixSize(2, 3), size) 357 | } 358 | 359 | @Test 360 | fun verifyContent() { 361 | assertFails { 362 | matrixOf( 363 | mutableListOf(1, 2, 3), 364 | mutableListOf(4, 5, 6), 365 | mutableListOf(7, 8, 9, 10, 11) 366 | ) 367 | 368 | matrixOf( 369 | mutableListOf(7, 8, 9, 10, 11), 370 | mutableListOf(1, 2, 3), 371 | mutableListOf(4, 5, 6) 372 | ) 373 | 374 | matrixOf( 375 | mutableListOf("1", "1", "1", "1"), 376 | mutableListOf(4, 5, 6) 377 | ) 378 | } 379 | } 380 | 381 | @Test 382 | fun matrixSizeWithConstructor() { 383 | val matrix1 = Matrix(size = MatrixSize(row = 3, column = 4)) 384 | val matrix2 = Matrix(size = MatrixSize(row = 1, column = 1)) 385 | 386 | assertEquals(expected = matrix1.size, actual = MatrixSize(3, 4)) 387 | assertFails { matrix1[1, 1] as Int} 388 | assertEquals(expected = matrix2.rows.size, 1) 389 | assertFails { 390 | Matrix(size = MatrixSize(row = -3, column = -4)) 391 | } 392 | } 393 | 394 | @Test 395 | fun compareTo() { 396 | val matrix1 = matrixOf( 397 | mutableListOf(1, 2, 3), 398 | mutableListOf(4, 5, 6), 399 | mutableListOf(7, 8, 9), 400 | ) 401 | val matrix2 = matrixOf( 402 | mutableListOf(1, 2), 403 | mutableListOf(3, 4) 404 | ) 405 | val matrix3 = matrixOf( 406 | mutableListOf(1, 2), 407 | mutableListOf(3, 4) 408 | ) 409 | 410 | val m1 = MatrixSize(1, 1) 411 | val m2 = MatrixSize(1, 2) 412 | val m3 = MatrixSize(1, 2) 413 | 414 | assertTrue(m1 < m2) 415 | assertTrue(m1 != m2) 416 | assertEquals(m2, m3) 417 | 418 | assertTrue(matrix1 > matrix2) 419 | assertTrue(matrix1 != matrix2) 420 | assertEquals(matrix2, matrix3) 421 | } 422 | 423 | @Test 424 | fun findInMatrix() { 425 | val matrix1 = matrixOf( 426 | mutableListOf(1, 2, 3), 427 | mutableListOf(4, 5, 6), 428 | mutableListOf(7, 8, 9), 429 | ) 430 | val e1: Int? = matrix1.find { 431 | it > 3 432 | } 433 | val e2: Int? = matrix1.find { 434 | it == 9 435 | } 436 | val e3: Int? = matrix1.find { 437 | it > 10 438 | } 439 | val e4: Int? = matrix1.find { 440 | (it in 21..49) || (it % 2 == 0 && it / 3 > 8) || (it == 30) 441 | } 442 | 443 | assertEquals(4, e1) 444 | assertEquals(9, e2) 445 | assertNull(e3) 446 | assertNull(e4) 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /library/src/commonTest/kotlin/more/math/other/OtherTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.other 2 | 3 | import more.math.MoreMath 4 | import kotlin.test.Test 5 | import kotlin.test.assertEquals 6 | import kotlin.test.assertFails 7 | 8 | class OtherTest { 9 | @Test 10 | fun testGCD() { 11 | assertEquals(6, MoreMath.gcd(48, 18)) 12 | assertEquals(1, MoreMath.gcd(13, 17)) 13 | assertEquals(12, MoreMath.gcd(36, 60)) 14 | assertEquals(0, MoreMath.gcd(0, 0)) 15 | } 16 | 17 | @Test 18 | fun testGCDNegativeInputs() { 19 | assertFails { 20 | MoreMath.gcd(-10, 5) 21 | } 22 | assertFails { 23 | MoreMath.gcd(10, -5) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /library/src/commonTest/kotlin/more/math/platform/MoreMathPlatformSpecificTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform 2 | 3 | import more.math.MoreMath 4 | import more.math.platform.model.BigFloat 5 | import more.math.platform.model.BigInt 6 | import kotlin.test.Test 7 | import kotlin.test.assertEquals 8 | 9 | class MoreMathPlatformSpecificTest { 10 | 11 | @Test 12 | fun bigFactorial() { 13 | val n = 22L 14 | val result = MoreMath.bigFactorial(n) 15 | assertEquals( 16 | expected = BigInt("1124000727777607680000").toString(), 17 | actual = result.toString() 18 | ) 19 | } 20 | 21 | @Test 22 | fun bigTetractionTest() { 23 | val result = MoreMath.bigTetraction(number = 2.0, other = 3) 24 | assertEquals(expected = BigFloat("16.0").toString(), actual = result.toString()) 25 | } 26 | } -------------------------------------------------------------------------------- /library/src/commonTest/kotlin/more/math/tetraction/TetractionTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.tetraction 2 | 3 | import more.math.MoreMath 4 | import kotlin.test.Test 5 | import kotlin.test.assertEquals 6 | 7 | class TetractionTest { 8 | @Test 9 | fun tetractionTest() { 10 | val result = MoreMath.tetraction(number = 2.0, other = 3) 11 | assertEquals(expected = 16.0, actual = result) 12 | } 13 | } -------------------------------------------------------------------------------- /library/src/commonTest/kotlin/more/math/vector/model/Vector2Test.kt: -------------------------------------------------------------------------------- 1 | package more.math.vector.model 2 | 3 | import more.math.vector2Of 4 | import kotlin.test.Test 5 | import kotlin.test.assertEquals 6 | 7 | class Vector2Test { 8 | 9 | @Test 10 | fun plusTest() { 11 | val vector1 = vector2Of(1, 2) 12 | val vector2 = vector2Of(3, 4) 13 | 14 | val res = vector1 + vector2 15 | assertEquals(expected = Vector2(x = 4, y = 6), actual = res) 16 | } 17 | 18 | @Test 19 | fun minusTest() { 20 | val vector1 = vector2Of(1, 2) 21 | val vector2 = vector2Of(3, 4) 22 | 23 | val res = vector1 - vector2 24 | assertEquals(expected = Vector2(x = -2, y = -2), actual = res) 25 | } 26 | 27 | @Test 28 | fun timesTest() { 29 | val vector1 = vector2Of(1, 2) 30 | val vector2 = vector2Of(3, 4) 31 | 32 | val res = vector1 * vector2 33 | assertEquals(expected = Vector2(x = 3, y = 8), actual = res) 34 | } 35 | 36 | @Test 37 | fun divTest() { 38 | val vector1 = vector2Of(1, 2) 39 | val vector2 = vector2Of(3, 4) 40 | 41 | val res = vector1 / vector2 42 | assertEquals(expected = Vector2(x = 1/3, y = 1/2), actual = res) 43 | } 44 | 45 | @Test 46 | fun length() { 47 | val vector1 = vector2Of(8.0, 6.0) 48 | 49 | val res = vector1.length() 50 | assertEquals(expected = 10.0, actual = res) 51 | } 52 | } -------------------------------------------------------------------------------- /library/src/iosMain/kotlin/more/math/native/model/NativeProvider.ios.kt: -------------------------------------------------------------------------------- 1 | package more.math.native.model 2 | 3 | import more.math.MoreMath 4 | import kotlin.math.pow 5 | 6 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 7 | internal actual class NativeProvider actual constructor() { 8 | 9 | actual fun nativeFactorial(number: Int): Long { 10 | return if (number == 0) 1L else number * nativeFactorial(number - 1) 11 | } 12 | 13 | actual fun nativeFactorial(number: Long): Long { 14 | return if (number == 0L) 1L else number * nativeFactorial(number - 1) 15 | } 16 | 17 | actual fun nativeAverage(vararg numbers: Int): Double { 18 | return numbers.average() 19 | } 20 | 21 | actual fun standardDeviation(vararg numbers: Double) : Double { 22 | val avg = numbers.average() 23 | val sumOfSquares = numbers.sumOf { (it - avg) * (it - avg) } 24 | return kotlin.math.sqrt(sumOfSquares / (numbers.size - 1)) 25 | } 26 | 27 | actual fun tetraction(number: Double, other: Int) : Double { 28 | return if (other == 0) { 29 | 1.0 30 | } else { 31 | number.pow(tetraction(number, other - 1)) 32 | } 33 | } 34 | 35 | actual fun gcd(a: Int, b: Int): Int { 36 | return if (b == 0) a else MoreMath.gcd(b, a % b) 37 | } 38 | } -------------------------------------------------------------------------------- /library/src/iosMain/kotlin/more/math/platform/model/BigFloat.ios.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 4 | actual class BigFloat actual constructor(value: String) { 5 | private val integerPart: BigInt 6 | private val fractionalPart: BigInt 7 | 8 | init { 9 | val parts = value.split(".") 10 | integerPart = BigInt(parts[0]) 11 | fractionalPart = if (parts.size > 1) BigInt(parts[1]) else BigInt("0") 12 | } 13 | 14 | actual companion object { 15 | actual val ZERO: BigFloat get() = BigFloat("0.0") 16 | actual val ONE: BigFloat get() = BigFloat("1.0") 17 | } 18 | 19 | actual fun add(other: BigFloat): BigFloat { 20 | val sumInteger = integerPart.add(other.integerPart) 21 | val sumFractional = fractionalPart.add(other.fractionalPart) 22 | 23 | return if (sumFractional.toString().length > fractionalPart.toString().length) { 24 | val newInteger = sumInteger.add(BigInt("1")) 25 | val newFractional = BigInt("0") 26 | BigFloat("$newInteger.$newFractional") 27 | } else { 28 | BigFloat("$sumInteger.$sumFractional") 29 | } 30 | } 31 | 32 | actual fun multiply(other: BigFloat): BigFloat { 33 | val productInteger = integerPart.multiply(other.integerPart) 34 | val productFractional = fractionalPart.multiply(other.fractionalPart) 35 | 36 | val combinedFractional = productInteger.add( 37 | productFractional 38 | ) 39 | 40 | return BigFloat("$combinedFractional.0") 41 | } 42 | 43 | actual override fun toString(): String { 44 | return "$integerPart.$fractionalPart" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /library/src/iosMain/kotlin/more/math/platform/model/BigInt.ios.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 4 | actual class BigInt actual constructor(value: String) { 5 | 6 | private val digits: List = value.reversed().map { it.digitToInt() } 7 | 8 | actual companion object { 9 | actual val ZERO: BigInt 10 | get() = BigInt("0") 11 | actual val ONE: BigInt 12 | get() = BigInt("1") 13 | } 14 | 15 | actual fun add(other: BigInt): BigInt { 16 | val maxLength = maxOf(this.digits.size, other.digits.size) 17 | val result = MutableList(maxLength + 1) { 0 } 18 | var carry = 0 19 | 20 | for (i in 0 until maxLength) { 21 | val thisDigit = if (i < this.digits.size) this.digits[i] else 0 22 | val otherDigit = if (i < other.digits.size) other.digits[i] else 0 23 | val sum = thisDigit + otherDigit + carry 24 | result[i] = sum % 10 25 | carry = sum / 10 26 | } 27 | 28 | if (carry > 0) { 29 | result[maxLength] = carry 30 | } 31 | 32 | return BigInt(result.reversed().dropWhile { it == 0 }.joinToString("") { it.toString() } 33 | .ifEmpty { "0" }) 34 | } 35 | 36 | actual fun multiply(other: BigInt): BigInt { 37 | val result = MutableList(this.digits.size + other.digits.size) { 0 } 38 | 39 | for (i in this.digits.indices) { 40 | for (j in other.digits.indices) { 41 | val product = this.digits[i] * other.digits[j] 42 | result[i + j] += product 43 | } 44 | } 45 | 46 | for (i in result.indices) { 47 | if (result[i] >= 10) { 48 | val carry = result[i] / 10 49 | result[i] %= 10 50 | if (i + 1 < result.size) { 51 | result[i + 1] += carry 52 | } else { 53 | result.add(carry) 54 | } 55 | } 56 | } 57 | 58 | return BigInt(result.reversed().dropWhile { it == 0 }.joinToString("") { it.toString() } 59 | .ifEmpty { "0" }) 60 | } 61 | 62 | actual override fun toString(): String { 63 | return digits.reversed().joinToString("") { it.toString() }.ifEmpty { "0" } 64 | } 65 | } -------------------------------------------------------------------------------- /library/src/iosTest/kotlin/more/math/MoreMathTest.kt: -------------------------------------------------------------------------------- 1 | package more.math 2 | 3 | import more.math.matrix.model.Matrix 4 | import more.math.matrix.model.determinant 5 | import more.math.matrix.model.transpose 6 | import more.math.vector.model.Vector2 7 | import kotlin.test.Test 8 | import kotlin.test.assertEquals 9 | 10 | class MoreMathTest { 11 | 12 | @Test 13 | fun test() { 14 | val matrix = matrixOf( 15 | listOf(1,2), 16 | listOf(3,4), 17 | ) 18 | val vector1 = vector2Of(1, 2) 19 | val vector2 = vector2Of(3, 4) 20 | 21 | assertEquals(expected = -2.0, actual = matrix.determinant()) 22 | assertEquals(expected = 6, MoreMath.factorial(3)) 23 | assertEquals(expected = 2.0, MoreMath.average(1, 2, 3)) 24 | assertEquals(expected = Matrix(listOf(1, 3), listOf(2, 4)), matrix.transpose()) 25 | assertEquals(expected = 16.0, MoreMath.tetraction(2.0, 3)) 26 | assertEquals(expected = Vector2(x = 4, y = 6), actual = (vector1 + vector2)) 27 | } 28 | } -------------------------------------------------------------------------------- /library/src/iosTest/kotlin/more/math/platform/model/Factorial_iosKtTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | import more.math.MoreMath 4 | import kotlin.test.Test 5 | import kotlin.test.assertEquals 6 | 7 | class Factorial_iosKtTest { 8 | 9 | @Test 10 | fun bigFactorial() { 11 | val n = 22L 12 | val result = MoreMath.bigFactorial(n) 13 | assertEquals( 14 | expected = BigInt("1124000727777607680000").toString(), 15 | actual = result.toString() 16 | ) 17 | } 18 | } -------------------------------------------------------------------------------- /library/src/jvmMain/kotlin/more/math/native/model/NativeProvider.jvm.kt: -------------------------------------------------------------------------------- 1 | package more.math.native.model 2 | 3 | import more.math.MoreMath 4 | import kotlin.math.pow 5 | 6 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 7 | internal actual class NativeProvider actual constructor() { 8 | 9 | actual fun nativeFactorial(number: Int): Long { 10 | return if (number == 0) 1L else number * nativeFactorial(number - 1) 11 | } 12 | 13 | //endregion 14 | actual fun nativeFactorial(number: Long): Long { 15 | return if (number == 0L) 1L else number * nativeFactorial(number - 1) 16 | } 17 | 18 | actual fun nativeAverage(vararg numbers: Int): Double { 19 | return numbers.average() 20 | } 21 | 22 | actual fun standardDeviation(vararg numbers: Double) : Double { 23 | val avg = numbers.average() 24 | val sumOfSquares = numbers.sumOf { (it - avg) * (it - avg) } 25 | return kotlin.math.sqrt(sumOfSquares / (numbers.size - 1)) 26 | } 27 | 28 | actual fun tetraction(number: Double, other: Int) : Double { 29 | return if (other == 0) { 30 | 1.0 31 | } else { 32 | number.pow(tetraction(number, other - 1)) 33 | } 34 | } 35 | 36 | actual fun gcd(a: Int, b: Int): Int { 37 | return if (b == 0) a else MoreMath.gcd(b, a % b) 38 | } 39 | } -------------------------------------------------------------------------------- /library/src/jvmMain/kotlin/more/math/platform/model/BigFloat.jvm.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | import java.math.BigDecimal 4 | 5 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 6 | actual class BigFloat actual constructor(value: String) { 7 | actual companion object { 8 | actual val ZERO: BigFloat get() = BigFloat(BigDecimal.ZERO.toString()) 9 | actual val ONE: BigFloat get() = BigFloat(BigDecimal.ONE.toString()) 10 | } 11 | 12 | private val bigFloat = BigDecimal(value) 13 | 14 | actual fun add(other: BigFloat): BigFloat { 15 | return BigFloat(this.bigFloat.add(other.bigFloat).toString()) 16 | } 17 | 18 | actual fun multiply(other: BigFloat): BigFloat { 19 | return BigFloat(this.bigFloat.multiply(other.bigFloat).toString()) 20 | } 21 | 22 | actual override fun toString(): String { 23 | return this.bigFloat.toString() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /library/src/jvmMain/kotlin/more/math/platform/model/BigInt.jvm.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | import java.math.BigInteger 4 | 5 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 6 | actual class BigInt actual constructor(value: String) { 7 | 8 | actual companion object { 9 | actual val ZERO: BigInt 10 | get() = BigInt("0") 11 | actual val ONE: BigInt 12 | get() = BigInt("1") 13 | } 14 | 15 | private val bigInt = BigInteger(value) 16 | 17 | actual fun add(other: BigInt): BigInt { 18 | return BigInt(this.bigInt.add(other.bigInt).toString()) 19 | } 20 | 21 | actual fun multiply(other: BigInt): BigInt { 22 | return BigInt(this.bigInt.multiply(other.bigInt).toString()) 23 | } 24 | 25 | actual override fun toString(): String { 26 | return this.bigInt.toString() 27 | } 28 | } -------------------------------------------------------------------------------- /library/src/jvmTest/kotlin/more/math/MoreMathTest.kt: -------------------------------------------------------------------------------- 1 | package more.math 2 | 3 | import more.math.matrix.model.Matrix 4 | import more.math.matrix.model.determinant 5 | import more.math.matrix.model.transpose 6 | import more.math.vector.model.Vector2 7 | import kotlin.test.Test 8 | import kotlin.test.assertEquals 9 | 10 | class MoreMathTest { 11 | 12 | @Test 13 | fun test() { 14 | val matrix = matrixOf( 15 | mutableListOf(1,2), 16 | mutableListOf(3,4), 17 | ) 18 | val vector1 = vector2Of(1, 2) 19 | val vector2 = vector2Of(3, 4) 20 | 21 | assertEquals(expected = -2.0, actual = matrix.determinant()) 22 | assertEquals(expected = 6, MoreMath.factorial(3)) 23 | assertEquals(expected = 2.0, MoreMath.average(1, 2, 3)) 24 | assertEquals(expected = Matrix(mutableListOf(1, 3), mutableListOf(2, 4)), matrix.transpose()) 25 | assertEquals(expected = 16.0, MoreMath.tetraction(2.0, 3)) 26 | assertEquals(expected = Vector2(x = 4, y = 6), actual = (vector1 + vector2)) 27 | } 28 | } -------------------------------------------------------------------------------- /library/src/jvmTest/kotlin/more/math/platform/model/Factorial_jvmKtTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | import more.math.MoreMath 4 | import kotlin.test.Test 5 | import kotlin.test.assertEquals 6 | 7 | class Factorial_jvmKtTest { 8 | 9 | @Test 10 | fun bigFactorial() { 11 | val n = 22L 12 | val result = MoreMath.bigFactorial(n) 13 | assertEquals(expected = BigInt("1124000727777607680000").toString(), actual = result.toString()) 14 | } 15 | } -------------------------------------------------------------------------------- /library/src/linuxX64Main/kotlin/more/math/native/model/NativeProvider.linuxX64.kt: -------------------------------------------------------------------------------- 1 | package more.math.native.model 2 | 3 | import more.math.MoreMath 4 | import kotlin.math.pow 5 | 6 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 7 | internal actual class NativeProvider actual constructor() { 8 | 9 | actual fun nativeFactorial(number: Int): Long { 10 | return if (number == 0) 1L else number * nativeFactorial(number - 1) 11 | } 12 | 13 | actual fun nativeFactorial(number: Long): Long { 14 | return if (number == 0L) 1L else number * nativeFactorial(number - 1) 15 | } 16 | 17 | actual fun nativeAverage(vararg numbers: Int): Double { 18 | return numbers.average() 19 | } 20 | 21 | actual fun standardDeviation(vararg numbers: Double) : Double { 22 | val avg = numbers.average() 23 | val sumOfSquares = numbers.sumOf { (it - avg) * (it - avg) } 24 | return kotlin.math.sqrt(sumOfSquares / (numbers.size - 1)) 25 | } 26 | 27 | actual fun tetraction(number: Double, other: Int) : Double { 28 | return if (other == 0) { 29 | 1.0 30 | } else { 31 | number.pow(tetraction(number, other - 1)) 32 | } 33 | } 34 | 35 | actual fun gcd(a: Int, b: Int): Int { 36 | return if (b == 0) a else MoreMath.gcd(b, a % b) 37 | } 38 | } -------------------------------------------------------------------------------- /library/src/linuxX64Main/kotlin/more/math/platform/model/BigFloat.linuxX64.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 4 | actual class BigFloat actual constructor(value: String) { 5 | private val integerPart: BigInt 6 | private val fractionalPart: BigInt 7 | 8 | init { 9 | val parts = value.split(".") 10 | integerPart = BigInt(parts[0]) 11 | fractionalPart = if (parts.size > 1) BigInt(parts[1]) else BigInt("0") 12 | } 13 | 14 | actual companion object { 15 | actual val ZERO: BigFloat get() = BigFloat("0.0") 16 | actual val ONE: BigFloat get() = BigFloat("1.0") 17 | } 18 | 19 | actual fun add(other: BigFloat): BigFloat { 20 | val sumInteger = integerPart.add(other.integerPart) 21 | val sumFractional = fractionalPart.add(other.fractionalPart) 22 | 23 | return if (sumFractional.toString().length > fractionalPart.toString().length) { 24 | val newInteger = sumInteger.add(BigInt("1")) 25 | val newFractional = BigInt("0") 26 | BigFloat("$newInteger.$newFractional") 27 | } else { 28 | BigFloat("$sumInteger.$sumFractional") 29 | } 30 | } 31 | 32 | actual fun multiply(other: BigFloat): BigFloat { 33 | val productInteger = integerPart.multiply(other.integerPart) 34 | val productFractional = fractionalPart.multiply(other.fractionalPart) 35 | 36 | val combinedFractional = productInteger.add( 37 | productFractional 38 | ) 39 | 40 | return BigFloat("$combinedFractional.0") 41 | } 42 | 43 | actual override fun toString(): String { 44 | return "$integerPart.$fractionalPart" 45 | } 46 | } -------------------------------------------------------------------------------- /library/src/linuxX64Main/kotlin/more/math/platform/model/BigInt.linuxX64.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") 4 | actual class BigInt actual constructor(value: String) { 5 | actual companion object { 6 | actual val ZERO: BigInt 7 | get() = BigInt("0") 8 | actual val ONE: BigInt 9 | get() = BigInt("1") 10 | } 11 | 12 | private val digits: List = value.reversed().map { it.digitToInt() } 13 | 14 | actual fun add(other: BigInt): BigInt { 15 | val maxLength = maxOf(this.digits.size, other.digits.size) 16 | val result = MutableList(maxLength + 1) { 0 } 17 | var carry = 0 18 | 19 | for (i in 0 until maxLength) { 20 | val thisDigit = if (i < this.digits.size) this.digits[i] else 0 21 | val otherDigit = if (i < other.digits.size) other.digits[i] else 0 22 | val sum = thisDigit + otherDigit + carry 23 | result[i] = sum % 10 24 | carry = sum / 10 25 | } 26 | 27 | if (carry > 0) { 28 | result[maxLength] = carry 29 | } 30 | 31 | return BigInt(result.reversed().dropWhile { it == 0 }.joinToString("") { it.toString() } 32 | .ifEmpty { "0" }) 33 | } 34 | 35 | actual fun multiply(other: BigInt): BigInt { 36 | val result = MutableList(this.digits.size + other.digits.size) { 0 } 37 | 38 | for (i in this.digits.indices) { 39 | for (j in other.digits.indices) { 40 | val product = this.digits[i] * other.digits[j] 41 | result[i + j] += product 42 | } 43 | } 44 | 45 | for (i in result.indices) { 46 | if (result[i] >= 10) { 47 | val carry = result[i] / 10 48 | result[i] %= 10 49 | if (i + 1 < result.size) { 50 | result[i + 1] += carry 51 | } else { 52 | result.add(carry) 53 | } 54 | } 55 | } 56 | 57 | return BigInt(result.reversed().dropWhile { it == 0 }.joinToString("") { it.toString() } 58 | .ifEmpty { "0" }) 59 | } 60 | 61 | actual override fun toString(): String { 62 | return digits.reversed().joinToString("") { it.toString() }.ifEmpty { "0" } 63 | } 64 | } -------------------------------------------------------------------------------- /library/src/linuxX64Test/kotlin/more/math/MoreMathTest.kt: -------------------------------------------------------------------------------- 1 | package more.math 2 | 3 | import more.math.matrix.model.Matrix 4 | import more.math.matrix.model.determinant 5 | import more.math.matrix.model.transpose 6 | import more.math.vector.model.Vector2 7 | import kotlin.test.Test 8 | import kotlin.test.assertEquals 9 | 10 | class MoreMathTest { 11 | 12 | @Test 13 | fun test() { 14 | val matrix = matrixOf( 15 | listOf(1,2), 16 | listOf(3,4), 17 | ) 18 | val vector1 = vector2Of(1, 2) 19 | val vector2 = vector2Of(3, 4) 20 | 21 | assertEquals(expected = -2.0, actual = matrix.determinant()) 22 | assertEquals(expected = 6, MoreMath.factorial(3)) 23 | assertEquals(expected = 2.0, MoreMath.average(1, 2, 3)) 24 | assertEquals(expected = Matrix(listOf(1, 3), listOf(2, 4)), matrix.transpose()) 25 | assertEquals(expected = 16.0, MoreMath.tetraction(2.0, 3)) 26 | assertEquals(expected = Vector2(x = 4, y = 6), actual = (vector1 + vector2)) 27 | } 28 | } -------------------------------------------------------------------------------- /library/src/linuxX64Test/kotlin/more/math/platform/model/Factorial_linuxX64KtTest.kt: -------------------------------------------------------------------------------- 1 | package more.math.platform.model 2 | 3 | import more.math.MoreMath 4 | import kotlin.test.Test 5 | import kotlin.test.assertEquals 6 | 7 | class Factorial_linuxX64KtTest { 8 | 9 | @Test 10 | fun bigFactorial() { 11 | val n = 22L 12 | val result = MoreMath.bigFactorial(n) 13 | assertEquals( 14 | expected = BigInt("1124000727777607680000").toString(), 15 | actual = result.toString() 16 | ) 17 | } 18 | } -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | } 7 | } 8 | 9 | dependencyResolutionManagement { 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | } 15 | 16 | rootProject.name = "more-math" 17 | include(":library") 18 | --------------------------------------------------------------------------------